Merge lp:~stylesen/lava-scheduler/multinode into lp:lava-scheduler/multinode
- multinode
- Merge into multinode
Proposed by
Senthil Kumaran S
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Neil Williams | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 249 | ||||
Proposed branch: | lp:~stylesen/lava-scheduler/multinode | ||||
Merge into: | lp:lava-scheduler/multinode | ||||
Diff against target: |
347 lines (+299/-7) 3 files modified
lava_scheduler_app/migrations/0031_auto__add_field_testjob_target_group.py (+161/-0) lava_scheduler_app/models.py (+52/-7) lava_scheduler_daemon/utils.py (+86/-0) |
||||
To merge this branch: | bzr merge lp:~stylesen/lava-scheduler/multinode | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Neil Williams | Approve | ||
Review via email: mp+171218@code.launchpad.net |
Commit message
Description of the change
Support for submitting multinode jobs to the scheduler and have sub-ids and unique target-groups.
To post a comment you must log in.
- 249. By Neil Williams
-
Merge Senthil's branch
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'lava_scheduler_app/migrations/0031_auto__add_field_testjob_target_group.py' |
2 | --- lava_scheduler_app/migrations/0031_auto__add_field_testjob_target_group.py 1970-01-01 00:00:00 +0000 |
3 | +++ lava_scheduler_app/migrations/0031_auto__add_field_testjob_target_group.py 2013-06-25 06:19:07 +0000 |
4 | @@ -0,0 +1,161 @@ |
5 | +# -*- coding: utf-8 -*- |
6 | +import datetime |
7 | +from south.db import db |
8 | +from south.v2 import SchemaMigration |
9 | +from django.db import models |
10 | + |
11 | + |
12 | +class Migration(SchemaMigration): |
13 | + |
14 | + def forwards(self, orm): |
15 | + # Adding field 'TestJob.target_group' |
16 | + db.add_column('lava_scheduler_app_testjob', 'target_group', |
17 | + self.gf('django.db.models.fields.CharField')(default='', max_length=64, blank=True), |
18 | + keep_default=False) |
19 | + |
20 | + |
21 | + def backwards(self, orm): |
22 | + # Deleting field 'TestJob.target_group' |
23 | + db.delete_column('lava_scheduler_app_testjob', 'target_group') |
24 | + |
25 | + |
26 | + models = { |
27 | + 'auth.group': { |
28 | + 'Meta': {'object_name': 'Group'}, |
29 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
30 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
31 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
32 | + }, |
33 | + 'auth.permission': { |
34 | + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
35 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
36 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
37 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
38 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
39 | + }, |
40 | + 'auth.user': { |
41 | + 'Meta': {'object_name': 'User'}, |
42 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
43 | + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
44 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
45 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
46 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
47 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
48 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
49 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
50 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
51 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
52 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
53 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
54 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
55 | + }, |
56 | + 'contenttypes.contenttype': { |
57 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
58 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
59 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
60 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
61 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
62 | + }, |
63 | + 'dashboard_app.bundle': { |
64 | + 'Meta': {'ordering': "['-uploaded_on']", 'object_name': 'Bundle'}, |
65 | + '_gz_content': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'db_column': "'gz_content'"}), |
66 | + '_raw_content': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'db_column': "'content'"}), |
67 | + 'bundle_stream': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bundles'", 'to': "orm['dashboard_app.BundleStream']"}), |
68 | + 'content_filename': ('django.db.models.fields.CharField', [], {'max_length': '256'}), |
69 | + 'content_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'unique': 'True', 'null': 'True'}), |
70 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
71 | + 'is_deserialized': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
72 | + 'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'uploaded_bundles'", 'null': 'True', 'to': "orm['auth.User']"}), |
73 | + 'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}) |
74 | + }, |
75 | + 'dashboard_app.bundlestream': { |
76 | + 'Meta': {'object_name': 'BundleStream'}, |
77 | + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}), |
78 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
79 | + 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
80 | + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
81 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), |
82 | + 'pathname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}), |
83 | + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), |
84 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) |
85 | + }, |
86 | + 'lava_scheduler_app.device': { |
87 | + 'Meta': {'object_name': 'Device'}, |
88 | + 'current_job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['lava_scheduler_app.TestJob']", 'blank': 'True', 'unique': 'True'}), |
89 | + 'device_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['lava_scheduler_app.DeviceType']"}), |
90 | + 'device_version': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}), |
91 | + 'health_status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
92 | + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'primary_key': 'True'}), |
93 | + 'last_health_report_job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['lava_scheduler_app.TestJob']", 'blank': 'True', 'unique': 'True'}), |
94 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}), |
95 | + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['lava_scheduler_app.Tag']", 'symmetrical': 'False', 'blank': 'True'}) |
96 | + }, |
97 | + 'lava_scheduler_app.devicestatetransition': { |
98 | + 'Meta': {'object_name': 'DeviceStateTransition'}, |
99 | + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), |
100 | + 'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
101 | + 'device': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'transitions'", 'to': "orm['lava_scheduler_app.Device']"}), |
102 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
103 | + 'job': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['lava_scheduler_app.TestJob']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), |
104 | + 'message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
105 | + 'new_state': ('django.db.models.fields.IntegerField', [], {}), |
106 | + 'old_state': ('django.db.models.fields.IntegerField', [], {}) |
107 | + }, |
108 | + 'lava_scheduler_app.devicetype': { |
109 | + 'Meta': {'object_name': 'DeviceType'}, |
110 | + 'display': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
111 | + 'health_check_job': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), |
112 | + 'name': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'primary_key': 'True'}) |
113 | + }, |
114 | + 'lava_scheduler_app.jobfailuretag': { |
115 | + 'Meta': {'object_name': 'JobFailureTag'}, |
116 | + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
117 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
118 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}) |
119 | + }, |
120 | + 'lava_scheduler_app.tag': { |
121 | + 'Meta': {'object_name': 'Tag'}, |
122 | + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
123 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
124 | + 'name': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}) |
125 | + }, |
126 | + 'lava_scheduler_app.testjob': { |
127 | + 'Meta': {'object_name': 'TestJob'}, |
128 | + '_results_bundle': ('django.db.models.fields.related.OneToOneField', [], {'null': 'True', 'db_column': "'results_bundle_id'", 'on_delete': 'models.SET_NULL', 'to': "orm['dashboard_app.Bundle']", 'blank': 'True', 'unique': 'True'}), |
129 | + '_results_link': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '400', 'null': 'True', 'db_column': "'results_link'", 'blank': 'True'}), |
130 | + 'actual_device': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'+'", 'null': 'True', 'blank': 'True', 'to': "orm['lava_scheduler_app.Device']"}), |
131 | + 'definition': ('django.db.models.fields.TextField', [], {}), |
132 | + 'description': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}), |
133 | + 'end_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
134 | + 'failure_comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
135 | + 'failure_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'failure_tags'", 'blank': 'True', 'to': "orm['lava_scheduler_app.JobFailureTag']"}), |
136 | + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}), |
137 | + 'health_check': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
138 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
139 | + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
140 | + 'log_file': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'null': 'True', 'blank': 'True'}), |
141 | + 'priority': ('django.db.models.fields.IntegerField', [], {'default': '50'}), |
142 | + 'requested_device': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'+'", 'null': 'True', 'blank': 'True', 'to': "orm['lava_scheduler_app.Device']"}), |
143 | + 'requested_device_type': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'+'", 'null': 'True', 'blank': 'True', 'to': "orm['lava_scheduler_app.DeviceType']"}), |
144 | + 'start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
145 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
146 | + 'sub_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), |
147 | + 'submit_time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
148 | + 'submit_token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['linaro_django_xmlrpc.AuthToken']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), |
149 | + 'submitter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}), |
150 | + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['lava_scheduler_app.Tag']", 'symmetrical': 'False', 'blank': 'True'}), |
151 | + 'target_group': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), |
152 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) |
153 | + }, |
154 | + 'linaro_django_xmlrpc.authtoken': { |
155 | + 'Meta': {'object_name': 'AuthToken'}, |
156 | + 'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
157 | + 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), |
158 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
159 | + 'last_used_on': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
160 | + 'secret': ('django.db.models.fields.CharField', [], {'default': "'1n07jwp73fldk40sk0hshidru6nh5rqlrn40oq4hs5f9wx99o0wemwme43raxx008kyfsbahl56x8wyndgyclbapc43maycile201e1snt6p8a02n4hgyc506fda8umq'", 'unique': 'True', 'max_length': '128'}), |
161 | + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_tokens'", 'to': "orm['auth.User']"}) |
162 | + } |
163 | + } |
164 | + |
165 | + complete_apps = ['lava_scheduler_app'] |
166 | \ No newline at end of file |
167 | |
168 | === modified file 'lava_scheduler_app/models.py' |
169 | --- lava_scheduler_app/models.py 2013-06-20 11:41:39 +0000 |
170 | +++ lava_scheduler_app/models.py 2013-06-25 06:19:07 +0000 |
171 | @@ -1,5 +1,7 @@ |
172 | import logging |
173 | import os |
174 | +import json |
175 | +import uuid |
176 | import simplejson |
177 | import urlparse |
178 | import copy |
179 | @@ -19,6 +21,7 @@ |
180 | from dashboard_app.models import Bundle, BundleStream |
181 | |
182 | from lava_dispatcher.job import validate_job_data |
183 | +from lava_scheduler_daemon import utils |
184 | |
185 | from linaro_django_xmlrpc.models import AuthToken |
186 | |
187 | @@ -256,6 +259,12 @@ |
188 | max_length = 200 |
189 | ) |
190 | |
191 | + target_group = models.CharField( |
192 | + verbose_name = _(u"Target Group"), |
193 | + blank = True, |
194 | + max_length = 64 |
195 | + ) |
196 | + |
197 | submitter = models.ForeignKey( |
198 | User, |
199 | verbose_name = _(u"Submitter"), |
200 | @@ -475,13 +484,49 @@ |
201 | except Tag.DoesNotExist: |
202 | raise JSONDataError("tag %r does not exist" % tag_name) |
203 | |
204 | - job = TestJob( |
205 | - definition=json_data, submitter=submitter, |
206 | - requested_device=target, requested_device_type=device_type, |
207 | - description=job_name, health_check=health_check, user=user, |
208 | - group=group, is_public=is_public, priority=priority) |
209 | - job.save() |
210 | - return job.id |
211 | + if 'device_group' in job_data: |
212 | + target_group = str(uuid.uuid4()) |
213 | + node_json, group_json = utils.split_multi_job(job_data, |
214 | + target_group) |
215 | + job_list = [] |
216 | + try: |
217 | + parent_id = (TestJob.objects.latest('id')).id + 1 |
218 | + except: |
219 | + parent_id = 1 |
220 | + child_id = 0 |
221 | + parent_job = str(parent_id) + '.' + str(child_id) |
222 | + |
223 | + for role in node_json: |
224 | + role_count = len(node_json[role]) |
225 | + for c in range(0, role_count): |
226 | + device_type = DeviceType.objects.get( |
227 | + name=node_json[role][c]["device_type"]) |
228 | + sub_id = str(parent_id) + '.' + str(child_id) |
229 | + logger = logging.getLogger("SUBMITLOGGER") |
230 | + logger.info(json.dumps(node_json[role][c])) |
231 | + |
232 | + job = TestJob( |
233 | + sub_id=sub_id, submitter=submitter, |
234 | + requested_device=target, description=job_name, |
235 | + requested_device_type=device_type, |
236 | + definition=json.dumps(node_json[role][c]), |
237 | + health_check=health_check, user=user, group=group, |
238 | + is_public=is_public, priority=priority, |
239 | + target_group=target_group) |
240 | + job.save() |
241 | + job_list.append(sub_id) |
242 | + child_id += 1 |
243 | + return job_list |
244 | + |
245 | + else: |
246 | + job = TestJob( |
247 | + definition=json_data, submitter=submitter, |
248 | + requested_device=target, requested_device_type=device_type, |
249 | + description=job_name, health_check=health_check, user=user, |
250 | + group=group, is_public=is_public, priority=priority, |
251 | + target_group=None) |
252 | + job.save() |
253 | + return job.id |
254 | |
255 | def _can_admin(self, user): |
256 | """ used to check for things like if the user can cancel or annotate |
257 | |
258 | === added file 'lava_scheduler_daemon/utils.py' |
259 | --- lava_scheduler_daemon/utils.py 1970-01-01 00:00:00 +0000 |
260 | +++ lava_scheduler_daemon/utils.py 2013-06-25 06:19:07 +0000 |
261 | @@ -0,0 +1,86 @@ |
262 | +# Copyright (C) 2013 Linaro Limited |
263 | +# |
264 | +# Author: Neil Williams <neil.williams@linaro.org> |
265 | +# Senthil Kumaran <senthil.kumaran@linaro.org> |
266 | +# |
267 | +# This file is part of LAVA Scheduler. |
268 | +# |
269 | +# LAVA Scheduler is free software: you can redistribute it and/or modify it |
270 | +# under the terms of the GNU Affero General Public License version 3 as |
271 | +# published by the Free Software Foundation |
272 | +# |
273 | +# LAVA Scheduler is distributed in the hope that it will be useful, but |
274 | +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
275 | +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
276 | +# more details. |
277 | +# |
278 | +# You should have received a copy of the GNU Affero General Public License |
279 | +# along with LAVA Scheduler. If not, see <http://www.gnu.org/licenses/>. |
280 | + |
281 | +import json |
282 | +import copy |
283 | +from socket import gethostname |
284 | + |
285 | + |
286 | +def split_multi_job(multi_job_data, target_group): |
287 | + group_json = {} |
288 | + node_json = {} |
289 | + all_nodes = {} |
290 | + node_actions = {} |
291 | + hostname = gethostname() |
292 | + port = 3079 |
293 | + json_jobdata = multi_job_data |
294 | + if "device_group" in json_jobdata: |
295 | + # multinode start, group stage 1 |
296 | + group_json["timeout"] = json_jobdata["timeout"] |
297 | + group_json["group_dispatcher"] = True |
298 | + # group stage 2 - configurable values |
299 | + # all the groupd_dispatcher really needs is the port number to use |
300 | + group_json["logging_level"] = "DEBUG" |
301 | + group_json["port"] = port |
302 | + group_json["hostname"] = hostname |
303 | + # multinode node stage 1 |
304 | + for actions in json_jobdata["actions"]: |
305 | + if "parameters" not in actions \ |
306 | + or 'role' not in actions["parameters"]: |
307 | + continue |
308 | + role = str(actions["parameters"]["role"]) |
309 | + node_actions[role] = [] |
310 | + for actions in json_jobdata["actions"]: |
311 | + if "parameters" not in actions \ |
312 | + or 'role' not in actions["parameters"]: |
313 | + # add to each node, e.g. submit_results |
314 | + all_nodes[actions["command"]] = actions |
315 | + continue |
316 | + role = str(actions["parameters"]["role"]) |
317 | + actions["parameters"].pop('role', None) |
318 | + node_actions[role].append({"command": actions["command"], |
319 | + "parameters": actions["parameters"]}) |
320 | + group_count = 0 |
321 | + for clients in json_jobdata["device_group"]: |
322 | + group_count += int(clients["count"]) |
323 | + for clients in json_jobdata["device_group"]: |
324 | + role = str(clients["role"]) |
325 | + count = int(clients["count"]) |
326 | + node_json[role] = [] |
327 | + for c in range(0, count): |
328 | + node_json[role].append({}) |
329 | + node_json[role][c]["timeout"] = json_jobdata["timeout"] |
330 | + node_json[role][c]["job_name"] = json_jobdata["job_name"] |
331 | + node_json[role][c]["tags"] = clients["tags"] |
332 | + node_json[role][c]["group_size"] = group_count |
333 | + node_json[role][c]["target_group"] = target_group |
334 | + node_json[role][c]["actions"] = copy.deepcopy( |
335 | + node_actions[role]) |
336 | + for key in all_nodes: |
337 | + node_json[role][c]["actions"].append(all_nodes[key]) |
338 | + node_json[role][c]["role"] = role |
339 | + # multinode node stage 2 |
340 | + node_json[role][c]["logging_level"] = "DEBUG" |
341 | + node_json[role][c]["port"] = port |
342 | + node_json[role][c]["hostname"] = hostname |
343 | + node_json[role][c]["device_type"] = clients["device_type"] |
344 | + |
345 | + return (node_json, group_json) |
346 | + |
347 | + return 0 |
OK, there are a few debug bits left in the split_multi_job function. The group_json doesn't need to know the hostname once the code from translate.py is migrated into the scheduler. Firstly because that will be the hostname of the machine running the scheduler daemon, not the machine running the GroupDispatcher. During debugging, translate.py was run on the same machine as the dispatcher. As the comment notes, the only thing the GroupDispatcher needs from group_json is the group_dispatcher = true flag and the port number. (In some ways, group_json is possibly redundant and the port number could be passed as an argument to __init__.)
However, this is harmless, so I'm happy to approve this merge, we will need to remove the hostname call (and therefore the import of hostname from socket) before the branch is finally merged.