Merge lp:~noise/tanuki-agent/tutorial-two-point-oh into lp:tanuki-agent

Proposed by Bret Barker
Status: Merged
Approved by: Bret Barker
Approved revision: 166
Merged at revision: 166
Proposed branch: lp:~noise/tanuki-agent/tutorial-two-point-oh
Merge into: lp:tanuki-agent
Diff against target: 489 lines (+475/-5)
2 files modified
docs/Makefile (+8/-5)
docs/tutorial2.md (+467/-0)
To merge this branch: bzr merge lp:~noise/tanuki-agent/tutorial-two-point-oh
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+278364@code.launchpad.net

Commit message

First pass of new tutorial for product-based auth, GM testing.

Description of the change

First pass of new tutorial for product-based auth, GM testing. Lots of TODO placeholders waiting until more code lands to use proper API endpoints and payloads.

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

LGTM. Made a change in my branch to make the agent print the list of accessible packages on registration like this tutorial says.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'docs/Makefile'
--- docs/Makefile 2015-11-04 15:57:51 +0000
+++ docs/Makefile 2015-11-23 20:04:49 +0000
@@ -1,5 +1,8 @@
1docs: tutorial.md notes.md api-reference.md agent-reference.md1%.html: %.md
2 ../env/bin/python3 build.py tutorial.md -o tutorial.html2 ../env/bin/python build.py -o $@ $<
3 ../env/bin/python3 build.py notes.md -o index.html3
4 ../env/bin/python3 build.py api-reference.md -o api-reference.html4all: $(addsuffix .html, $(basename $(wildcard *.md)))
5 ../env/bin/python3 build.py agent-reference.md -o agent-reference.html5 mv notes.html index.html
6
7clean:
8 rm -f *.html
69
=== added file 'docs/tutorial2.md'
--- docs/tutorial2.md 1970-01-01 00:00:00 +0000
+++ docs/tutorial2.md 2015-11-23 20:04:49 +0000
@@ -0,0 +1,467 @@
1Title: Getting Started with Ubuntu Product Integration
2Version: 20151119
3
4Ubuntu Product Integration is a system for automated integration
5testing of products built upon Ubuntu Core. Once configured, the system will
6monitor for updates to components of your product and run automated
7tests against target devices to determine if those updates are
8compatible, and allow you to control the flow of those updates to your
9customers.
10
11This tutorial will guide you step-by-step to create a snap for an application,
12define a product that includes that application, create a laboratory
13environment where integration tests for that product can run, and set up the
14system so that it automatically executes tests in that laboratory when new
15versions of the snap become available.
16
17The document is organized as follows:
18
19- **[What you will need:](#what-you-will-need)** A description of everything needed to complete the tutorial.
20- **[Lab setup:](#lab-setup)** Create and configure your own laboratory.
21- **[Gold Master Candidate Testing:](#gold-master-candidate-testing)** Testing of Product images composed from the stable channel, to support releasing Gold Master Images.
22- **[Product update testing:](#product-update-testing)** Testing of software updates prior to releasing them to customers.
23- **[First-boot update testing:](#first-boot-update-testing)** First-boot update scenario tesitng.
24
25<div class="panel panel-info">
26 <div class="panel-heading">
27 <h3 class="panel-title">Conventions</h3>
28 </div>
29 <div class="panel-body">
30 From time to time you will need to execute commands in a terminal. This
31 will be indicated using <code>this particular font and background color</code>,
32 normally on a separate line. This font will also be used to specify
33 filenames or any other cases where spelling matters.
34 </div>
35</div>
36
37
38## What you will need
39
40In order to complete this tutorial, you will need the following resources:
41
42- A host computer running [Ubuntu 14.04 (64-bit)](http://www.ubuntu.com/download/desktop), with an SD card reader and at least 6 GB free drive space.
43- A [Raspberry Pi 2 Model B](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/).
44- A 4GB (minimum) Micro SDHC card.
45- The host computer and Raspberry Pi connected on the same local ethernet network.
46- Access to the Internet from the host computer.
47- An optional serial USB cable, for debugging the RPI boot sequence.
48- Ubuntu One OAuth credentials. This will be covered below
49 during [Lab setup](#lab-setup).
50
51## Lab setup
52
53In order to run tests on your product, the system needs a host computer to serve as a
54bridge between your device and itself. This computer can be as simple as your
55desktop, or part of a full device laboratory.
56
57For the purposes of this tutorial, your desktop computer will serve as the
58host and you will use a Raspberry Pi as the product device. The host computer
59will run a small application called the Agent, which will communicate with
60Canonical's servers and manage integration tests on the Raspberry Pi.
61
62### Setting up the host computer
63
64On your host computer, first install the latest Snappy tools:
65
66 sudo add-apt-repository ppa:snappy-dev/tools
67 sudo apt-get update
68 sudo apt-get dist-upgrade
69 sudo apt-get install snappy-tools
70
71See [Snappy Getting Started Guide](https://developer.ubuntu.com/en/snappy/start/) for further details.
72
73Also install the software dependencies of the Agent:
74
75 sudo apt-get install python-requests pv
76
77Next you will install and configure the Agent. The most recent release of the Agent can always be found at [this location](https://spi.canonical.com/assets/agent.tar.gz).
78
79Download and install the Agent from your host computer as follows:
80
81 wget https://spi.canonical.com/assets/agent.tar.gz
82 tar -zxf agent.tar.gz
83 cd agent-binaries
84
85### Configuring the Agent
86
87Once the Agent is installed, you will need to create its configuration:
88
89TODO: make interactive-login generate default config as well to condense these steps
90
91 ./agent.py --default-config > config.ini
92
93The Agent authenticates using an Ubuntu One account . To use it, first create an
94[Ubuntu One account](https://login.ubuntu.com), then instruct the Agent to put
95your credentials in a configuration file:
96
97 ./agent.py --interactive-login config.ini
98
99<div class="panel panel-danger">
100 <div class="panel-heading">
101 <h3 class="panel-title">Security warning</h3>
102 </div>
103 <div class="panel-body">
104 The config file now has data (<code>consumer_secret</code>,
105 <code>token_secret</code>, and <code>token_key</code>) that are equivalent
106 to your password. You are responsible for storing this securely. The device
107 on which the Agent runs should be protected from unauthorized access.
108 </div>
109</div>
110
111
112Note: It is best practice to create a separate Ubuntu One account to use for your Agents, but we'll keep things simple for the purposes of this tutorial.
113
114### Testing Agent Authorization
115
116Before we proceed, let's ensure that your Agent is properly configured.
117
118 ./agent.py --register config.ini
119
120You should see a message similiar to the following:
121
122 [agent-queue] Registered at https://spi.canonical.com/...TODO
123 [] ... available products: [ ]
124
125Please double check your credentials and config.ini if you instead see an error similiar to the following:
126
127 {
128 "id": "unauthorized",
129 "message": "unauthorized"
130 }
131
132Once successfully registered, you can do a test run of the Agent:
133
134 ./agent.py -v --once config.ini
135
136If successful, this will produce output similar to the following:
137
138 [agent-queue] Registered at https://spi.canonical.com/... TODO
139 [agent-queue] No tests at https://spi.canonical.com/... TODO
140
141
142### Agent Provisioning Kit setup
143
144When the Agent receives tests from the server, it will try to run the commands to provision, set up, and run the tests.
145
146Together these scripts are called a "Provisioning Kit." A sample kit has been provided for this tutorial and as a starting point for your own projects.
147
148Edit ```config.ini``` and replace the following three fields:
149
150 provcommand = PATH_TO_AGENT/rpi2-sample-provkit/provision
151 setupcommand = PATH_TO_AGENT/rpi2-sample-provkit/setup
152 testcommand = PATH_TO_AGENT/rpi2-sample-provkit/runtest
153
154<div class="panel panel-warning">
155 <div class="panel-heading">
156 <h3 class="panel-title">Path sensitivity</h3>
157 </div>
158 <div class="panel-body">
159 The paths in <code>config.ini</code> must be absolute. Be sure to replace
160 the correct values.
161 </div>
162</div>
163
164
165### Raspberry Pi Setup
166
167Next, you will do a tgest provisioning to ensure your Raspberry Pi is setup properly.
168
169Download an already prepared sample image:
170
171 wget https://spi.canonical.com/assets/spi-test_pi2.img.xz
172
173Verify that the MD5 hash for the downloaded file matches the value shown below:
174
175 md5sum spi-test_pi2.img.xz
176 be7cf02999e576aa5eb76e7e85713812 spi-test_pi2.img.xz
177
178Because remotely flashing the Raspberry Pi is a feature still in active
179development, you will need to manually flash an SD card with the image.
180
181On the host machine, insert your SD card and determine which device it is
182(using ```df -h``` or other tools), then copy the image to your flash device:
183
184 xzcat spi-test_pi2.img | pv -s 4g | sudo dd of=/dev/sdX bs=32M
185 sync
186
187<div class="panel panel-danger">
188 <div class="panel-heading">
189 <h3 class="panel-title">Careful device selection</h3>
190 </div>
191 <div class="panel-body">
192 Be careful select the correct output device ('of' flag). The dd command
193 will offer no prompt, nor any protection from accidentally selecting your
194 hard drive.
195 </div>
196</div>
197
198This should take less than five minutes on most modern hardware. For additional instructions see [Getting started with a Raspberry Pi 2](https://developer.ubuntu.com/en/snappy/start/raspberry-pi-2/)
199
200When the flashing is complete, insert the SD card in your Raspberry Pi 2, power
201it on, and wait for it to boot. This typically takes less than a minute to
202complete.
203
204You can check whether it's online just by running:
205
206 ping webdm.local
207
208If the device is not accessible, you can troubleshoot by using a serial cable
209to [obtain a console on the Raspberry Pi](http://elinux.org/RPi_Serial_Connection).
210Note that the pins are the same for both versions of the Raspberry Pi.
211
212Alternatively, it may be that the image is not properly written. If the device
213fails to boot, put the SD card back in the host machine and write the image a
214second time. Verify the write was succesful by confirming that the following
215commands both return the same hash:
216
217 sudo dd if=/dev/sdX | head -c `stat -c "%s" spi-test_pi2.img` | pv -s `stat -c "%s" spi-test_pi2.img` | sha1sum
218 sha1sum spi-test_pi2.img
219
220
221## Creating a Product
222
223Now it is time to create your first product based on Ubuntu Core.
224
225A special type of snap called a "Gadget Snap" (sometimes refererred to as an "OEM Snap" in the current docs) is used to define the components of a device image, i.e. the software stack that powers your device. This includes specifying the base Ubuntu OS, the specific kernel to use, pre-installed applications, configuring hardware access, etc. See [Snappy OEM Documentation](https://developer.ubuntu.com/en/snappy/guides/oem/) for more details.
226
227Product Integration data is associated to a snap that you own, which may be either an Application or Gadget snap.
228
229For the purposes of this tutorial, you will use the reference ```rpi2.canonical``` gadget snap, and define your product based on an Application snap that you will own. For a real product you would create and manage your own Gadget snap as well.
230
231
232### Publishing an Application Snap
233
234We will start by having you publish a copy of our test application snap under your own MyApps account.
235
236First, download the test snap:
237 wget https://spi.canonical.com/assets/test-snap_1_all.snap
238
239Then you need to publish the snap under your MyApps account, as follows:
240
241- visit https://myapps.developer.ubuntu.com/dev/click-apps/upload/
242- drag and drop or otherwise select the example snap for upload
243- select "rolling-core" as the release
244- select "Developer Tools" as the department
245- select "GNU GPL v3" as the license
246- select "stable" as the channel
247- click "Submit to the Ubuntu store"
248
249If all went well, you should now see a page for the package, named like "test-snap.<username>". It will also state "Package status is Ready to Publish".
250
251Note: when you have a separate Ubuntu One user for your Agents, this is where you would share access to the Product, by sharing this "primary snap" with the Agent user.
252
253Note: Currently only private packages can be shared; public package sharing is under development.
254
255Now click the "Publish" button on the test-snap.<username> MyApps page. You will then see details showing that sequence 1 is published in all channels.
256
257### Defining the Product
258
259So far we have published the application snap, and can build an image with it pre-installed on top of the reference Rasberry Pi Gadget snap. Now we want to codify that arrangement by defining a Product in the Ubuntu Product Integration system.
260
261For the purposes of Product Integration testing, we are only concerned about the list of snaps that compose the product and some additional metadata decribed here:
262
263- ```name```: A short name to identify this Product, does not need to be unique.
264- ```release```: the Ubuntu Core release this products aims for (currently "15.04-core" or "rolling-core" as known by the Store)
265- ```base_image_reference```: optional (TODO: we should make it optional as it shouldn't be needed in all-snaps land anymore)
266- ```snaps```: the list of snap names that that comprise the product
267
268TODO: instruct them to export SSO_USERNAME or have the agent login step do it.
269
270TODO: sidebar about the api_example script, oauth, etc.
271
272In the agent directory on your computer (where you already authenticated during
273the [Lab setup](#lab-setup) above), issue the following HTTP request using the api_example.py helper script included with the Agent distribution:
274
275 ./api_example.py -X POST config.ini https://spi.canonical.com/products --data '{
276 "name": "test-product.$SSO_USERNAME",
277 "primary_snap_name": "test-snap.$SSO_USERNAME",
278 "release": "rolling-core",
279 "snaps": [
280 "ubuntu-core.canonical",
281 "pi2.canonical",
282 "webdm.canonical",
283 "test-snap.$SSO_USERNAME"
284 ]
285 }'
286
287output will contain the ID newly created product definition. You will need to export this as an environment variable for use in later API calls as follows:
288
289 export PRODUCT_ID=<id from output above>
290
291NOTE/TODO: we are not yet in all-snaps land so there is no kernel snap listed here.
292
293
294## Testing
295
296### Defining a Test
297
298Next you will define your test scenario via a Test Specification, with the following fields:
299
300- ```name```: a unique reference to identify tests and their results
301- ```product_id```: the unique id for the Product to test
302- ```channels```: a list of channel pairs. 'base' is the target/live channel generally, and 'update' is where the system will look for changes to trigger update test runs (covered in a later chapter).
303- ```test_payload```: information for the test to be run; in this case we put where the tests can be downloaded, and the command to trigger their execution
304
305Execute the following command to create this Test Specification:
306
307 ./api_example.py -X POST config.ini https://spi.canonical.com/products/$PRODUCT_ID/tests/specs --data '{
308 "name": "Tutorial Example Test Specification",
309 "product_id": "$PRODUCT_ID",
310 "channels": [ ['base': 'stable', 'update': 'edge'] ],
311 "test_payload": {
312 "tarball_url": "https://spi.canonical.com/assets/test_tarball2.tar.gz",
313 "test_cmd": "./test"
314 }
315 }'
316
317At this point the system is configured for your product and tests, and will supervise the Store for new versions of the snaps listed in your Product.
318
319TODO: note about not being in all-snaps land yet.
320
321
322### First test run
323
324TODO: system should trigger an initial GM test when the TestSpec is created.
325
326This test will be what is called a Gold Master Candidate test. It is triggered by a change to any of the component snaps in the monitored base channel defined in the Test Specification (stable in this case). The server will generate a Test Opportunity that instructs the provisioning kit script to compose a new GM candidate image from the Product's snaps, using the current sequences published in the base channel, provision that image, and then run tests against it. Later chapters of the tutorial will discuss additional testing scenarios.
327
328When we first defined our Test Specification, the system generated a new Test Opportunity to test the initial Gold Master Candidate image, since that combination of snaps had not yet been tested.
329
330Further GM tests will be automatically generated each time a component snap is updated in the base_channel.
331
332You can now run the agent to consume and run your first test. Run the following command:
333
334 ./agent.py -v --once config.ini
335
336As remote flashing of the Raspberry Pi is still in active development, the
337Raspberry Pi will need to be set up manually. After receiving the test to run,
338the Agent will output instructions explaining how to write the composed image
339to the device. Please follow those instructions and let the Agent know when
340you are ready by pressing the Enter key when prompted.
341
342After executing the test, the Agent will automatically retrieve the
343results and send them back to Canonical's servers. You can query these results
344in the next section, [Checking test progress and results](#checking-test-progress-and-results).
345
346
347### Checking test progress and results
348
349At any time, you can check the progress of tests generated in the
350system:
351
352TODO: we need a way to get our test opp id now that we are not manually triggering
353
354 ./api_example.py config.ini \
355 https://spi.canonical.com/products/$PRODUCT_ID/tests/events?test_opportunity_id=<test_opportunity_id>
356
357This produces a large JSON document containing all the events that relate to this test, for example:
358
359 {"event_logs": [
360 {
361 "updated_at": "2015-10-28T18:35:38.197000+00:00",
362 "events": [
363 {
364 "timestamp": "2015-10-28T18:34:56.614000+00:00",
365 "event_type": "QUEUED_FOR_AGENTS"
366 },
367 {
368 "platform": "spi-tutorial-raspi2",
369 "timestamp": "2015-10-28T18:34:58.988000+00:00",
370 "agent_group": "default",
371 "agent_id": "special",
372 "event_type": "PICKED_BY_AGENT"
373 },
374
375The ```event_type``` field will describe what happened, there is a timestamp, and extra information related
376to the event.
377
378It will also contain all the information relevant to the test, such as:
379
380 "queued_at": "2015-10-28T18:34:56.614000+00:00",
381 "test_spec_id": "2991e1d1-ae89-4afe-9801-140207526f21",
382 "spec_name": "Tutorial Example Test Specification",
383 "image_unique_id": "5e6ff512-87b6-427e-917d-615c4d1c0aec",
384
385As well as the test itself in the ```test_opportunity``` field.
386
387You can also check the results for an specific image (you can get the image
388id from the response of the query when you told the system above that a
389new snap revision was available):
390
391 ./api_example.py config.ini \
392 https://spi.canonical.com/products/$PRODUCT_ID/tests/events?image_unique_id=<unique_image_id>
393
394Or you may directly poll for specific results using filters, as below:
395
396 ./api_example.py config.ini https://spi.canonical.com/products/$PRODUCT_ID/results... TODO
397
398The result query will return a document describing one or more test results.
399Each will contain, among other things, the pass or failure status of the test
400run, as well as all related information such as the manifest, test spec, and so
401on:
402
403 {
404 "test_results": [
405 {
406 "created_at": "2015-10-28T18:34:56.614000+00:00",
407 "result_id": "7348dac1-9191-454c-93f0-cedb463aa477",
408 "test_status": "PASSED",
409 "manifest": {
410 ...
411 "test_spec": {
412 "platform": "spi-tutorial-raspi2",
413 "image_name": "tutorial-raspi2-image",
414 "test_payload": {
415 "test_cmd": "./test",
416 "tarball_url": "https://spi.canonical.com/assets/test_tarball.tar.gz"
417 },
418 "name": "Tutorial Example Test Specification",
419 "id": "2991e1d1-ae89-4afe-9801-140207526f21",
420 "created_at": "2015-10-28T16:42:42.989056",
421 "active": true
422 },
423 ...
424
425### Artifacts and logs
426
427Logs containing the output and errors of the provisioning kit's scripts are always stored in ```logs/```.
428Saving those logs and any artifacts the provisioning kit creates is the responsibility of your test command.
429
430The example provisioning kit will create a tarball with the test opportunity, the test result
431and all the provisioning kit logs, using this code:
432
433 ARTIFACTS = [
434 'spi_test_result.json',
435 'spi_test_opportunity.json',
436 'logs/provisioning.log',
437 'logs/setup.log',
438 'logs/testing.log'
439 ]
440
441 [...]
442
443 artifact_dir = os.getenv('ARTIFACT_DIR', '/tmp')
444 save_cmd = 'tar czvf {} {}'.format(
445 os.path.join(artifact_dir, test_opp['id'] + '.tar.gz'),
446 ' '.join(ARTIFACTS),
447 )
448 log.info('Saving artifact with %s', save_cmd)
449 subprocess.check_call(save_cmd, shell=True)
450
451Here, the tarball is stored in /tmp by default, but you can override it in the ```[environment]``` section of your ```config.ini```:
452
453 [environment]
454 ARTIFACT_DIR='/home/user/artifacts'
455
456#### Generated GM Candidate images
457
458The images that are generated by the provisioning kit may be stored for later use. For example if tests pass and you would like to release the image you will want to retrieve the binary from the Agent host.
459
460The sample provisioning kit stores the images in a ./images subdirector of the agent installation. You are responsible for handling transport of the images to a storage system of your choice.
461
462Note: the sample kit does not remove old images and they can quickly eat a lot of disk space.
463
464## Update Testing
465
466Future revisions of this document will cover update testing scenarios allowing for verifying updates before new versions are made available to customers
467

Subscribers

People subscribed via source and target branches

to all changes: