LEFT | RIGHT |
(no file at all) | |
| 1 Modified support for working with relations |
| 2 =========================================== |
| 3 |
| 4 Overview |
| 5 -------- |
| 6 |
| 7 This proposal pulls together a number of changes, backed by use cases |
| 8 from bug reports, for modifying Juju's current relation support as |
| 9 follows: |
| 10 |
| 11 * Enable working with relation ids. This includes adding a new |
| 12 environment variable `$JUJU_RELATION_ID` for relation hooks. |
| 13 |
| 14 * Enable `relation-get`, `relation-set`, `relation-list` to work in |
| 15 any hook on arbitrary relations, as specified by a relation name or |
| 16 unambiguously by relation id. |
| 17 |
| 18 * Add a new relation hook command, `relation-info`, for listing the |
| 19 relation ids associated with a service. |
| 20 |
| 21 * Fix a bug in `juju status` status for the scenario that a service |
| 22 has multiple established relations to consuming clients, each using |
| 23 the same relation name from the provider's perspective. This fix |
| 24 does introduce a backwards breaking change. |
| 25 |
| 26 |
| 27 Referring to relations |
| 28 ---------------------- |
| 29 |
| 30 A number of use cases in Juju require explicit reference to |
| 31 a relation. Such references should be supported by either using the |
| 32 relation name or the relation id: |
| 33 |
| 34 * The **relation name** is currently visible in Juju: it's a |
| 35 component of relation hook script names and corresponding |
| 36 `metadata.yaml`, and it's made available as the environment |
| 37 variable `$JUJU_RELATION` to relation hook scripts. |
| 38 |
| 39 * Currently the **relation id** is not visible to user scripts, but |
| 40 an internal version is used by Juju itself. With this proposal, a |
| 41 new environment variable, `$JUJU_RELATION_ID`, is defined for |
| 42 relation hooks. |
| 43 |
| 44 Relation ids are also sometimes required. This is because a service |
| 45 may **provide** an interface to multiple consuming services with the |
| 46 same relation name; each of these is a different established |
| 47 relation. For example the ``mysql`` service might provide the |
| 48 ``mysql`` interface to multiple consuming clients using the relation |
| 49 name ``db``. In this scenario, to specify a relation, it's necessary |
| 50 to use its relation id, not the relation name. |
| 51 |
| 52 Relation ids can be looked up by `relation-info`, a new hook command, |
| 53 as described in a subsequent section. |
| 54 |
| 55 To ensure readibility of this relation id, its format is specified to |
| 56 be ``<interface name>-<normalized internal relation |
| 57 id>``. (Normalization removes any padding zeros from the internal id.) |
| 58 This format was mentioned in `bug #767195 |
| 59 https://bugs.launchpad.net/juju/+bug/767195`_. |
| 60 |
| 61 Example: if the relation is associated with interface ``http`` and the |
| 62 specific interal relation id is ``relation-0000000042``, then the |
| 63 relation id is ``http-42``. |
| 64 |
| 65 As a consequence of this format change, the following restriction is |
| 66 made on relation names so they may always be distinguished from |
| 67 relation ids: a relation name is invalid if it ends with a hyphen |
| 68 followed by a number. |
| 69 |
| 70 Lastly, relation ids are never visible outside of relation hooks or |
| 71 relation hook commands. In particular, they are not seen in juju |
| 72 status output. |
| 73 |
| 74 |
| 75 Commands to work with relation settings and membership |
| 76 ------------------------------------------------------ |
| 77 |
| 78 The hook commands working with relation settings (`relation-get`, |
| 79 `relation-set`, and `relation-list`) are modified to enable their use |
| 80 with other relations than the implied relation and also for other |
| 81 hooks besides relation hooks:: |
| 82 |
| 83 relation-get [-r RELATION_NAME_OR_ID] [-|SETTING] [UNIT_NAME] |
| 84 |
| 85 relation-set [-r RELATION_NAME_OR_ID] |
| 86 [SETTING=VALUE [SETTING=VALUE ...]] [UNIT_NAME] |
| 87 |
| 88 relation-list [-r RELATION_NAME_OR_ID] [UNIT_NAME] |
| 89 |
| 90 The current behavior for these commands is to use the **implied |
| 91 relation**. This relation is the one in effect when the relation hook |
| 92 command is used in a relation hook. When not running in the context of |
| 93 a relation hook and its implied relation, it is necessary to specify a |
| 94 relation unambiguously. Note that there can be several possible |
| 95 implied relations for a given relation name, in which case the |
| 96 relation id *must* be used to specify the desired relation. |
| 97 |
| 98 Example. To get the user name from the relation named `db` from |
| 99 `mysql/0` from any hook:: |
| 100 |
| 101 user=`relation-get -r db user mysql/0` |
| 102 |
| 103 For the relational hook commands `relation-get`, `relation-set`, and |
| 104 `relation-list`, the following apply for non-implied relations when |
| 105 run from any hook: |
| 106 |
| 107 * Referring to a relation causes its hook context to be instantiated |
| 108 and cached. Subsequent reads of settings and the relation listing |
| 109 will return the same values for the duration of the hook calling |
| 110 these hook commands ("consistency"). |
| 111 |
| 112 * If a relation name is specified with `-r` and the relation cannot |
| 113 be precisely determined by this name, an error is raised stating |
| 114 "Ambiguous relation name". |
| 115 |
| 116 * If the relation does not exist at the time of read/caching, an |
| 117 error is raised stating "Relation not found". |
| 118 |
| 119 * If the hook exits with status code 0, the hook contexts are then |
| 120 written into ZooKeeper, one at a time. In between this write and |
| 121 the initial read, it is possible for the relation to have been |
| 122 removed. However, this will be quietly ignored, as is the current |
| 123 case in say exiting from `<relation name>-relation-changed`. |
| 124 |
| 125 (Implementation note: this current behavior is due to the fact |
| 126 that such nodes are not garbage-collected from ZooKeeper, even if |
| 127 the separate topology node itself has been changed.) |
| 128 |
| 129 Note this is different than the special context seen in for broken |
| 130 hooks for the implied relation, which do allow for reading the |
| 131 local unit settings, but returns an empty membership and prohibits |
| 132 other gets/sets. |
| 133 |
| 134 The current behavior for the implied relation of relation hooks is |
| 135 that the relation context is read prior to the invocation of the |
| 136 corresponding hook script; this proposal does not alter this behavior. |
| 137 |
| 138 |
| 139 New `relation-info` hook command |
| 140 -------------------------------- |
| 141 |
| 142 This proposal adds a new relation hook command to enumerate the |
| 143 relations a service participates in:: |
| 144 |
| 145 relation-info [--interface INTERFACE] [-r RELATION_NAME_OR_ID] |
| 146 [SERVICE_OR_UNIT_NAME] |
| 147 |
| 148 The output is a whitespace separated list of relation ids, if any. |
| 149 |
| 150 The service name is defaulted to the one for which this hook is |
| 151 running. Using unit name instead is allowed as a convenience: only the |
| 152 service portion is meaningful. In the case of using this command |
| 153 outside of a relation hook, the service or unit name must be |
| 154 specified. |
| 155 |
| 156 Notes: |
| 157 |
| 158 * Since the interface is encoded in the relation id, it is also |
| 159 possible to filter that as desired without using the `--interface` |
| 160 option. |
| 161 |
| 162 * `relation-info` taking a relation id with `-r` can be used to |
| 163 verify the continued existence of this relation id for the |
| 164 service. If `-r` is specified with a relation name, all |
| 165 corresponding relation ids for that name are returned. |
| 166 |
| 167 * For any hook, the data for the `relation-info` for the the |
| 168 corresponding default service is cached prior to calling the hook |
| 169 script. Calling `relation-info` for other services is read at that |
| 170 time and cached for the duration of the hook. |
| 171 |
| 172 Example. The keystone charm has the following definition in its |
| 173 `metadata.yaml`:: |
| 174 |
| 175 name: keystone |
| 176 summary: Proposed OpenStack identity service - Daemons |
| 177 description: | |
| 178 Proposed OpenStack identity service - Daemons |
| 179 provides: |
| 180 identity-service: |
| 181 interface: keystone |
| 182 keystone-service: |
| 183 interface: keystone |
| 184 requires: |
| 185 shared-db: |
| 186 interface: mysql-shared |
| 187 |
| 188 For a keystone service unit, `relation-info` can be used to create a |
| 189 list of relation ids that provide the keystone interface, then |
| 190 enumerated over to set the ready for each relation. Setting this value |
| 191 will then trigger `<relation name>-relation-changed` hooks for service |
| 192 units on the opposite side of these relations:: |
| 193 |
| 194 for relation_id in $(relation-info --interface=keystone); do |
| 195 relation-set -r $relation_id ready=true |
| 196 done |
| 197 |
| 198 In certain cases, this specific triggering could be initiated in this |
| 199 example as follows:: |
| 200 |
| 201 relation-set -r identity-service ready=true |
| 202 relation-set -r keystone-service ready=true |
| 203 |
| 204 However, the loop above with `relation-info` is more general. It will |
| 205 also not break if there were multiple clients using, for example, |
| 206 ``identity-service``. |
| 207 |
| 208 |
| 209 Relation information in ``juju status`` XXX |
| 210 --------------------------------------- |
| 211 |
| 212 For each service and each service unit, `juju status` currently |
| 213 outputs the ``relations`` key, which maps relation names to a service |
| 214 and a the state of the relation unit lifecycle. This is a bug in Juju: |
| 215 currently in `juju status`, the implementation will collect status |
| 216 information such that only the *last* relation iterated over for a |
| 217 service or unit is recorded for a given relation name. |
| 218 |
| 219 To fix this bug, the following backwards breaking changes are made: |
| 220 |
| 221 * For the relations key for each service, a list of dictionaries |
| 222 including the relation name and service name is output. Example:: |
| 223 |
| 224 relations: - {name: db, service: blog1} |
| 225 - {name: db, service: blog2} |
| 226 |
| 227 * For the relations key for each service unit, a list of dictionaries |
| 228 including the relation name and relation workflow state is |
| 229 output:: |
| 230 |
| 231 relations: - {name: db, service: blog1, state: up} |
| 232 - {name: db, service: blog2, state: down} |
| 233 |
| 234 Note that the relation id is not visible in this output. |
| 235 |
| 236 |
| 237 Use cases |
| 238 --------- |
| 239 |
| 240 The following use cases are derived from the feature requests of the |
| 241 following bug reports and mailing list discussion: |
| 242 |
| 243 * https://bugs.launchpad.net/juju/+bug/726467 |
| 244 * https://bugs.launchpad.net/juju/+bug/731532 |
| 245 * https://bugs.launchpad.net/juju/+bug/767195 |
| 246 * https://bugs.launchpad.net/juju/+bug/791370 |
| 247 * https://bugs.launchpad.net/juju/+bug/873116 |
| 248 * https://lists.ubuntu.com/archives/juju/2011-December/001125.html |
| 249 * https://lists.ubuntu.com/archives/juju/2012-February/001258.html |
| 250 |
| 251 |
| 252 Relation membership and settings |
| 253 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 254 |
| 255 `Bug #726467 https://bugs.launchpad.net/juju/+bug/726467`_ presents |
| 256 this scenario: the wordpress charm needs to check its dependent |
| 257 relations before negotiating settings with its haproxy relation. |
| 258 |
| 259 In this case, `relation-info` is not necessary, since wordpress |
| 260 already knows the relations it depends upon (mysql, maybe memcached, |
| 261 etc). The script working with haproxy needs to be able to use |
| 262 `relation-list` to get the members of each relation using the `-r` |
| 263 option, then likely use `relation-get` to check settings as well. |
| 264 |
| 265 |
| 266 Using relation hooks in nonrelational hooks |
| 267 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 268 |
| 269 `Bug #873116 https://bugs.launchpad.net/juju/+bug/873116`_ describes |
| 270 the scenario that the `upgrade-charm` hook needs to support a |
| 271 mechanism to "refresh the relationships" after deploying a new |
| 272 charm. Being able to use `relation-set` in any hook, on any relation |
| 273 for any unit, can support this. This functionality removes the need to |
| 274 remove and re-create relationships following `juju upgrade-charm`. |
| 275 |
| 276 |
| 277 Enumerating and querying relations |
| 278 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 279 |
| 280 `Bug #767195 https://bugs.launchpad.net/juju/+bug/767195`_ requests |
| 281 that hooks must be able to enumerate and query relations, as might be |
| 282 needed in an upgrade hook. The example presented is that the mysql |
| 283 service supports two instances of wordpress, say blog1 and |
| 284 blog2. Simply using the db relation name is not sufficient to |
| 285 disambiguate. |
| 286 |
| 287 The new `relation-info` command can be used:: |
| 288 |
| 289 relation_ids = `relation-info -r db` |
| 290 |
| 291 As detailed earlier, this command will return a whitespace separated |
| 292 list of relation ids, such as "mysql-1 mysql-2". The unique relation |
| 293 ids support `bug #791370 |
| 294 https://bugs.launchpad.net/juju/+bug/791370`_. |
| 295 |
| 296 The upgrade hook in this example can then query and otherwise work |
| 297 with these relations by their ids using `relation-get` (`bug #731532 |
| 298 https://bugs.launchpad.net/juju/+bug/731532`_), `relation-set`, and |
| 299 `relation-list` with the `-r` option specifying the desired |
| 300 relation. This might like look the following:: |
| 301 |
| 302 for relation_id in $(relation-info -r db); do |
| 303 do-something-with `relation-get -r $relation_id database` |
| 304 done |
| 305 |
| 306 The mailing list discussions also bring up this |
| 307 functionality. However, the aspect of out-of-band execution (not in |
| 308 any hook) is deferred to a possible future proposal. |
| 309 |
| 310 |
| 311 Implementation plan |
| 312 ------------------- |
| 313 |
| 314 Branches are required for the following features; these may be further |
| 315 subdivided: |
| 316 |
| 317 * Relation id support |
| 318 * Relation hook contexts can be looked up for a relation id, are |
| 319 cached, and properly written |
| 320 * Augment `relation-get`, `relation-set`, `relation-list` to take |
| 321 options (each of these will be separate branches) |
| 322 * Add `relation-info` command |
| 323 * Fix relation output in `juju status` |
LEFT | RIGHT |