#!/usr/bin/python import itertools import os import subprocess import sys flatten = itertools.chain.from_iterable def powerset(iterable): "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" s = list(iterable) return flatten(itertools.combinations(s, r) for r in range(len(s)+1)) valid_option_sets = frozenset(( ('spawn-novlan', frozenset(('PXEBOOT_DEPLOYER_INTERFACE',))), ('spawn-vlan', frozenset(('PXEBOOT_DEPLOYER_INTERFACE', 'PXEBOOT_VLAN'))), ('existing-dhcp', frozenset(('PXEBOOT_DEPLOYER_INTERFACE', 'PXEBOOT_CONFIG_TFTP_ADDRESS'))), ('existing-server', frozenset(('PXEBOOT_CONFIG_TFTP_ADDRESS', 'PXEBOOT_ROOTFS_RSYNC_ADDRESS'))), )) valid_modes = frozenset(mode for mode, opt_set in valid_option_sets) def compute_matches(env): complete_matches = set() for mode, opt_set in valid_option_sets: if all(k in env for k in opt_set): complete_matches.add(opt_set) return complete_matches complete_matches = compute_matches(os.environ) def word_separate_options(options): assert options s = options.pop(-1) if options: s = '%s and %s' % (', '.join(options), s) return s valid_options = frozenset(flatten(opt_set for (mode, opt_set) in valid_option_sets)) matched_options = frozenset(o for o in valid_options if o in os.environ) if not complete_matches: addable_sets = frozenset(frozenset(os) - matched_options for os in valid_options if frozenset(os) - matched_options) print('Please provide %s' % ' or '.join( word_separate_options(list(opt_set)) for opt_set in addable_sets if opt_set)) sys.exit(1) elif len(complete_matches) > 1: removable_sets = frozenset(matched_options - frozenset(os) for os in powerset(matched_options) if len(compute_matches(os)) == 1) print('WARNING: Following options might not be needed: %s' % ' or '.join( word_separate_options(list(opt_set)) for opt_set in removable_sets if opt_set)) if 'PXEBOOT_MODE' in os.environ: mode = os.environ['PXEBOOT_MODE'] else: try: mode, = (mode for (mode, opt_set) in valid_option_sets if all(o in os.environ for o in opt_set)) except ValueError as e: print ('More than one candidate for PXEBOOT_MODE, please ' 'set a value for it. Type `morph help pxeboot.write for ' 'more info') sys.exit(1) if mode not in valid_modes: print('%s is not a valid PXEBOOT_MODE' % mode) sys.exit(1) if mode != 'existing-server': with open(os.devnull, 'w') as devnull: if subprocess.call(['systemctl', 'is-active', 'nfs-server'], stdout=devnull) != 0: print ('ERROR: nfs-server.service is not running and is needed ' 'for this deployment. Please, run `systemctl start nfs-server` ' 'and try `morph deploy` again.') sys.exit(1)