[openstack-dev] [Heat] [TripleO] Extended get_attr support for ResourceGroup

Zane Bitter zbitter at redhat.com
Sat Jul 12 04:41:33 UTC 2014

On 11/07/14 09:37, Tomas Sedovic wrote:
> Hi all,
> This is a follow-up to Clint Byrum's suggestion to add the `Map`
> intrinsic function[0], Zane Bitter's response[1] and Randall Burt's
> addendum[2].
> Sorry for bringing it up again, but I'd love to reach consensus on this.
> The summary of the previous conversation:

Please keep bringing it up until you get a straight answer ;)

> 1. TripleO is using some functionality currently not supported by Heat
> around scaled-out resources
> 2. Clint proposed a `map` intrinsic function that would solve it
> 3. Zane said Heat have historically been against a for-loop functionality
> 4. Randall suggested ResourceGroup's attribute passthrough may do what
> we need
> I've looked at the ResourceGroup code and experimented a bit. It does do
> some of what TripleO needs but not all.

Many thanks for putting this together Tomas, this is exactly the kind of 
information that is _incredibly_ helpful in knowing what sort of 
features we need in HOT. Fantastic work :)

> Here's what we're doing with our scaled-out resources (what we'd like to
> wrap in a ResourceGroup or similar in the future):
> 1. Building a coma-separated list of RabbitMQ nodes:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/overcloud-source.yaml#L642
> This one is easy with ResourceGroup's inner attribute support:
>      list_join:
>      - ", "
>      - {get_attr: [controller_group, name]}
> (controller_group is a ResourceGroup of Nova servers)
> 2. Get the name of the first Controller node:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/overcloud-source.yaml#L339
> Possible today:
>      {get_attr: [controller_group, resource.0.name]}
> 3. List of IP addresses of all controllers:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/overcloud-source.yaml#L405
> We cannot do this, because resource group doesn't support extended
> attributes.
> Would need something like:
>      {get_attr: [controller_group, networks, ctlplane, 0]}
> (ctlplane is the network controller_group servers are on)

I was going to give an explanation of how we could implement this, but 
then I realised a patch was going to be easier:


> 4. IP address of the first node in the resource group:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/swift-deploy.yaml#L29
> Can't do: extended attributes are not supported for the n-th node for
> the group either.

I believe this is possible today using:

   {get_attr: [controller_group, resource.0.networks, ctlplane, 0]}

> This can be solved by `get_resource` working with resource IDs:
>     get_attr:
>     - {get_attr: [controller_group, resource.0]}
>     - [networks, ctlplane, 0]
> (i.e. we get the server's ID from the ResourceGroup and change
> `get_attr` to work with the ID's too. Would also work if `get_resource`
> understood IDs).

This is never going to happen.

Think of get_resource as returning an object whose string representation 
is the UUID of the named resource (get_attr is similar, but returning 
attributes instead). It doesn't mean that having the UUID of a resource 
is the same as having the resource itself; the UUID could have come from 
anywhere. What you're talking about is a radical departure from the 
existing, very simple but extremely effective, model toward something 
that's extremely difficult to analyse with lots of nasty edge cases. 
It's common for people to think they want this, but it always turns out 
there's a better way to achieve their goal within the existing data model.

> Alternatively, we could extend the ResourceGroup's get_attr behaviour:
>      {get_attr: [controller_group, resource.0.networks.ctlplane.0]}
> but the former is a bit cleaner and more generic.

I wrote a patch that implements this (and also handles (3) above in a 
similar manner), but in the end I decided that this:

   {get_attr: [controller_group, resource.0, networks, ctlplane, 0]}

would be better than either that or the current syntax (which was 
obviously obscure enough that you didn't discover it). My only 
reservation was that it might make things a little weird when we have an 
autoscaling API to get attributes from compared with the dotted syntax 
that you suggest, but I soon got over it ;)

> ---
> That was the easy stuff, where we can get by with the current
> functionality (plus a few fixes).
> What follows are examples that really need new intrinsic functions (or
> seriously complicating the ResourceGroup attribute code and syntax).
> 5. Building a list of {ip: ..., name: ...} dictionaries to configure
> haproxy:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/overcloud-source.yaml#L478
> This really calls for a mapping/for-each kind of functionality. Trying
> to invent a ResourceGroup syntax for this would be perverse.
> Here's what it could look like under Clint's `map` proposal:
>      map:
>      - ip: {get_attr: [{get_resource: "$1"}, networks, ctlplane, 0]
>        name: {get_attr: [{get_resource: "$1"}, name]}
>      - {get_attr: [compute_group, refs]}

This has always been the tricky one :D

IMHO the real problem here is that we're trying to collate the data at 
the point where it is consumed, not the point where it is produced. It's 
not like we were just given a big blob of data and now have to somehow 
extract the useful parts; we produced it ourselves by combining data 
from the scaled units. If we didn't get the right data, we have only 
ourselves to blame ;)

So if the provider template that defines e.g. a compute node contains 
the section:

         ip: {get_attr: [compute_server, networks, ctlplane, 0]}
         name: {get_attr: [compute_server, name]}

Then in your main template all you need to do is:

   {getattr: [compute_group, host_entry]}

to get the list of {ip: ..., name: ...} dicts. (As a bonus, this is 
about as straightforward to read as I can imagine it ever getting.)

Note that you *will* want to be using a provider template as the scaled 
unit _anyway_, because each compute_server will have associated software 
deployments and quite possibly a bunch of other resources that need to 
be in the scaled unit.

There is one aspect of this that probably doesn't work yet: originally 
outputs and attributes were only allowed to be strings. We changed that 
for attributes, but probably not yet for outputs (even though outputs of 
provider templates become attributes of the facade resource). But that 
should be easy to fix. (And if your data can be returned as a string, it 
should already work.)

> (this relies on `get_resource` working with resource IDs. Alternatively,

That's a show-stopper right out of the gate. If we implemented the map 
thing you would have to use something like:

       - ip:$1
         name: $2
       - {get_attr: [compute_group, networks, ctlplane, 0]}
       - {get_attr: [compute_group, name]}

(which is IMHO about 50 times easier to read anyway.)

> we could have a `resources` attribute for ResourceGroup that returns
> objects that can be used with get_attr.

Sounds increasingly hacky.

> 6. Building the /etc/hosts file
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/overcloud-source.yaml#L585
> Same as above, but also joining two lists together.
> We can use nested {list_join: ["\n", [...]} just as we're doing now, but
> having a `concat_list` function would make this and some other cases
> shorter and clearer.

I'm not strongly opposed to this one. We were trying to keep the number 
of functions in HOT as small as possible... and it does look like it is 
possible to do what you need already... so I would treat this as a low 

> 7. Building the list of Swift devices:
> https://github.com/openstack/tripleo-heat-templates/blob/a7f2a2c928e9c78a18defb68feb40da8c7eb95d6/swift-deploy.yaml#L23
> In addition to the abowe, we're adding a single element at the beginning
> of a list.
> Asking for a `cons` support is pushing it, right? ;-)

lol, Greenspun's Tenth Law in action right here :D

> We could just wrap that in a list and use `concat_list` or keep using
> nested `list_join`s as in the /etc/hosts case.


> ----
> So this boils down to 4 features proposals:
> 1. Support extended attributes in ResourceGroup's members


> 2. Allow a way to use a Resource ID (e.g. what you get by {get_attr:
> [ResourceGroup, refs]} or {get_attr: [ResourceGroup, resource.0]}) with
> existing intrinsic functions (get_resource, get_attr)

No dice, but (1) solves the problem anyway.

> 3. A `map` intrinsic function that turns a list of items to another list
> by doing operations on each item

There may be a better solution available to us already, so IMO 
investigate that first. If that turns out not to be the case then we'll 
need to reach a consensus on whether map is something we want.

> 4. A `concat_list` intrinsic function that joins multiple lists into one.

Low priority.

> I think the first two are not controversial. What about the other two?
> I've shown you some examples where we would find a good use in the
> TripleO templates. The lack of `map` actually blocks us from going all-Heat.

Hopefully that's not actually the case.

> The alternative would be to say that this sort of stuff to be done
> inside the instance by os-apply-config et al. It would complicate things
> for TripleO, but oh well.

It seems to me that the alternative is not necessarily to modify 
os-apply-config, but rather to provide a software config with a script 
that converts the data from whatever format Heat can supply to whatever 
format is needed by the application. Although I don't think it's even 
required in the specific case you mention, I find that a much better 
answer for the general case than turning the template format into the 
JSON equivalent of XSLT ;)

> Either way, can we come to a clear answer? I would love to convert our
> templates to 100% Natural Heat during Juno and I'm willing to put my
> time towards coding the necessary features.

+1 that is a worthy goal and we appreciate your contributions toward 
reaching it.


> Tomas
> [0]:
> http://lists.openstack.org/pipermail/openstack-dev/2014-February/027536.html
> [1]:
> http://lists.openstack.org/pipermail/openstack-dev/2014-April/031944.html
> [2]:
> http://lists.openstack.org/pipermail/openstack-dev/2014-April/032074.html
> _______________________________________________
> OpenStack-dev mailing list
> OpenStack-dev at lists.openstack.org
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

More information about the OpenStack-dev mailing list