Jira (PUP-4669) Varargs support for "args by name" calls to user defined resource types and EPP templates

2 views
Skip to first unread message

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:49:03 PM2/20/16
to puppe...@googlegroups.com
Henrik Lindberg updated an issue
 
Puppet / Improvement PUP-4669
Varargs support for "args by name" calls to user defined resource types and EPP templates
Change By: Henrik Lindberg
Summary: Varargs support for  (  "args by name" calls to user defined )  resource  types  ( and  possibly classes)  EPP templates
Add Comment Add Comment
 
This message was sent by Atlassian JIRA (v6.4.12#64027-sha1:e3691cc)
Atlassian logo

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:51:03 PM2/20/16
to puppe...@googlegroups.com
Henrik Lindberg updated an issue
UPDATED
----
For advanced use cases when defining resources e.g. a resource that delegates to one or more other resources it is of great value
to be able to capture parameter key-values instead of having to wrap such in a Hash since that makes it impossible to use the new resource as a drop in replacement for what it delegates to without having to update all logic where the replacement should be used (see examples below in comments). (There are also other variations on this theme).

Add support for varargs/captures in user defined resources by allowing the same syntax that is used for functions to specify that extra parameters are captured into a
 Hash  variable.  For functions this is an {{Array}}, and for "args by name" calls, this is a {{Hash}}.

{code:puppet}
define foo($a, $b, *$captured) {
}
{code}
In the body the variable $capture is always a {{Hash}}, it may be empty, or contain any keys the user has given. To restrict the keys, the user can type the parameter with a {{Hash\[String, <wanted-data-type>, min, max]}}, or a {{Struct}}. When using a {{Struct}} the keys can be pattern based (as defined in PUP-5942) and it is thus possible to type different pattern based parameters to different types.

{code:puppet}
define foo($a, $b, Struct[{Patter[/prefix_[a-z]+/] => Integer}], *$captured) {
}
{code}
See PUP-5942 for how to constraint the number of keys (from min required to max allowed).

The above definition of {{foo}} allows this:
{code:puppet}
foo { 'example':
  prefix_abc => 1,
  prefix_bcd => 2,
}
{code}

* The same varargs support should also be added to EPP templates since they use "args by name".
* This should *not* be added to classes (there is no way to do data binding, and parameters are part of the class' API and they are externally addressable).

A concern has been raised that adding "varargs" support is less declarative, but that is only a matter of perception - something that is defined by a pattern is just as specified as a concrete specification. What we cannot accept though is that the API of something changes depending on how it is used - this means that varargs support cannot be added to classes unless the varargs hash is made into a private variable in that class thus making it impossible to refer to its individual matching parameters from outside of the class body. The captured hash itself could be made public. Support for varargs in classes is therefore not included in this ticket. If wanted a new ticket should be opened, and that ticket  should depend on the ability to have private variables in class scopes.

ORIGINAL
----
Through roles and profiles, a pattern started to emerge where we write a wrapper {{define}}, for convenience, for better naming, both, or other reasons.

Example:

{code}
define http2https_vhost (
  $servername    = $name,
  $serveraliases = undef,
) {
  apache::vhost ( "http-${servername}":
    servername      => $servername,
    serveraliases   => $serveraliases,
    redirect_status => '301',
    redirect_dest   => "https://{servername}/",
  }

  apache::vhost ( "https-${servername}":
    servername => $servername,
    ssl_ca     => "/etc/ssl/certs/${servername}s.ca.pem",
    ssl_cert   => "/etc/ssl/certs/${servername}.crt.pem",
    ssl_key    => "/etc/ssl/private/${servername}.key.pem",
  }
}
{code}

This is nice and convenient for the most simple of cases. If we need more options from apache::vhost, we have to extend our wrapper profile.
Similarly, if apache::vhost changes, and new admins want to use those new options, we (or they!) have to touch our convenience wrappers.

We could do a gruesome hack, such as:

{code}
define http2https_vhost (
  $servername    = $name,
  $serveraliases = undef,
  $options       = {},
) {
  apache::vhost ( "http-${servername}":
    servername      => $servername,
    serveraliases   => $serveraliases,
    redirect_status => '301',
    redirect_dest   => "https://{servername}/",
  }

  create_resources('apache::vhost', { "https-${servername}" => $options}, {
    servername => $servername,
    ssl_ca     => "/etc/ssl/certs/${servername}s.ca.pem",
    ssl_cert   => "/etc/ssl/certs/${servername}.crt.pem",
    ssl_key    => "/etc/ssl/private/${servername}.key.pem",
  })
{code}

but the additional indirection through {{$options}} is hard to follow, and with more complex wrappers it's also hard to know where _our options_ start, and where _their options_ end… what is a default, what's being overwritten, etc…

I propose we introduce a syntax which helps us create such, or even more powerful wrappers, analogous to clojure's {{&rest}}:

{code}
define http2https_vhost (
  $servername    = $name,
  $serveraliases = undef,
  &rest,
) {
  apache::vhost ( "http-${servername}":
    servername      => $servername,
    serveraliases   => $serveraliases,
    redirect_status => '301',
    redirect_dest   => "https://{servername}/",
  }

  apache::vhost ( "https-${servername}":
    servername => $servername,
    docroot    => "/srv/web/${servername}/htdocs",
    ssl_ca     => "/etc/ssl/certs/${servername}s.ca.pem",
    ssl_cert   => "/etc/ssl/certs/${servername}.crt.pem",
    ssl_key    => "/etc/ssl/private/${servername}.key.pem",
    &rest,
  }
}
{code}

Example use:

{code}
http2https_vhost { 'blag.esotericsystems.at':
  fallbackresource => '/index.php'
}
{code}

This passes {{fallbackresource}} down to the second {{apache::vhost}}.

It might be useful to _filter_ for specific prefixes,

{code}
define tc_and_apache_vhost (
  $servername    = $name,
  $port          = 8080,
  &tomcat_,
  &apache_,
) {

  apache::vhost ( "https-${servername}":
    servername => $servername,
    ssl_ca     => "/etc/ssl/certs/${servername}s.ca.pem",
    ssl_cert   => "/etc/ssl/certs/${servername}.crt.pem",
    ssl_key    => "/etc/ssl/private/${servername}.key.pem",
    proxy_pass => '/',
    proxy_dest => "http://localhost:${port}/"
    &apache_,
  }

  tomcat::instance ( "tc-${servername}":
    application => $servername,
    proxy      => "https://servername:443/"
    &tomcat_,
  }
}
{code}

The idea here is that all parameters passed to a {{tc_and_apache_vhost}} that start with {{apache_}} would be routed into the {{apache::vhost}}, and all parameters that start with {{tomcat_}} would be routed to {{tomcat::instance}}.

I'm not sure yet, if they should be stripped of their prefix before being routed, or not.

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:52:03 PM2/20/16
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:52:05 PM2/20/16
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:54:03 PM2/20/16
to puppe...@googlegroups.com
Henrik Lindberg updated an issue
UPDATED
----
For advanced use cases when defining resources e.g. a resource that delegates to one or more other resources it is of great value
to be able to capture parameter key-values instead of having to wrap such in a Hash since that makes it impossible to use the new resource as a drop in replacement for what it delegates to without having to update all logic where the replacement should be used (see examples below in comments). (There are also other variations on this theme).

Add support for varargs/captures in user defined resources by allowing the same syntax that is used for functions to specify that extra parameters are captured into a variable. For functions this is an {{Array}}, and for "args by name" calls, this is a {{Hash}}.


{code:puppet}
define foo($a, $b, *$captured) {
}
{code}
In the body the variable $capture is always a {{Hash}}, it may be empty, or contain any keys the user has given. To restrict the keys, the user can type the parameter with a {{Hash\[String, <wanted-data-type>, min, max]}}, or a {{Struct}}. When using a {{Struct}} the keys can be pattern based (as defined in PUP-5942) and it is thus possible to type different pattern based parameters to different types.

{code:puppet}
define foo($a, $b, Struct[{Patter[/prefix_[a-z]+/] => Integer}], *$captured) {
}
{code}
See PUP-5942 for how to constraint the number of keys (from min required to max allowed).

The above definition of {{foo}} allows this:
{code:puppet}
foo { 'example':
  prefix_abc => 1,
  prefix_bcd => 2,
}
{code}

* The same varargs support should also be added to EPP templates since they use "args by name".
* This should *not* be added to classes (there is no way to do data binding, and parameters are part of the class' API and they are externally addressable).

A concern has been raised that adding "varargs" support is less declarative, but that is only a matter of perception - something that is defined by a pattern is just as specified as a concrete specification  when this is side effect free . What we cannot accept though is that the API of something changes depending on how it is used - this means that varargs support cannot be added to classes unless the varargs hash is made into a private variable in that class thus making it impossible to refer to its individual matching parameters from outside of the class body. The captured hash itself could be made public. Support for varargs in classes is therefore not included in this ticket. If wanted a new ticket should be opened, and that ticket  should depend on the ability to have private variables in class scopes.

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:55:03 PM2/20/16
to puppe...@googlegroups.com
A concern has been raised that adding "varargs" support is less declarative, but that is only a matter of perception - something that is defined by a pattern is just as specified as a concrete specification when this is side effect free. What we cannot accept though is that the API of something changes depending on how it is used - this means that varargs support cannot be added to classes unless the  expansion of the  varargs hash  into individual variables  is made  into a private variable in  such  that  those variables are private to the  class  body  thus making it impossible to refer to its individual matching parameters from outside of the class body. The captured hash itself could be made public. Support for varargs in classes is therefore not included in this ticket. If wanted a new ticket should be opened, and that ticket  should depend on the ability to have private variables in class scopes.

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:59:03 PM2/20/16
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
Feb 20, 2016, 11:59:04 PM2/20/16
to puppe...@googlegroups.com
Henrik Lindberg commented on Improvement PUP-4669
 
Re: Varargs support for "args by name" calls to user defined resource types and EPP templates

I have updated the description with I think should be implemented - for defines and EPP since they both use "args by name", and not for classes (at least not until we have implemented support for real private variables which requires a new implementation of Scope).

Julien Pivotto (JIRA)

unread,
Feb 29, 2016, 1:55:03 AM2/29/16
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
Sep 7, 2016, 6:12:26 PM9/7/16
to puppe...@googlegroups.com
Henrik Lindberg updated an issue
Change By: Henrik Lindberg
Team: Puppet Developer Support
This message was sent by Atlassian JIRA (v6.4.14#64029-sha1:ae256fe)
Atlassian logo

Henrik Lindberg (JIRA)

unread,
Apr 6, 2017, 5:48:02 PM4/6/17
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
May 15, 2017, 2:45:08 PM5/15/17
to puppe...@googlegroups.com

David Schmitt (JIRA)

unread,
Aug 3, 2017, 1:47:03 PM8/3/17
to puppe...@googlegroups.com

David Schmitt (JIRA)

unread,
Aug 3, 2017, 1:53:03 PM8/3/17
to puppe...@googlegroups.com

Henrik Lindberg (JIRA)

unread,
Feb 11, 2019, 12:28:05 PM2/11/19
to puppe...@googlegroups.com
Henrik Lindberg commented on Improvement PUP-4669
 
Re: Varargs support for "args by name" calls to user defined resource types and EPP templates

The interest in this seems to have peaked around 2015/2016. Now, 3-4 years later... I am closing this as a won't do.

I can imagine adding support for a `Like` data type in the future that would enable typing that a parameter accepts all parameters that a resource data type accepts as that would be helpful in the style of wrapping/delegation that is shown in the devco blog post above.

This message was sent by Atlassian JIRA (v7.7.1#77002-sha1:e75ca93)
Atlassian logo

Josh Cooper (JIRA)

unread,
Jul 15, 2019, 7:45:05 PM7/15/19
to puppe...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages