[openstack-dev] [tripleo] When to use parameters vs parameter_defaults

Jay Dobies jason.dobies at redhat.com
Mon Nov 16 19:34:08 UTC 2015


> Hi all,
>
> I wanted to start some discussion re $subject, because it's been apparrent
> that we have a lack of clarity on this issue (and have done ever since we
> started using parameter_defaults).
>
> Some context:
>
> - Historically TripleO has provided a fairly comprehensive "top level"
>    parameters interface, where many per-role and common options are
>    specified, then passed in to the respective ResourceGroups on deployment
>
> https://git.openstack.org/cgit/openstack/tripleo-heat-templates/tree/overcloud-without-mergepy.yaml#n14
>
> The nice thing about this approach is it gives a consistent API to the
> operator, e.g the parameters schema for the main overcloud template defines
> most of the expected inputs to the deployment.
>
> The main disadvantage is a degree of template bloat, where we wire dozens
> of parameters into each ResourceGroup, and from there into whatever nested
> templates consume them.
>
> - When we started adding interfaces (such as all the OS::TripleO::*ExtraConfig*
>    interfaces, there was a need to enable passing arbitrary additional
>    values to nested templates, with no way of knowing what they are (e.g to
>    enable wiring in third-party pieces we have no knowledge of or which
>    require implementation-specific arguments which don't make sense for all
>    deployments.
>
> To do this, we made use of the heat parameter_defaults interface, which
> (unlike normal parameters) have global scope (visible to all nested stacks,
> without explicitly wiring in the values from the parent):
>
> http://docs.openstack.org/developer/heat/template_guide/environment.html#define-defaults-to-parameters
>
> The nice thing about this approach is its flexibility, any arbitrary
> values can be provided without affecting the parent templates, and it can
> allow for a terser implementation because you only specify the parameter
> definition where it's actually used.
>
> The main disadvantage of this approach is it becomes very much harder to
> discover an API surface for the operator, e.g the parameters that must be
> provided on deployment by any CLI/UI tools etc.  This has been partially
> addressed by the new-for-liberty nested validation heat feature, but
> there's still a bunch of unsolved complexity around how to actually consume
> that data and build a coherent consolidated API for user interaction:
>
> https://github.com/openstack/heat-specs/blob/master/specs/liberty/nested-validation.rst
>
> My question is, where do we draw the line on when to use each interface?
>
> My position has always been that we should only use parameter_defaults for
> the ExtraConfig interfaces, where we cannot know what reasonable parameters
> are.  And for all other "core" functionality, we should accept the increased
> template verbosity and wire arguments in from overcloud-without-mergepy.
>
> However we've got some patches which fall into a grey area, e.g this SSL
> enablement patch:
>
> https://review.openstack.org/#/c/231930/46/overcloud-without-mergepy.yaml
>
> Here we're actually removing some existing (non functional) top-level
> parameters, and moving them to parameter_defaults.
>
> I can see the logic behind it, it does make the templates a bit cleaner,
> but at the expense of discoverablility of those (probably not
> implementation dependent) parameters.
>
> How do people feel about this example, and others like it, where we're
> enabling common, but not mandatory functionality?
>
> In particular I'm keen to hear from Mainn and others interested in building
> UIs on top of TripleO as to which is best from that perspective, and how
> such arguments may be handled relative to the capabilities mapping proposed
> here:
>
> https://review.openstack.org/#/c/242439/
>
> Thanks!
>
> Steve
>

(in re-reading this, I realize I'm not providing an answer to how I feel 
about the example as I am adding some more thoughts in general; 
apologies for that)

I see there being a few issues with the current approach:

- I'll get this one out of the way first, even though it's not the 
biggest issue. The name 'parameter_defaults' tends to confuse new 3rd 
party integrators since we're not using it as a default per se. I 
understand from Heat's point of view it's defaulting a parameter value, 
but from the user's standpoint, they are setting an actual value to be 
used. Perhaps this can be solved with better docs, and I largely mention 
it because I can see most of what you wrote in here turning into 
documentation, so it'll be good to have it mentioned.

- Back to the point of your e-mail, there are two ways to view it.

-- If you define too few parameters at the top level, you end up with a 
lot of comments like the following inside of nested templates:

ControlPlaneSubnetCidr: # Override this via parameter_defaults

or

# To be defined via a local or global environment in parameter_defaults
   rhel_reg_activation_key:
     type: string

There are other examples too, but the thing to note is that we've so far 
been pretty good about adding those comments. It's not a programmatic 
marker, which may be a problem for a UX, but at least the information is 
there when someone is reading the templates.

Like Steve mentioned, there has been work in Heat to analyze the larger 
context of the parent and nested templates to help make that information 
programmatically accessible.

-- If you have too many of the top-level parameters, you end up with 
boilerplate code inside the nested templates with parameters that it 
doesn't care to use. I couldn't immediately find any examples of that in 
THT, though I think there are a few.

More concerning is that the addition of new top-level parameters breaks 
backward compatibility. Unless I'm mistaken, if we pass a parameter to a 
nested stack, the stack *must* be defined to take the parameter. There's 
no way to have Heat ignore extraneous values.

There's also no versioning scheme, so we can't do something like:

   resource_def:
       type: OS::TripleO::ObjectStorage
       properties:
         KeyName: {get_param: KeyName} # as of version 1.2

Ignore the syntax there; my point is, the top-level (where "top" means 
anything with a nested resource) resources act as an API, but you only 
get to use the current version.

Since the bulk of our integrations are done through ExtraConfig, for now 
we only have to be really careful in changing the parameters to those 
resources. At some point, we'll need to start being really careful about 
other nested resource interfaces as well if we want to support extension 
at those levels

- One more example, and I'm not at all picking on this one particular 
implementation, but we have:

parameter_defaults:
   # Required to fill in:
   NeutronBigswitchRestproxyServers:
   NeutronBigswitchRestproxyServerAuth:

   # Optional:
   # NeutronBigswitchRestproxyAutoSyncOnFailure:
   # NeutronBigswitchRestproxyConsistencyInterval:


I 100% understand why it's done this way given the current template 
constraints. But it's difficult to fashion a UX around this when we 
don't actually capture the required/optional nature of these parameters 
in a way that's consumable. If we look at the template, they are all 
"optional" (in the sense that they are defaulted). But it shows how the 
parameter_defaults is a bit more of a workaround than a formal concept 
of how to dynamically add parameters.

- I do like the capabilities map concept. From the beginning I thought 
this was information that Tuskar would carry outside of the templates 
themselves. I don't see a problem with acknowledging the templates don't 
want to carry everything a UI would need and supplying that data 
elsewhere. It's possible that the sorts of extra information I described 
in the last bullet point are carried either in a similar fashion or in a 
comment convention that Tuskar knows how to interpret.



More information about the OpenStack-dev mailing list