Revision 7f623b20 image_creator/dialog_main.py
b/image_creator/dialog_main.py | ||
---|---|---|
46 | 46 |
from image_creator.disk import Disk |
47 | 47 |
from image_creator.os_type import os_cls |
48 | 48 |
from image_creator.kamaki_wrapper import Kamaki, ClientError |
49 |
from image_creator.help import get_help_file |
|
49 | 50 |
|
50 | 51 |
MSGBOX_WIDTH = 60 |
51 | 52 |
YESNO_WIDTH = 50 |
52 | 53 |
MENU_WIDTH = 70 |
53 | 54 |
INPUTBOX_WIDTH = 70 |
54 |
|
|
55 |
CONFIGURATION_TASKS = { |
|
56 |
"FixPartitionTable": |
|
57 |
"Enlarge last partition to use all the available space", |
|
58 |
"FilesystemResizeUnmounted": |
|
59 |
"Resize file system to use all the available space", |
|
60 |
"AddSwap": "Set up the swap partition and add an entry in fstab", |
|
61 |
"DeleteSSHKeys": "Remove ssh keys and in some cases recreate them", |
|
62 |
"DisableRemoteDesktopConnections": |
|
63 |
"Temporary Disable Remote Desktop Connections", |
|
64 |
"40SELinuxAutorelabel": "Force the system to relabel at next boot", |
|
65 |
"AssignHostname": "Assign Hostname/Computer Name to the instance", |
|
66 |
"ChangePassword": "Changes Password for specified users", |
|
67 |
"EnforcePersonality": "Inject files to the instance", |
|
68 |
"FilesystemResizeMounted": |
|
69 |
"Resize filesystem to use all the available space"} |
|
55 |
CHECKBOX_WIDTH = 70 |
|
56 |
|
|
57 |
CONFIGURATION_TASKS = [ |
|
58 |
("Partition table manipulation", ["FixPartitionTable"], |
|
59 |
["linux", "windows"]), |
|
60 |
("File system resize", |
|
61 |
["FilesystemResizeUnmounted", "FilesystemResizeMounted"], |
|
62 |
["linux", "windows"]), |
|
63 |
("Swap partition configuration", ["AddSwap"], ["linux"]), |
|
64 |
("SSH keys removal", ["DeleteSSHKeys"], ["linux"]), |
|
65 |
("Temporal RDP disabling", ["DisableRemoteDesktopConnections"], ["windows"]), |
|
66 |
("SELinux relabeling at next boot", ["SELinuxAutorelabel"], |
|
67 |
["linux"]), |
|
68 |
("Hostname/Computer Name assignment", ["AssignHostname"], |
|
69 |
["windows", "linux"]), |
|
70 |
("Password change", ["ChangePassword"], ["windows", "linux"]), |
|
71 |
("File injection", ["EnforcePersonality"], ["windows", "linux"]) |
|
72 |
] |
|
70 | 73 |
|
71 | 74 |
|
72 | 75 |
class Reset(Exception): |
... | ... | |
234 | 237 |
|
235 | 238 |
d.msgbox("Image file `%s' was successfully uploaded to pithos+" % filename, |
236 | 239 |
width=MSGBOX_WIDTH) |
240 |
|
|
237 | 241 |
return True |
238 | 242 |
|
239 | 243 |
|
... | ... | |
429 | 433 |
choices.append((key, "%s" % val, 0)) |
430 | 434 |
|
431 | 435 |
(code, to_delete) = d.checklist("Choose which properties to delete:", |
432 |
choices=choices) |
|
436 |
choices=choices, width=CHECKBOX_WIDTH)
|
|
433 | 437 |
count = len(to_delete) |
434 | 438 |
# If the user exits with ESC or CANCEL, the returned tag list is empty. |
435 | 439 |
for i in to_delete: |
... | ... | |
439 | 443 |
d.msgbox("%d image properties were deleted.", width=MSGBOX_WIDTH) |
440 | 444 |
|
441 | 445 |
|
442 |
def exclude_task(session): |
|
446 |
def exclude_tasks(session):
|
|
443 | 447 |
d = session['dialog'] |
444 | 448 |
|
449 |
index = 0 |
|
450 |
displayed_index = 1 |
|
445 | 451 |
choices = [] |
446 |
for (key, val) in session['metadata'].items(): |
|
447 |
choices.append((key, "%s" % val, 0)) |
|
452 |
mapping = {} |
|
453 |
if 'excluded_tasks' not in session: |
|
454 |
session['excluded_tasks'] = [] |
|
455 |
|
|
456 |
if -1 in session['excluded_tasks']: |
|
457 |
if not d.yesno("Image deployment configuration is disabled. " |
|
458 |
"Do you wish to enable it?", width=YESNO_WIDTH): |
|
459 |
session['excluded_tasks'].remove(-1) |
|
460 |
else: |
|
461 |
return |
|
462 |
|
|
463 |
for (msg, task, osfamily) in CONFIGURATION_TASKS: |
|
464 |
if session['metadata']['OSFAMILY'] in osfamily: |
|
465 |
checked = 1 if index in session['excluded_tasks'] else 0 |
|
466 |
choices.append((str(displayed_index), msg, checked)) |
|
467 |
mapping[displayed_index] = index |
|
468 |
displayed_index += 1 |
|
469 |
index += 1 |
|
448 | 470 |
|
449 |
(code, to_delete) = d.checklist("Choose which properties to delete:", |
|
450 |
choices=choices) |
|
451 |
count = len(to_delete) |
|
452 |
# If the user exits with ESC or CANCEL, the returned tag list is empty. |
|
453 |
for i in to_delete: |
|
454 |
del session['metadata'][i] |
|
471 |
while 1: |
|
472 |
(code, tags) = d.checklist( |
|
473 |
"Please choose which configuration tasks you would like to " |
|
474 |
"prevent from running during image deployment. " |
|
475 |
"Press <No Config> to supress any configuration. " |
|
476 |
"Press <Help> for more help on the image deployment configuration " |
|
477 |
"tasks.", height=19, list_height=8, |
|
478 |
title="Exclude Configuration Tasks", choices=choices, |
|
479 |
width=CHECKBOX_WIDTH, help_button=1, extra_button=1, |
|
480 |
extra_label="No Config") |
|
455 | 481 |
|
456 |
if count > 0: |
|
457 |
d.msgbox("%d image properties were deleted.", width=MSGBOX_WIDTH) |
|
482 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): |
|
483 |
break |
|
484 |
elif code == d.DIALOG_HELP: |
|
485 |
help_file = get_help_file("configuration_tasks") |
|
486 |
assert os.path.exists(help_file) |
|
487 |
d.textbox(help_file, title="Configuration Tasks", |
|
488 |
width=70, height=40) |
|
489 |
continue |
|
490 |
elif code == d.DIALOG_EXTRA: |
|
491 |
session['excluded_tasks'] = [-1] |
|
492 |
session['task_metadata'] = ["EXCLUDE_ALL_TASKS"] |
|
493 |
break |
|
494 |
elif code == d.DIALOG_OK: |
|
495 |
session['excluded_tasks'] = [] |
|
496 |
for tag in tags: |
|
497 |
session['excluded_tasks'].append(mapping[int(tag)]) |
|
458 | 498 |
|
499 |
exclude_metadata = [] |
|
500 |
for task in session['excluded_tasks']: |
|
501 |
exclude_metadata.extend(CONFIGURATION_TASKS[task][1]) |
|
459 | 502 |
|
460 |
def deploy_menu(session): |
|
503 |
session['task_metadata'] = \ |
|
504 |
map(lambda x: "EXCLUDE_TASK_%s" % x, exclude_metadata) |
|
505 |
break |
|
506 |
|
|
507 |
|
|
508 |
def sysprep(session): |
|
461 | 509 |
d = session['dialog'] |
510 |
image_os = session['image_os'] |
|
511 |
|
|
512 |
syspreps = image_os.list_syspreps() |
|
513 |
|
|
514 |
wrapper = textwrap.TextWrapper() |
|
515 |
wrapper.width = 65 |
|
516 |
sysprep_help = "System Preperation Tasks" |
|
517 |
sysprep_help += "\n%s\n\n" % ('=' * len(sysprep_help)) |
|
462 | 518 |
|
463 |
default_item = "View/Modify" |
|
464 |
actions = {"View/Modify": modify_properties, "Delete": delete_properties} |
|
519 |
while 1: |
|
520 |
choices = [] |
|
521 |
index = 0 |
|
522 |
for sysprep in syspreps: |
|
523 |
name, descr = image_os.sysprep_info(sysprep) |
|
524 |
display_name = name.replace('-', ' ').capitalize() |
|
525 |
sysprep_help += "%s\n%s\n%s\n\n" % \ |
|
526 |
(display_name, '-' * len(display_name), |
|
527 |
wrapper.fill(" ".join(descr.split()))) |
|
528 |
enabled = 1 if sysprep.enabled else 0 |
|
529 |
choices.append((str(index + 1), display_name, enabled)) |
|
530 |
index += 1 |
|
531 |
|
|
532 |
(code, tags) = d.checklist( |
|
533 |
"Please choose which system preperation tasks you would like to " |
|
534 |
"run on the image. Press <Help> to see details about the system " |
|
535 |
"preperation tasks.", |
|
536 |
title="Run system preperation tasks", choices=choices, |
|
537 |
width=70, ok_label="Run", help_button=1) |
|
538 |
|
|
539 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): |
|
540 |
break |
|
541 |
if code == d.DIALOG_HELP: |
|
542 |
d.scrollbox(sysprep_help, width=70) |
|
543 |
continue |
|
544 |
|
|
545 |
|
|
546 |
def customize_menu(session): |
|
547 |
d = session['dialog'] |
|
548 |
|
|
549 |
default_item = "Sysprep" |
|
550 |
actions = {"Sysprep": sysprep, |
|
551 |
"View/Modify": modify_properties, |
|
552 |
"Delete": delete_properties, |
|
553 |
"Exclude": exclude_tasks} |
|
465 | 554 |
while 1: |
466 | 555 |
(code, choice) = d.menu( |
467 | 556 |
"Choose one of the following or press <Back> to exit.", |
468 | 557 |
width=MENU_WIDTH, |
469 |
choices=[("View/Modify", "View/Modify image properties"), |
|
558 |
choices=[("Sysprep", "Run various image preperation tasks"), |
|
559 |
("Shrink", "Shrink image"), |
|
560 |
("View/Modify", "View/Modify image properties"), |
|
470 | 561 |
("Delete", "Delete image properties"), |
471 |
("Exclude", "Exclude configuration tasks from running")], |
|
472 |
cancel="Back", |
|
473 |
default_item=default_item, |
|
474 |
title="Image Deployment Menu") |
|
562 |
("Exclude", |
|
563 |
"Exclude various deployment tasks from running")], |
|
564 |
cancel="Back", |
|
565 |
default_item=default_item, |
|
566 |
title="Image Customization Menu") |
|
475 | 567 |
|
476 | 568 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): |
477 | 569 |
break |
... | ... | |
484 | 576 |
d = session['dialog'] |
485 | 577 |
dev = session['device'] |
486 | 578 |
d.setBackgroundTitle("OS: %s, Distro: %s" % (dev.ostype, dev.distro)) |
487 |
actions = {"Deploy": deploy_menu,
|
|
579 |
actions = {"Customize": customize_menu,
|
|
488 | 580 |
"Register": kamaki_menu, |
489 | 581 |
"Extract": extract_image} |
490 | 582 |
default_item = "Customize" |
... | ... | |
493 | 585 |
(code, choice) = d.menu( |
494 | 586 |
"Choose one of the following or press <Exit> to exit.", |
495 | 587 |
width=MENU_WIDTH, |
496 |
choices=[("Customize", "Run various image customization tasks"),
|
|
497 |
("Deploy", "Configure ~okeanos image deployment options"),
|
|
588 |
choices=[("Customize", |
|
589 |
"Customize image and ~okeanos deployment options"),
|
|
498 | 590 |
("Register", "Register image to ~okeanos"), |
499 | 591 |
("Extract", "Dump image to local file system"), |
500 | 592 |
("Reset", "Reset everything and start over again"), |
501 | 593 |
("Help", "Get help for using snf-image-creator")], |
502 |
cancel="Exit", |
|
503 |
default_item=default_item, |
|
594 |
cancel="Exit", menu_height=5, height=13, default_item=default_item, |
|
504 | 595 |
title="Image Creator for ~okeanos (snf-image-creator version %s)" % |
505 | 596 |
version) |
506 | 597 |
|
507 | 598 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): |
508 | 599 |
if confirm_exit(d): |
509 | 600 |
break |
510 |
else: |
|
511 |
continue |
|
512 |
|
|
513 |
if choice == "Reset": |
|
601 |
elif choice == "Reset": |
|
514 | 602 |
if confirm_reset(d): |
515 | 603 |
d.infobox("Resetting snf-image-creator. Please wait...") |
516 | 604 |
raise Reset |
517 |
else: |
|
518 |
continue |
|
519 | 605 |
elif choice in actions: |
520 | 606 |
actions[choice](session) |
521 | 607 |
|
... | ... | |
542 | 628 |
return media |
543 | 629 |
|
544 | 630 |
|
545 |
def collect_metadata(dev, out): |
|
546 |
|
|
547 |
out.output("Collecting image metadata...") |
|
548 |
metadata = dev.meta |
|
549 |
dev.mount(readonly=True) |
|
550 |
cls = os_cls(dev.distro, dev.ostype) |
|
551 |
image_os = cls(dev.root, dev.g, out) |
|
552 |
dev.umount() |
|
553 |
metadata.update(image_os.meta) |
|
554 |
out.success("done") |
|
555 |
|
|
556 |
return metadata |
|
557 |
|
|
558 |
|
|
559 | 631 |
def image_creator(d): |
560 | 632 |
basename = os.path.basename(sys.argv[0]) |
561 | 633 |
usage = "Usage: %s [input_media]" % basename |
... | ... | |
580 | 652 |
snapshot = disk.snapshot() |
581 | 653 |
dev = disk.get_device(snapshot) |
582 | 654 |
|
583 |
metadata = collect_metadata(dev, out) |
|
655 |
out.output("Collecting image metadata...") |
|
656 |
metadata = dev.meta |
|
657 |
dev.mount(readonly=True) |
|
658 |
cls = os_cls(dev.distro, dev.ostype) |
|
659 |
image_os = cls(dev.root, dev.g, out) |
|
660 |
dev.umount() |
|
661 |
metadata.update(image_os.meta) |
|
662 |
out.success("done") |
|
584 | 663 |
out.cleanup() |
585 | 664 |
|
586 | 665 |
# Make sure the signal handler does not call out.cleanup again |
... | ... | |
593 | 672 |
"disk": disk, |
594 | 673 |
"snapshot": snapshot, |
595 | 674 |
"device": dev, |
675 |
"image_os": image_os, |
|
596 | 676 |
"metadata": metadata} |
597 | 677 |
|
598 | 678 |
main_menu(session) |
Also available in: Unified diff