Merge lp:~cprov/adt-cloud-worker/adt-runs into lp:adt-cloud-worker

Proposed by Celso Providelo
Status: Merged
Merged at revision: 7
Proposed branch: lp:~cprov/adt-cloud-worker/adt-runs
Merge into: lp:adt-cloud-worker
Diff against target: 216 lines (+81/-87)
2 files modified
.adt-service.conf (+3/-2)
adt-cloud-worker.py (+78/-85)
To merge this branch: bzr merge lp:~cprov/adt-cloud-worker/adt-runs
Reviewer Review Type Date Requested Status
Francis Ginther Approve
Review via email: mp+251624@code.launchpad.net

Description of the change

Supporting nova.extra_args configuration for setting bootstack net-id (and other possible stack-dependant options) and also took the opportunity for refactoring some logic inside AdtNovaWorker consumer by passing the configuration object in. Now process & run_adt are more concise and easier to understand and test.

`adt-cloud-worker` works for libpng on trusty (using the test producer from lp:adt-request-proxy), now we have to store results on swift and call it feature complete.

Yes, you might have noticed we still have no unittests :-/

To post a comment you must log in.
Revision history for this message
Francis Ginther (fginther) wrote :

Looks good. I first thought it a mistake to leave out "# TODO: do sensible things with the exit code:", but I believe this is really a task for the result-checker.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.adt-service.conf'
--- .adt-service.conf 2015-03-03 02:15:49 +0000
+++ .adt-service.conf 2015-03-03 16:37:14 +0000
@@ -12,5 +12,6 @@
12os_username = foo12os_username = foo
13os_tenant_name = foo_project13os_tenant_name = foo_project
14os_password = <redacted>14os_password = <redacted>
15os_auth_url = https://keystone.canonistack.canonical.com:443/v2.0/15os_auth_url = http://172.20.161.138:5000/v2.0/
16os_region_name = lcy0116os_region_name = bot-prototype
17extra_args = --net-id=415a0839-eb05-4e7a-907c-413c657f4bf5
1718
=== modified file 'adt-cloud-worker.py'
--- adt-cloud-worker.py 2015-03-03 12:16:42 +0000
+++ adt-cloud-worker.py 2015-03-03 16:37:14 +0000
@@ -36,95 +36,102 @@
36logger = get_logger(__name__)36logger = get_logger(__name__)
3737
3838
39class Worker(ConsumerMixin):39class AdtNovaWorker(ConsumerMixin):
4040
41 def __init__(self, name, connection, queues):41 def __init__(self, connection, config):
42 self.name = name
43 self.connection = connection42 self.connection = connection
44 self.queues = queues43 self.config = config
44 self.name = self.config.get('adt', 'name')
4545
46 def get_consumers(self, Consumer, channel):46 def get_consumers(self, Consumer, channel):
47 return [Consumer(queues=self.queues, callbacks=[self.process])]47 """Return consumers instances for all configured queues."""
48 exchange = kombu.Exchange("adt.exchange", type="topic")
49 queues = [
50 kombu.Queue(
51 'adt.requests.{}'.format(tag), exchange, routing_key=tag)
52 for tag in self.config.get('adt', 'tags').split()
53 ]
54 return [Consumer(queues=queues, callbacks=[self.process])]
4855
49 def process(self, body, message):56 def process(self, body, message):
57 """Process incomming test request.
58
59 Run requested tests and posts results to the 'adt_results' queue
60 for later checking.
61 """
50 logger.info('Got: {}'.format(body))62 logger.info('Got: {}'.format(body))
51 # TODO: body validation63 # TODO: body validation
52 # Ack message once it's valid or message.reject()
53 message.ack()64 message.ack()
5465 body['worker'] = self.name
55 result_dir = tempfile.mkdtemp(66 # Run requested tests safely.
56 prefix='adt-{}'.format(body['request_id']))
57
58 try:67 try:
59 # what information do we need from the message?68 # Create and temporary directory for storing adt results.
60 adt_run_args = [69 result_dir = tempfile.mkdtemp(
61 '--apt-source', body['package_name'],70 prefix='adt-{}-{}'.format(self.name, body['request_id']))
62 '--output-dir', result_dir, # TODO: replace me71 adt_kwargs = body.copy()
63 ]72 adt_kwargs['result_dir'] = result_dir
64 if 'apt_pocket' in body:73 body['exit_code'] = self.run_adt(**adt_kwargs)
65 adt_run_args += [
66 '--apt-pocket', body['apt_pocket'],
67 '--apt-upgrade',
68 ]
69 adt_ssh_nova_args = [
70 '--',
71 '--flavor', body['nova_flavor'],
72 '--image', body['nova_image'],
73 ]
74
75 exit_code = run_adt(
76 adt_run_args +
77 [
78 '---',
79 'ssh',
80 '-s', 'nova',
81 ] +
82 adt_ssh_nova_args
83 )
84
85 # TODO: do sensible things with the exit code:
86 # 0 all tests passed
87 # 2 at least one test skipped
88 # 4 at least one test failed
89 # 6 at least one test failed and at least one test skipped
90 # 8 no tests in this package
91 # 12 erroneous package
92 # 16 testbed failure
93 # 20 other unexpected failures including bad usage
94
95 # TODO: tar/gzip the output directory.74 # TODO: tar/gzip the output directory.
96 # TODO: upload to swift instance at 'swift_container'75 # TODO: upload to swift instance at 'swift_container'
97
98 except Exception as e:76 except Exception as e:
77 # Unexpected failures ...
99 logger.error(e, exc_info=True)78 logger.error(e, exc_info=True)
79 body['exit_code'] = '100'
100 finally:80 finally:
101 # build the result message81 # Drop the result directory and post results
102 body['worker'] = self.name82 shutil.rmtree(result_dir)
103 body['exit_code'] = exit_code
104 # TODO: send error logging to result-checker in the message83 # TODO: send error logging to result-checker in the message
10584 # TODO: resilience agains rabbit hiccups, otherwise the request
85 # will be lost.
106 queue = self.connection.SimpleQueue('adt.results')86 queue = self.connection.SimpleQueue('adt.results')
107 queue.put(body)87 queue.put(body)
108 queue.close()88 queue.close()
109 # Drop the result directory89
110 # TODO: it could be possibly useful for clients.90 def run_adt(self, **kwargs):
111 shutil.rmtree(result_dir)91 """Run adt-run according to the given request parameters.
11292
11393 Always resets the environment with configured nova variables.
114def run_adt(arguments):94
115 """Run adt-run with the given arguments.95 Returns the exit code from adt-run.
11696 """
117 Returns the exit code from adt-run.97 # TODO: We probably want something more clever here:
11898
119 """99 # what information do we need from the message?
120 # TODO: We probably want something more clever here:100 adt_run_args = [
121 try:101 '--apt-source', kwargs['package_name'],
122 subprocess.check_call(['adt-run'] + arguments)102 '--output-dir', kwargs['result_dir'],
123 except subprocess.CalledProcessError as e:103 ]
124 # log?104 if 'apt_pocket' in kwargs:
125 # TODO: filter log content to avoid leaking cloud credentials.105 adt_run_args += [
126 return e.returncode106 '--apt-pocket', kwargs['apt_pocket'],
127 return 0107 '--apt-upgrade',
108 ]
109 adt_ssh_nova_args = [
110 '--',
111 '--flavor', kwargs['nova_flavor'],
112 '--image', kwargs['nova_image'],
113 ]
114
115 arguments = (
116 adt_run_args +
117 ['---', 'ssh', '-s', 'nova'] +
118 adt_ssh_nova_args +
119 self.config.get('nova', 'extra_args').split()
120 )
121
122 # Setup nova environment variables based on the configuration file.
123 for k, v in self.config.items('nova'):
124 if not k.startswith('os_'):
125 continue
126 os.environ[k.upper()] = str(v)
127
128 try:
129 subprocess.check_call(['adt-run'] + arguments)
130 except subprocess.CalledProcessError as e:
131 # log?
132 # TODO: filter log content to avoid leaking cloud credentials.
133 return e.returncode
134 return 0
128135
129136
130def main():137def main():
@@ -139,25 +146,11 @@
139 # Load configuration options.146 # Load configuration options.
140 config = configparser.ConfigParser()147 config = configparser.ConfigParser()
141 config.read(args.conf)148 config.read(args.conf)
142 worker_name = config.get('adt', 'name')
143 routing_keys = config.get('adt', 'tags').split()
144 amqp_uris = config.get('amqp', 'uris').split()149 amqp_uris = config.get('amqp', 'uris').split()
145150
146 # Setup nova environment variables based on the configuration file.
147 for k, v in config.items('nova'):
148 os.environ[k.upper()] = str(v)
149
150 adt_exchange = kombu.Exchange("adt.exchange", type="topic")
151 queues = []
152 for routing_key in routing_keys:
153 queues.append(
154 kombu.Queue('adt.requests.{}'.format(routing_key) ,
155 adt_exchange, routing_key=routing_key)
156 )
157
158 with kombu.Connection(amqp_uris) as conn:151 with kombu.Connection(amqp_uris) as conn:
159 try:152 try:
160 worker = Worker(worker_name, conn, queues)153 worker = AdtNovaWorker(conn, config)
161 worker.run()154 worker.run()
162 except KeyboardInterrupt:155 except KeyboardInterrupt:
163 print('Bye!')156 print('Bye!')

Subscribers

People subscribed via source and target branches