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

Subscribers

People subscribed via source and target branches

to all changes: