| Adam Israel | c3e6c2e | 2018-03-01 09:31:50 -0500 | [diff] [blame] | 1 | Syncing Upstream Updates |
| 2 | ======================== |
| Adam Israel | dcdf82b | 2017-08-15 15:26:43 -0400 | [diff] [blame] | 3 | |
| 4 | Updating the facade and definitions code generated from the schema |
| 5 | to reflect changes in upstream Juju consists of two steps: |
| 6 | |
| 7 | * Creating a new `schemas-juju-<version>.json` file from the Juju code-base |
| 8 | * Generating the libjuju Python code from that schema |
| 9 | |
| 10 | Rarely, you may also have to add or update an override. |
| 11 | |
| 12 | |
| 13 | Creating a Schema File |
| 14 | ---------------------- |
| 15 | |
| 16 | First, you will need to fetch SchemaGen_ and a copy of the Juju source. |
| 17 | Once your copy of the Juju source is at the version you want to update to |
| 18 | (probably the `develop` branch, or a release tag) and you have updated |
| 19 | and reinstalled SchemaGen to reflect those changes, you just need to send |
| 20 | the output into a file in the libjuju repository: |
| 21 | |
| 22 | .. code:: bash |
| 23 | |
| 24 | schemagen > juju/client/schemas-juju-2.2-rc1.json |
| 25 | |
| 26 | The version number you use in the filename should match the upstream |
| 27 | version of Juju. You should then also move the `latest` pointer to |
| 28 | the new file: |
| 29 | |
| 30 | .. code:: bash |
| 31 | |
| 32 | rm juju/client/schemas-juju-latest.json |
| 33 | ln -s schemas-juju-2.2-rc1.json juju/client/schemas-juju-latest.json |
| 34 | |
| 35 | |
| 36 | Generating the Python Code |
| 37 | -------------------------- |
| 38 | |
| 39 | Once you have a new schema file, you can update the Python code |
| 40 | using the `client` make target: |
| 41 | |
| 42 | .. code:: bash |
| 43 | |
| 44 | make client |
| 45 | |
| 46 | You should expect to see updates to the `juju/client/_definitions.py` file, |
| 47 | as well as one or more of the `juju/client/_clientX.py` files, depending on |
| 48 | which facades were touched. |
| 49 | |
| 50 | |
| Adam Israel | b094366 | 2018-08-02 15:32:00 -0400 | [diff] [blame] | 51 | Integrating into the Object Layer |
| 52 | --------------------------------- |
| 53 | |
| 54 | Once the raw client APIs are synced, you may need to integrate any new or |
| 55 | changed API calls into the object layer, to provide a clean, Pythonic way |
| 56 | to interact with the model. This may be as simple as adding an optional |
| 57 | parameter to an existing model method, tweaking what manipulations, if any |
| 58 | the model method does to the data before it is sent to the API, or it may |
| 59 | require adding an entirely new model method to capture the new functionality. |
| 60 | |
| 61 | In general, the approach should be to make the interactions with the model |
| 62 | layer use the same patterns as when you use the CLI, just with Python idioms |
| 63 | and OO approaches. |
| 64 | |
| 65 | When trying to determine what client calls need to be made and what data to |
| 66 | be sent for a given Juju CLI action, it is very useful to add |
| 67 | `--debug --logging-config TRACE` to any Juju CLI command to view the full |
| 68 | conversation between the CLI client and the API server. For example: |
| 69 | |
| 70 | ``` |
| 71 | [johnsca@murdoch:~] $ juju deploy --debug --logging-config TRACE ./builds/test |
| 72 | 11:51:20 INFO juju.cmd supercommand.go:56 running juju [2.3.5 gc go1.10] |
| 73 | 11:51:20 DEBUG juju.cmd supercommand.go:57 args: []string{"/snap/juju/3884/bin/juju", "deploy", "--debug", "--logging-config", "TRACE", "./builds/test"} |
| 74 | 11:51:20 INFO juju.juju api.go:67 connecting to API addresses: [35.172.119.191:17070 172.31.94.16:17070 252.94.16.1:17070] |
| 75 | 11:51:20 TRACE juju.api certpool.go:49 cert dir "/etc/juju/certs.d" does not exist |
| 76 | 11:51:20 DEBUG juju.api apiclient.go:843 successfully dialed "wss://35.172.119.191:17070/model/a7317969-6dab-4ba4-844b-af3d661c228d/api" |
| 77 | 11:51:20 INFO juju.api apiclient.go:597 connection established to "wss://35.172.119.191:17070/model/a7317969-6dab-4ba4-844b-af3d661c228d/api" |
| 78 | ... |
| 79 | 11:51:20 INFO juju.cmd.juju.application series_selector.go:71 with the configured model default series "xenial" |
| 80 | 11:51:20 DEBUG httpbakery client.go:244 client do POST https://35.172.119.191:17070/model/a7317969-6dab-4ba4-844b-af3d661c228d/charms?revision=0&schema=local&series=xenial { |
| 81 | 11:51:21 DEBUG httpbakery client.go:246 } -> error <nil> |
| 82 | 11:51:21 INFO cmd deploy.go:1096 Deploying charm "local:xenial/test-0". |
| 83 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:225 -> {"request-id":3,"type":"Charms","version":2,"request":"CharmInfo","params":{"url":"local:xenial/test-0"}} |
| 84 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:120 <- {"request-id":3,"response":{"revision":0,"url":"local:xenial/test-0","config":{"test":{"type":"string","default":""}},"meta":{"name":"test","summary":"test","description":"test","subordinate":false,"series":["xenial"],"resources":{"dummy":{"name":"dummy","type":"file","path":"dummy.snap","description":"dummy snap"}},"min-juju-version":"0.0.0"},"actions":{}}} |
| 85 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:225 -> {"request-id":4,"type":"Charms","version":2,"request":"IsMetered","params":{"url":"local:xenial/test-0"}} |
| 86 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:120 <- {"request-id":4,"response":{"metered":false}} |
| 87 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:225 -> {"request-id":5,"type":"Resources","version":1,"request":"AddPendingResources","params":{"tag":"application-test","url":"local:xenial/test-0","channel":"","macaroon":null,"resources":[{"name":"dummy","type":"file","path":"dummy.snap","description":"dummy snap","origin":"store","revision":-1,"fingerprint":"","size":0}]}} |
| 88 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:120 <- {"request-id":5,"response":{"pending-ids":["c0ffdd92-da23-4fb2-8d41-d82d58423447"]}} |
| 89 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:225 -> {"request-id":6,"type":"Application","version":5,"request":"Deploy","params":{"applications":[{"application":"test","series":"xenial","charm-url":"local:xenial/test-0","channel":"","num-units":1,"config-yaml":"","constraints":{},"resources":{"dummy":"c0ffdd92-da23-4fb2-8d41-d82d58423447"}}]}} |
| 90 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:120 <- {"request-id":6,"response":{"results":[{}]}} |
| 91 | 11:51:21 TRACE juju.rpc.jsoncodec codec.go:123 <- error: read tcp 192.168.1.102:52168->35.172.119.191:17070: use of closed network connection (closing true) |
| 92 | 11:51:21 DEBUG juju.api monitor.go:35 RPC connection died |
| 93 | 11:51:21 INFO cmd supercommand.go:465 command finished |
| 94 | ``` |
| 95 | |
| 96 | Note that this will contain login information (which has been removed from the above). |
| 97 | |
| 98 | |
| Adam Israel | dcdf82b | 2017-08-15 15:26:43 -0400 | [diff] [blame] | 99 | Overrides |
| 100 | --------- |
| 101 | |
| 102 | It should be quite rare, but occasionally the generated Python code does |
| 103 | not capture all of the logic needed to properly parse the output from the API |
| 104 | or may otherwise need some small amount of tweaking. This is what the |
| 105 | `juju/client/overrides.py` file is for. An example of this is the `Number` |
| 106 | type, which isn't standard JSON and must be parsed slightly differently. |
| 107 | |
| 108 | At the top of that file are two lists, `__all__` and `__patches__`. The |
| 109 | former replaces entire class implementations, while the latter patches |
| 110 | the attributes of the override classes into the matching generated class, |
| 111 | leaving the rest of the generated class untouched. |
| 112 | |
| 113 | |
| 114 | .. _SchemaGen: https://github.com/juju/schemagen |