blob: 845da0f9f68feaa967f293b93b17669aa62df770 [file] [log] [blame]
Dan Shi784df0c2014-11-26 10:11:15 -08001# Copyright 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""
6The server module contains the objects and methods used to manage servers in
7Autotest.
8
9The valid actions are:
10list: list all servers in the database
11create: create a server
12delete: deletes a server
13modify: modify a server's role or status.
14
15The common options are:
16--role / -r: role that's related to server actions.
17
18See topic_common.py for a High Level Design and Algorithm.
19"""
20
21import common
22
23from autotest_lib.cli import action_common
Ningning Xia84190b82018-04-16 15:01:40 -070024from autotest_lib.cli import skylab_utils
Dan Shi784df0c2014-11-26 10:11:15 -080025from autotest_lib.cli import topic_common
26from autotest_lib.client.common_lib import error
Shuqian Zhaodb205af2018-02-28 15:13:03 -080027from autotest_lib.client.common_lib import global_config
Ningning Xia84190b82018-04-16 15:01:40 -070028from autotest_lib.client.common_lib import revision_control
Dan Shib9144a42014-12-01 16:09:32 -080029# The django setup is moved here as test_that uses sqlite setup. If this line
30# is in server_manager, test_that unittest will fail.
Dan Shi56f1ba72014-12-03 19:16:53 -080031from autotest_lib.frontend import setup_django_environment
Dan Shi784df0c2014-11-26 10:11:15 -080032from autotest_lib.site_utils import server_manager
Dan Shi56f1ba72014-12-03 19:16:53 -080033from autotest_lib.site_utils import server_manager_utils
Ningning Xiaa043aad2018-04-23 15:07:09 -070034from chromite.lib import gob_util
Ningning Xia9c188b92018-04-27 15:34:23 -070035
36try:
37 from skylab_inventory import text_manager
38 from skylab_inventory import translation_utils
39 from skylab_inventory.lib import server as skylab_server
40except ImportError:
41 pass
Ningning Xia84190b82018-04-16 15:01:40 -070042
43
Shuqian Zhaodb205af2018-02-28 15:13:03 -080044RESPECT_SKYLAB_SERVERDB = global_config.global_config.get_config_value(
45 'SKYLAB', 'respect_skylab_serverdb', type=bool, default=False)
46ATEST_DISABLE_MSG = ('Updating server_db via atest server command has been '
47 'disabled. Please use use go/cros-infra-inventory-tool '
48 'to update it in skylab inventory service.')
49
Dan Shi784df0c2014-11-26 10:11:15 -080050
51class server(topic_common.atest):
52 """Server class
53
54 atest server [list|create|delete|modify] <options>
55 """
56 usage_action = '[list|create|delete|modify]'
57 topic = msg_topic = 'server'
58 msg_items = '<server>'
59
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -070060 def __init__(self, hostname_required=True, allow_multiple_hostname=False):
Dan Shi784df0c2014-11-26 10:11:15 -080061 """Add to the parser the options common to all the server actions.
62
63 @param hostname_required: True to require the command has hostname
64 specified. Default is True.
65 """
66 super(server, self).__init__()
67
68 self.parser.add_option('-r', '--role',
69 help='Name of a role',
70 type='string',
71 default=None,
72 metavar='ROLE')
Dan Shi56f1ba72014-12-03 19:16:53 -080073 self.parser.add_option('-x', '--action',
74 help=('Set to True to apply actions when role '
75 'or status is changed, e.g., restart '
Ningning Xia3748b5f2018-05-21 16:33:08 -070076 'scheduler when a drone is removed. %s' %
77 skylab_utils.MSG_INVALID_IN_SKYLAB),
Dan Shi56f1ba72014-12-03 19:16:53 -080078 action='store_true',
79 default=False,
80 metavar='ACTION')
Dan Shi784df0c2014-11-26 10:11:15 -080081
Allen Li44fbd132018-06-12 20:18:06 +000082 self.add_skylab_options()
Ningning Xia84190b82018-04-16 15:01:40 -070083
Dan Shi784df0c2014-11-26 10:11:15 -080084 self.topic_parse_info = topic_common.item_parse_info(
85 attribute_name='hostname', use_leftover=True)
86
87 self.hostname_required = hostname_required
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -070088 self.allow_multiple_hostname = allow_multiple_hostname
Dan Shi784df0c2014-11-26 10:11:15 -080089
90
91 def parse(self):
92 """Parse command arguments.
93 """
94 role_info = topic_common.item_parse_info(attribute_name='role')
95 kwargs = {}
96 if self.hostname_required:
97 kwargs['req_items'] = 'hostname'
98 (options, leftover) = super(server, self).parse([role_info], **kwargs)
99 if options.web_server:
100 self.invalid_syntax('Server actions will access server database '
101 'defined in your local global config. It does '
102 'not rely on RPC, no autotest server needs to '
103 'be specified.')
104
105 # self.hostname is a list. Action on server only needs one hostname at
106 # most.
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700107 if (not self.hostname and self.hostname_required):
108 self.invalid_syntax('`server` topic requires hostname. '
109 'Use -h to see available options.')
110
111 if (self.hostname_required and not self.allow_multiple_hostname and
Dan Shi784df0c2014-11-26 10:11:15 -0800112 len(self.hostname) > 1):
113 self.invalid_syntax('`server` topic can only manipulate 1 server. '
114 'Use -h to see available options.')
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700115
Dan Shi784df0c2014-11-26 10:11:15 -0800116 if self.hostname:
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700117 if not self.allow_multiple_hostname or not self.skylab:
118 # Only support create multiple servers in skylab.
119 # Override self.hostname with the first hostname in the list.
120 self.hostname = self.hostname[0]
121
Dan Shi784df0c2014-11-26 10:11:15 -0800122 self.role = options.role
Ningning Xia84190b82018-04-16 15:01:40 -0700123
124 if self.skylab and self.role:
125 translation_utils.validate_server_role(self.role)
126
Dan Shi784df0c2014-11-26 10:11:15 -0800127 return (options, leftover)
128
129
130 def output(self, results):
131 """Display output.
132
133 For most actions, the return is a string message, no formating needed.
134
135 @param results: return of the execute call.
136 """
137 print results
138
139
140class server_help(server):
141 """Just here to get the atest logic working. Usage is set by its parent.
142 """
143 pass
144
145
146class server_list(action_common.atest_list, server):
147 """atest server list [--role <role>]"""
148
149 def __init__(self):
150 """Initializer.
151 """
152 super(server_list, self).__init__(hostname_required=False)
Ningning Xia84190b82018-04-16 15:01:40 -0700153
Allen Li44fbd132018-06-12 20:18:06 +0000154 self.parser.add_option('-t', '--table',
155 help=('List details of all servers in a table, '
156 'e.g., \tHostname | Status | Roles | '
157 'note\t\tserver1 | primary | scheduler | '
158 'lab. %s' %
159 skylab_utils.MSG_INVALID_IN_SKYLAB),
160 action='store_true',
161 default=False)
Dan Shi784df0c2014-11-26 10:11:15 -0800162 self.parser.add_option('-s', '--status',
Ningning Xia84190b82018-04-16 15:01:40 -0700163 help='Only show servers with given status.',
Dan Shi784df0c2014-11-26 10:11:15 -0800164 type='string',
165 default=None,
166 metavar='STATUS')
Allen Li44fbd132018-06-12 20:18:06 +0000167 self.parser.add_option('-u', '--summary',
168 help=('Show the summary of roles and status '
169 'only, e.g.,\tscheduler: server1(primary) '
170 'server2(backup)\t\tdrone: server3(primary'
171 ') server4(backup). %s' %
172 skylab_utils.MSG_INVALID_IN_SKYLAB),
173 action='store_true',
174 default=False)
Allen Lica17e7c2016-10-27 15:37:17 -0700175 self.parser.add_option('--json',
Ningning Xia32b26682018-05-23 14:25:18 -0700176 help=('Format output as JSON.'),
Allen Lica17e7c2016-10-27 15:37:17 -0700177 action='store_true',
178 default=False)
Aviv Keshete1729bb2017-05-31 13:27:09 -0700179 self.parser.add_option('-N', '--hostnames-only',
Ningning Xia3748b5f2018-05-21 16:33:08 -0700180 help=('Only return hostnames.'),
Aviv Keshete1729bb2017-05-31 13:27:09 -0700181 action='store_true',
182 default=False)
Dan Shi784df0c2014-11-26 10:11:15 -0800183
184
185 def parse(self):
186 """Parse command arguments.
187 """
188 (options, leftover) = super(server_list, self).parse()
Allen Lica17e7c2016-10-27 15:37:17 -0700189 self.json = options.json
Allen Li44fbd132018-06-12 20:18:06 +0000190 self.table = options.table
Dan Shi784df0c2014-11-26 10:11:15 -0800191 self.status = options.status
Allen Li44fbd132018-06-12 20:18:06 +0000192 self.summary = options.summary
Aviv Keshete1729bb2017-05-31 13:27:09 -0700193 self.namesonly = options.hostnames_only
Ningning Xia84190b82018-04-16 15:01:40 -0700194
Allen Li44fbd132018-06-12 20:18:06 +0000195 # TODO(nxia): support all formats for skylab inventory.
196 if (self.skylab and (self.table or self.summary)):
197 self.invalid_syntax('The format (table|summary)'
198 ' is not supported with --skylab.')
199
200 if sum([self.table, self.summary, self.json, self.namesonly]) > 1:
Aviv Keshete1729bb2017-05-31 13:27:09 -0700201 self.invalid_syntax('May only specify up to 1 output-format flag.')
Dan Shi784df0c2014-11-26 10:11:15 -0800202 return (options, leftover)
203
204
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700205 def execute_skylab(self):
206 """Execute 'atest server list --skylab'
207
208 @return: A list of servers matched the given hostname and role.
209 """
210 inventory_repo = skylab_utils.InventoryRepo(
211 self.inventory_repo_dir)
212 inventory_repo.initialize()
213 infrastructure = text_manager.load_infrastructure(
214 inventory_repo.get_data_dir())
215
216 return skylab_server.get_servers(
217 infrastructure,
218 self.environment,
219 hostname=self.hostname,
220 role=self.role,
221 status=self.status)
222
223
Dan Shi784df0c2014-11-26 10:11:15 -0800224 def execute(self):
225 """Execute the command.
226
227 @return: A list of servers matched given hostname and role.
228 """
Ningning Xia84190b82018-04-16 15:01:40 -0700229 if self.skylab:
230 try:
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700231 return self.execute_skylab()
Ningning Xia84190b82018-04-16 15:01:40 -0700232 except (skylab_server.SkylabServerActionError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700233 revision_control.GitError,
234 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700235 self.failure(e, what_failed='Failed to list servers from skylab'
236 ' inventory.', item=self.hostname, fatal=True)
237 else:
238 try:
239 return server_manager_utils.get_servers(
240 hostname=self.hostname,
241 role=self.role,
242 status=self.status)
243 except (server_manager_utils.ServerActionError,
244 error.InvalidDataError) as e:
245 self.failure(e, what_failed='Failed to find servers',
246 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800247
248
249 def output(self, results):
250 """Display output.
251
252 @param results: return of the execute call, a list of server object that
253 contains server information.
254 """
Allen Li90a84ea2016-10-27 15:07:42 -0700255 if results:
Allen Lica17e7c2016-10-27 15:37:17 -0700256 if self.json:
Ningning Xia32b26682018-05-23 14:25:18 -0700257 if self.skylab:
258 formatter = skylab_server.format_servers_json
259 else:
260 formatter = server_manager_utils.format_servers_json
Allen Li44fbd132018-06-12 20:18:06 +0000261 elif self.table:
262 formatter = server_manager_utils.format_servers_table
263 elif self.summary:
264 formatter = server_manager_utils.format_servers_summary
Aviv Keshete1729bb2017-05-31 13:27:09 -0700265 elif self.namesonly:
266 formatter = server_manager_utils.format_servers_nameonly
Allen Li90a84ea2016-10-27 15:07:42 -0700267 else:
268 formatter = server_manager_utils.format_servers
269 print formatter(results)
270 else:
Dan Shi784df0c2014-11-26 10:11:15 -0800271 self.failure('No server is found.',
272 what_failed='Failed to find servers',
273 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800274
275
276class server_create(server):
277 """atest server create hostname --role <role> --note <note>
278 """
279
280 def __init__(self):
281 """Initializer.
282 """
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700283 super(server_create, self).__init__(allow_multiple_hostname=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800284 self.parser.add_option('-n', '--note',
285 help='note of the server',
286 type='string',
287 default=None,
288 metavar='NOTE')
289
290
291 def parse(self):
292 """Parse command arguments.
293 """
294 (options, leftover) = super(server_create, self).parse()
295 self.note = options.note
296
297 if not self.role:
298 self.invalid_syntax('--role is required to create a server.')
299
300 return (options, leftover)
301
302
Ningning Xia84190b82018-04-16 15:01:40 -0700303 def execute_skylab(self):
304 """Execute the command for skylab inventory changes."""
305 inventory_repo = skylab_utils.InventoryRepo(
306 self.inventory_repo_dir)
307 inventory_repo.initialize()
308 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700309 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700310
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700311 new_servers = []
312 for hostname in self.hostname:
313 new_servers.append(skylab_server.create(
314 infrastructure,
315 hostname,
316 self.environment,
317 role=self.role,
318 note=self.note))
Ningning Xiae8714052018-04-30 18:58:54 -0700319 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700320
321 message = skylab_utils.construct_commit_message(
322 'Add new server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700323 self.change_number = inventory_repo.upload_change(
324 message, draft=self.draft, dryrun=self.dryrun,
325 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700326
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700327 return new_servers
Ningning Xia84190b82018-04-16 15:01:40 -0700328
329
Dan Shi784df0c2014-11-26 10:11:15 -0800330 def execute(self):
331 """Execute the command.
332
333 @return: A Server object if it is created successfully.
334 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800335 if RESPECT_SKYLAB_SERVERDB:
336 self.failure(ATEST_DISABLE_MSG,
337 what_failed='Failed to create server',
338 item=self.hostname, fatal=True)
339
Ningning Xia84190b82018-04-16 15:01:40 -0700340 if self.skylab:
341 try:
342 return self.execute_skylab()
343 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700344 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700345 gob_util.GOBError,
346 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xiae8714052018-04-30 18:58:54 -0700347 self.failure(e, what_failed='Failed to create server in skylab '
Ningning Xia84190b82018-04-16 15:01:40 -0700348 'inventory.', item=self.hostname, fatal=True)
349 else:
350 try:
351 return server_manager.create(
352 hostname=self.hostname,
353 role=self.role,
354 note=self.note)
355 except (server_manager_utils.ServerActionError,
356 error.InvalidDataError) as e:
357 self.failure(e, what_failed='Failed to create server',
358 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800359
360
361 def output(self, results):
362 """Display output.
363
364 @param results: return of the execute call, a server object that
365 contains server information.
366 """
367 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700368 print 'Server %s is added.\n' % self.hostname
Dan Shi784df0c2014-11-26 10:11:15 -0800369 print results
370
Ningning Xiaa043aad2018-04-23 15:07:09 -0700371 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700372 print skylab_utils.get_cl_message(self.change_number)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700373
Ningning Xia84190b82018-04-16 15:01:40 -0700374
Dan Shi784df0c2014-11-26 10:11:15 -0800375
376class server_delete(server):
377 """atest server delete hostname"""
378
Ningning Xia84190b82018-04-16 15:01:40 -0700379 def execute_skylab(self):
380 """Execute the command for skylab inventory changes."""
381 inventory_repo = skylab_utils.InventoryRepo(
382 self.inventory_repo_dir)
383 inventory_repo.initialize()
384 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700385 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700386
Ningning Xiae8714052018-04-30 18:58:54 -0700387 skylab_server.delete(infrastructure, self.hostname, self.environment)
388 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700389
390 message = skylab_utils.construct_commit_message(
391 'Delete server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700392 self.change_number = inventory_repo.upload_change(
393 message, draft=self.draft, dryrun=self.dryrun,
394 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700395
396
Dan Shi784df0c2014-11-26 10:11:15 -0800397 def execute(self):
398 """Execute the command.
399
400 @return: True if server is deleted successfully.
401 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800402 if RESPECT_SKYLAB_SERVERDB:
403 self.failure(ATEST_DISABLE_MSG,
404 what_failed='Failed to delete server',
405 item=self.hostname, fatal=True)
406
Ningning Xia84190b82018-04-16 15:01:40 -0700407 if self.skylab:
408 try:
409 self.execute_skylab()
410 return True
411 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700412 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700413 gob_util.GOBError,
414 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700415 self.failure(e, what_failed='Failed to delete server from '
416 'skylab inventory.', item=self.hostname,
417 fatal=True)
418 else:
419 try:
420 server_manager.delete(hostname=self.hostname)
421 return True
422 except (server_manager_utils.ServerActionError,
423 error.InvalidDataError) as e:
424 self.failure(e, what_failed='Failed to delete server',
425 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800426
427
428 def output(self, results):
429 """Display output.
430
431 @param results: return of the execute call.
432 """
433 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700434 print ('Server %s is deleted.\n' %
Dan Shi784df0c2014-11-26 10:11:15 -0800435 self.hostname)
436
Ningning Xiaa043aad2018-04-23 15:07:09 -0700437 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700438 print skylab_utils.get_cl_message(self.change_number)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700439
Ningning Xia84190b82018-04-16 15:01:40 -0700440
Dan Shi784df0c2014-11-26 10:11:15 -0800441
442class server_modify(server):
443 """atest server modify hostname
444
445 modify action can only change one input at a time. Available inputs are:
446 --status: Status of the server.
447 --note: Note of the server.
448 --role: New role to be added to the server.
449 --delete_role: Existing role to be deleted from the server.
450 """
451
452 def __init__(self):
453 """Initializer.
454 """
455 super(server_modify, self).__init__()
456 self.parser.add_option('-s', '--status',
457 help='Status of the server',
458 type='string',
459 metavar='STATUS')
460 self.parser.add_option('-n', '--note',
461 help='Note of the server',
462 type='string',
463 default=None,
464 metavar='NOTE')
465 self.parser.add_option('-d', '--delete',
466 help=('Set to True to delete given role.'),
467 action='store_true',
468 default=False,
469 metavar='DELETE')
470 self.parser.add_option('-a', '--attribute',
471 help='Name of the attribute of the server',
472 type='string',
473 default=None,
474 metavar='ATTRIBUTE')
475 self.parser.add_option('-e', '--value',
476 help='Value for the attribute of the server',
477 type='string',
478 default=None,
479 metavar='VALUE')
480
481
482 def parse(self):
483 """Parse command arguments.
484 """
485 (options, leftover) = super(server_modify, self).parse()
486 self.status = options.status
487 self.note = options.note
488 self.delete = options.delete
489 self.attribute = options.attribute
490 self.value = options.value
Dan Shi56f1ba72014-12-03 19:16:53 -0800491 self.action = options.action
Dan Shi784df0c2014-11-26 10:11:15 -0800492
493 # modify supports various options. However, it's safer to limit one
494 # option at a time so no complicated role-dependent logic is needed
495 # to handle scenario that both role and status are changed.
496 # self.parser is optparse, which does not have function in argparse like
497 # add_mutually_exclusive_group. That's why the count is used here.
498 flags = [self.status is not None, self.role is not None,
499 self.attribute is not None, self.note is not None]
500 if flags.count(True) != 1:
501 msg = ('Action modify only support one option at a time. You can '
502 'try one of following 5 options:\n'
503 '1. --status: Change server\'s status.\n'
504 '2. --note: Change server\'s note.\n'
505 '3. --role with optional -d: Add/delete role from server.\n'
506 '4. --attribute --value: Set/change the value of a '
507 'server\'s attribute.\n'
508 '5. --attribute -d: Delete the attribute from the '
509 'server.\n'
510 '\nUse option -h to see a complete list of options.')
511 self.invalid_syntax(msg)
512 if (self.status != None or self.note != None) and self.delete:
513 self.invalid_syntax('--delete does not apply to status or note.')
514 if self.attribute != None and not self.delete and self.value == None:
515 self.invalid_syntax('--attribute must be used with option --value '
516 'or --delete.')
Ningning Xia84190b82018-04-16 15:01:40 -0700517
518 # TODO(nxia): crbug.com/832964 support --action with --skylab
519 if self.skylab and self.action:
520 self.invalid_syntax('--action is currently not supported with'
521 ' --skylab.')
522
Dan Shi784df0c2014-11-26 10:11:15 -0800523 return (options, leftover)
524
525
Ningning Xia84190b82018-04-16 15:01:40 -0700526 def execute_skylab(self):
527 """Execute the command for skylab inventory changes."""
528 inventory_repo = skylab_utils.InventoryRepo(
529 self.inventory_repo_dir)
530 inventory_repo.initialize()
531 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700532 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700533
534 target_server = skylab_server.modify(
535 infrastructure,
536 self.hostname,
Ningning Xiae8714052018-04-30 18:58:54 -0700537 self.environment,
Ningning Xia84190b82018-04-16 15:01:40 -0700538 role=self.role,
539 status=self.status,
540 delete_role=self.delete,
541 note=self.note,
542 attribute=self.attribute,
543 value=self.value,
544 delete_attribute=self.delete)
Ningning Xiae8714052018-04-30 18:58:54 -0700545 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700546
547 status = inventory_repo.git_repo.status()
548 if not status:
549 print('Nothing is changed for server %s.' % self.hostname)
550 return
551
552 message = skylab_utils.construct_commit_message(
553 'Modify server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700554 self.change_number = inventory_repo.upload_change(
555 message, draft=self.draft, dryrun=self.dryrun,
556 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700557
558 return target_server
559
560
Dan Shi784df0c2014-11-26 10:11:15 -0800561 def execute(self):
562 """Execute the command.
563
564 @return: The updated server object if it is modified successfully.
565 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800566 if RESPECT_SKYLAB_SERVERDB:
567 self.failure(ATEST_DISABLE_MSG,
568 what_failed='Failed to modify server',
569 item=self.hostname, fatal=True)
570
Ningning Xia84190b82018-04-16 15:01:40 -0700571 if self.skylab:
572 try:
573 return self.execute_skylab()
574 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700575 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700576 gob_util.GOBError,
577 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700578 self.failure(e, what_failed='Failed to modify server in skylab'
579 ' inventory.', item=self.hostname, fatal=True)
580 else:
581 try:
582 return server_manager.modify(
583 hostname=self.hostname, role=self.role,
584 status=self.status, delete=self.delete,
585 note=self.note, attribute=self.attribute,
586 value=self.value, action=self.action)
587 except (server_manager_utils.ServerActionError,
588 error.InvalidDataError) as e:
589 self.failure(e, what_failed='Failed to modify server',
590 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800591
592
593 def output(self, results):
594 """Display output.
595
596 @param results: return of the execute call, which is the updated server
597 object.
598 """
599 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700600 print 'Server %s is modified.\n' % self.hostname
Dan Shi784df0c2014-11-26 10:11:15 -0800601 print results
Ningning Xia84190b82018-04-16 15:01:40 -0700602
Ningning Xiaa043aad2018-04-23 15:07:09 -0700603 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700604 print skylab_utils.get_cl_message(self.change_number)