blob: a60c7e613b6f74f15b74fd4bd8dbd313317f546e [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 Li75e3d342018-08-06 19:04:31 +000082 self.add_skylab_options(enforce_skylab=True)
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
Dan Shi784df0c2014-11-26 10:11:15 -0800154 self.parser.add_option('-s', '--status',
Ningning Xia84190b82018-04-16 15:01:40 -0700155 help='Only show servers with given status.',
Dan Shi784df0c2014-11-26 10:11:15 -0800156 type='string',
157 default=None,
158 metavar='STATUS')
Allen Lica17e7c2016-10-27 15:37:17 -0700159 self.parser.add_option('--json',
Ningning Xia32b26682018-05-23 14:25:18 -0700160 help=('Format output as JSON.'),
Allen Lica17e7c2016-10-27 15:37:17 -0700161 action='store_true',
162 default=False)
Aviv Keshete1729bb2017-05-31 13:27:09 -0700163 self.parser.add_option('-N', '--hostnames-only',
Ningning Xia3748b5f2018-05-21 16:33:08 -0700164 help=('Only return hostnames.'),
Aviv Keshete1729bb2017-05-31 13:27:09 -0700165 action='store_true',
166 default=False)
Allen Li75e3d342018-08-06 19:04:31 +0000167 # TODO(crbug.com/850344): support '--table' and '--summary' formats.
Dan Shi784df0c2014-11-26 10:11:15 -0800168
169
170 def parse(self):
171 """Parse command arguments.
172 """
173 (options, leftover) = super(server_list, self).parse()
Allen Lica17e7c2016-10-27 15:37:17 -0700174 self.json = options.json
Dan Shi784df0c2014-11-26 10:11:15 -0800175 self.status = options.status
Aviv Keshete1729bb2017-05-31 13:27:09 -0700176 self.namesonly = options.hostnames_only
Ningning Xia84190b82018-04-16 15:01:40 -0700177
Allen Li75e3d342018-08-06 19:04:31 +0000178 if sum([self.json, self.namesonly]) > 1:
Aviv Keshete1729bb2017-05-31 13:27:09 -0700179 self.invalid_syntax('May only specify up to 1 output-format flag.')
Dan Shi784df0c2014-11-26 10:11:15 -0800180 return (options, leftover)
181
182
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700183 def execute_skylab(self):
184 """Execute 'atest server list --skylab'
185
186 @return: A list of servers matched the given hostname and role.
187 """
188 inventory_repo = skylab_utils.InventoryRepo(
189 self.inventory_repo_dir)
190 inventory_repo.initialize()
191 infrastructure = text_manager.load_infrastructure(
192 inventory_repo.get_data_dir())
193
194 return skylab_server.get_servers(
195 infrastructure,
196 self.environment,
197 hostname=self.hostname,
198 role=self.role,
199 status=self.status)
200
201
Dan Shi784df0c2014-11-26 10:11:15 -0800202 def execute(self):
203 """Execute the command.
204
205 @return: A list of servers matched given hostname and role.
206 """
Ningning Xia84190b82018-04-16 15:01:40 -0700207 if self.skylab:
208 try:
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700209 return self.execute_skylab()
Ningning Xia84190b82018-04-16 15:01:40 -0700210 except (skylab_server.SkylabServerActionError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700211 revision_control.GitError,
212 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700213 self.failure(e, what_failed='Failed to list servers from skylab'
214 ' inventory.', item=self.hostname, fatal=True)
215 else:
216 try:
217 return server_manager_utils.get_servers(
218 hostname=self.hostname,
219 role=self.role,
220 status=self.status)
221 except (server_manager_utils.ServerActionError,
222 error.InvalidDataError) as e:
223 self.failure(e, what_failed='Failed to find servers',
224 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800225
226
227 def output(self, results):
228 """Display output.
229
230 @param results: return of the execute call, a list of server object that
231 contains server information.
232 """
Allen Li90a84ea2016-10-27 15:07:42 -0700233 if results:
Allen Lica17e7c2016-10-27 15:37:17 -0700234 if self.json:
Ningning Xia32b26682018-05-23 14:25:18 -0700235 if self.skylab:
236 formatter = skylab_server.format_servers_json
237 else:
238 formatter = server_manager_utils.format_servers_json
Aviv Keshete1729bb2017-05-31 13:27:09 -0700239 elif self.namesonly:
240 formatter = server_manager_utils.format_servers_nameonly
Allen Li90a84ea2016-10-27 15:07:42 -0700241 else:
242 formatter = server_manager_utils.format_servers
243 print formatter(results)
244 else:
Dan Shi784df0c2014-11-26 10:11:15 -0800245 self.failure('No server is found.',
246 what_failed='Failed to find servers',
247 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800248
249
250class server_create(server):
251 """atest server create hostname --role <role> --note <note>
252 """
253
254 def __init__(self):
255 """Initializer.
256 """
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700257 super(server_create, self).__init__(allow_multiple_hostname=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800258 self.parser.add_option('-n', '--note',
259 help='note of the server',
260 type='string',
261 default=None,
262 metavar='NOTE')
263
264
265 def parse(self):
266 """Parse command arguments.
267 """
268 (options, leftover) = super(server_create, self).parse()
269 self.note = options.note
270
271 if not self.role:
272 self.invalid_syntax('--role is required to create a server.')
273
274 return (options, leftover)
275
276
Ningning Xia84190b82018-04-16 15:01:40 -0700277 def execute_skylab(self):
278 """Execute the command for skylab inventory changes."""
279 inventory_repo = skylab_utils.InventoryRepo(
280 self.inventory_repo_dir)
281 inventory_repo.initialize()
282 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700283 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700284
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700285 new_servers = []
286 for hostname in self.hostname:
287 new_servers.append(skylab_server.create(
288 infrastructure,
289 hostname,
290 self.environment,
291 role=self.role,
292 note=self.note))
Ningning Xiae8714052018-04-30 18:58:54 -0700293 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700294
295 message = skylab_utils.construct_commit_message(
296 'Add new server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700297 self.change_number = inventory_repo.upload_change(
298 message, draft=self.draft, dryrun=self.dryrun,
299 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700300
Xixuan Wu9e0cfaa2018-07-25 16:28:31 -0700301 return new_servers
Ningning Xia84190b82018-04-16 15:01:40 -0700302
303
Dan Shi784df0c2014-11-26 10:11:15 -0800304 def execute(self):
305 """Execute the command.
306
307 @return: A Server object if it is created successfully.
308 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800309 if RESPECT_SKYLAB_SERVERDB:
310 self.failure(ATEST_DISABLE_MSG,
311 what_failed='Failed to create server',
312 item=self.hostname, fatal=True)
313
Ningning Xia84190b82018-04-16 15:01:40 -0700314 if self.skylab:
315 try:
316 return self.execute_skylab()
317 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700318 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700319 gob_util.GOBError,
320 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xiae8714052018-04-30 18:58:54 -0700321 self.failure(e, what_failed='Failed to create server in skylab '
Ningning Xia84190b82018-04-16 15:01:40 -0700322 'inventory.', item=self.hostname, fatal=True)
323 else:
324 try:
325 return server_manager.create(
326 hostname=self.hostname,
327 role=self.role,
328 note=self.note)
329 except (server_manager_utils.ServerActionError,
330 error.InvalidDataError) as e:
331 self.failure(e, what_failed='Failed to create server',
332 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800333
334
335 def output(self, results):
336 """Display output.
337
338 @param results: return of the execute call, a server object that
339 contains server information.
340 """
341 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700342 print 'Server %s is added.\n' % self.hostname
Dan Shi784df0c2014-11-26 10:11:15 -0800343 print results
344
Ningning Xiaa043aad2018-04-23 15:07:09 -0700345 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700346 print skylab_utils.get_cl_message(self.change_number)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700347
Ningning Xia84190b82018-04-16 15:01:40 -0700348
Dan Shi784df0c2014-11-26 10:11:15 -0800349
350class server_delete(server):
351 """atest server delete hostname"""
352
Ningning Xia84190b82018-04-16 15:01:40 -0700353 def execute_skylab(self):
354 """Execute the command for skylab inventory changes."""
355 inventory_repo = skylab_utils.InventoryRepo(
356 self.inventory_repo_dir)
357 inventory_repo.initialize()
358 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700359 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700360
Ningning Xiae8714052018-04-30 18:58:54 -0700361 skylab_server.delete(infrastructure, self.hostname, self.environment)
362 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700363
364 message = skylab_utils.construct_commit_message(
365 'Delete server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700366 self.change_number = inventory_repo.upload_change(
367 message, draft=self.draft, dryrun=self.dryrun,
368 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700369
370
Dan Shi784df0c2014-11-26 10:11:15 -0800371 def execute(self):
372 """Execute the command.
373
374 @return: True if server is deleted successfully.
375 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800376 if RESPECT_SKYLAB_SERVERDB:
377 self.failure(ATEST_DISABLE_MSG,
378 what_failed='Failed to delete server',
379 item=self.hostname, fatal=True)
380
Ningning Xia84190b82018-04-16 15:01:40 -0700381 if self.skylab:
382 try:
383 self.execute_skylab()
384 return True
385 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700386 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700387 gob_util.GOBError,
388 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700389 self.failure(e, what_failed='Failed to delete server from '
390 'skylab inventory.', item=self.hostname,
391 fatal=True)
392 else:
393 try:
394 server_manager.delete(hostname=self.hostname)
395 return True
396 except (server_manager_utils.ServerActionError,
397 error.InvalidDataError) as e:
398 self.failure(e, what_failed='Failed to delete server',
399 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800400
401
402 def output(self, results):
403 """Display output.
404
405 @param results: return of the execute call.
406 """
407 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700408 print ('Server %s is deleted.\n' %
Dan Shi784df0c2014-11-26 10:11:15 -0800409 self.hostname)
410
Ningning Xiaa043aad2018-04-23 15:07:09 -0700411 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700412 print skylab_utils.get_cl_message(self.change_number)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700413
Ningning Xia84190b82018-04-16 15:01:40 -0700414
Dan Shi784df0c2014-11-26 10:11:15 -0800415
416class server_modify(server):
417 """atest server modify hostname
418
419 modify action can only change one input at a time. Available inputs are:
420 --status: Status of the server.
421 --note: Note of the server.
422 --role: New role to be added to the server.
423 --delete_role: Existing role to be deleted from the server.
424 """
425
426 def __init__(self):
427 """Initializer.
428 """
429 super(server_modify, self).__init__()
430 self.parser.add_option('-s', '--status',
431 help='Status of the server',
432 type='string',
433 metavar='STATUS')
434 self.parser.add_option('-n', '--note',
435 help='Note of the server',
436 type='string',
437 default=None,
438 metavar='NOTE')
439 self.parser.add_option('-d', '--delete',
440 help=('Set to True to delete given role.'),
441 action='store_true',
442 default=False,
443 metavar='DELETE')
444 self.parser.add_option('-a', '--attribute',
445 help='Name of the attribute of the server',
446 type='string',
447 default=None,
448 metavar='ATTRIBUTE')
449 self.parser.add_option('-e', '--value',
450 help='Value for the attribute of the server',
451 type='string',
452 default=None,
453 metavar='VALUE')
454
455
456 def parse(self):
457 """Parse command arguments.
458 """
459 (options, leftover) = super(server_modify, self).parse()
460 self.status = options.status
461 self.note = options.note
462 self.delete = options.delete
463 self.attribute = options.attribute
464 self.value = options.value
Dan Shi56f1ba72014-12-03 19:16:53 -0800465 self.action = options.action
Dan Shi784df0c2014-11-26 10:11:15 -0800466
467 # modify supports various options. However, it's safer to limit one
468 # option at a time so no complicated role-dependent logic is needed
469 # to handle scenario that both role and status are changed.
470 # self.parser is optparse, which does not have function in argparse like
471 # add_mutually_exclusive_group. That's why the count is used here.
472 flags = [self.status is not None, self.role is not None,
473 self.attribute is not None, self.note is not None]
474 if flags.count(True) != 1:
475 msg = ('Action modify only support one option at a time. You can '
476 'try one of following 5 options:\n'
477 '1. --status: Change server\'s status.\n'
478 '2. --note: Change server\'s note.\n'
479 '3. --role with optional -d: Add/delete role from server.\n'
480 '4. --attribute --value: Set/change the value of a '
481 'server\'s attribute.\n'
482 '5. --attribute -d: Delete the attribute from the '
483 'server.\n'
484 '\nUse option -h to see a complete list of options.')
485 self.invalid_syntax(msg)
486 if (self.status != None or self.note != None) and self.delete:
487 self.invalid_syntax('--delete does not apply to status or note.')
488 if self.attribute != None and not self.delete and self.value == None:
489 self.invalid_syntax('--attribute must be used with option --value '
490 'or --delete.')
Ningning Xia84190b82018-04-16 15:01:40 -0700491
492 # TODO(nxia): crbug.com/832964 support --action with --skylab
493 if self.skylab and self.action:
494 self.invalid_syntax('--action is currently not supported with'
495 ' --skylab.')
496
Dan Shi784df0c2014-11-26 10:11:15 -0800497 return (options, leftover)
498
499
Ningning Xia84190b82018-04-16 15:01:40 -0700500 def execute_skylab(self):
501 """Execute the command for skylab inventory changes."""
502 inventory_repo = skylab_utils.InventoryRepo(
503 self.inventory_repo_dir)
504 inventory_repo.initialize()
505 data_dir = inventory_repo.get_data_dir()
Ningning Xiae8714052018-04-30 18:58:54 -0700506 infrastructure = text_manager.load_infrastructure(data_dir)
Ningning Xia84190b82018-04-16 15:01:40 -0700507
508 target_server = skylab_server.modify(
509 infrastructure,
510 self.hostname,
Ningning Xiae8714052018-04-30 18:58:54 -0700511 self.environment,
Ningning Xia84190b82018-04-16 15:01:40 -0700512 role=self.role,
513 status=self.status,
514 delete_role=self.delete,
515 note=self.note,
516 attribute=self.attribute,
517 value=self.value,
518 delete_attribute=self.delete)
Ningning Xiae8714052018-04-30 18:58:54 -0700519 text_manager.dump_infrastructure(data_dir, infrastructure)
Ningning Xia84190b82018-04-16 15:01:40 -0700520
521 status = inventory_repo.git_repo.status()
522 if not status:
523 print('Nothing is changed for server %s.' % self.hostname)
524 return
525
526 message = skylab_utils.construct_commit_message(
527 'Modify server: %s' % self.hostname)
Ningning Xiaa043aad2018-04-23 15:07:09 -0700528 self.change_number = inventory_repo.upload_change(
529 message, draft=self.draft, dryrun=self.dryrun,
530 submit=self.submit)
Ningning Xia84190b82018-04-16 15:01:40 -0700531
532 return target_server
533
534
Dan Shi784df0c2014-11-26 10:11:15 -0800535 def execute(self):
536 """Execute the command.
537
538 @return: The updated server object if it is modified successfully.
539 """
Shuqian Zhaodb205af2018-02-28 15:13:03 -0800540 if RESPECT_SKYLAB_SERVERDB:
541 self.failure(ATEST_DISABLE_MSG,
542 what_failed='Failed to modify server',
543 item=self.hostname, fatal=True)
544
Ningning Xia84190b82018-04-16 15:01:40 -0700545 if self.skylab:
546 try:
547 return self.execute_skylab()
548 except (skylab_server.SkylabServerActionError,
Ningning Xiaa043aad2018-04-23 15:07:09 -0700549 revision_control.GitError,
Ningning Xiad23cf2f2018-06-04 17:50:35 -0700550 gob_util.GOBError,
551 skylab_utils.InventoryRepoDirNotClean) as e:
Ningning Xia84190b82018-04-16 15:01:40 -0700552 self.failure(e, what_failed='Failed to modify server in skylab'
553 ' inventory.', item=self.hostname, fatal=True)
554 else:
555 try:
556 return server_manager.modify(
557 hostname=self.hostname, role=self.role,
558 status=self.status, delete=self.delete,
559 note=self.note, attribute=self.attribute,
560 value=self.value, action=self.action)
561 except (server_manager_utils.ServerActionError,
562 error.InvalidDataError) as e:
563 self.failure(e, what_failed='Failed to modify server',
564 item=self.hostname, fatal=True)
Dan Shi784df0c2014-11-26 10:11:15 -0800565
566
567 def output(self, results):
568 """Display output.
569
570 @param results: return of the execute call, which is the updated server
571 object.
572 """
573 if results:
Ningning Xia84190b82018-04-16 15:01:40 -0700574 print 'Server %s is modified.\n' % self.hostname
Dan Shi784df0c2014-11-26 10:11:15 -0800575 print results
Ningning Xia84190b82018-04-16 15:01:40 -0700576
Ningning Xiaa043aad2018-04-23 15:07:09 -0700577 if self.skylab and not self.dryrun and not self.submit:
Ningning Xiaef35cb52018-05-04 17:58:20 -0700578 print skylab_utils.get_cl_message(self.change_number)