示例#1
0
    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),
        )
示例#2
0
    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),
        )
示例#3
0
    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),
        )
示例#4
0
	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,))
示例#5
0
    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, ))
示例#6
0
    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, ))
示例#7
0
    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, ))
示例#8
0
    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()
示例#9
0
    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,
        )
示例#10
0
    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,
        )
示例#11
0
    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)
示例#12
0
    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),
        )
示例#13
0
	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."
				)
			)
示例#14
0
    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),
        )
示例#15
0
    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
        }
示例#16
0
    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()
示例#17
0
    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()
示例#18
0
	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()