def validate_imp(self, imp): """Validate that the implementation doesn't already exist in the database, and that the implementation files are on disk.""" # Should not already exist if self.owner.imp_exists(imp=imp): raise ArgError( cmd=self.owner, arg="name", msg= f"An implementation named {imp} already exists in the database.", ) # Should exist on disk list_firmware_imp = Path( inspect.getsourcefile(stack.commands.list.host.firmware), ).parent.resolve() / f"imp_{imp}.py" sync_firmware_imp = Path( inspect.getsourcefile(stack.commands.sync.host.firmware), ).parent.resolve() / f"imp_{imp}.py" if not list_firmware_imp.exists() or not sync_firmware_imp.exists(): raise ArgError( cmd=self.owner, arg="name", msg= (f"Could not find an implementation named imp_{imp}.py. Please ensure an" " implementation file is placed into each of the following locations:\n" f"{list_firmware_imp}\n{sync_firmware_imp}"), )
def validate_regex(self, regex): """Make sure the provided regex is a valid Python regex.""" # Don't allow empty string, which will compile into a regex fine. if not regex: raise ArgError(cmd=self.owner, arg="regex", msg=f"Regex cannot be an empty string.") # Require the version_regex to be a valid regex try: re.compile(regex) except re.error as exception: raise ArgError(cmd=self.owner, arg="regex", msg=f"Invalid regex supplied: {exception}.")
def run(self, params, args): (scope, device, mountpoint) = self.fillParams([('scope', 'global'), ('device', None), ('mountpoint', None)]) oses = [] appliances = [] hosts = [] name = None accepted_scopes = ['global', 'os', 'appliance', 'host'] # Some checking that we got usable input if scope not in accepted_scopes: raise ParamValue(self, '%s' % params, 'one of the following: %s' % accepted_scopes) elif scope == 'global' and len(args) >= 1: raise ArgError( self, '%s' % args, 'unexpected, please provide a scope: %s' % accepted_scopes) elif scope == 'global' and (device is None and mountpoint is None): raise ParamRequired(self, 'device OR mountpoint') elif scope != 'global' and len(args) < 1: raise ArgRequired(self, '%s name' % scope) if scope == "os": oses = self.getOSNames(args) elif scope == "appliance": appliances = self.getApplianceNames(args) elif scope == "host": hosts = self.getHostnames(args) if scope != 'global': name = args[0] # Look up the id in the appropriate 'scope' table if scope == 'appliance': tableid = self.db.select('id from appliances where name=%s', [name])[0][0] elif scope == 'os': tableid = self.db.select('id from oses where name=%s', [name])[0][0] elif scope == 'host': tableid = self.db.select('id from nodes where name=%s', [name])[0][0] else: tableid = -1 query = 'delete from storage_partition where scope = %s and tableid = %s' values = [scope, tableid] if device and device != '*': query += ' and device = %s' values.append(device) if mountpoint and mountpoint != '*': query += ' and mountpoint = %s' values.append(mountpoint) self.db.execute(query, values)
def run(self, params, args): (host, interface, port) = self.fillParams([('host', None), ('interface', None), ('port', None)]) switches = self.getSwitchNames(args) if len(switches) == 0: raise ArgRequired(self, 'switch') if len(switches) > 1: raise ArgUnique(self, 'switch') switch = switches[0] hosts = self.getHostnames([host]) host = hosts[0] if not host: raise ParamRequired(self, ('host')) if not interface: raise ParamRequired(self, ('interface')) if not port: raise ParamRequired(self, ('port')) try: port = int(port) except: raise ParamType(self, 'port', 'integer') # # check if the host/port is defined for this switch # found = False for o in self.call('list.switch.host', [switch]): if o['host'] == host and o['port'] == port: found = True if not found: raise ArgError(self, 'host/port', '"%s/%s" not found' % (host, port)) # # see if the interface exists for this host # row = self.db.select("""net.id from networks net, nodes n where n.name='%s' and net.device='%s' and net.node = n.id""" % (host, interface)) if not row: raise CommandError( self, 'interface "%s" does not exist for host "%s"' % (interface, host)) interfaceid, = row[0] self.db.execute("""update switchports set interface=%s where port=%s and switch=(select id from nodes where name='%s') """ % (interfaceid, port, switch))
def run(self, params, args): (scope, device, mountpoint) = self.fillParams([ ('scope', 'global'), ('device', None), ('mountpoint', None)]) oses = [] appliances = [] hosts = [] name = None accepted_scopes = ['global', 'os', 'appliance', 'host'] # Some checking that we got usable input.: if scope not in accepted_scopes: raise ParamValue(self, '%s' % params, 'one of the following: %s' % accepted_scopes ) elif scope == 'global' and len(args) >= 1: raise ArgError(self, '%s' % args, 'unexpected, please provide a scope: %s' % accepted_scopes) elif scope == 'global' and (device is None and mountpoint is None): raise ParamRequired(self, 'device OR mountpoint') elif scope != 'global' and len(args) < 1: raise ArgRequired(self, '%s name' % scope) if scope == "os": oses = self.getOSNames(args) elif scope == "appliance": appliances = self.getApplianceNames(args) elif scope == "host": hosts = self.getHostnames(args) if scope != 'global': name = args[0] # # look up the id in the appropriate 'scope' table # tableid = -1 tablename = {"os":"oses", "appliance":"appliances", "host":"nodes"} if scope != 'global': self.db.execute("""select id from %s where name = '%s' """ % (tablename[scope], name)) tableid, = self.db.fetchone() deletesql = """delete from storage_partition where scope = '%s' and tableid = %s """ % (scope, tableid) if device and device != '*': deletesql += """ and device = '%s'""" % device if mountpoint and mountpoint != '*': deletesql += """ and mountpoint = '%s'""" % mountpoint self.db.execute(deletesql)
def validate_version(self, version, make, model): """Attempts to validate the version number against a version_regex if one is set for the make or model provided as well as ensuring the firmware version doesn't already exist. """ # Attempt to get the version regex entry. regex = self.owner.try_get_version_regex(make=make, model=model) if regex and not re.search( pattern=regex.regex, string=version, flags=re.IGNORECASE): raise ArgError( cmd=self.owner, arg="version", msg= (f"The format of the version number {version} does not validate based on the regex {regex.regex}" f" named {regex.name}{f' with description {regex.description}' if regex.description else ''}." ), ) if self.owner.firmware_exists(make=make, model=model, version=version): raise ArgError( cmd=self.owner, arg="version", msg= f"The firmware version {version} for make {make} and model {model} already exists.", )
def run(self, params, args): switches = self.getSwitchNames(args) if not switches: raise ArgRequired(self, 'switch') elif len(switches) > 1: raise ArgUnique(self, 'switch') switch = switches[0] (host, interface, port) = self.fillParams([ ('host', None), ('interface', None), ('port', None) ]) hosts = self.getHostnames([host]) if not hosts: raise ParamRequired(self, ('host')) elif len(hosts) > 1: raise ParamUnique(self, 'host') host = hosts[0] try: port = int(port) except: raise ParamType(self, 'port', 'integer') # Check if the host/port is defined for this switch for row in self.call('list.switch.host', [switch]): if row['host'] == host and row['port'] == port: break else: raise ArgError(self, 'host/port', f'"{host}/{port}" not found') # See if the interface exists for this host row = self.db.select(""" networks.id FROM networks, nodes WHERE nodes.name=%s AND networks.device=%s AND networks.node=nodes.id """, (host, interface)) if not row: raise CommandError( self, f'interface "{interface}" does not exist for host "{host}"' ) self.db.execute(""" UPDATE switchports SET interface=%s WHERE port=%s AND switch=(SELECT id FROM nodes WHERE name=%s) """, (row[0][0], port, switch))
def run(self, params, args): switches = self.getSwitchNames(args) if not switches: raise ArgRequired(self, 'switch') elif len(switches) > 1: raise ArgUnique(self, 'switch') switch = switches[0] (host, interface, port) = self.fillParams([('host', None), ('interface', None), ('port', None)]) hosts = self.getHostnames([host]) if not hosts: raise ParamRequired(self, ('host')) elif len(hosts) > 1: raise ParamUnique(self, 'host') host = hosts[0] try: port = int(port) except: raise ParamType(self, 'port', 'integer') # Check if the host/interface is defined for this switch for row in self.call('list.switch.host', [switch]): if row['host'] == host and row['interface'] == interface: break else: raise ArgError(self, 'host/interface', f'"{host}/{interface}" not found') # Update the switch port self.db.execute( """ UPDATE switchports SET port=%s WHERE interface=( SELECT networks.id FROM networks, nodes WHERE nodes.name=%s AND networks.device=%s AND networks.node=nodes.id ) AND switch=(SELECT id FROM nodes WHERE name=%s) """, (port, host, interface, switch))
def run(self, args): params, hosts = args make, model, versions, sort, = self.owner.fillParams(names=[ ("make", ""), ("model", ""), ("versions", ""), ("sort", "host") ], params=params) sort_map = { "host": "nodes.Name", "make": "firmware_make.name", "model": "firmware_model.name", "version": "firmware.version", } # sort must be one of the allowed values try: # also convert to the column name for use in ORDER BY sort = sort_map[sort] except KeyError: raise ParamError( cmd=self.owner, param="sort", msg=f"Sort must be one of: {list(sort_map.keys())}") # process hosts if present if hosts: # hosts must exist hosts = self.owner.getHosts(args=hosts) # process make if present if make: # ensure the make exists if not self.owner.make_exists(make=make): raise ParamError(cmd=self.owner, param="make", msg=f"The make {make} doesn't exist.") # process model if present if model: # make is now required if not make: raise ParamRequired(cmd=self.owner, param="make") # ensure the model exists if not self.owner.model_exists(make=make, model=model): raise ParamError( cmd=self.owner, param="model", msg=f"The model {model} doesn't exist for make {make}.") # Process versions if present if versions: # make and model are now required if not make: raise ParamRequired(cmd=self.owner, param="make") if not model: raise ParamRequired(cmd=self.owner, param="model") # turn a comma separated string into a list of versions and # get rid of any duplicate names versions = tuple( unique_everseen((version.strip() for version in versions.split(",") if version.strip()))) # ensure the versions exist try: self.owner.ensure_firmwares_exist(make=make, model=model, versions=versions) except CommandError as exception: raise ArgError(cmd=self.owner, arg="version", msg=exception.message()) results = self.get_firmware_mappings( hosts=hosts, make=make, model=model, versions=versions, sort=sort, ) # return the results return { "keys": ["host", "version", "make", "model"], "values": results }
def run(self, params, args): scope = None oses = [] appliances = [] hosts = [] if len(args) == 0: scope = 'global' elif len(args) == 1: try: oses = self.getOSNames(args) except: oses = [] try: appliances = self.getApplianceNames() except: appliances = [] try: hosts = self.getHostnames() except: hosts = [] else: raise ArgError(self, 'scope', 'must be unique or missing') if not scope: if args[0] in oses: scope = 'os' elif args[0] in appliances: scope = 'appliance' elif args[0] in hosts: scope = 'host' if not scope: raise ParamValue(self, 'scope', 'valid os, appliance name or host name') query = None if scope == 'global': query = """select adapter, enclosure, slot, raidlevel, arrayid, options from storage_controller where scope = 'global' order by enclosure, adapter, slot""" elif scope == 'os': # # not currently supported # return elif scope == 'appliance': query = """select adapter, enclosure, slot, raidlevel, arrayid, options from storage_controller where scope = "appliance" and tableid = (select id from appliances where name = '%s') order by enclosure, adapter, slot""" % args[0] elif scope == 'host': query = """select adapter, enclosure, slot, raidlevel, arrayid, options from storage_controller where scope = "host" and tableid = (select id from nodes where name = '%s') order by enclosure, adapter, slot""" % args[0] if not query: return name = None if scope == 'global': name = 'global' elif scope in ['appliance', 'host']: name = args[0] self.beginOutput() self.db.execute(query) i = 0 for row in self.db.fetchall(): adapter, enclosure, slot, raidlevel, arrayid, options = row if i > 0: name = None if adapter == -1: adapter = None if enclosure == -1: enclosure = None if slot == -1: slot = '*' if raidlevel == '-1': raidlevel = 'hotspare' if arrayid == -1: arrayid = 'global' elif arrayid == -2: arrayid = '*' # Remove leading and trailing double quotes options = options.strip("\"") self.addOutput( name, [enclosure, adapter, slot, raidlevel, arrayid, options]) i += 1 self.endOutput(header=[ 'scope', 'enclosure', 'adapter', 'slot', 'raidlevel', 'arrayid', 'options' ], trimOwner=False)
def run(self, params, args): scope = None oses = [] appliances = [] hosts = [] globalOnly, = self.fillParams([('globalOnly', 'n')]) globalOnlyFlag = self.str2bool(globalOnly) if len(args) == 0: scope = 'global' elif len(args) == 1: try: oses = self.getOSNames(args) except: oses = [] try: appliances = self.getApplianceNames() except: appliances = [] try: hosts = self.getHostnames() except: hosts = [] else: raise ArgError(self, 'scope', 'must be unique or missing') if not scope: if args[0] in oses: scope = 'os' elif args[0] in appliances: scope = 'appliance' elif args[0] in hosts: scope = 'host' if not scope: raise ParamValue(self, 'scope', 'valid os, appliance name or host name') query = None if scope == 'global': if globalOnlyFlag: query = """select scope, device, mountpoint, size, fstype, options, partid from storage_partition where scope = 'global' order by device,partid,fstype, size""" else: query = """(select scope, device, mountpoint, size, fstype, options, partid from storage_partition where scope = 'global') UNION ALL (select a.name, p.device, p.mountpoint, p.size, p.fstype, p.options, p.partid from storage_partition as p inner join nodes as a on p.tableid=a.id where p.scope='host') UNION ALL (select a.name, p.device, p.mountpoint, p.size, p.fstype, p.options, p.partid from storage_partition as p inner join appliances as a on p.tableid=a.id where p.scope='appliance') order by scope,device,partid,size,fstype""" elif scope == 'os': query = """select scope, device, mountpoint, size, fstype, options, partid from storage_partition where scope = "os" and tableid = (select id from oses where name = %s) order by device,partid,fstype,size""" elif scope == 'appliance': query = """select scope, device, mountpoint, size, fstype, options, partid from storage_partition where scope = "appliance" and tableid = (select id from appliances where name = %s) order by device,partid,fstype, size""" elif scope == 'host': query = """select scope, device, mountpoint, size, fstype, options, partid from storage_partition where scope="host" and tableid = (select id from nodes where name = %s) order by device,partid,fstype, size""" if not query: return self.beginOutput() if scope == 'global': self.db.execute(query) else: self.db.execute(query, [args[0]]) for name, device, mountpoint, size, fstype, options, partid in self.db.fetchall( ): if size == -1: size = "recommended" elif size == -2: size = "hibernation" if name == "host" or name == "appliance" or name == "os": name = args[0] if mountpoint == 'None': mountpoint = None if fstype == 'None': fstype = None if partid == 0: partid = None self.addOutput(name, [device, partid, mountpoint, size, fstype, options]) self.endOutput(header=[ 'scope', 'device', 'partid', 'mountpoint', 'size', 'fstype', 'options' ], trimOwner=False)
def run(self, params, args): scope = None oses = [] appliances = [] hosts = [] if len(args) == 0: scope = 'global' elif len(args) == 1: try: oses = self.getOSNames(args) except: oses = [] try: appliances = self.getApplianceNames(args) except: appliances = [] try: hosts = self.getHostnames(args) except: hosts = [] else: raise ArgError(self, 'scope', 'must be unique or missing') if not scope: if args[0] in oses: scope = 'os' elif args[0] in appliances: scope = 'appliance' elif args[0] in hosts: scope = 'host' if not scope: raise ParamValue(self, 'scope', 'valid os, appliance name or host name') if scope == 'global': name = None else: name = args[0] device, mountpoint = self.fillParams([('device', None), ('mountpoint', None)]) # # look up the id in the appropriate 'scope' table # tableid = None if scope == 'global': tableid = -1 elif scope == 'appliance': self.db.execute("""select id from appliances where name = '%s' """ % name) tableid, = self.db.fetchone() elif scope == 'host': self.db.execute("""select id from nodes where name = '%s' """ % name) tableid, = self.db.fetchone() deletesql = """delete from storage_partition where scope = '%s' and tableid = %s """ % (scope, tableid) if device and device != '*': deletesql += """ and device = '%s'""" % device if mountpoint and mountpoint != '*': deletesql += """ and mountpoint = '%s'""" % mountpoint self.db.execute(deletesql)
def run(self, args): params, args = args make, model = self.owner.fillParams( names = [ ('make', None), ('model', None) ], params = params ) # get rid of any duplicate names versions = tuple(unique_everseen(args)) if versions: # if versions were provided, require a make and model if make is None: raise ParamRequired(cmd = self.owner, param = 'make') if model is None: raise ParamRequired(cmd = self.owner, param = 'model') # ensure the versions exist in the DB try: self.owner.ensure_firmwares_exist(make = make, model = model, versions = versions) except CommandError as exception: raise ArgError( cmd = self.owner, arg = 'version', msg = exception.message() ) # check the files for the versions specified for row in self.owner.db.select( ''' firmware.version, firmware.source, firmware.hash_alg, firmware.hash, firmware.file FROM firmware INNER JOIN firmware_model ON firmware.model_id=firmware_model.id INNER JOIN firmware_make ON firmware_model.make_id=firmware_make.id WHERE firmware.version IN %s AND firmware_make.name=%s AND firmware_model.name=%s ''', (versions, make, model) ): version, source, hash_alg, hash_value, local_file = row # check that the local file exists, and fetch it if not if not Path(local_file).exists(): try: local_file = stack.firmware.fetch_firmware( source = source, make = make, model = model, filename = local_file.name ) except stack.firmware.FirmwareError as exception: raise CommandError( cmd = self.owner, msg = f'Error while fetching version {version} for make {make} and model {model}: {exception}' ) # verify the hash try: stack.firmware.calculate_hash(file_path = local_file, hash_alg = hash_alg, hash_value = hash_value) except stack.firmware.FirmwareError as exception: raise CommandError( cmd = self.owner, msg = f'Error during file verification: {exception}' ) else: for row in self.owner.db.select( ''' firmware.version, firmware.source, firmware.hash_alg, firmware.hash, firmware.file, firmware_make.name, firmware_model.name FROM firmware INNER JOIN firmware_model ON firmware.model_id=firmware_model.id INNER JOIN firmware_make ON firmware_model.make_id=firmware_make.id ''' ): version, source, hash_alg, hash_value, local_file, make, model = row local_file = Path(local_file) # check that the local file exists, and fetch it if not if not local_file.exists(): try: local_file = stack.firmware.fetch_firmware( source = source, make = make, model = model, filename = local_file.name ) except stack.firmware.FirmwareError as exception: raise CommandError( cmd = self.owner, msg = f'Error while fetching version {version} for make {make} and model {model}: {exception}' ) # verify the hash try: stack.firmware.calculate_hash(file_path = local_file, hash_alg = hash_alg, hash_value = hash_value) except stack.firmware.FirmwareError as exception: raise CommandError( cmd = self.owner, msg = f'Error during file verification: {exception}' ) # prune any files that shouldn't be there files_expected = [ Path(file_path).resolve(strict = True) for file_path in (row[0] for row in self.owner.db.select('firmware.file FROM firmware')) ] for file_path in stack.firmware.BASE_PATH.glob('**/*'): file_path = file_path.resolve(strict = True) if file_path.is_file() and file_path not in files_expected: file_path.unlink()