def test_str2bool(): for true in ['yes', 'true', 'on', '1']: assert str2bool(true) for false in ['no', 'false', 'off', '0']: assert not str2bool(false)
def test_str2bool(): for true in [ 'yes', 'true', 'on', '1' ]: assert str2bool(true) for false in [ 'no', 'false', 'off', '0' ]: assert not str2bool(false)
def traverse_stack_package(self, node): """Expands <stack:package> to native autoyast syntax, later passes will collect all these section to create a single <software> section. <software> <patterns config:type="list"> <!-- stack:type="meta" --> <pattern>?</pattern> </patterns> <packages config:type="list"> <package>?</package> ... </package> </software> """ stage = self.getAttr(node, 'stack:stage', default='install') meta = self.getAttr(node, 'stack:meta', default='false') meta = str2bool(meta) enabled = self.getAttr(node, 'stack:enable', default='true') enabled = str2bool(enabled) pkgs = [] for line in self.collect(node).split('\n'): pkg = line.strip() if pkg: pkgs.append(pkg) if not meta: if stage == 'boot': packages = self.newElementNode('sles:post-packages') else: packages = self.newElementNode('sles:packages') self.setAttribute(packages, 'config:type', 'list') for rpm in pkgs: package = self.newElementNode('sles:package') package.appendChild(self.newTextNode(rpm)) packages.appendChild(package) else: packages = self.newElementNode('sles:patterns') self.setAttribute(packages, 'config:type', 'list') for rpm in pkgs: package = self.newElementNode('sles:pattern') package.appendChild(self.newTextNode(rpm)) packages.appendChild(package) software = self.newElementNode('sles:software') software.appendChild(packages) node.parentNode.replaceChild(software, node) return False
def partitions(self): """ Return a dictionary of the partitions. partition['partition_name'] = {'pkey': int, 'ipoib': bool, 'guids': [list, of, member, guids]} """ partitions = {} cur_partition = None for line in self.proc.ask('show ib partition'): if re.match(members_header, line): # drop the 'members' line, because it can look like partition names # lord help us if someone names their partition 'members' continue if re.match(partition_name, line): cur_partition = line.strip() partitions[cur_partition] = { 'pkey': '', 'ipoib': False, 'guids': [], } continue line = line.strip() if line.startswith('PKey'): _, key = line.split('=') partitions[cur_partition]['pkey'] = int(key, 16) elif line.startswith('ipoib'): _, ipoib = line.split('=') partitions[cur_partition]['ipoib'] = str2bool(ipoib.strip()) elif line.startswith('GUID'): m = re.search(guid_format, line) partitions[cur_partition]['guids'].append(m.group(0)) info(partitions.keys()) return partitions
def run(self, params, args): (order, expanded) = self.fillParams([ ('order', 'asc'), ('expanded', False), ]) self.expanded = str2bool(expanded) switches = self.getSwitchNames(args) header = ['switch'] values = {} for switch in switches: values[switch] = [] for (provides, result) in self.runPlugins(switches): header.extend(result['keys']) for h, v in result['values'].items(): values[h].extend(v) self.beginOutput() for switch in switches: if values[switch]: self.addOutput(switch, values[switch]) self.endOutput(header=header, trimOwner=False)
def run(self, params, args): if len(args) != 1: raise ArgUnique(self, 'switch') sm_switch = args[0] (disable, ) = self.fillParams([ ('disable', False), ]) disable = str2bool(disable) ibswitches = [sw for sw in self.call('list.switch') if sw['model'] == 'm7800'] ib_switch_names = [sw['switch'] for sw in ibswitches] if sm_switch not in ib_switch_names: msg = f'host {sm_switch} is not a supported infiniband switch\n' msg += 'Please verify the make and model attributes for this host.' raise CommandError(self, msg) self.switch_attrs = self.getHostAttrDict(ib_switch_names) if self.switch_attrs[sm_switch].get('switch_type') != 'infiniband': msg = f'{sm_switch} is not an infiniband switch, please verify "stack list host attr {sm_switch} attr=switch_type"' if disable: # explicit disable only affects this switch switch = self.get_sw_handle(sm_switch) switch.subnet_manager = False switch.disconnect() return # NOTE assumes a single management port with options set. # this obviously breaks if a switch can someday be on multiple fabrics fabric = self.switch_attrs[sm_switch].get('ibfabric') if not fabric: raise CommandError(self, f'switch {sm_switch} does not have its ibfabric set') switches_to_disable = [] for ib_sw in ib_switch_names: if ib_sw == sm_switch: # this one is the sm continue sw_fabric = self.switch_attrs[ib_sw].get('ibfabric') if not sw_fabric or sw_fabric == fabric: # switches with no fabric specified should be disabled # other switches on the same fabric should be disabled switches_to_disable.append(ib_sw) continue for switch in switches_to_disable: sw_handle = self.get_sw_handle(switch) sw_handle.subnet_manager = False sw_handle.disconnect() sw_handle = self.get_sw_handle(sm_switch) sw_handle.subnet_manager = True sw_handle.disconnect()
def traverse_stack_file(self, node): """<stack:file> Convert the file tags the shell code along with rcs ci/co. """ fileName = self.getAttr(node, 'stack:name') fileMode = self.getAttr(node, 'stack:mode') fileOwner = self.getAttr(node, 'stack:owner') filePerms = self.getAttr(node, 'stack:perms') fileQuoting = self.getAttr(node, 'stack:vars', default='literal') fileCommand = self.getAttr(node, 'stack:expr') fileText = self.collect(node) fileRCS = self.getAttr(node, 'stack:rcs', default='true') fileRCS = str2bool(fileRCS) if fileName: p, f = os.path.split(fileName) s = 'if [ ! -e %s ]; then mkdir -p %s; fi\n' % (p, p) if fileRCS: s += self.rcsBegin(fileName, fileOwner, filePerms) if fileMode == 'append': gt = '>>' else: gt = '>' if fileCommand: s += '%s %s %s\n' % (fileCommand, gt, fileName) if not fileText: s += 'touch %s\n' % fileName else: if fileQuoting == 'expanded': eof = "EOF" else: eof = "'EOF'" s += "cat %s %s << %s" % (gt, fileName, eof) if fileText[0] != '\n': s += '\n' s += fileText if fileText[-1] != '\n': s += '\n' s += 'EOF\n' if fileOwner: s += 'chown %s %s\n' % (fileOwner, fileName) if filePerms: s += 'chmod %s %s\n' % (filePerms, fileName) node.parentNode.replaceChild(self.newTextNode(s), node) return False
def run(self, params, args): document, self.exec_commands, self.force = self.fillParams([ ('document', None), ('exec', False), ('force', False), ]) self.exec_commands = str2bool(self.exec_commands) self.force = str2bool(self.force) if not document: if not args: raise ArgRequired(self, 'filename') if len(args) > 1: raise ArgUnique(self, 'filename') document = self.load_file(args[0]) self.main(document)
def test_call(): """ Test the stack.api.Call function to verify it returns a list of dictionaries. """ found = False for dict in Call('list appliance'): if dict['appliance'] == 'backend': found = True assert str2bool(dict['public']) assert found
def partitions(self): """ Return a dictionary of the partitions. partition['partition_name'] = {'pkey': int, 'ipoib': bool, 'guids': [list, of, member, guids]} """ partitions = {} cur_partition = None new_console_format = None for line in remove_blank_lines( lines=self.proc.ask('show ib partition')): if re.match(members_header, line): # drop the 'members' line, because it can look like partition names # lord help us if someone names their partition 'members' continue header_match = re.match(partition_name, line) if header_match: # This should be the first thing we encounter when looping through the console # response, so we use it to set the format for the rest of the loop if new_console_format is None: if header_match.group("format_1"): new_console_format = False elif header_match.group("format_2"): new_console_format = True elif new_console_format and not header_match.group("format_2"): continue elif not new_console_format and not header_match.group( "format_1"): continue cur_partition = line.strip().strip(":") partitions[cur_partition] = { 'pkey': '', 'ipoib': False, 'guids': {}, } continue line = line.strip() if line.startswith('PKey'): _, key = line.split(':' if new_console_format else '=') partitions[cur_partition]['pkey'] = int(key, 16) elif line.startswith('ipoib'): _, ipoib = line.split(':' if new_console_format else '=') partitions[cur_partition]['ipoib'] = str2bool(ipoib.strip()) elif line.startswith('GUID'): m = re.search(guid_member_format, line) guid, membership = m.groups()[0].lower(), m.groups()[2] partitions[cur_partition]['guids'][guid] = membership info(partitions.keys()) return partitions
def partitions(self): """ Return a dictionary of the partitions. partition['partition_name'] = {'pkey': int, 'ipoib': bool, 'guids': [list, of, member, guids]} """ partitions = {} cur_partition = None new_console_format = None for line in remove_blank_lines(lines = self.proc.ask('show ib partition')): if re.match(members_header, line): # drop the 'members' line, because it can look like partition names # lord help us if someone names their partition 'members' continue header_match = re.match(partition_name, line) if header_match: # This should be the first thing we encounter when looping through the console # response, so we use it to set the format for the rest of the loop if new_console_format is None: if header_match.group("format_1"): new_console_format = False elif header_match.group("format_2"): new_console_format = True elif new_console_format and not header_match.group("format_2"): continue elif not new_console_format and not header_match.group("format_1"): continue cur_partition = line.strip().strip(":") partitions[cur_partition] = { 'pkey': '', 'ipoib': False, 'guids': {}, } continue line = line.strip() if line.startswith('PKey'): _, key = line.split(':' if new_console_format else '=') partitions[cur_partition]['pkey'] = int(key, 16) elif line.startswith('ipoib'): _, ipoib = line.split(':' if new_console_format else '=') partitions[cur_partition]['ipoib'] = str2bool(ipoib.strip()) elif line.startswith('GUID'): m = re.search(guid_member_format, line) guid, membership = m.groups()[0].lower(), m.groups()[2] partitions[cur_partition]['guids'][guid] = membership info(partitions.keys()) return partitions
def run(self, params, args): attrs, = self.fillParams([('attribute', None)]) if attrs is not None: attrs = attrs.split(',') else: attrs = [] groups = {} for row in self.call('list.host.attr'): host = row['host'] attr = row['attr'] val = row['value'] # TODO - Update to use the qualifier to scope these # groups (e.g. a:backend) if attr == 'appliance': if val not in groups: groups[val] = {'hosts': []} groups[val]['hosts'].append(host) elif attr == 'rack': rack = 'rack%s' % val if rack not in groups: groups[rack] = {'hosts': []} groups[rack]['hosts'].append(host) elif attr == 'managed': if str2bool(val) is True: if attr not in groups: groups[attr] = {'hosts': []} groups['managed']['hosts'].append(host) elif attr in attrs: if attr not in groups: groups[attr] = {'hosts': []} groups[attr]['hosts'].append(host) self.beginOutput() self.addOutput('', '<stack:file stack:name="/etc/ansible/hosts">') for cat in groups: self.addOutput('', '[%s]' % cat) hostlist = '\n'.join(groups[cat]['hosts']) self.addOutput('', hostlist) self.addOutput('', '') self.addOutput('', '</stack:file>') self.endOutput(padChar='')
def traverse_stack_package(self, node): """<stack:package> Build the packageSet. """ nodefile = self.getAttr(node, 'stack:file') meta = self.getAttr(node, 'stack:meta', default='false') meta = str2bool(meta) enabled = self.getAttr(node, 'stack:enable', default='true') enabled = str2bool(enabled) for line in self.collect(node).split('\n'): pkg = line.strip() if pkg: if meta: pkg = '@%s' % pkg self.gen.packageSet.append(pkg, enabled, nodefile) return False
def traverse(self, node): """<*> stack:gc="true" means garabage collect the node. Any previous traversal can set this attribute to have the tag removed from the tree. """ gc = self.getAttr(node, 'stack:gc') gc = str2bool(gc) if gc: self.removeNode(node) return True
def doSecureErase(self, enclosure, adapter, slot): if enclosure: slotaddress = '/c%d/e%d/s%d' % \ (adapter, enclosure, slot) else: slotaddress = '/c%d/s%d' % (adapter, slot) res = self.run([slotaddress, 'show', 'all']) if res['Command Status']['Status'] == 'Failure': return s = res['Response Data'][ 'Drive %s - Detailed Information' % slotaddress]['Drive %s Policies/Settings' % slotaddress]['Cryptographic Erase Capable'] if str2bool(s): self.run([slotaddress, 'secureerase', 'force'])
def run(self, params, args): prms = self._params # Get Host Attributes s = self.call('list.host.attr') host_bucket = {'managed': {'hosts': []}} for i in s: host = i['host'] attr = i['attr'] val = i['value'] # Categorize by appliances if attr == 'appliance': if val not in host_bucket: host_bucket[val] = {'hosts': []} host_bucket[val]['hosts'].append(host) # Categorize by rack if attr == 'rack': rack = 'rack%s' % val if rack not in host_bucket: host_bucket[rack] = {'hosts': []} host_bucket[rack]['hosts'].append(host) # Managed Hosts if attr == 'managed': if str2bool(val) == True: host_bucket['managed']['hosts'].append(host) # if len(prms) > 0: if prms: k = list(prms.keys()) if 'attribute' in k: for i in prms['attribute'].split(','): if attr == i: if attr not in host_bucket: host_bucket[attr] = {'hosts': []} host_bucket[attr]['hosts'].append(host) else: raise CommandError(self, 'argument "%s" not recognized' % k[0]) self.beginOutput() self.addOutput('', '<stack:file stack:name="/etc/ansible/hosts">') for cat in host_bucket: self.addOutput('', '[%s]' % cat) hostlist = '\n'.join(host_bucket[cat]['hosts']) self.addOutput('', hostlist) self.addOutput('', '') self.addOutput('', '</stack:file>') self.endOutput()
def traverse_stack_script(self, node): """<stack:script> """ nodefile = self.getAttr(node, 'stack:file') stage = self.getAttr(node, 'stack:stage', default='install-post') shell = self.getAttr(node, 'stack:shell') flags = [ ] if stage == 'install-post': chroot = str2bool(self.getAttr(node, 'stack:chroot', default='true')) else: chroot = False if stage == 'install-post' and not chroot: flags.append('--nochroot') flags.append('--log /mnt/sysimage%s' % self.gen.log) else: flags.append('--log %s' % self.gen.log) if shell: flags.append('--interpreter %s' % shell) script = [ ] if stage in self.stages: script.append('%%%s %s' % (self.stages[stage], ' '.join(flags))) script.append(self.collect(node)) script.append('%end') elif stage in [ 'boot-pre', 'boot-post' ]: boot, when = stage.split('-') script = [ '%%post --log %s' % self.gen.log ] script.append("cat >> /etc/sysconfig/stack-%s << '__EOF__'" % when) script.append(self.collect(node)) script.append('__EOF__') script.append('%end') self.gen.scriptSection.append('\n'.join(script), nodefile) return False
def traverse_stack_script(self, node): """<stack:script> """ nodefile = self.getAttr(node, 'stack:file') stage = self.getAttr(node, 'stack:stage', default='install-post') shell = self.getAttr(node, 'stack:shell') flags = [] if stage == 'install-post': chroot = str2bool( self.getAttr(node, 'stack:chroot', default='true')) else: chroot = False if stage == 'install-post' and not chroot: flags.append('--nochroot') flags.append('--log /mnt/sysimage%s' % self.gen.log) else: flags.append('--log %s' % self.gen.log) if shell: flags.append('--interpreter %s' % shell) script = [] if stage in self.stages: script.append('%%%s %s' % (self.stages[stage], ' '.join(flags))) script.append(self.collect(node)) script.append('%end') elif stage in ['boot-pre', 'boot-post']: boot, when = stage.split('-') script = ['%%post --log %s' % self.gen.log] script.append("cat >> /etc/sysconfig/stack-%s << '__EOF__'" % when) script.append(self.collect(node)) script.append('__EOF__') script.append('%end') self.gen.scriptSection.append('\n'.join(script), nodefile) return False
def run(self, args): host = args[0] bond_reg = re.compile('bond[0-9]+') udev_output = "" result = self.owner.call('list.host.interface', [ 'expanded=true', host ]) for o in result: interface = o['interface'] default = str2bool(o['default']) ip = o['ip'] netname = o['network'] vlanid = o['vlan'] mac = o['mac'] if mac: mac = mac.lower() channel = o['channel'] options = o['options'] netmask = o['mask'] gateway = o['gateway'] startmode = None bootproto = 'static' if ip and not netname: Warn(f'WARNING: skipping interface "{interface}" on host "{o["host"]}" - ' 'interface has an IP but no network') continue # If we don't have an interface, we don't need a config file if not interface: continue if netname and ip and netmask: net = ipaddress.IPv4Network('%s/%s' % (ip, netmask), strict=False) broadcast = str(net.broadcast_address) network = str(net.network_address) else: broadcast = None network = None if options: options = shlex.split(o['options']) else: options = [] if 'noreport' in options: continue # don't do anything if noreport set ib_re = re.compile('^ib[0-9]+$') if mac: if not ib_re.match(interface) and interface != 'ipmi': udev_output += 'SUBSYSTEM=="net", ' udev_output += 'ACTION=="add", ' udev_output += 'DRIVERS=="?*", ' udev_output += 'ATTR{address}=="%s", ' % mac udev_output += 'ATTR{type}=="1", ' udev_output += 'KERNEL=="eth*", ' udev_output += 'NAME="%s"\n\n' % interface if interface == 'ipmi': ipmisetup = '/tmp/ipmisetup' self.owner.addOutput(host, '<stack:file stack:name="%s">' % ipmisetup) self.owner.writeIPMI(host, ip, channel, netmask, gateway, vlanid) self.owner.addOutput(host, '</stack:file>') self.owner.addOutput(host, 'chmod 500 %s' % ipmisetup) continue if len(interface.split(':')) == 2: # # virtual interface configuration # self.owner.addOutput(host, '<stack:file stack:mode="append" stack:name="/etc/sysconfig/network/ifcfg-%s">' % interface.split(':')[0]) self.owner.addOutput(host, '# AUTHENTIC STACKI') vnum = interface.split(':')[1] if ip: self.owner.addOutput(host, 'IPADDR%s=%s' % (vnum, ip)) if netmask: self.owner.addOutput(host, 'NETMASK%s=%s' % (vnum, netmask)) if network: self.owner.addOutput(host, 'NETWORK%s=%s' % (vnum, network)) if broadcast: self.owner.addOutput(host, 'BROADCAST%s=%s' % (vnum, broadcast)) self.owner.addOutput(host, 'LABEL%s=%s' % (vnum, vnum)) else: self.owner.addOutput(host, '<stack:file stack:name="/etc/sysconfig/network/ifcfg-%s">' % interface) self.owner.addOutput(host, '# AUTHENTIC STACKI') if vlanid and self.owner.host_based_routing(host, interface, vlanid): parent_device = interface.strip().split('.')[0] self.owner.addOutput(host, 'ETHERDEVICE=%s' % parent_device) self.owner.addOutput(host, 'VLAN=yes') startmode = 'auto' else: self.owner.addOutput(host, 'USERCONTROL=no') dhcp = 'dhcp' in options if dhcp: bootproto = 'dhcp' if default: self.owner.addOutput(host, 'DHCLIENT_SET_HOSTNAME="yes"') self.owner.addOutput(host, 'DHCLIENT_SET_DEFAULT_ROUTE="yes"') else: self.owner.addOutput(host, 'DHCLIENT_SET_HOSTNAME="no"') self.owner.addOutput(host, 'DHCLIENT_SET_DEFAULT_ROUTE="no"') if 'onboot=no' in options: startmode = 'manual' elif ip or dhcp or channel or 'bridge' in options: # # if there is an IP address, or this # interface should DHCP, or anything in # the 'channel' field (e.g., this is a # bridged or bonded interface), or if 'bridge' # is in the options, then turn this interface on # startmode = 'auto' if not dhcp: if ip: self.owner.addOutput(host, 'IPADDR=%s' % ip) if netmask: self.owner.addOutput(host, 'NETMASK=%s' % netmask) if network: self.owner.addOutput(host, 'NETWORK=%s' % network) if broadcast: self.owner.addOutput(host, 'BROADCAST=%s' % broadcast) if mac: self.owner.addOutput(host, 'HWADDR=%s' % mac.strip()) # # bonded interface, e.g., 'bond0' # if bond_reg.match(interface): # # if a 'bond*' device is present, then always make # sure it is enabled on boot. # startmode = 'auto' self.owner.addOutput(host, 'BONDING_MASTER=yes') # # find the interfaces that are part of this bond # i = 0 for p in result: if p['channel'] == interface: self.owner.addOutput(host, 'BONDING_SLAVE%d="%s"' % (i, p['interface'])) i = i + 1 # # Check if there are bonding options set # for opt in options: if opt.startswith('bonding-opts='): i = opt.find('=') bo = opt[i + 1:] self.owner.addOutput(host, 'BONDING_MODULE_OPTS="%s"' % bo) break # # check if this is part of a bonded channel # if channel and bond_reg.match(channel): startmode = 'auto' bootproto = 'none' if not startmode: startmode = 'off' self.owner.addOutput(host, 'STARTMODE=%s' % startmode) self.owner.addOutput(host, 'BOOTPROTO=%s' % bootproto) # # if this is a bridged interface, then go look for the # physical interface this bridge is associated with # if 'bridge' in options: for p in result: if p['channel'] == interface: self.owner.addOutput(host, 'BRIDGE=yes') self.owner.addOutput(host, 'BRIDGE_FORWARDDELAY=0') self.owner.addOutput(host, 'BRIDGE_STP=off') self.owner.addOutput(host, 'BRIDGE_PORTS=%s' % p['interface']) break self.owner.addOutput(host, '\n') self.owner.addOutput(host, '</stack:file>') if udev_output: self.owner.addOutput(host, '<stack:file stack:name="/etc/udev/rules.d/70-persistent-net.rules">') self.owner.addOutput(host, udev_output) self.owner.addOutput(host, '</stack:file>')
def addHostAttrs(self, attributes): readonly = {} versions = {} for row in self.call('list.pallet'): # Compute a version number for each os pallet # # If the pallet already has a '.' take everything # before the '.' and add '.x'. If the version has no # '.' add '.x' name = row['name'] version = row['version'] release = row['release'] key = '%s-%s-%s' % (name, version, release) if name in ['SLES', 'CentOS']: # FIXME: Ubuntu is missing versions[key] = (name, '%s.x' % version.split('.')[0]) boxes = {} for row in self.call('list.box'): pallets = row['pallets'].split() carts = row['carts'].split() name = 'unknown' version = 'unknown' for pallet in pallets: if pallet in versions.keys(): (name, version) = versions[pallet] break boxes[row['name']] = { 'pallets': pallets, 'carts': carts, 'os.name': name, 'os.version': version } for (name, environment, rack, rank, metadata) in self.db.select(""" n.name, e.name, n.rack, n.rank, n.metadata from nodes n left join environments e on n.environment=e.id """): readonly[name] = {} readonly[name]['rack'] = rack readonly[name]['rank'] = rank if environment: readonly[name]['environment'] = environment if metadata: readonly[name]['metadata'] = metadata for (name, box, appliance) in self.db.select(""" n.name, b.name, a.name from nodes n, boxes b, appliances a where n.appliance=a.id and n.box=b.id """): readonly[name]['box'] = box readonly[name]['pallets'] = boxes[box]['pallets'] readonly[name]['carts'] = boxes[box]['carts'] # readonly[name]['os.name'] = boxes[box]['os.name'] readonly[name]['os.version'] = boxes[box]['os.version'] readonly[name]['appliance'] = appliance for (name, zone, address) in self.db.select(""" n.name, s.zone, nt.ip from networks nt, nodes n, subnets s where nt.main=true and nt.node=n.id and nt.subnet=s.id """): if address: readonly[name]['hostaddr'] = address readonly[name]['domainname'] = zone for host in readonly: readonly[host]['os'] = self.db.getHostOS(host) readonly[host]['hostname'] = host for row in self.call('list.host.group'): for group in row['groups'].split(): readonly[row['host']]['group.%s' % group] = 'true' readonly[row['host']]['groups'] = row['groups'] for host in attributes: a = attributes[host] r = readonly[host] ro = True if 'const_overwrite' in a: # This attribute allows a host to overwrite # constant attributes. This is crazy dangerous, # do not use this attribute. (n, v, t, s) = a['const_overwrite'] ro = str2bool(v) if ro: for key in r: # slam consts on top of attrs a[key] = (r[key], 'const', 'host') else: for key in r: # only add new consts to attrs if key not in a: a[key] = (r[key], 'const', 'host') return attributes
try: help.run({'subdir': submodpath}, []) except stack.exception.CommandError, e: sys.stderr.write('%s\n' % e) return -1 print help.getText() return -1 # Check to see if STACKDEBUG variable is set. # This determines if the stack trace should be # dumped when an exception occurs. STACKDEBUG = None if os.environ.has_key('STACKDEBUG'): STACKDEBUG = str2bool(os.environ['STACKDEBUG']) try: command = getattr(module, 'Command')(Database) t0 = time.time() rc = command.runWrapper(name, args[i:]) # syslog.syslog(syslog.LOG_INFO, 'runtime %.3f' % (time.time() - t0)) except stack.exception.CommandError as e: sys.stderr.write('%s\n' % e) syslog.syslog(syslog.LOG_ERR, '%s' % e) return -1 except: # Sanitize Exceptions, and log them. exc, msg, tb = sys.exc_info() for line in traceback.format_tb(tb): syslog.syslog(syslog.LOG_DEBUG, '%s' % line)
def run(self, args): host = args[0] bond_reg = re.compile('bond[0-9]+') udev_output = "" result = self.owner.call('list.host.interface', ['expanded=true', host]) for o in result: interface = o['interface'] default = str2bool(o['default']) ip = o['ip'] netname = o['network'] vlanid = o['vlan'] mac = o['mac'] if mac: mac = mac.lower() channel = o['channel'] options = o['options'] netmask = o['mask'] gateway = o['gateway'] startmode = None bootproto = 'static' if ip and not netname: Warn( f'WARNING: skipping interface "{interface}" on host "{o["host"]}" - ' 'interface has an IP but no network') continue if netname and ip and netmask: net = ipaddress.IPv4Network('%s/%s' % (ip, netmask), strict=False) broadcast = str(net.broadcast_address) network = str(net.network_address) else: broadcast = None network = None if options: options = shlex.split(o['options']) else: options = [] if 'noreport' in options: continue # don't do anything if noreport set ib_re = re.compile('^ib[0-9]+$') if mac: if not ib_re.match(interface) and interface != 'ipmi': udev_output += 'SUBSYSTEM=="net", ' udev_output += 'ACTION=="add", ' udev_output += 'DRIVERS=="?*", ' udev_output += 'ATTR{address}=="%s", ' % mac udev_output += 'ATTR{type}=="1", ' udev_output += 'KERNEL=="eth*", ' udev_output += 'NAME="%s"\n\n' % interface if not interface: continue if interface == 'ipmi': ipmisetup = '/tmp/ipmisetup' self.owner.addOutput( host, '<stack:file stack:name="%s">' % ipmisetup) self.owner.writeIPMI(host, ip, channel, netmask, gateway, vlanid) self.owner.addOutput(host, '</stack:file>') self.owner.addOutput(host, 'chmod 500 %s' % ipmisetup) continue if len(interface.split(':')) == 2: # # virtual interface configuration # self.owner.addOutput( host, '<stack:file stack:mode="append" stack:name="/etc/sysconfig/network/ifcfg-%s">' % interface.split(':')[0]) self.owner.addOutput(host, '# AUTHENTIC STACKI') vnum = interface.split(':')[1] if ip: self.owner.addOutput(host, 'IPADDR%s=%s' % (vnum, ip)) if netmask: self.owner.addOutput(host, 'NETMASK%s=%s' % (vnum, netmask)) if network: self.owner.addOutput(host, 'NETWORK%s=%s' % (vnum, network)) if broadcast: self.owner.addOutput(host, 'BROADCAST%s=%s' % (vnum, broadcast)) self.owner.addOutput(host, 'LABEL%s=%s' % (vnum, vnum)) else: self.owner.addOutput( host, '<stack:file stack:name="/etc/sysconfig/network/ifcfg-%s">' % interface) self.owner.addOutput(host, '# AUTHENTIC STACKI') if vlanid and self.owner.host_based_routing( host, interface, vlanid): parent_device = interface.strip().split('.')[0] self.owner.addOutput(host, 'ETHERDEVICE=%s' % parent_device) self.owner.addOutput(host, 'VLAN=yes') startmode = 'auto' else: self.owner.addOutput(host, 'USERCONTROL=no') dhcp = 'dhcp' in options if dhcp: bootproto = 'dhcp' if default: self.owner.addOutput(host, 'DHCLIENT_SET_HOSTNAME="yes"') self.owner.addOutput( host, 'DHCLIENT_SET_DEFAULT_ROUTE="yes"') else: self.owner.addOutput(host, 'DHCLIENT_SET_HOSTNAME="no"') self.owner.addOutput( host, 'DHCLIENT_SET_DEFAULT_ROUTE="no"') if 'onboot=no' in options: startmode = 'manual' elif ip or dhcp or channel or 'bridge' in options: # # if there is an IP address, or this # interface should DHCP, or anything in # the 'channel' field (e.g., this is a # bridged or bonded interface), or if 'bridge' # is in the options, then turn this interface on # startmode = 'auto' if not dhcp: if ip: self.owner.addOutput(host, 'IPADDR=%s' % ip) if netmask: self.owner.addOutput(host, 'NETMASK=%s' % netmask) if network: self.owner.addOutput(host, 'NETWORK=%s' % network) if broadcast: self.owner.addOutput(host, 'BROADCAST=%s' % broadcast) if mac: self.owner.addOutput(host, 'HWADDR=%s' % mac.strip()) # # bonded interface, e.g., 'bond0' # if bond_reg.match(interface): # # if a 'bond*' device is present, then always make # sure it is enabled on boot. # startmode = 'auto' self.owner.addOutput(host, 'BONDING_MASTER=yes') # # find the interfaces that are part of this bond # i = 0 for p in result: if p['channel'] == interface: self.owner.addOutput( host, 'BONDING_SLAVE%d="%s"' % (i, p['interface'])) i = i + 1 # # Check if there are bonding options set # for opt in options: if opt.startswith('bonding-opts='): i = opt.find('=') bo = opt[i + 1:] self.owner.addOutput( host, 'BONDING_MODULE_OPTS="%s"' % bo) break # # check if this is part of a bonded channel # if channel and bond_reg.match(channel): startmode = 'auto' bootproto = 'none' if not startmode: startmode = 'off' self.owner.addOutput(host, 'STARTMODE=%s' % startmode) self.owner.addOutput(host, 'BOOTPROTO=%s' % bootproto) # # if this is a bridged interface, then go look for the # physical interface this bridge is associated with # if 'bridge' in options: for p in result: if p['channel'] == interface: self.owner.addOutput(host, 'BRIDGE=yes') self.owner.addOutput(host, 'BRIDGE_FORWARDDELAY=0') self.owner.addOutput(host, 'BRIDGE_STP=off') self.owner.addOutput( host, 'BRIDGE_PORTS=%s' % p['interface']) break self.owner.addOutput(host, '\n') self.owner.addOutput(host, '</stack:file>') if udev_output: self.owner.addOutput( host, '<stack:file stack:name="/etc/udev/rules.d/70-persistent-net.rules">' ) self.owner.addOutput(host, udev_output) self.owner.addOutput(host, '</stack:file>')
def run(self, args): hosts, interfaces = args existinghosts = self.getHostnames() existing_memberships = {} existing_groups = {} for group in self.owner.call('list.group'): existing_groups[group['group']] = group['hosts'] for member in self.owner.call('list.host.group'): existing_memberships[member['host']] = member['groups'].split() # prune group assignments for incoming hosts for host in hosts.keys(): # no need to prune hosts not from the spreadsheet, or totally new hosts if host not in existinghosts: continue for group in existing_memberships[host]: self.owner.call('remove.host.group', [host, 'group=%s' % group]) sys.stderr.write('\tAdd Host\n') for host in hosts.keys(): sys.stderr.write('\t\t%s\r' % host) # # add the host if it doesn't exist # if host not in existinghosts: args = [host] appliance = hosts[host].get('appliance') box = hosts[host].get('box') rack = hosts[host].get('rack') rank = hosts[host].get('rank') for paramName in ['appliance', 'box', 'rack', 'rank']: paramValue = hosts[host].get(paramName) if paramValue: args.append('%s=%s' % (paramName, paramValue)) del hosts[host][paramName] self.owner.call('add.host', args) if 'installaction' in hosts[host]: self.owner.call('set.host.bootaction', [ host, 'sync=false', 'type=install', 'action=%s' % hosts[host]['installaction'] ]) del hosts[host]['installaction'] if 'osaction' in hosts[host]: self.owner.call('set.host.bootaction', [ host, 'sync=false', 'type=os', 'action=%s' % hosts[host]['osaction'] ]) del hosts[host]['osaction'] if 'groups' in hosts[host]: for groupname in hosts[host]['groups']: if groupname not in existing_groups: self.owner.call('add.group', [groupname]) existing_groups[groupname] = None param = 'group=%s' % groupname self.owner.call('add.host.group', [host, param]) del hosts[host]['groups'] # # set the host attributes that are explicitly # identified in the spreadsheet # for key in hosts[host].keys(): if key == 'boss': continue if key == 'comment': self.owner.call( 'set.host.comment', [host, 'comment=%s' % hosts[host][key]]) else: self.owner.call( 'set.host.%s' % key, [host, '%s=%s' % (key, hosts[host][key])]) sys.stderr.write('\t\t%s\r' % (' ' * len(host))) # # process the host's interface(s) # hosts = interfaces.keys() argv = [] for a in interfaces.keys(): argv.append(a) if argv: # remove previous host interfaces (if any) argv.append('all=true') self.owner.call('remove.host.interface', argv) sys.stderr.write('\tAdd Host Interface\n') for host in hosts: sys.stderr.write('\t\t%s\r' % host) for interface in interfaces[host].keys(): ip = None mac = None network = None ifhostname = None channel = None options = None vlan = None default = None if 'ip' in interfaces[host][interface].keys(): ip = interfaces[host][interface]['ip'] if 'mac' in interfaces[host][interface].keys(): mac = interfaces[host][interface]['mac'] if 'network' in interfaces[host][interface].keys(): network = interfaces[host][interface]['network'] if 'ifhostname' in interfaces[host][interface].keys(): ifhostname = interfaces[host][interface]['ifhostname'] if 'channel' in interfaces[host][interface].keys(): channel = interfaces[host][interface]['channel'] if 'options' in interfaces[host][interface].keys(): options = interfaces[host][interface]['options'] if 'vlan' in interfaces[host][interface].keys(): vlan = interfaces[host][interface]['vlan'] if 'default' in interfaces[host][interface].keys(): default = str2bool(interfaces[host][interface]['default']) else: default = False # # now add the interface # cmdparams = [ host, 'unsafe=true', 'interface=%s' % interface, 'default=%s' % default ] if mac: cmdparams.append('mac=%s' % mac) if ip: cmdparams.append('ip=%s' % ip) if network: cmdparams.append('network=%s' % network) if ifhostname: cmdparams.append('name=%s' % ifhostname) if vlan: cmdparams.append('vlan=%d' % vlan) if default: cmdparams.append('name=%s' % host) if 'bond' == interface[:4]: cmdparams.append('module=bonding') self.owner.call('add.host.interface', cmdparams) if channel: cmdparams = [ host, 'interface=%s' % interface, 'channel=%s' % channel ] self.owner.call('set.host.interface.channel', cmdparams) if options: cmdparams = [ host, 'interface=%s' % interface, 'options=%s' % options ] self.owner.call('set.host.interface.options', cmdparams) sys.stderr.write('\t\t%s\r' % (' ' * len(host)))
def run(self, args): filename, = args self.list_host_interface = \ self.owner.call('list.host.interface') self.appliances = self.getApplianceNames() # need all the info from networks(/subnets) self.networks = dict((k, next(v)) for k, v in groupby( self.owner.call('list.network'), itemgetter('network'))) self.boxes = self.getBoxNames() self.actions = [ entry['bootaction'] for entry in self.owner.call('list.bootaction') ] try: reader = stack.csv.reader(open(filename, encoding='ascii')) header = None for row in reader: if not header: header = row # # make checking the header easier # required = [ 'name', 'appliance', 'ip', 'mac', 'interface', 'rack', 'rank', 'network' ] for i in range(0, len(row)): if header[i] in required: required.remove(header[i]) if len(required) > 0: msg = 'the following required fields are not present in the input file: "%s"' % ', '.join( required) raise CommandError(self.owner, msg) continue name = None box = None appliance = None rack = None rank = None ip = None mac = None interface = None network = None ifhostname = None channel = None options = None vlan = None boss = None default = None comment = None installaction = None osaction = None groups = None for i in range(0, len(row)): field = row[i] if not field: continue if header[i] == 'name': name = field.lower() if header[i] == 'box': box = field if header[i] == 'appliance': appliance = field elif header[i] == 'rack': rack = field elif header[i] == 'rank': rank = field elif header[i] == 'ip': try: if field == "auto" or ipaddress.IPv4Address(field): ip = field except: msg = 'invalid IP %s in the input file' % ip raise CommandError(self.owner, msg) elif header[i] == 'mac': # # make sure the MAC has lowercase # letters # mac = field.lower() elif header[i] == 'interface': interface = field.lower() elif header[i] == 'network': network = field.lower() elif header[i] == 'interface hostname': ifhostname = field.lower() elif header[i] == 'channel': channel = field elif header[i] == 'options': options = field elif header[i] == 'vlan': try: vlan = int(field) except: msg = 'VLAN "%s" must be an integer' % field raise CommandError(self.owner, msg) if vlan < 1: msg = 'VLAN "%s" must be greater than 0' % vlan raise CommandError(self.owner, msg) elif header[i] == 'boss': boss = field elif header[i] == 'default': default = field elif header[i] == 'comment': comment = field elif header[i] == 'installaction': installaction = field elif header[i] in ['osaction', 'runaction']: osaction = field elif header[i] == 'groups': groups = field if not name: msg = 'empty host name found in "name" column' raise CommandError(self.owner, msg) if name not in self.owner.hosts.keys(): self.owner.hosts[name] = {} if box: self.checkBox(box) self.owner.hosts[name]['box'] = box if appliance: if 'appliance' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['appliance'] != appliance: msg = 'two different appliance types specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['appliance'] = appliance if rack: if 'rack' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['rack'] != rack: msg = 'two different rack numbers specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['rack'] = rack if rank: if 'rank' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['rank'] != rank: msg = 'two different rank numbers specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['rank'] = rank if not interface: continue if name not in self.owner.interfaces.keys(): self.owner.interfaces[name] = {} if interface in self.owner.interfaces[name].keys(): msg = 'interface "%s" already specified for host "%s"' % ( interface, name) raise CommandError(self.owner, msg) self.owner.interfaces[name][interface] = {} if default: self.owner.interfaces[name][interface]['default'] = default if ip: if not network: raise CommandError( self.owner, 'inclusion of IP requires inclusion of network') self.owner.interfaces[name][interface]['ip'] = ip if mac: self.owner.interfaces[name][interface]['mac'] = mac if network: self.owner.interfaces[name][interface]['network'] = network if ifhostname: self.owner.interfaces[name][interface][ 'ifhostname'] = ifhostname if channel: self.owner.interfaces[name][interface]['channel'] = channel if options: self.owner.interfaces[name][interface]['options'] = options if vlan: self.owner.interfaces[name][interface]['vlan'] = vlan if boss: self.owner.hosts[name]['boss'] = boss if comment: if 'comment' not in self.owner.hosts[name].keys(): self.owner.hosts[name]['comment'] = comment else: self.owner.hosts[name]['comment'] += \ ', %s' % comment if installaction: if installaction not in self.actions: msg = 'installaction "%s" does not exist in the database' % installaction raise CommandError(self.owner, msg) else: self.owner.hosts[name]['installaction'] = installaction if osaction: if osaction not in self.actions: msg = 'bootaction "%s" does not exist in the database' % osaction raise CommandError(self.owner, msg) else: self.owner.hosts[name]['osaction'] = osaction if groups: self.owner.hosts[name]['groups'] = groups.split(',') except UnicodeDecodeError: raise CommandError(self.owner, 'non-ascii character in file') # # check if the 'Boss' column was set # thisboss = self.db.getHostname('localhost') hasboss = 0 for name in self.owner.hosts.keys(): if 'boss' in self.owner.hosts[name]: if self.owner.hosts[name]['boss'] == thisboss: hasboss = 1 break if hasboss: # # now remove all hosts not associated with this Boss # for name in self.owner.hosts.keys(): if self.owner.hosts[name]['boss'] != thisboss: del self.owner.hosts[name] for o in self.list_host_interface: if o['name'] == name: self.owner.call('remove.host', [name]) # # sanity checks # macs = [] ips = {} for name in self.owner.hosts.keys(): # # ensure at least one of the host entries has an # appliance associated with it # if 'appliance' not in self.owner.hosts[name].keys(): msg = 'must supply an appliance type for host "%s"' % (name) raise CommandError(self.owner, msg) else: self.checkAppliance(self.owner.hosts[name]['appliance']) # # 'default' checking # ifaces = self.owner.interfaces[name].keys() # # if there is only one interface, make it the default # if len(ifaces) == 1: for interface in ifaces: self.owner.interfaces[name][interface]['default'] = 'True' else: # # if there is more than one interface for this # host, make sure that one of the interfaces # is specified as the 'default' interface # default = False multiple_defaults = False for interface in ifaces: if 'default' in self.owner.interfaces[name][ interface] and str2bool( self.owner.interfaces[name][interface] ['default']) is True: if not default: default = True else: multiple_defaults = True if not default: msg = 'host "%s" has multiple interfaces but none of the interfaces are designated as\na "default" interface. add a "default" column to your spreadsheet and\nmark one of the interfaces as "True" in the default column' % name raise CommandError(self.owner, msg) if multiple_defaults: msg = 'host "%s" has more than one interface designated as the "default" interface.\nedit your spreadsheet so that only one interface is the "default".' % name raise CommandError(self.owner, msg) # # interface specific checks # for interface in self.owner.interfaces[name].keys(): try: ip = self.owner.interfaces[name][interface]['ip'] except: ip = None try: vlan = self.owner.interfaces[name][interface]['vlan'] except: vlan = 'default' if ip: # self.checkIP(ip) if vlan in ips: if ip != 'auto' and ip in ips[vlan]: msg = 'duplicate IP "%s" in the input file' % ip raise CommandError(self.owner, msg) else: ips[vlan] = [] ips[vlan].append(ip) try: mac = self.owner.interfaces[name][interface]['mac'] except: mac = None if mac: # self.checkMAC(mac) if mac in macs: msg = 'duplicate MAC "%s" in the input file' % mac raise CommandError(self.owner, msg) macs.append(mac) try: network = self.owner.interfaces[name][interface]['network'] except: network = None if network: self.checkNetwork(network) if ip: # check if 'ip' could exist in 'network' network_ip, netmask = itemgetter('address', 'mask')( self.networks[network]) ipnetwork = ipaddress.IPv4Network(network_ip + '/' + netmask) # Handle cases where ipaddr = "auto" if ip != "auto" and \ ipaddress.IPv4Address(ip) not in ipnetwork: msg = 'IP "%s" is not in the "%s" IP space (%s/%s)' % \ (ip, network, network_ip, ipnetwork.prefixlen) raise CommandError(self.owner, msg) # # if 'channel' is specified and if it starts # with 'bond', make sure there is an interface # for this host that matches the the bond value # if re.match('bond[0-9]+$', interface): found = 0 for iface in self.owner.interfaces[name].keys(): if 'channel' not in self.owner.interfaces[name][ iface].keys(): continue if interface == self.owner.interfaces[name][iface][ 'channel']: found = 1 break if not found: msg = 'bonded interface "%s" is specified for host "%s", ' % ( interface, name) msg += 'but there is no channel "%s" specified for any interface associated with this host' % ( interface) raise CommandError(self.owner, msg)
def run(self, params, args): filename, sync, = self.fillParams([ ('file', None, True), ('sync', True), ]) if not os.path.exists(filename): raise CommandError(self, f'file {filename} does not exist') with open(os.path.abspath(filename), 'r') as f: try: loaded_json = f.read() self.data = json.loads(loaded_json) except ValueError as e: # determine the location of the invalid character and print a helpful error message # the json module returnes a message containing the location of the bad character location = int(re.search(r'char (.*?)\)', str(e)).group(1)) # make two strings, before and after the bad character b = loaded_json[:location] a = loaded_json[location:] # grab the entire line that the error is on error_line = (b[b.rfind('\n'):] + a[:a.find('\n')]).strip() # determine the length of the error line before the bad character blen = len((b[b.rfind('\n'):]).strip()) pointer_line = ' ' * blen + '^' raise CommandError( self, f'Invalid json document:\n{error_line}\n{pointer_line}\n{e}' ) # run a few pre checks self.checks(args) # make a backup of the database in its current state in the event of any errors s = subprocess.run(['/etc/cron.daily/backup-cluster-db']) if s.returncode != 0: raise CommandError( self, 'unable to backup the cluster database, aborting') # so that we are able to report how successful the load was self.successes = 0 self.warnings = 0 self.errors = 0 # start a logger self.log = logging.getLogger("load-json") logging.basicConfig(filename='/var/log/load-json.log', filemode='w+', level=logging.INFO) try: self.runPlugins(args) # the usual load commands sync their configs after the load if str2bool(sync): self.notify('\tSyncing config\n') self.command('sync.config') self.log.info('config synced') self.notify('\n\tSyncing host network localhost\n') self.command('sync.host.network', ['localhost']) self.log.info('config synced') except CommandError as e: self.log.info(f'Load terminated early: {e}') self.errors += 1 # report how well the load went self.notify( f'\nload finished with:\n{self.successes} successes\n{self.warnings} warnings\n{self.errors} errors\nCheck /var/log/load-json.log for details.\n' ) # if there are errors, revert db changes and raise a CommandError if self.errors != 0: self.notify( '\nThere were errors during the load, restoring the database. Check /var/log/load-json.log for details.\n' ) s = subprocess.run(['bash', '/var/db/restore-stacki-database.sh']) if s.returncode != 0: raise CommandError( self, 'There were errors and the database could not be restored. Check /var/log/load-json.log for details' ) raise CommandError( self, 'The database has been restored. No changes have been made.')
def run(self, params, args): if len(args) != 1: raise ArgUnique(self, 'switch') sm_switch = args[0] (disable, ) = self.fillParams([ ('disable', False), ]) disable = str2bool(disable) ibswitches = [ sw for sw in self.call('list.switch') if sw['model'] == 'm7800' ] ib_switch_names = [sw['switch'] for sw in ibswitches] if sm_switch not in ib_switch_names: msg = f'host {sm_switch} is not a supported infiniband switch\n' msg += 'Please verify the make and model attributes for this host.' raise CommandError(self, msg) ib_sw_nets = self.call('list.host.interface', ib_switch_names) self.switch_attrs = self.getHostAttrDict(ib_switch_names) if disable: switch = self.get_sw_handle(sm_switch) switch.subnet_manager = False switch.disconnect() return # NOTE assumes a single management port with options set. # this obviously breaks if a switch can someday be on multiple fabrics opts = next(sw['options'] for sw in ib_sw_nets if sw['host'] == sm_switch) if not opts: raise CommandError( self, f'switch {sm_switch} does not have its ibfabric set') for opt in shlex.split(opts): if opt.startswith('ibfabric='): _, fabric = opt.split('=') break if not fabric: raise CommandError( self, f'switch {sm_switch} does not have its ibfabric set') switches_to_disable = [] for ib_sw in ib_sw_nets: if ib_sw['host'] == sm_switch: # this is the sm continue if not ib_sw['options']: # switches with no fabric specified should be disabled switches_to_disable.append(ib_sw['host']) continue opts = [ opt for opt in shlex.split(ib_sw['options']) if opt.startswith('ibfabric=') ] if not opts: # switches with no fabric specified should be disabled switches_to_disable.append(ib_sw['host']) continue _, sw_fabric = opts[0].split('=') if sw_fabric == fabric: # other switches on the same fabric should be disabled switches_to_disable.append(ib_sw['host']) continue for switch in switches_to_disable: sw_handle = self.get_sw_handle(switch) sw_handle.subnet_manager = False sw_handle.disconnect() sw_handle = self.get_sw_handle(sm_switch) sw_handle.subnet_manager = True sw_handle.disconnect()
def traverse_stack_package(self, node): """Expands <stack:package> to native autoyast syntax, later passes will collect all these section to create a single <software> section. <software> <patterns config:type="list"> <!-- stack:type="meta" --> <pattern>?</pattern> </patterns> <packages config:type="list"> <package>?</package> ... </package> </software> """ stage = self.getAttr(node, 'stack:stage', default='install') enabled = str2bool(self.getAttr(node, 'stack:enable', default='true')) pattern = str2bool(self.getAttr(node, 'stack:meta', default='fase')) pkgs = [] for line in self.collect(node).split('\n'): pkg = line.strip() if pkg: pkgs.append(pkg) if not pattern: # Figure out if the package(s) are: # # post-packages - installed on first boot for broken RPMs # packages - installed during installation as God intended # remove-packages - deletes a package for no good reason innerTag = 'sles:package' if stage == 'boot': outerTag = 'sles:post-packages' else: outerTag = 'sles:packages' if not enabled: outerTag = 'sles:remove-packages' else: # Patterns only support: # # post-pattern # pattern # (no remove patterns) innerTag = 'sles:pattern' if stage == 'boot': outerTag = 'sles:post-patterns' else: outerTag = 'sles:patterns' outer = self.newElementNode(outerTag) self.setAttribute(outer, 'config:type', 'list') for rpm in pkgs: inner = self.newElementNode(innerTag) inner.appendChild(self.newTextNode(rpm)) outer.appendChild(inner) software = self.newElementNode('sles:software') software.appendChild(outer) node.parentNode.replaceChild(software, node) return False
def main(): """Where the magic begins.""" global host_partitions global csv_partitions host_disks = get_host_disks() count = 5 while count > 0: if len(host_disks) == 0: time.sleep(1) count -= 1 host_disks = get_host_disks() else: break # # if fstab is corrupted, get_host_fstab() will throw and exception. # catch it and just report an empty fstab # try: host_fstab = get_host_fstab(host_disks) except: host_fstab = [] host_partitions = get_host_partitions(host_disks, host_fstab) if not csv_partitions: if attributes['os.version'] == "11.x" and attributes['os'] == "sles": ostype = "sles11" elif attributes['os.version'] == "12.x" and attributes['os'] == "sles": ostype = "sles12" else: # Give ostype some default ostype = "sles11" if os.path.exists('/sys/firmware/efi'): default = 'uefi' else: default = 'default' var = '%s_%s' % (ostype, default) if hasattr(sles, var): parts = getattr(sles, var) else: parts = getattr(sles, 'default') if 'boot_device' in attributes: bootdisk = attributes['boot_device'] else: bootdisk = host_disks[0] csv_partitions = [] partid = 1 for m, s, f in parts: csv_partitions.append( { 'partid': partid, 'scope': 'global', 'device': bootdisk, 'mountpoint': m, 'size': s, 'fstype': f, 'options': '' }) partid += 1 # # there are 2 scenarios: # # 1) nukedisks == True # 2) nukedisks == False # 3) nukedisks == a list of disks to nuke <-- Not sure we actually handle this yet. # # 1 is easy -- nuke the disks and recreate the partitions specified in the # "partitions" variable # # For 2, reformat "/", "/boot" (if present) and "/var" on the boot disk, then # reconnect all other discovered partitions. # if host_fstab is an empty list, turning on nukedisks=True" to avoid SLES defaults if host_fstab == []: nuke_disks = True attributes['nukedisks'] = "True" elif 'nukedisks' in attributes: nuke_disks = str2bool(attributes['nukedisks']) else: nuke_disks = False attributes['nukedisks'] = "False" if not nuke_disks: # Need output of the existing fstab to be utilized for post-install script. if not os.path.exists(fs_info): os.makedirs(fs_info) with open(str(fs_info + '/__init__.py'), 'w') as fstab_info: fstab_info.write('old_fstab = %s\n\n' % host_fstab) # # process all nuked disks first # nuke_list = get_nukes(host_disks, nuke_disks, attributes['nukedisks']) for disk in nuke_list: nuke_it(disk) initialize = True output_disk(disk, initialize) # # now process all non-nuked disks # initialize = False for disk in host_disks: if disk not in nuke_list: output_disk(disk, initialize) print(prettify(partitioning_config))
if adapter != None: return (ctrl, adapter) return (None, None) ## ## MAIN ## # Halt the install with an error message on the console and in the message queue # if we are unable to create a RAID. # To override, set the attribute 'halt_install_on_error=False'. halt_on_error = str2bool(attributes.get('halt_install_on_error', True)) nukecontroller = str2bool(attributes.get('nukecontroller', False)) secureerase = str2bool(attributes.get('secureerase', False)) # # if 'secureerase' is true, then that implies that 'nukecontroller' is true # if secureerase: nukecontroller = True # # only run this code if 'nukecontroller' is true # if not nukecontroller: sys.exit(0)
def run(self, args): filename, = args self.list_host_interface = \ self.owner.call('list.host.interface') self.appliances = self.getApplianceNames() # need all the info from networks(/subnets) self.networks = dict((k, next(v)) for k, v in groupby(self.owner.call('list.network'), itemgetter('network'))) self.boxes = self.getBoxNames() self.actions = [entry['bootaction'] for entry in self.owner.call('list.bootaction')] try: reader = stack.csv.reader(open(filename, encoding='ascii')) header = None for row in reader: if not header: header = row # # make checking the header easier # required = [ 'name', 'appliance', 'ip', 'mac', 'interface', 'rack', 'rank', 'network' ] for i in range(0, len(row)): if header[i] in required: required.remove(header[i]) if len(required) > 0: msg = 'the following required fields are not present in the input file: "%s"' % ', '.join(required) raise CommandError(self.owner, msg) continue name = None box = None appliance = None rack = None rank = None ip = None mac = None interface = None network = None ifhostname = None channel = None options = None vlan = None boss = None default = None comment = None installaction = None osaction = None groups = None for i in range(0, len(row)): field = row[i] if not field: continue if header[i] == 'name': name = field.lower() if header[i] == 'box': box = field if header[i] == 'appliance': appliance = field elif header[i] == 'rack': rack = field elif header[i] == 'rank': rank = field elif header[i] == 'ip': try: if field == "auto" or ipaddress.IPv4Address(field): ip = field except: msg = 'invalid IP %s in the input file' % ip raise CommandError(self.owner, msg) elif header[i] == 'mac': # # make sure the MAC has lowercase # letters # mac = field.lower() elif header[i] == 'interface': interface = field.lower() elif header[i] == 'network': network = field.lower() elif header[i] == 'interface hostname': ifhostname = field.lower() elif header[i] == 'channel': channel = field elif header[i] == 'options': options = field elif header[i] == 'vlan': try: vlan = int(field) except: msg = 'VLAN "%s" must be an integer' % field raise CommandError(self.owner, msg) if vlan < 1: msg = 'VLAN "%s" must be greater than 0' % vlan raise CommandError(self.owner, msg) elif header[i] == 'boss': boss = field elif header[i] == 'default': default = field elif header[i] == 'comment': comment = field elif header[i] == 'installaction': installaction = field elif header[i] in [ 'osaction', 'runaction' ]: osaction = field elif header[i] == 'groups': groups = field if not name: msg = 'empty host name found in "name" column' raise CommandError(self.owner, msg) if name not in self.owner.hosts.keys(): self.owner.hosts[name] = {} if box: self.checkBox(box) self.owner.hosts[name]['box'] = box if appliance: if 'appliance' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['appliance'] != appliance: msg = 'two different appliance types specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['appliance'] = appliance if rack: if 'rack' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['rack'] != rack: msg = 'two different rack numbers specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['rack'] = rack if rank: if 'rank' in self.owner.hosts[name].keys() and \ self.owner.hosts[name]['rank'] != rank: msg = 'two different rank numbers specified for host "%s"' % name raise CommandError(self.owner, msg) self.owner.hosts[name]['rank'] = rank if not interface: continue if name not in self.owner.interfaces.keys(): self.owner.interfaces[name] = {} if interface in self.owner.interfaces[name].keys(): msg = 'interface "%s" already specified for host "%s"' % (interface, name) raise CommandError(self.owner, msg) self.owner.interfaces[name][interface] = {} if default: self.owner.interfaces[name][interface]['default'] = default if ip: if not network: raise CommandError(self.owner, 'inclusion of IP requires inclusion of network') self.owner.interfaces[name][interface]['ip'] = ip if mac: self.owner.interfaces[name][interface]['mac'] = mac if network: self.owner.interfaces[name][interface]['network'] = network if ifhostname: self.owner.interfaces[name][interface]['ifhostname'] = ifhostname if channel: self.owner.interfaces[name][interface]['channel'] = channel if options: self.owner.interfaces[name][interface]['options'] = options if vlan: self.owner.interfaces[name][interface]['vlan'] = vlan if boss: self.owner.hosts[name]['boss'] = boss if comment: if 'comment' not in self.owner.hosts[name].keys(): self.owner.hosts[name]['comment'] = comment else: self.owner.hosts[name]['comment'] += \ ', %s' % comment if installaction: if installaction not in self.actions: msg = 'installaction "%s" does not exist in the database' % installaction raise CommandError(self.owner, msg) else: self.owner.hosts[name]['installaction'] = installaction if osaction: if osaction not in self.actions: msg = 'bootaction "%s" does not exist in the database' % osaction raise CommandError(self.owner, msg) else: self.owner.hosts[name]['osaction'] = osaction if groups: self.owner.hosts[name]['groups'] = groups.split(',') except UnicodeDecodeError: raise CommandError(self.owner, 'non-ascii character in file') # # check if the 'Boss' column was set # thisboss = self.db.getHostname('localhost') hasboss = 0 for name in self.owner.hosts.keys(): if 'boss' in self.owner.hosts[name]: if self.owner.hosts[name]['boss'] == thisboss: hasboss = 1 break if hasboss: # # now remove all hosts not associated with this Boss # for name in self.owner.hosts.keys(): if self.owner.hosts[name]['boss'] != thisboss: del self.owner.hosts[name] for o in self.list_host_interface: if o['name'] == name: self.owner.call( 'remove.host', [ name ]) # # sanity checks # macs = [] ips = {} for name in self.owner.hosts.keys(): # # ensure at least one of the host entries has an # appliance associated with it # if 'appliance' not in self.owner.hosts[name].keys(): msg = 'must supply an appliance type for host "%s"' % (name) raise CommandError(self.owner, msg) else: self.checkAppliance( self.owner.hosts[name]['appliance']) # # 'default' checking # ifaces = self.owner.interfaces[name].keys() # # if there is only one interface, make it the default # if len(ifaces) == 1: for interface in ifaces: self.owner.interfaces[name][interface]['default'] = 'True' else: # # if there is more than one interface for this # host, make sure that one of the interfaces # is specified as the 'default' interface # default = False multiple_defaults = False for interface in ifaces: if 'default' in self.owner.interfaces[name][interface] and str2bool(self.owner.interfaces[name][interface]['default']) is True: if not default: default = True else: multiple_defaults = True if not default: msg = 'host "%s" has multiple interfaces but none of the interfaces are designated as\na "default" interface. add a "default" column to your spreadsheet and\nmark one of the interfaces as "True" in the default column' % name raise CommandError(self.owner, msg) if multiple_defaults: msg = 'host "%s" has more than one interface designated as the "default" interface.\nedit your spreadsheet so that only one interface is the "default".' % name raise CommandError(self.owner, msg) # # interface specific checks # for interface in self.owner.interfaces[name].keys(): try: ip = self.owner.interfaces[name][interface]['ip'] except: ip = None try: vlan = self.owner.interfaces[name][interface]['vlan'] except: vlan = 'default' if ip: # self.checkIP(ip) if vlan in ips: if ip != 'auto' and ip in ips[vlan]: msg = 'duplicate IP "%s" in the input file' % ip raise CommandError(self.owner, msg) else: ips[vlan] = [] ips[vlan].append(ip) try: mac = self.owner.interfaces[name][interface]['mac'] except: mac = None if mac: # self.checkMAC(mac) if mac in macs: msg = 'duplicate MAC "%s" in the input file' % mac raise CommandError(self.owner, msg) macs.append(mac) try: network = self.owner.interfaces[name][interface]['network'] except: network = None if network: self.checkNetwork(network) if ip: # check if 'ip' could exist in 'network' network_ip, netmask = itemgetter('address', 'mask')(self.networks[network]) ipnetwork = ipaddress.IPv4Network(network_ip + '/' + netmask) # Handle cases where ipaddr = "auto" if ip != "auto" and \ ipaddress.IPv4Address(ip) not in ipnetwork: msg = 'IP "%s" is not in the "%s" IP space (%s/%s)' % \ (ip, network, network_ip, ipnetwork.prefixlen) raise CommandError(self.owner, msg) # # if 'channel' is specified and if it starts # with 'bond', make sure there is an interface # for this host that matches the the bond value # if re.match('bond[0-9]+$', interface): found = 0 for iface in self.owner.interfaces[name].keys(): if 'channel' not in self.owner.interfaces[name][iface].keys(): continue if interface == self.owner.interfaces[name][iface]['channel']: found = 1 break if not found: msg = 'bonded interface "%s" is specified for host "%s", ' % (interface, name) msg += 'but there is no channel "%s" specified for any interface associated with this host' % (interface) raise CommandError(self.owner, msg)
def run(self, args): hosts, interfaces = args existinghosts = self.getHostnames() existing_memberships = {} existing_groups = {} for group in self.owner.call('list.group'): existing_groups[group['group']] = group['hosts'] for member in self.owner.call('list.host.group'): existing_memberships[member['host']] = member['groups'].split() # prune group assignments for incoming hosts for host in hosts.keys(): # no need to prune hosts not from the spreadsheet, or totally new hosts if host not in existinghosts: appliance = hosts[host].get('appliance') if appliance == 'frontend': raise CommandError(self, 'Renaming frontend is not supported!') continue for group in existing_memberships[host]: self.owner.call('remove.host.group', [host, 'group=%s' % group]) sys.stderr.write('\tAdd Host\n') for host in hosts.keys(): sys.stderr.write('\t\t%s\r' % host) # # add the host if it doesn't exist # if host not in existinghosts: args = [ host ] appliance = hosts[host].get('appliance') box = hosts[host].get('box') rack = hosts[host].get('rack') rank = hosts[host].get('rank') for paramName in [ 'appliance', 'box', 'rack', 'rank' ]: paramValue = hosts[host].get(paramName) if paramValue: args.append('%s=%s' % (paramName, paramValue)) del hosts[host][paramName] self.owner.call('add.host', args) if 'installaction' in hosts[host]: self.owner.call('set.host.bootaction', [ host, 'sync=false', 'type=install', 'action=%s' % hosts[host]['installaction'] ]) del hosts[host]['installaction'] if 'osaction' in hosts[host]: self.owner.call('set.host.bootaction', [ host, 'sync=false', 'type=os', 'action=%s' % hosts[host]['osaction'] ]) del hosts[host]['osaction'] if 'groups' in hosts[host]: for groupname in hosts[host]['groups']: if groupname not in existing_groups: self.owner.call('add.group', [groupname]) existing_groups[groupname] = None param = 'group=%s' % groupname self.owner.call('add.host.group', [host, param]) del hosts[host]['groups'] # # set the host attributes that are explicitly # identified in the spreadsheet # for key in hosts[host].keys(): if key == 'boss': continue if key == 'comment': self.owner.call('set.host.comment', [ host, 'comment=%s' % hosts[host][key] ]) else: self.owner.call('set.host.%s' % key, [ host, '%s=%s' % (key, hosts[host][key]) ]) sys.stderr.write('\t\t%s\r' % (' ' * len(host))) # # process the host's interface(s) # hosts = list(interfaces.keys()) # ensure the fronted is the first to get loaded _frontend = self.db.getHostname('localhost') for index, host in enumerate(hosts): if host == _frontend: tmp_host = hosts[0] hosts[0] = host hosts[index] = tmp_host argv = [] for a in interfaces.keys(): argv.append(a) if argv: # remove previous host interfaces (if any) argv.append('all=true') self.owner.call('remove.host.interface', argv) sys.stderr.write('\tAdd Host Interface\n') autoip_list = [] for host in hosts: sys.stderr.write('\t\t%s\r' % host) for interface in interfaces[host].keys(): ip = None mac = None network = None ifhostname = None channel = None options = None vlan = None default = None if 'ip' in interfaces[host][interface].keys(): ip = interfaces[host][interface]['ip'] if 'mac' in interfaces[host][interface].keys(): mac = interfaces[host][interface]['mac'] if 'network' in interfaces[host][interface].keys(): network = interfaces[host][interface]['network'] if 'ifhostname' in interfaces[host][interface].keys(): ifhostname = interfaces[host][interface]['ifhostname'] if 'channel' in interfaces[host][interface].keys(): channel = interfaces[host][interface]['channel'] if 'options' in interfaces[host][interface].keys(): options = interfaces[host][interface]['options'] if 'vlan' in interfaces[host][interface].keys(): vlan = interfaces[host][interface]['vlan'] if 'default' in interfaces[host][interface].keys(): default = str2bool(interfaces[host][interface]['default']) else: default = False # # now add the interface # cmdparams = [ host, 'unsafe=true', 'interface=%s' % interface, 'default=%s' % default ] if mac: cmdparams.append('mac=%s' % mac) if ip: cmdparams.append('ip=%s' % ip) if network: cmdparams.append('network=%s' % network) if ifhostname: cmdparams.append('name=%s' % ifhostname) if vlan: cmdparams.append('vlan=%d' % vlan) if default: cmdparams.append('name=%s' % host) if 'bond' == interface[:4]: cmdparams.append('module=bonding') if channel: cmdparams.append('channel=%s' % channel) if options: cmdparams.append('options=%s' % options) if ip != 'auto': self.owner.call('add.host.interface', cmdparams) else: autoip_list.append(cmdparams) sys.stderr.write('\t\t%s\r' % (' ' * len(host))) # Add interfaces with ip=AUTO at the end. for t in autoip_list: self.owner.call('add.host.interface', t)
# Once we import, get the CLI, adapter ctrl = controller.CLI() adapter = ctrl.getAdapter() if adapter != None: return (ctrl, adapter) return(None, None) ## ## MAIN ## if 'nukecontroller' in attributes: nukecontroller = str2bool(attributes['nukecontroller']) else: nukecontroller = False if 'secureerase' in attributes: secureerase = str2bool(attributes['secureerase']) else: secureerase = False # # if 'secureerase' is true, then that implies that 'nukecontroller' is true # if secureerase: nukecontroller = True #
def main(): """Where the magic begins.""" global host_partitions global csv_partitions host_disks = get_host_disks() count = 5 while count > 0: if len(host_disks) == 0: time.sleep(1) count -= 1 host_disks = get_host_disks() else: break # # if fstab is corrupted, get_host_fstab() will throw and exception. # catch it and just report an empty fstab # try: host_fstab = get_host_fstab(host_disks) except: host_fstab = [] host_partitions = get_host_partitions(host_disks, host_fstab) if not csv_partitions: if attributes['os.version'] == "11.x" and attributes['os'] == "sles": ostype = "sles11" elif attributes['os.version'] == "12.x" and attributes['os'] == "sles": ostype = "sles12" else: # Give ostype some default ostype = "sles11" if os.path.exists('/sys/firmware/efi'): default = 'uefi' else: default = 'default' var = '%s_%s' % (ostype, default) if hasattr(sles, var): parts = getattr(sles, var) else: parts = getattr(sles, 'default') if 'boot_device' in attributes: bootdisk = attributes['boot_device'] else: bootdisk = host_disks[0] csv_partitions = [] partid = 1 for m, s, f in parts: csv_partitions.append({ 'partid': partid, 'scope': 'global', 'device': bootdisk, 'mountpoint': m, 'size': s, 'fstype': f, 'options': '' }) partid += 1 # # there are 2 scenarios: # # 1) nukedisks == True # 2) nukedisks == False # 3) nukedisks == a list of disks to nuke <-- Not sure we actually handle this yet. # # 1 is easy -- nuke the disks and recreate the partitions specified in the # "partitions" variable # # For 2, reformat "/", "/boot" (if present) and "/var" on the boot disk, then # reconnect all other discovered partitions. # if host_fstab is an empty list, turning on nukedisks=True" to avoid SLES defaults if host_fstab == []: nuke_disks = True attributes['nukedisks'] = "True" elif 'nukedisks' in attributes: nuke_disks = str2bool(attributes['nukedisks']) else: nuke_disks = False attributes['nukedisks'] = "False" if not nuke_disks: # Need output of the existing fstab to be utilized for post-install script. if not os.path.exists(fs_info): os.makedirs(fs_info) with open(str(fs_info + '/__init__.py'), 'w') as fstab_info: fstab_info.write('old_fstab = %s\n\n' % host_fstab) # # process all nuked disks first # nuke_list = get_nukes(host_disks, nuke_disks, attributes['nukedisks']) for disk in nuke_list: nuke_it(disk) initialize = True output_disk(disk, initialize) # # now process all non-nuked disks # initialize = False for disk in host_disks: if disk not in nuke_list: output_disk(disk, initialize) print(prettify(partitioning_config))
def run(self, params, args): if len(args) != 1: raise ArgUnique(self, 'switch') sm_switch = args[0] (disable, ) = self.fillParams([ ('disable', False), ]) disable = str2bool(disable) ibswitches = [ sw for sw in self.call('list.switch') if sw['model'] == 'm7800' ] ib_switch_names = [sw['switch'] for sw in ibswitches] if sm_switch not in ib_switch_names: msg = f'host {sm_switch} is not a supported infiniband switch\n' msg += 'Please verify the make and model attributes for this host.' raise CommandError(self, msg) self.switch_attrs = self.getHostAttrDict(ib_switch_names) if self.switch_attrs[sm_switch].get('switch_type') != 'infiniband': msg = f'{sm_switch} is not an infiniband switch, please verify "stack list host attr {sm_switch} attr=switch_type"' if disable: # explicit disable only affects this switch switch = self.get_sw_handle(sm_switch) switch.subnet_manager = False switch.disconnect() return # NOTE assumes a single management port with options set. # this obviously breaks if a switch can someday be on multiple fabrics fabric = self.switch_attrs[sm_switch].get('ibfabric') if not fabric: raise CommandError( self, f'switch {sm_switch} does not have its ibfabric set') switches_to_disable = [] for ib_sw in ib_switch_names: if ib_sw == sm_switch: # this one is the sm continue sw_fabric = self.switch_attrs[ib_sw].get('ibfabric') if not sw_fabric or sw_fabric == fabric: # switches with no fabric specified should be disabled # other switches on the same fabric should be disabled switches_to_disable.append(ib_sw) continue for switch in switches_to_disable: sw_handle = self.get_sw_handle(switch) sw_handle.subnet_manager = False sw_handle.disconnect() sw_handle = self.get_sw_handle(sm_switch) sw_handle.subnet_manager = True sw_handle.disconnect()
def addHostAttrs(self, attributes): readonly = {} versions = {} for row in self.call('list.pallet'): # Compute a version number for each os pallet # # If the pallet already has a '.' take everything # before the '.' and add '.x'. If the version has no # '.' add '.x' name = row['name'] version = row['version'] release = row['release'] key = '%s-%s-%s' % (name, version, release) if name in [ 'SLES', 'CentOS' ]: # FIXME: Ubuntu is missing versions[key] = (name, '%s.x' % version.split('.')[0]) boxes = {} for row in self.call('list.box'): pallets = row['pallets'].split() carts = row['carts'].split() name = 'unknown' version = 'unknown' for pallet in pallets: if pallet in versions.keys(): (name, version) = versions[pallet] break boxes[row['name']] = { 'pallets' : pallets, 'carts' : carts, 'os.name' : name, 'os.version' : version } for (name, environment, rack, rank, metadata) in self.db.select( """ n.name, e.name, n.rack, n.rank, n.metadata from nodes n left join environments e on n.environment=e.id """): readonly[name] = {} readonly[name]['rack'] = rack readonly[name]['rank'] = rank if environment: readonly[name]['environment'] = environment if metadata: readonly[name]['metadata'] = metadata for (name, box, appliance) in self.db.select( """ n.name, b.name, a.name from nodes n, boxes b, appliances a where n.appliance=a.id and n.box=b.id """): readonly[name]['box'] = box readonly[name]['pallets'] = boxes[box]['pallets'] readonly[name]['carts'] = boxes[box]['carts'] # readonly[name]['os.name'] = boxes[box]['os.name'] readonly[name]['os.version'] = boxes[box]['os.version'] readonly[name]['appliance'] = appliance for (name, zone, address) in self.db.select( """ n.name, s.zone, nt.ip from networks nt, nodes n, subnets s where nt.main=true and nt.node=n.id and nt.subnet=s.id """): if address: readonly[name]['hostaddr'] = address readonly[name]['domainname'] = zone for host in readonly: readonly[host]['os'] = self.db.getHostOS(host) readonly[host]['hostname'] = host for row in self.call('list.host.group'): for group in row['groups'].split(): readonly[row['host']]['group.%s' % group] = 'true' readonly[row['host']]['groups'] = row['groups'] for host in attributes: a = attributes[host] r = readonly[host] ro = True if 'const_overwrite' in a: # This attribute allows a host to overwrite # constant attributes. This is crazy dangerous, # do not use this attribute. (n, v, t, s) = a['const_overwrite'] ro = str2bool(v) if ro: for key in r: # slam consts on top of attrs a[key] = (r[key], 'const', 'host') else: for key in r: # only add new consts to attrs if key not in a: a[key] = (r[key], 'const', 'host') return attributes
# Once we import, get the CLI, adapter ctrl = controller.CLI() adapter = ctrl.getAdapter() if adapter != None: return (ctrl, adapter) return (None, None) ## ## MAIN ## if 'nukecontroller' in attributes: nukecontroller = str2bool(attributes['nukecontroller']) else: nukecontroller = False if 'secureerase' in attributes: secureerase = str2bool(attributes['secureerase']) else: secureerase = False # # if 'secureerase' is true, then that implies that 'nukecontroller' is true # if secureerase: nukecontroller = True #