comparison usr/src/cmd/beadm/beadm.py @ 13025:3c7681e3e323

PSARC 2010/059 SNAP BE Management 6964804 SNAP BE management into ON 6971379 libbe should capture and give useful error when installgrub or ict.py fails. 6971390 beadm does not support labeled brand zones 6971394 BEADM_ERR_BE_DOES_NOT_EXIST has an extra space 6971397 libbe error messages need internationalization 6971402 Remove be_get_last_zone_be_callback 6971409 be_create_menu returns errors from both be_errno_t and errno sets
author Glenn Lagasse <glenn.lagasse@oracle.com>
date Wed, 04 Aug 2010 12:28:19 -0700
parents
children
comparison
equal deleted inserted replaced
13024:c176c071a066 13025:3c7681e3e323
1 #!/usr/bin/python2.6
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22
23 #
24 # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25 #
26
27 """
28 beadm - The Boot Environment Administration tool. Use this CLI to
29 manage boot environments.
30 """
31
32 import getopt
33 import gettext
34 import os
35 import sys
36 import shutil
37 import traceback
38 import time
39 import subprocess
40
41 from beadm import _
42 from beadm.BootEnvironment import *
43 import beadm.messages as msg
44 import libbe_py as lb
45
46 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 def usage():
48 '''Defines parameters and options of the command beadm.'''
49 print >> sys.stderr, _("""
50 Usage:
51 beadm subcommand cmd_options
52
53 subcommands:
54
55 beadm activate beName
56 beadm create [-a] [-d description]
57 [-e non-activeBeName | beName@snapshot]
58 [-o property=value] ... [-p zpool] beName
59 beadm create beName@snapshot
60 beadm destroy [-fF] beName | beName@snapshot
61 beadm list [[-a] | [-d] [-s]] [-H] [beName]
62 beadm mount beName mountpoint
63 beadm rename beName newBeName
64 beadm unmount [-f] beName""")
65 sys.exit(1)
66
67
68 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
69 # Public Command Line functions described in beadm(1)
70 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71
72 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73 def activate(opts):
74 """
75 Function: activate
76
77 Description: Activate a Boot Environment.The following is the
78 subcommand, options and args that make up the
79 opts object passed in:
80
81 Parameters:
82 opts - A string containing the active subcommand
83
84 Returns:
85 0 - Success
86 1 - Failure
87 """
88
89 if len(opts) != 1:
90 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
91 usage()
92
93 be = BootEnvironment()
94
95 if lb.beVerifyBEName(opts[0]) != 0:
96 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
97 return 1
98
99 rc = lb.beActivate(opts[0])
100 if rc == 0:
101 return 0
102
103 be.msg_buf["0"] = opts[0]
104 if rc == msg.Msgs.BE_ERR_BE_NOENT:
105 be.msg_buf["1"] = \
106 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, opts[0])
107 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
108 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
109 msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)
110 return 1
111 else:
112 be.msg_buf["1"] = lb.beGetErrDesc(rc)
113 if be.msg_buf["1"] == None:
114 be.msg_buf["1"] = \
115 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
116
117 msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)
118 return 1
119
120
121 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122 def create(opts):
123 """
124 Function: create
125
126 Description: Create a Boot Environment. The following is the
127 subcommand, options and args that make up the
128 opts object passed in:
129
130 create [-a] [-d description]
131 [-e non-activeBeName | beName@Snapshot]
132 [-o property=value] ... [-p zpool] beName
133
134 create beName@Snapshot
135
136 Parameters:
137 opts - A object containing the create subcommand
138 and all the options and arguments passed in
139 on the command line mentioned above.
140
141 Returns:
142 0 - Success
143 1 - Failure
144 """
145
146 be = BootEnvironment()
147
148 activate = False
149
150 try:
151 opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts,
152 "ad:e:o:p:")
153 except getopt.GetoptError:
154 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
155 usage()
156
157 # Counters for detecting multiple options.
158 # e.g. beadm create -p rpool -p rpool2 newbe
159 num_a_opts = 0
160 num_e_opts = 0
161 num_p_opts = 0
162 num_d_opts = 0
163
164 for opt, arg in opts_args:
165 if opt == "-a":
166 activate = True
167 num_a_opts += 1
168 elif opt == "-e":
169 be.src_be_name_or_snapshot = arg
170 num_e_opts += 1
171 elif opt == "-o":
172 key, value = arg.split("=")
173 be.properties[key] = value
174 elif opt == "-p":
175 be.trgt_rpool = arg
176 num_p_opts += 1
177 elif opt == "-d":
178 be.description = arg
179 num_d_opts += 1
180
181 if num_a_opts > 1 or num_e_opts > 1 or num_p_opts > 1 or num_d_opts > 1:
182 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
183 usage()
184
185 # Check that all info provided from the user is legitimate.
186 if (verifyCreateOptionsArgs(be) != 0):
187 usage()
188
189 if initBELog("create", be) != 0:
190 return 1
191
192 msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_START,
193 be.trgt_be_name_or_snapshot[0], be.log_id)
194
195 if '@' in be.trgt_be_name_or_snapshot[0]:
196 # Create a snapshot
197 rc = createSnapshot(be)
198 else:
199 if lb.beVerifyBEName(be.trgt_be_name_or_snapshot[0]) != 0:
200 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
201 return 1
202
203 # Create a BE based on a snapshot
204 if be.src_be_name_or_snapshot is not None and \
205 '@' in be.src_be_name_or_snapshot:
206 # Create a BE from a snapshot
207 rc = createBEFromSnapshot(be)
208 else:
209 rc = createBE(be)
210
211 # Activate the BE if the user chose to.
212 if activate and rc == 0:
213 rc = activateBE(be)
214 cleanupBELog(be)
215
216 return rc
217
218 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
219 def destroy(opts):
220 """
221 Function: destroy
222
223 Description: Destroy a Boot Environment. The following is the
224 subcommand, options and args that make up the
225 opts object passed in:
226
227 destroy [-fF] beName | beName@snapshot
228
229 Parameters:
230 opts - A object containing the destroy subcommand
231 and all the options and arguments passed in
232 on the command line mentioned above.
233
234 Returns:
235 0 - Success
236 1 - Failure
237 """
238
239 force_unmount = 0
240 suppress_prompt = False
241 be_active_on_boot = None
242 be = BootEnvironment()
243
244 try:
245 opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts, "fF")
246 except getopt.GetoptError:
247 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
248 usage()
249
250 # Counters for detecting multiple options.
251 # e.g. beadm destroy -f -f newbe
252 num_f_opts = 0
253 num_sf_opts = 0
254
255 for opt, arg in opts_args:
256 if opt == "-f":
257 force_unmount = 1
258 num_sf_opts += 1
259 elif opt == "-F":
260 suppress_prompt = True
261 num_f_opts += 1
262
263 if num_sf_opts > 1 or num_f_opts > 1:
264 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
265 usage()
266
267 if len(be.trgt_be_name_or_snapshot) != 1:
268 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
269 usage()
270
271 is_snapshot = False
272
273 if "@" in be.trgt_be_name_or_snapshot[0]:
274 is_snapshot = True
275 be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@")
276 if lb.beVerifyBEName(be_name) != 0:
277 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
278 return 1
279 else:
280 if lb.beVerifyBEName(be.trgt_be_name_or_snapshot[0]) != 0:
281 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
282 return 1
283
284 # Get the 'active' BE and the 'active on boot' BE.
285 be_active, be_active_on_boot = getActiveBEAndActiveOnBootBE()
286
287 # If the user is trying to destroy the 'active' BE then quit now.
288 if not is_snapshot and be_active == be.trgt_be_name_or_snapshot[0]:
289 be.msg_buf["0"] = be.msg_buf["1"] = be_active
290 msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY_ACTIVE, be.msg_buf, -1)
291 return 1
292
293 if not suppress_prompt:
294
295 # Display a destruction question and wait for user response.
296 # Quit if negative user response.
297
298 if not displayDestructionQuestion(be):
299 return 0
300
301 if is_snapshot:
302
303 # Destroy a snapshot.
304 rc = lb.beDestroySnapshot(be_name, snap_name)
305 else:
306
307 # Destroy a BE. Passing in 1 for the second arg destroys
308 # any snapshots the BE may have as well.
309
310 rc = lb.beDestroy(be.trgt_be_name_or_snapshot[0], 1, force_unmount)
311
312 # Check if the BE that was just destroyed was the
313 # 'active on boot' BE. If it was, display a message letting
314 # the user know that the 'active' BE is now also the
315 # 'active on boot' BE.
316 if be_active_on_boot == be.trgt_be_name_or_snapshot[0] and rc == 0:
317 msg.printMsg(msg.Msgs.BEADM_MSG_ACTIVE_ON_BOOT,
318 be_active, -1)
319
320 if rc == 0:
321 try:
322 shutil.rmtree("/var/log/beadm/" + \
323 be.trgt_be_name_or_snapshot[0], True)
324 except:
325 msg.printMsg(msg.Msgs.BEADM_ERR_LOG_RM,
326 "/var/log/beadm/" + be.trgt_be_name_or_snapshot[0], -1)
327
328 return 0
329
330 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
331 if rc == msg.Msgs.BE_ERR_MOUNTED:
332 be.msg_buf["1"] = be.msg_buf["2"] = be.trgt_be_name_or_snapshot[0]
333 msg.printMsg(msg.Msgs.BEADM_ERR_MOUNTED, be.msg_buf, -1)
334 return 1
335 elif rc == msg.Msgs.BE_ERR_DESTROY_CURR_BE:
336 msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY_ACTIVE, \
337 be.msg_buf["0"], -1)
338 return 1
339 elif rc == msg.Msgs.BE_ERR_ZONES_UNMOUNT:
340 be.msg_buf["1"] = be.trgt_be_name_or_snapshot[0]
341 msg.printMsg(msg.Msgs.BE_ERR_ZONES_UNMOUNT, be.msg_buf, -1)
342 return 1
343 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
344 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
345 msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY, be.msg_buf, -1)
346 return 1
347 else:
348 be.msg_buf["1"] = lb.beGetErrDesc(rc)
349 if be.msg_buf["1"] == None:
350 be.msg_buf["1"] = \
351 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
352
353 msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY, be.msg_buf, -1)
354 return 1
355
356 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
357 def list(opts):
358 """
359 Description: List the attributes of a Boot Environment.
360 The following is the subcommand, options
361 and args that make up the opts object
362 passed in:
363
364 list [[-a] | [-d] [-s]] [-H] [beName]
365
366 -a displays all info
367 -d displays BE info plus dataset info
368 -s displays BE info plus snapshot info
369 -H displays info parsable by a computer
370
371 Parameters:
372 opts - A object containing the list subcommand
373 and all the options and arguments passed in
374 on the command line mentioned above.
375
376 Returns:
377 0 - Success
378 1 - Failure
379 """
380
381 be = BootEnvironment()
382
383 list_all_attrs = ""
384 list_datasets = ""
385 list_snapshots = ""
386 dont_display_headers = False
387 be_name = None
388 be_list = None
389
390 # Counters for detecting multiple options.
391 # e.g. beadm list -a -a newbe
392 num_a_opts = 0
393 num_d_opts = 0
394 num_s_opts = 0
395 num_h_opts = 0
396
397 try:
398 opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts, "adHs")
399 except getopt.GetoptError:
400 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
401 usage()
402
403 for opt, arg in opts_args:
404 if opt == "-a":
405 list_all_attrs = opt
406 num_a_opts += 1
407 elif opt == "-d":
408 list_datasets = opt
409 num_d_opts += 1
410 elif opt == "-s":
411 list_snapshots = opt
412 num_s_opts += 1
413 elif opt == "-H":
414 dont_display_headers = True
415 num_h_opts += 1
416
417 if num_a_opts > 1 or num_d_opts > 1 or num_s_opts > 1 or num_h_opts > 1:
418 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
419 usage()
420
421 if len(be.trgt_be_name_or_snapshot) > 1:
422 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
423 usage()
424
425 if len(be.trgt_be_name_or_snapshot) == 1:
426 be_name = be.trgt_be_name_or_snapshot[0]
427 if lb.beVerifyBEName(be_name) != 0:
428 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
429 return 1
430
431 if (list_all_attrs == "-a" and (list_datasets == "-d" \
432 or list_snapshots == "-s")):
433 msg.printMsg(msg.Msgs.BEADM_ERR_MUTUALLY_EXCL,
434 list_all_attrs + " " + list_datasets + " " +
435 list_snapshots, -1)
436 usage()
437
438 list_options = ""
439
440 # When zones are implemented add "listZones == "-z" below
441
442 # Coelesce options to pass to displayBEs
443
444 if (list_datasets == "-d" and list_snapshots == "-s" or \
445 list_all_attrs == "-a"):
446 list_options = "-a"
447 elif list_datasets != "" or list_snapshots != "" or list_all_attrs != "":
448 list_options = list_datasets + " " + list_snapshots
449
450 rc, be_list = lb.beList()
451 if rc != 0:
452 if rc == msg.Msgs.BE_ERR_BE_NOENT:
453 if be_name == None:
454 msg.printMsg(msg.Msgs.BEADM_ERR_NO_BES_EXIST,
455 None, -1)
456 return 1
457
458 string = \
459 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
460 be_name)
461 else:
462 string = lb.beGetErrDesc(rc)
463 if string == None:
464 string = \
465 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
466
467 msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
468 return 1
469
470 # classify according to command line options
471 if list_options.find("-a") != -1 or \
472 (list_options.find("-d") != -1 and list_options.find("-s") != -1):
473 list_object = CompleteList(dont_display_headers) #all
474 elif list_options.find("-d") != -1:
475 list_object = DatasetList(dont_display_headers) #dataset
476 elif list_options.find("-s") != -1:
477 list_object = SnapshotList(dont_display_headers) #snapshot
478 else: list_object = BEList(dont_display_headers) #only BE
479
480 # use list method for object
481 if list_object.list(be_list, dont_display_headers, be_name) != 0:
482 msg.printMsg(msg.Msgs.BEADM_ERR_LIST_DATA, None, -1)
483 return 1
484
485 return 0
486
487 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
488 def mount(opts):
489 """
490 Description: Mount a Boot Environment on a directory.
491 The following is the subcommand, options
492 and args that make up the opts object
493 passed in:
494
495 mount beName [mountpoint]
496
497 Parameters:
498 opts - A object containing the mount subcommand
499 and all the options and arguments passed in
500 on the command line mentioned above.
501
502 Returns:
503 0 - Success
504 1 - Failure
505 """
506
507 be = BootEnvironment()
508
509 mountpoint = None
510
511 try:
512 be_name_mnt_point = getopt.getopt(opts, "")[1]
513 except getopt.GetoptError:
514 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
515 usage()
516
517 mnt_point_len = len(be_name_mnt_point)
518
519 if mnt_point_len != 2:
520 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
521 usage()
522 else:
523 # Check for leading / in mount point
524 mountpoint = be_name_mnt_point[1]
525 if not mountpoint.startswith('/'):
526 msg.printMsg(msg.Msgs.BEADM_ERR_MOUNTPOINT,
527 mountpoint, -1)
528 return 1
529
530 if lb.beVerifyBEName(be_name_mnt_point[0]) != 0:
531 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
532 return 1
533
534 rc = lb.beMount(be_name_mnt_point[0], mountpoint)
535 if rc == 0:
536 return 0
537
538 be.msg_buf["0"] = be_name_mnt_point[0]
539 if rc == msg.Msgs.BE_ERR_MOUNTED:
540 be.msg_buf["1"] = \
541 msg.getMsg(msg.Msgs.BEADM_ERR_MOUNT_EXISTS,
542 be_name_mnt_point[0])
543 elif rc == msg.Msgs.BE_ERR_BE_NOENT:
544 be.msg_buf["1"] = \
545 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
546 be_name_mnt_point[0])
547 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
548 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
549 msg.printMsg(msg.Msgs.BEADM_ERR_MOUNT, be.msg_buf, -1)
550 return 1
551 else:
552 be.msg_buf["1"] = lb.beGetErrDesc(rc)
553 if be.msg_buf["1"] == None:
554 be.msg_buf["1"] = \
555 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
556
557 msg.printMsg(msg.Msgs.BEADM_ERR_MOUNT, be.msg_buf, -1)
558 return 1
559
560 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
561 def unmount(opts):
562 """
563 Description: Unmount a Boot Environment.
564 The following is the subcommand, options
565 and args that make up the opts object
566 passed in:
567
568 unmount [-f] beName
569
570 Parameters:
571 opts - A object containing the unmount subcommand
572 and all the options and arguments passed in
573 on the command line mentioned above.
574
575 Returns:
576 0 - Success
577 1 - Failure
578 """
579
580 be = BootEnvironment()
581
582 force_unmount = 0
583
584 # Counter for detecting multiple options.
585 # e.g. beadm unmount -f -f newbe
586 num_f_opts = 0
587
588 try:
589 optlist, args = getopt.getopt(opts, "f")
590 except getopt.GetoptError:
591 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
592 usage()
593
594 for opt, arg in optlist:
595 if opt == "-f":
596 force_unmount = 1
597 num_f_opts += 1
598
599 if num_f_opts > 1:
600 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
601 usage()
602
603 if len(args) != 1:
604 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
605 usage()
606
607 if lb.beVerifyBEName(args[0]) != 0:
608 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
609 return 1
610
611 rc = lb.beUnmount(args[0], force_unmount)
612 if rc == 0:
613 return 0
614
615 be.msg_buf["0"] = args[0]
616 if rc == msg.Msgs.BE_ERR_UMOUNT_CURR_BE:
617 be.msg_buf["1"] = \
618 msg.getMsg(msg.Msgs.BEADM_ERR_UNMOUNT_ACTIVE,
619 args[0])
620 elif rc == msg.Msgs.BE_ERR_UMOUNT_SHARED:
621 be.msg_buf["1"] = \
622 msg.getMsg(msg.Msgs.BEADM_ERR_SHARED_FS, args[0])
623 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
624 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
625 msg.printMsg(msg.Msgs.BEADM_ERR_UNMOUNT, be.msg_buf, -1)
626 return 1
627 else:
628 be.msg_buf["1"] = lb.beGetErrDesc(rc)
629 if be.msg_buf["1"] == None:
630 be.msg_buf["1"] = \
631 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
632
633 msg.printMsg(msg.Msgs.BEADM_ERR_UNMOUNT, be.msg_buf, -1)
634 return 1
635
636 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
637 def rename(opts):
638 """
639 Description: Rename the name of a Boot Environment.
640 The following is the subcommand, options
641 and args that make up the opts object
642 passed in:
643
644 rename beName newBeName
645
646 Parameters:
647 opts - A object containing the mount subcommand
648 and all the options and arguments passed in
649 on the command line mentioned above.
650
651 Returns:
652 0 - Success
653 1 - Failure
654 """
655
656 be = BootEnvironment()
657
658 try:
659 be_names = getopt.getopt(opts, "")[1]
660 except getopt.GetoptError:
661 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
662 usage()
663
664 if len(be_names) != 2:
665 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
666 usage()
667
668 if lb.beVerifyBEName(be_names[0]) != 0:
669 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
670 return 1
671
672 if lb.beVerifyBEName(be_names[1]) != 0:
673 msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
674 return 1
675
676 rc = lb.beRename(be_names[0], be_names[1])
677
678 if rc == 0:
679 return 0
680
681 be.msg_buf["0"] = be_names[0]
682 if rc == msg.Msgs.BE_ERR_BE_NOENT:
683 be.msg_buf["1"] = \
684 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
685 be_names[0])
686 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
687 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
688 msg.printMsg(msg.Msgs.BEADM_ERR_RENAME, be.msg_buf, -1)
689 return 1
690 else:
691 be.msg_buf["1"] = lb.beGetErrDesc(rc)
692 if be.msg_buf["1"] == None:
693 be.msg_buf["1"] = \
694 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
695
696 msg.printMsg(msg.Msgs.BEADM_ERR_RENAME, be.msg_buf, -1)
697 return 1
698
699 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700 # End of CLI public functions
701 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
702
703 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
704 # Verify the options and arguments for the beadm create subcommand
705
706 def verifyCreateOptionsArgs(be):
707 """Check valid BE names."""
708
709 len_be_args = len(be.trgt_be_name_or_snapshot)
710 if len_be_args < 1:
711 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
712 return 1
713 if len_be_args > 1:
714 msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
715 idx = 0
716 while len_be_args > idx:
717 msg.printMsg(msg.Msgs.BEADM_MSG_FREE_FORMAT,
718 be.trgt_be_name_or_snapshot[idx], -1)
719 idx += 1
720 return 1
721
722 return 0
723
724 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
725 def parseCLI(cli_opts_args):
726 """Parse command line interface arguments."""
727
728 gettext.install("beadm", "/usr/lib/locale")
729
730 if len(cli_opts_args) == 0:
731 usage()
732
733 subcommand = cli_opts_args[0]
734 opts_args = cli_opts_args[1:]
735
736 if subcommand == "activate":
737 rc = activate(opts_args)
738 elif subcommand == "create":
739 rc = create(opts_args)
740 elif subcommand == "destroy":
741 rc = destroy(opts_args)
742 elif subcommand == "list":
743 rc = list(opts_args)
744 elif subcommand == "mount":
745 rc = mount(opts_args)
746 elif subcommand == "rename":
747 rc = rename(opts_args)
748 elif subcommand == "upgrade":
749 rc = upgrade(opts_args)
750 elif subcommand == "unmount" or \
751 subcommand == "umount": #aliased for convenience
752 rc = unmount(opts_args)
753 elif subcommand == "verify":
754 rc = verify()
755 else:
756 msg.printMsg(msg.Msgs.BEADM_ERR_ILL_SUBCOMMAND,
757 subcommand, -1)
758 usage()
759
760 return(rc)
761
762 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763 def main():
764 """main function."""
765
766 gettext.install("beadm", "/usr/lib/locale")
767
768 if not isBeadmSupported():
769 return(1)
770
771 return(parseCLI(sys.argv[1:]))
772
773 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
774 def initBELog(log_id, be):
775 """
776 Initiate the BE log
777
778 Format of the log
779 yyyymmdd_hhmmss - 20071130_140558
780 yy - year; 2007
781 mm - month; 11
782 dd - day; 30
783 hh - hour; 14
784 mm - minute; 05
785 ss - second; 58
786 """
787
788 # /var/log/beadm/<beName>/<logId>.log.<yyyymmdd_hhmmss>
789
790 date = time.strftime("%Y%m%d_%H%M%S", time.localtime())
791
792 be.log = "/var/log/beadm/" + be.trgt_be_name_or_snapshot[0] + \
793 "/" + log_id + ".log" + "." + date
794
795 if not os.path.isfile(be.log) and not os.path.islink(be.log):
796 if not os.path.isdir(os.path.dirname(be.log)):
797 try:
798 os.makedirs(os.path.dirname(be.log), 0644)
799 except OSError:
800 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
801 be.msg_buf["1"] = \
802 msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS,
803 0)
804 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE,
805 be.msg_buf, -1)
806 return 1
807 try:
808 be.log_id = open(be.log, "a")
809 except IOError:
810 msg.printMsg(msg.Msgs.BEADM_ERR_LOG_CREATE,
811 None, -1)
812 return 1
813 else:
814 # Should never happen due to new time stamp each call
815 msg.printMsg(msg.Msgs.BEADM_ERR_LOG_CREATE, None, -1)
816 return 1
817
818 return 0
819
820 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
821 def cleanupBELog(be):
822 """Clean up BE log."""
823
824 be.log_id.close()
825
826 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
827 def displayDestructionQuestion(be):
828 """Display a destruction question and wait for user response."""
829
830 msg.printMsg(msg.Msgs.BEADM_MSG_DESTROY, be.trgt_be_name_or_snapshot[0], -1)
831 while True:
832 try:
833 value = raw_input().strip().upper()
834 except KeyboardInterrupt:
835 return False
836 if (value == 'Y' or value == 'YES'):
837 return True
838 elif len(value) == 0 or value == 'N' or value == 'NO':
839 msg.printMsg(msg.Msgs.BEADM_MSG_DESTROY_NO,
840 be.trgt_be_name_or_snapshot[0], -1)
841 return False
842 else:
843 msg.printMsg(msg.Msgs.BEADM_ERR_INVALID_RESPONSE,
844 -1)
845
846 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
847 def setMaxColumnWidths(be_max_w, ds_max_w, ss_max_w, be_list):
848 """Figure out max column widths for BE's, Datasets and Snapshots."""
849
850 for be_item in be_list:
851 if be_item.get("orig_be_name") is not None:
852 determineMaxBEColWidth(be_item, be_max_w)
853 if be_item.get("dataset") is not None:
854 determineMaxDSColWidth(be_item, ds_max_w)
855 if be_item.get("snap_name") is not None:
856 determineMaxSSColWidth(be_item, ss_max_w)
857
858 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
859 def getActiveBEAndActiveOnBootBE():
860 """Return the 'active on boot' BE, the 'active' BE or None."""
861
862 active_be = None
863 active_be_on_boot = None
864
865 rc, be_list = lb.beList()
866
867 if rc != 0:
868 if rc == msg.Msgs.BE_ERR_BE_NOENT:
869 string = \
870 msg.getMsg(msg.Msgs.BEADM_ERR_NO_BES_EXIST)
871 else:
872 string = lb.beGetErrDesc(rc)
873 if string == None:
874 string = \
875 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
876
877 msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
878 return None
879
880 for be_vals in be_list:
881 srcBeName = be_vals.get("orig_be_name")
882 if be_vals.get("active"):
883 active_be = srcBeName
884 if be_vals.get("active_boot"):
885 active_be_on_boot = srcBeName
886 if active_be is not None and active_be_on_boot is not None:
887 break
888
889 return active_be, active_be_on_boot
890
891 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
892 def createSnapshot(be):
893 """Create a snapshot."""
894
895 be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@")
896
897 rc = lb.beCreateSnapshot(be_name, snap_name)[0]
898
899 if rc == 0:
900 return 0
901
902 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
903 if rc == msg.Msgs.BE_ERR_BE_NOENT:
904 be.msg_buf["1"] = \
905 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
906 be_name)
907 elif rc == msg.Msgs.BE_ERR_SS_EXISTS:
908 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_SNAP_EXISTS,
909 be.trgt_be_name_or_snapshot[0])
910 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
911 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
912 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
913 return 1
914 else:
915 be.msg_buf["1"] = lb.beGetErrDesc(rc)
916 if be.msg_buf["1"] == None:
917 be.msg_buf["1"] = \
918 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
919
920 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
921
922 return 1
923
924 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
925 def createBE(be):
926 """Create a Boot Environment."""
927
928 rc = lb.beCopy(be.trgt_be_name_or_snapshot[0], be.src_be_name_or_snapshot,
929 None, be.trgt_rpool, be.properties, be.description)[0]
930
931 if rc == 0:
932 msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_SUCCESS,
933 be.trgt_be_name_or_snapshot[0], be.log_id)
934 return 0
935
936 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
937 if rc == msg.Msgs.BE_ERR_BE_NOENT:
938 be.msg_buf["1"] = \
939 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
940 be.src_be_name_or_snapshot)
941 elif rc == msg.Msgs.BE_ERR_BE_EXISTS:
942 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_BE_EXISTS,
943 be.trgt_be_name_or_snapshot[0])
944 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
945 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
946 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
947 return 1
948 else:
949 be.msg_buf["1"] = lb.beGetErrDesc(rc)
950 if be.msg_buf["1"] == None:
951 be.msg_buf["1"] = \
952 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
953
954 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, be.log_id)
955
956 return 1
957
958 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
959 def createBEFromSnapshot(be):
960 """Create a BE based off a snapshot."""
961
962 be_name, snap_name = be.src_be_name_or_snapshot.split("@")
963
964 rc = lb.beCopy(be.trgt_be_name_or_snapshot[0], be_name, snap_name,
965 be.trgt_rpool, be.properties, be.description)[0]
966
967 if rc == 0:
968 msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_SUCCESS,
969 be.trgt_be_name_or_snapshot[0], be.log_id)
970 return 0
971
972 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
973 if rc == msg.Msgs.BE_ERR_SS_NOENT:
974 be.msg_buf["1"] = \
975 msg.getMsg(msg.Msgs.BEADM_ERR_SNAP_DOES_NOT_EXISTS,
976 be.src_be_name_or_snapshot)
977 elif rc == msg.Msgs.BE_ERR_BE_EXISTS:
978 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_BE_EXISTS, \
979 be.trgt_be_name_or_snapshot[0])
980 elif rc == msg.Msgs.BE_ERR_BE_NOENT:
981 be.msg_buf["1"] = \
982 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, \
983 be_name)
984 elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
985 be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
986 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
987 return 1
988 else:
989 be.msg_buf["1"] = lb.beGetErrDesc(rc)
990 if be.msg_buf["1"] == None:
991 be.msg_buf["1"] = \
992 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
993
994 msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, be.log_id)
995
996 return 1
997
998 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
999 def activateBE(be):
1000 """
1001 Activate a BE. Called from create() when -a is provided as CLI
1002 Option.
1003 """
1004
1005 rc = lb.beActivate(be.trgt_be_name_or_snapshot[0])
1006 if rc == 0:
1007 return 0
1008
1009 be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
1010 if rc == msg.Msgs.BE_ERR_BE_NOENT:
1011 be.msg_buf["1"] = \
1012 msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, opts[0])
1013 else:
1014 be.msg_buf["1"] = lb.beGetErrDesc(rc)
1015 if be.msg_buf["1"] == None:
1016 be.msg_buf["1"] = \
1017 msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
1018
1019 msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)
1020
1021 return 1
1022
1023 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1024 def isBeadmSupported():
1025 """
1026 Currently the only environment that beadm is supported in is
1027 a global zone. Check that beadm is executing in a
1028 global zone and not in a non-global zone.
1029 """
1030
1031 try:
1032 proc = subprocess.Popen("/sbin/zonename",
1033 stdout = subprocess.PIPE,
1034 stderr = subprocess.STDOUT)
1035 # Grab stdout.
1036 zonename = proc.communicate()[0].rstrip('\n')
1037 except OSError, (errno, strerror):
1038 msg.printMsg(msg.Msgs.BEADM_ERR_OS, strerror, -1)
1039 # Ignore a failed attempt to retreive the zonename.
1040 return True
1041
1042 if zonename != "global":
1043 msg.printMsg(msg.Msgs.BEADM_ERR_NOT_SUPPORTED_NGZ, None, -1)
1044 return False
1045
1046 return True
1047
1048
1049 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1050 if __name__ == "__main__":
1051 try:
1052 RC = main()
1053 except SystemExit, e:
1054 raise e
1055 except:
1056 traceback.print_exc()
1057 sys.exit(99)
1058 sys.exit(RC)