Merge ~pwlars/testflinger-cli:offer-cancel-job into testflinger-cli:master

Proposed by Paul Larson
Status: Merged
Approved by: Paul Larson
Approved revision: a2ec8186917cfce50803767a22aa69dd8c85c24c
Merged at revision: ee433cb7d8844b0628c210c76c03929f37774201
Proposed branch: ~pwlars/testflinger-cli:offer-cancel-job
Merge into: testflinger-cli:master
Diff against target: 83 lines (+37/-19)
1 file modified
testflinger_cli/__init__.py (+37/-19)
Reviewer Review Type Date Requested Status
Lukas Waymann (community) Approve
Sheila Miguez (community) Approve
Review via email: mp+394263@code.launchpad.net

Description of the change

Small improvement from a suggested Lukas had today - when a user presses ctrl-C while polling the output, we can offer to either let them cancel the job or keep the job running in the background. I also added an option to let it just continue running the job and polling. Here's what a session looks like, showing all three selections:

13:55 $ testflinger reserve

Which queue do you want to use? ('?' to list) rpi3bp

Enter the name of the image you want to use or URL for a valid image starting with http(s)://... ('?' to list) core20-armhf-beta

Enter the ssh key(s) you wish to use: (ex: lp:userid, gh:userid) lp:pwlars

The following yaml will be submitted:
job_queue: rpi3bp
provision_data:
    url: http://cdimage.ubuntu.com/ubuntu-core/20/dangerous-beta/pending/ubuntu-core-20-armhf+raspi.img.xz
reserve_data:
    ssh_keys:
    - lp:pwlars
Proceed? (Y/n)
Job submitted successfully!
job_id: 17e8e062-6aa8-40f5-b23d-a02830f7b08d
This job is waiting on a node to become available.
Jobs ahead in queue: 0
**************************************************

* Starting testflinger setup phase on rpi3bp-004 *

**************************************************

Cleaning up container if it exists...
Error: No such container: rpi3bp004

******************************************************

* Starting testflinger provision phase on rpi3bp-004 *

******************************************************
^C
Cancel job 17e8e062-6aa8-40f5-b23d-a02830f7b08d before exiting (y)es/(N)o/(c)ontinue? c
2020-11-20 19:56:37,003 rpi3bp_004 INFO: DEVICE AGENT: BEGIN provision
2020-11-20 19:56:37,003 rpi3bp_004 INFO: DEVICE AGENT: Booting Master Image
2020-11-20 19:56:37,003 rpi3bp_004 INFO: DEVICE AGENT: Making sure the master image is booted
2020-11-20 19:56:37,003 rpi3bp_004 INFO: DEVICE AGENT: Checking if test image booted.
2020-11-20 19:56:37,174 rpi3bp_004 INFO: DEVICE AGENT: Checking if master image booted.
2020-11-20 19:56:37,503 rpi3bp_004 INFO: DEVICE AGENT: Downloading file from http://cdimage.ubuntu.com/ubuntu-core/20/dangerous-beta/pending/ubuntu-core-20-armhf+raspi.img.xz
^C
Cancel job 17e8e062-6aa8-40f5-b23d-a02830f7b08d before exiting (y)es/(N)o/(c)ontinue?

13:57 $ testflinger poll 17e8e062-6aa8-40f5-b23d-a02830f7b08d
2020-11-20 19:57:08,742 rpi3bp_004 INFO: DEVICE AGENT: Flashing Test Image

2020-11-20 19:57:09,195 rpi3bp_004 INFO: DEVICE AGENT: Running: nc.traditional 10.101.49.222 35473| xzcat| sudo dd of=/dev/mmcblk0 bs=16M
^C
Cancel job 17e8e062-6aa8-40f5-b23d-a02830f7b08d before exiting (y)es/(N)o/(c)ontinue? y

13:57 $ testflinger status 17e8e062-6aa8-40f5-b23d-a02830f7b08d
cancelled

To post a comment you must log in.
Revision history for this message
Paul Larson (pwlars) wrote :

(ignore the bad line break in the middle of the options, it doesn't look that way - just lp reformatting it for me)

Revision history for this message
Sheila Miguez (codersquid) wrote :

lgtm. Maybe ask Lukas if he likes the interface.

review: Approve
Revision history for this message
Lukas Waymann (meribold) wrote :

Looks good to me!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/testflinger_cli/__init__.py b/testflinger_cli/__init__.py
2index 0bd12e7..862f51d 100644
3--- a/testflinger_cli/__init__.py
4+++ b/testflinger_cli/__init__.py
5@@ -178,8 +178,11 @@ class TestflingerCli:
6 if job_state in ('complete', 'cancelled'):
7 raise SystemExit('Job {} is already in {} state and cannot be '
8 'cancelled.'.format(self.args.job_id, job_state))
9- self.client.post_job_state(self.args.job_id, 'cancelled')
10- self.history.update(self.args.job_id, 'cancelled')
11+ self.do_cancel(self.args.job_id)
12+
13+ def do_cancel(self, job_id):
14+ self.client.post_job_state(job_id, 'cancelled')
15+ self.history.update(job_id, 'cancelled')
16
17 def configure(self):
18 if self.args.setting:
19@@ -323,25 +326,38 @@ class TestflingerCli:
20 while job_state != 'complete':
21 if job_state == 'cancelled':
22 break
23- if job_state == 'waiting':
24+ try:
25+ if job_state == 'waiting':
26+ try:
27+ queue_pos = self.client.get_job_position(job_id)
28+ if int(queue_pos) != prev_queue_pos:
29+ prev_queue_pos = int(queue_pos)
30+ print('Jobs ahead in queue: {}'.format(queue_pos))
31+ except Exception:
32+ # Ignore any bad response, this will retry
33+ pass
34+ time.sleep(10)
35+ output = ''
36 try:
37- queue_pos = self.client.get_job_position(job_id)
38- if int(queue_pos) != prev_queue_pos:
39- prev_queue_pos = int(queue_pos)
40- print('Jobs ahead in queue: {}'.format(queue_pos))
41+ output = self.get_latest_output(job_id)
42 except Exception:
43- # Ignore any bad response, this will retry
44- pass
45- time.sleep(10)
46- output = ''
47- try:
48- output = self.get_latest_output(job_id)
49- except Exception:
50- continue
51- if output:
52- print(output, end='', flush=True)
53- job_state = self.get_job_state(job_id)
54- self.history.update(job_id, job_state)
55+ continue
56+ if output:
57+ print(output, end='', flush=True)
58+ job_state = self.get_job_state(job_id)
59+ self.history.update(job_id, job_state)
60+ except KeyboardInterrupt:
61+ choice = input('\nCancel job {} before exiting '
62+ '(y)es/(N)o/(c)ontinue? '.format(job_id))
63+ if choice:
64+ choice = choice[0].lower()
65+ if choice == 'c':
66+ continue
67+ if choice == 'y':
68+ self.do_cancel(job_id)
69+ # Both y and n will allow the external handler deal with it
70+ raise
71+
72 print(job_state)
73
74 def jobs(self):
75@@ -461,6 +477,8 @@ class TestflingerCli:
76 image = ""
77 flex_url = ""
78 if images and images[list(images.keys())[0]].startswith('url:'):
79+ # If this device can take URLs, offer to let the user enter one
80+ # instead of just using the known images
81 flex_url = "or URL for a valid image starting with http(s)://... "
82 while not image or image == "?":
83 image = input("\nEnter the name of the image you want to use " +

Subscribers

People subscribed via source and target branches