def run(self, args): params, args = args make, = lowered( self.owner.fillParams( names=[("make", "")], params=params, )) # get rid of any duplicate names models = tuple(unique_everseen(lowered(args))) # ensure the make and models exist self.owner.ensure_models_exist(make=make, models=models) # remove associated firmware self.remove_related_firmware(make=make, models=models) # now delete the models self.owner.db.execute( """ DELETE firmware_model FROM firmware_model INNER JOIN firmware_make ON firmware_model.make_id=firmware_make.id WHERE firmware_model.name IN %s AND firmware_make.name=%s """, (models, make), )
def run(self, args): params, args = args models = tuple(unique_everseen(lowered(args))) imp, make, = lowered( self.owner.fillParams( names=[ ("imp", ""), ("make", ""), ], params=params, ), ) self.owner.ensure_models_exist(make=make, models=models) self.owner.ensure_imp_exists(imp=imp) # get the implementation ID imp_id = self.owner.get_imp_id(imp=imp) # associate the models with the imp self.owner.db.execute( """ UPDATE firmware_model INNER JOIN firmware_make ON firmware_model.make_id = firmware_make.id SET firmware_model.imp_id=%s WHERE firmware_make.name = %s AND firmware_model.name IN %s """, (imp_id, make, models), )
def run(self, args): params, args = args # Lowercase and make all args unique. models = tuple(unique_everseen(lowered(args))) make, version_regex, = lowered( self.owner.fillParams( names=[ ("make", ""), ("version_regex", ""), ], params=params, ), ) self.owner.ensure_models_exist(make=make, models=models) self.owner.ensure_version_regex_exists(name=version_regex) # get the version_regex ID version_regex_id = self.owner.get_version_regex_id(name=version_regex) # associate the models with the version_regex self.owner.db.execute( """ UPDATE firmware_model INNER JOIN firmware_make ON firmware_make.id = firmware_model.make_id SET firmware_model.version_regex_id=%s WHERE firmware_model.name IN %s AND firmware_make.name=%s """, (version_regex_id, models, make), )
def run(self, args): # lowercase all args and remove any duplicates names = tuple(unique_everseen(lowered(args))) # The version_regexes must exist self.owner.ensure_version_regexes_exist(names = names) # remove the version_regexes self.owner.db.execute("DELETE FROM firmware_version_regex WHERE name IN %s", (names,))
def run(self, args): params, args = args hosts = tuple(unique_everseen(lowered(args))) # process hosts if present if hosts: # hosts must exist hosts = self.owner.getHosts(args=hosts) make, model, versions = lowered( self.owner.fillParams( names=[ ("make", ""), ("model", ""), ("versions", ""), ], params=params, ), ) # process make if present self.validate_make(make=make) # process model if present self.validate_model(make=make, model=model) # Process versions if present if versions: # 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 self.owner.ensure_firmwares_exist(make=make, model=model, versions=versions) mappings_to_remove = self.get_firmware_mappings_to_remove( hosts=hosts, versions=versions, make=make, model=model, ) # remove the mappings if mappings_to_remove: self.owner.db.execute( "DELETE FROM firmware_mapping WHERE id IN %s", (mappings_to_remove, ))
def run(self, args): # get rid of any duplicate names makes = tuple(unique_everseen(lowered(args))) # ensure the make names already exist self.owner.ensure_makes_exist(makes=makes) # Remove any related models. self.remove_related_models(makes=makes) # now delete the makes self.owner.db.execute("DELETE FROM firmware_make WHERE name IN %s", (makes, ))
def run(self, args): # Require make names if not args: raise ArgRequired(cmd=self.owner, arg="makes") # lowercase all args and remove any duplicates args = tuple(unique_everseen(lowered(args))) # The makes must exist self.owner.ensure_makes_exist(makes=args) # disassociate the makes from version_regexes self.owner.db.execute( "UPDATE firmware_make SET version_regex_id=NULL WHERE name IN %s", (args, ))
def run(self, args): params, args = args make, imp, = lowered( self.owner.fillParams( names=[ ("make", ""), ("imp", ""), ], params=params, ), ) # require a make if not make: raise ParamRequired(cmd=self.owner, param="make") # require an implementation if not imp: raise ParamRequired(cmd=self.owner, param="imp") # get rid of any duplicate names models = tuple(unique_everseen(lowered(args))) # ensure the model name doesn't already exist for the given make self.owner.ensure_unique_models(make=make, models=models) with ExitStack() as cleanup: # create the make if it doesn't already exist self.create_missing_make(make=make, cleanup=cleanup) # create the implementation if it doesn't already exist self.create_missing_imp(imp=imp, cleanup=cleanup) # get the ID of the make to associate with make_id = self.owner.get_make_id(make=make) # get the ID of the imp to associate with imp_id = self.owner.get_imp_id(imp=imp) self.owner.db.execute( """ INSERT INTO firmware_model ( name, make_id, imp_id ) VALUES (%s, %s, %s) """, [(model, make_id, imp_id) for model in models], many=True, ) # everything was successful, dismiss cleanup. cleanup.pop_all()
def run(self, args): # get rid of any duplicate names makes = tuple(unique_everseen(lowered(args))) # ensure the make names don't already exist self.owner.ensure_unique_makes(makes=makes) self.owner.db.execute( """ INSERT INTO firmware_make ( name ) VALUES (%s) """, [(make, ) for make in makes], many=True, )
def run(self, args): params, args = args args = tuple(unique_everseen(lowered(args))) hosts = self.owner.getHosts(args=args) version, make, model, = lowered( self.owner.fillParams( names=[ ("version", ""), ("make", ""), ("model", ""), ], params=params, )) # Make, model, and version are required. This checks them all. self.owner.ensure_firmware_exists(make=make, model=model, version=version) # Make sure the proposed mappings are unique. self.ensure_unique_mappings(hosts=hosts, make=make, model=model, version=version) # Get the ID's of all the hosts node_ids = (row[0] for row in self.owner.db.select( "ID FROM nodes WHERE Name in %s", (hosts, ))) # Get the firmware version ID firmware_id = self.owner.get_firmware_id(make=make, model=model, version=version) # Add the mapping entries. self.owner.db.execute( """ INSERT INTO firmware_mapping ( node_id, firmware_id ) VALUES (%s, %s) """, [(node_id, firmware_id) for node_id in node_ids], many=True, )
def run(self, args): params, args = args models = tuple(unique_everseen(lowered(args))) expanded, make = lowered( self.owner.fillParams( names=[("expanded", "false"), ("make", "")], params=params, )) expanded = self.owner.str2bool(expanded) self.validate_make(make=make) self.validate_models(make=make, models=models) # If expanded is true, also list the implementation and any version regex associated with the model. if expanded: return self.get_expanded_results(make=make, models=models) # Otherwise just return the names of the makes and models. return self.get_results(make=make, models=models)
def run(self, args): params, args = args # Lowercase all args and remove any duplicates. models = tuple(unique_everseen(lowered(args))) make, = lowered( self.owner.fillParams(names=[("make", "")], params=params)) # The make and models must exist. self.owner.ensure_models_exist(models=models, make=make) # disassociate the models from version_regexes self.owner.db.execute( """ UPDATE firmware_model INNER JOIN firmware_make ON firmware_make.id = firmware_model.make_id SET firmware_model.version_regex_id=NULL WHERE firmware_model.name IN %s AND firmware_make.name=%s """, (models, make), )
def run(self, args): # remove any duplicates args = tuple(unique_everseen(lowered(args))) # The imps must exist self.owner.ensure_imps_exist(imps = args) # remove the implementations try: self.owner.db.execute("DELETE FROM firmware_imp WHERE name IN %s", (args,)) except IntegrityError: raise CommandError( cmd = self.owner, msg = ( "Failed to remove all implementations because some are still in use." " Please run 'stack list firmware model expanded=true' to list the" " models still using the implementation and 'stack remove firmware model'" " to remove them." ) )
def run(self, args): params, args = args makes = tuple(unique_everseen(lowered(args))) version_regex, = lowered( self.owner.fillParams(names=[("version_regex", "")], params=params), ) # The makes must exist self.owner.ensure_makes_exist(makes=makes) # The version_regex must exist self.owner.ensure_version_regex_exists(name=version_regex) # get the version_regex ID version_regex_id = self.owner.get_version_regex_id(name=version_regex) # associate the makes with the version_regex self.owner.db.execute( "UPDATE firmware_make SET version_regex_id=%s WHERE name in %s", (version_regex_id, makes), )
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, args): params, args = args self.validate_args(args=args) version_regex = args[0] self.validate_regex(regex=version_regex) name, description, make, models = self.owner.fillParams( names=[ ("name", ""), ("description", ""), ("make", ""), ("models", ""), ], params=params, ) name = name.lower() self.validate_name(name=name) make = make.lower() models = models.lower() # Process models if specified if models: models = tuple( unique_everseen((model.strip() for model in models.split(',') if model.strip()))) # The make and models must exist self.owner.ensure_models_exist(make=make, models=models) else: # Only need to check that the make exists. self.owner.ensure_make_exists(make=make) with ExitStack() as cleanup: # add the regex self.owner.db.execute( """ INSERT INTO firmware_version_regex ( regex, name, description ) VALUES (%s, %s, %s) """, (version_regex, name, description), ) cleanup.callback(self.owner.call, command="remove.firmware.version_regex", args=[name]) # If models are specified, associate it with the relevant models for the given make if models: self.owner.call( command="set.firmware.model.version_regex", args=[*models, f"make={make}", f"version_regex={name}"], ) # else associate it with just the make else: self.owner.call( command="set.firmware.make.version_regex", args=[make, f"version_regex={name}"], ) # everything worked, dismiss cleanup cleanup.pop_all()
def run(self, args): params, args = args self.validate_args(args=args) version = args[0].lower() *params_to_lower, hash_value, source = self.owner.fillParams( names=[ ("make", ""), ("model", ""), ("imp", ""), ("hosts", ""), ("hash_alg", "md5"), ("hash", ""), ("source", ""), ], params=params, ) # Lowercase all params that can be. make, model, imp, hosts, hash_alg = lowered(params_to_lower) self.validate_inputs( source=source, make=make, model=model, version=version, imp=imp, hash_alg=hash_alg, ) # Convert hosts to a list if set if hosts: # Make sure the host names are unique. hosts = tuple( unique_everseen(host.strip() for host in hosts.split(",") if host.strip())) # Validate the hosts exist. hosts = self.owner.getHosts(args=hosts) # we use ExitStack to hold our cleanup operations and roll back should something fail. with ExitStack() as cleanup: # Get the firmware file on disk in the right location and add the metadata to the database. self.add_firmware( source=source, make=make, model=model, version=version, imp=imp, hash_value=hash_value, hash_alg=hash_alg, cleanup=cleanup, ) # if hosts are provided, set the firmware relation if hosts: self.owner.call(command="add.host.firmware.mapping", args=[ *hosts, f"version={version}", f"make={make}", f"model={model}" ]) # everything went down without a problem, dismiss the cleanup cleanup.pop_all()
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()