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:

https://review.openstack.org/#/c/106541/
https://review.openstack.org/#/c/106542/

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:

  outputs:
    host_entry:
      value:
        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:

      map:
      - 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 priority.

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.

+1

----


So this boils down to 4 features proposals:

1. Support extended attributes in ResourceGroup's members

Sorted.

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.

cheers,
Zane.

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@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev



_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

Reply via email to