Relation's need config too

Clint Byrum clint at ubuntu.com
Thu Jul 19 00:44:18 UTC 2012


I"ve run into this problem a few times, and I think there's a hole in
the current model that needs filling.

Recently Juan Negron and Tom Haddon submitted a really awesome set of
enhancements for the haproxy charm.

https://code.launchpad.net/~mthaddon/charms/precise/haproxy/mini-sprint-sf/+merge/114951

You can see there a lot of it was some nice abstraction for juju commands
which I think belongs in its own package. But thats not what I'm writing
about.

Tom and Juan felt that there needed to be a way to assign units of
a backend web service to servics, which were created by dumping raw
haproxy service configs into a config option.

They're right! But I have some deep concerns about the proposed method.

The merge proposal wants to add a parameter for the "provides" side of
the http interface which uniquely identifies which endpoint service this
web server wants to belong to. Right now most web services do something
like this in an http interface 'joined' hook:

relation-set hostname=$(unit-get private-address) port=$(config-get myport)

Then load balancers can just add this hostname/port combo to their
backend list to spray content to.

This presents issues though, because now we can't do multi-site on either
the load balancer *or* the backend. This is what the Host: header is
meant for.

The proposal has us passing in a yaml list of services to define:

  - service_name: website1
    service_host: "website1.foo.bar"
    service_port: 80
    service_options: [balance leastconn]
    server_options: maxconn 100
  - service_name: website2
    service_host: "website2.foo.bar"
    service_port: 80
    service_options: [balance leastconn]
    server_options: maxconn 100

Then each backend service which wants to be able to be bound to a specific
frontend would change their joined to do:

relation-set hostname=$(unit-get private-address) \
             port=$(config-get myport) \
             service_name=$(config-get my-service-name)

This feels *very* limiting. In order to close the loop we have to set
configs on both ends of a relationship, and the configs we have to set
are extremely complicated and error prone.

I think there's a need for relations to have config items, as this would
solve the problem far more elegantly.

I'd propose that it work like this:

* metadata.yaml:

requires:
  backends:
    interface: http
    options:
        endpoint-host:
            type: string
            description: Host to tie this traffic to.
        endpoint-port:
            type: int
            default: 80
            description: Port to tie this traffic to.

* relation-config-get

A new command, like config-get, but works in relation context only to
pick these up. Changes to relation config settings would fire the same
relation-changed hooks as changes on the units fire.

* juju add-relation , juju set-relation

Commands to set values for these per-relation. So

juju add-relation wp1 loadbalancer endpoint-host="website1.foo.bar"

For the simple case (one frontend, one backend) nothing would then change,
but this would also allow this:

juju add-relation wp2 loadbalancer endpoint-host="website2.foo.bar"

So now haproxy has become multi-site, which is crucial, as load balancing
is really quite a low-impact duty and one m1.small can handle thousands
of requests per second.

But what about wordpress? It could be multi-site too. So I think we
should also enable this:

juju add-relation wp1 loadbalancer endpoint-host="website1.foo.bar"
juju add-relation wp1 loadbalancer endpoint-host="website2.foo.bar"

Note that this is the same two services related, but with two different
relationships.  This would allow both haproxy and wordpress to be
multi-site.

This is not the only case of this. There are quite a few others. For
instance one might want to have multiple services accessing the same
mysql db. This makes more sense doing at relation time, and not with
config settings. The way it works now:

juju deploy mysql mydb
juju deploy service1 --set store-db=foo
juju deploy service2 --set service-db=foo
juju add-relation mydb service1
juju add-relation mydb service2

Versus

juju deploy mysql mydb
juju deploy service1
juju deploy service2
juju add-relation mydb service1 db=foo
juju add-relation mydb service2 db=foo

Thoughts?



More information about the Juju mailing list