Exemplo n.º 1
0
    def validate_imp(self, make, model, imp):
        """Validate whether an imp is required due to the model not already existing,
		and validate that if the model exists that any requested implementation matches.
		"""
        # require an implementation if the model does not exist.
        if not imp and not self.owner.model_exists(make=make, model=model):
            # Get the list of valid makes + models and add them to the error message in an attempt to be helpful
            makes_and_models = "\n".join(
                f"{make_model['make']} + {make_model['model']}"
                for make_model in self.owner.call(
                    command="list.firmware.model"))
            raise ParamError(
                cmd=self.owner,
                param="imp",
                msg=
                (f"is required because make and model combination {make} + {model} doesn't exist."
                 f" Did you mean to use one of the below makes and/or models?\n{makes_and_models}"
                 ),
            )
        # Raise an error if the implementation was provided for an already existing model, and it does not match.
        if imp and self.owner.model_exists(make=make, model=model):
            existing_imp = self.owner.call(command="list.firmware.model",
                                           args=[model, f"make={make}"
                                                 ])[0]["implementation"]

            if imp != existing_imp:
                raise ParamError(
                    cmd=self.owner,
                    param="imp",
                    msg=
                    (f"The provided imp {imp} doesn't match the existing imp {existing_imp} for the already existing"
                     f" make + model {make} + {model}. Did you not mean to specify an imp? The parameter is not required"
                     " for existing models.\nIf you want to change what implementation is used, run"
                     " 'stack set firmware model imp'."),
                )
Exemplo n.º 2
0
    def run(self, params, args):
        if not len(args):
            raise ArgRequired(self, 'host')

        cmd, debug = self.fillParams([('command', None, True),
                                      ('debug', False)])

        if cmd == 'status':
            #
            # used by "stack list host power" -- this is an easy way in which to
            # share code between the two commands
            #
            # set 'debug' to True in order to get output from the status command
            #
            debug = True
        elif cmd not in ['on', 'off', 'reset']:
            raise ParamError(self, 'command', 'must be "on", "off" or "reset"')

        self.debug = self.str2bool(debug)

        for host in self.getHostnames(args):
            for o in self.call('list.host.interface', [host]):
                if o['interface'] == 'ipmi':
                    self.doPower(host, o['ip'], cmd)
                    break
Exemplo n.º 3
0
 def validate_hash_alg_supported(self, hash_alg):
     """Validates that the requested hash algorithm is supported."""
     try:
         stack.firmware.ensure_hash_alg_supported(hash_alg=hash_alg)
     except stack.firmware.FirmwareError as exception:
         raise ParamError(
             cmd=self.owner,
             param="hash_alg",
             msg=f"{exception}",
         ) from exception
Exemplo n.º 4
0
 def calculate_hash(self, file_path, hash_alg, hash_value):
     """Calculate the file hash and verify it against the provided hash, if present."""
     try:
         return stack.firmware.calculate_hash(file_path=file_path,
                                              hash_alg=hash_alg,
                                              hash_value=hash_value)
     except stack.firmware.FirmwareError as exception:
         raise ParamError(
             cmd=self.owner,
             param="hash",
             msg=f"{exception}",
         ) from exception
Exemplo n.º 5
0
    def validate_name(self, name):
        """Validate the name is provided and is unique."""
        # A name is required
        if not name:
            raise ParamRequired(cmd=self.owner, param="name")

        # The name must not already exist
        if self.owner.version_regex_exists(name=name):
            raise ParamError(
                cmd=self.owner,
                param="name",
                msg=
                f"A version_regex with the name {name} already exists in the database."
            )
Exemplo n.º 6
0
    def fetch_firmware(self, source, make, model, cleanup):
        """Try to fetch the firmware from the source and return the path to the file."""
        try:
            file_path = stack.firmware.fetch_firmware(
                source=source,
                make=make,
                model=model,
            )

            cleanup.callback(self.file_cleanup, file_path=file_path)
            return file_path

        except stack.firmware.FirmwareError as exception:
            raise ParamError(
                cmd=self.owner,
                param="source",
                msg=f"{exception}",
            ) from exception
Exemplo n.º 7
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
        }
Exemplo n.º 8
0
	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 CommandError(self, 'must supply zero or one argument')

		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 CommandError(self, 'argument "%s" must be a valid os, appliance name or host name' % args[0])

		if scope == 'global':
			name = 'global'
		else:
			name = args[0]

		adapter, enclosure, slot, hotspare, raidlevel, arrayid, options, force = self.fillParams([
			('adapter', None),
			('enclosure', None),
			('slot', None),
			('hotspare', None),
			('raidlevel', None),
			('arrayid', None, True),
			('options', ''),
			('force', 'n')
			])

		if not hotspare and not slot:
			raise ParamRequired(self, [ 'slot', 'hotspare' ])
		if arrayid != 'global' and not raidlevel:
			raise ParamRequired(self, 'raidlevel')

		if adapter:
			try:
				adapter = int(adapter)
			except:
				raise ParamType(self, 'adapter', 'integer')
			if adapter < 0:
				raise ParamValue(self, 'adapter', '>= 0')
		else:
			adapter = -1

		if enclosure:
			try:
				enclosure = int(enclosure)
			except:
				raise ParamType(self, 'enclosure', 'integer')
			if enclosure < 0:
				raise ParamValue(self, 'enclosure', '>= 0')
		else:
			enclosure = -1

		slots = []
		if slot:
			for s in slot.split(','):
				if s == '*':
					#
					# represent '*' in the database as '-1'
					#
					s = -1
				else:
					try:
						s = int(s)
					except:
						raise ParamType(self, 'slot', 'integer')
					if s < 0:
						raise ParamValue(self, 'slot', '>= 0')
					if s in slots:
						raise ParamError(self, 'slot', ' "%s" is listed twice' % s)
				slots.append(s)

		hotspares = []
		if hotspare:
			for h in hotspare.split(','):
				try:
					h = int(h)
				except:	
					raise ParamType(self, 'hotspare', 'integer')
				if h < 0:
					raise ParamValue(self, 'hostspare', '>= 0')
				if h in hotspares:
					raise ParamError(self, 'hostspare', ' "%s" is listed twice' % h)
				hotspares.append(h)

		if arrayid in [ 'global', '*' ]:
			pass
		else:
			try:
				arrayid = int(arrayid)
			except:
				raise ParamType(self, 'arrayid', 'integer')
			if arrayid < 1:
				raise ParamValue(self, 'arrayid', '>= 0')

		if arrayid == 'global' and len(hotspares) == 0:
			raise ParamError(self, 'arrayid', 'is "global" with no hotspares. Please supply at least one hotspare')

		#
		# 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()

		#
		# make sure the specification doesn't already exist
		#
		force = self.str2bool(force)
		for slot in slots:
			if not force:
				self.checkIt(name, scope, tableid, adapter, enclosure,
					slot)
		for hotspare in hotspares:
			if not force:
				self.checkIt(name, scope, tableid, adapter, enclosure,
					hotspare)

		if arrayid == 'global':
			arrayid = -1
		elif arrayid == '*':
			arrayid = -2

		#
		# now add the specifications to the database
		#
		for slot in slots:
			self.db.execute("""insert into storage_controller
				(scope, tableid, adapter, enclosure, slot,
				raidlevel, arrayid, options) values ('%s', %s, %s, %s,
				%s, %s, %s, '%s') """ % (scope, tableid, adapter,
				enclosure, slot, raidlevel, arrayid, options))

		for hotspare in hotspares:
			raidlevel = -1
			if arrayid == 'global':
				arrayid = -1

			self.db.execute("""insert into storage_controller
				(scope, tableid, adapter, enclosure, slot,
				raidlevel, arrayid, options) values ('%s', %s, %s, %s,
				%s, %s, %s, '%s') """ % (scope, tableid, adapter,
				enclosure, hotspare, raidlevel, arrayid, options))
Exemplo n.º 9
0
	def doParams(self):

		(service, network, outnetwork, chain, action, protocol, flags,
			comment, table, rulename) = self.fillParams([
				('service',		None,	True),
				('network',		None),
				('output-network',	None),
				('chain',		None,	True),
				('action',		None,	True),
				('protocol',		None,	True),
				('flags',		None),
				('comment',		None),
				('table',		'filter'),
				('rulename',		None),
			])
		
		if not network and not outnetwork:
			raise ParamRequired(self, ('network', 'output-network'))

		if table not in [ 'filter', 'raw', 'mangle', 'nat']:
			raise ParamError(self, 'table', 'is not valid')

		#
		# check if the network exists
		#
		if network == 'all':
			network = 0
		elif network:
			rows = self.db.execute("""select id from subnets where
				name = '%s'""" % (network))

			if rows == 0:
				raise CommandError(self, 'network "%s" not in the database. Run "stack list network" to get a list of valid networks.' % network)

			network, = self.db.fetchone()
		else:
			network = 'NULL'

		if outnetwork == 'all':
			outnetwork = 0
		elif outnetwork:
			rows = self.db.execute("""select id from subnets where
				name = '%s'""" % (outnetwork))

			if rows == 0:
				raise CommandError(self, 'output-network "%s" not in the database. Run "stack list network" to get a list of valid networks.')

			outnetwork, = self.db.fetchone()
		else:
			outnetwork = 'NULL'

		self.serviceCheck(service)

		action = action.upper()
		chain = chain.upper()

		if protocol:
			protocol = '"%s"' % protocol
		else:
			protocol = 'NULL'

		if flags:
			flags = '"%s"' % flags
		else:
			flags = 'NULL'

		if comment:
			comment = '"%s"' % comment
		else:
			comment = 'NULL'

		if not rulename:
			import uuid
			rulename = "%s" % uuid.uuid1()

		return (service, network, outnetwork, chain, action,
			protocol, flags, comment, table, rulename)
Exemplo n.º 10
0
    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 ArgRequired(self, 'scope')

        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 ArgValue(self, 'scope',
                           'a valid os, appliance name or host name')

        if scope == 'global':
            name = None
        else:
            name = args[0]

        adapter, enclosure, slot = self.fillParams([('adapter', None),
                                                    ('enclosure', None),
                                                    ('slot', None, True)])

        if adapter and adapter != '*':
            try:
                adapter = int(adapter)
            except:
                raise ParamType(self, 'adapter', 'integer')
            if adapter < 0:
                raise ParamValue(self, 'adapter', '>= 0')
        else:
            adapter = -1

        if enclosure and enclosure != '*':
            try:
                enclosure = int(enclosure)
            except:
                raise ParamType(self, 'enclosure', 'integer')
            if enclosure < 0:
                raise ParamValue(self, 'enclosure', '>= 0')
        else:
            enclosure = -1

        slots = []
        if slot and slot != '*':
            for s in slot.split(','):
                try:
                    s = int(s)
                except:
                    raise ParamType(self, 'slot', 'integer')
                if s < 0:
                    raise ParamValue(self, 'slot', '>= 0')
                if s in slots:
                    raise ParamError(self, 'slot', '"%s" is listed twice' % s)
                slots.append(s)

        #
        # 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_controller where
			scope = '%s' and tableid = %s """ % (scope, tableid)

        if adapter != -1:
            deletesql += ' and adapter = %s' % adapter

        if enclosure != -1:
            deletesql += ' and enclosure = %s' % enclosure

        if slot != '*':
            for slot in slots:
                dsql = '%s and slot = %s' % (deletesql, slot)
                self.db.execute(dsql)
        else:
            self.db.execute(deletesql)
Exemplo n.º 11
0
    def run(self, params, args):
        # Get the scope and make sure the args are valid
        scope, = self.fillParams([('scope', 'global')])
        scope_mappings = self.getScopeMappings(args, scope)

        # Now validate the params
        adapter, enclosure, slot = self.fillParams([('adapter', None),
                                                    ('enclosure', None),
                                                    ('slot', None, True)])

        # Make sure the adapter is an integer greater than 0, if it exists
        if adapter and adapter != '*':
            try:
                adapter = int(adapter)
            except:
                raise ParamType(self, 'adapter', 'integer')

            if adapter < 0:
                raise ParamValue(self, 'adapter', '>= 0')
        else:
            adapter = None

        # Make sure the enclosure is an integer greater than 0, if it exists
        if enclosure and enclosure != '*':
            try:
                enclosure = int(enclosure)
            except:
                raise ParamType(self, 'enclosure', 'integer')

            if enclosure < 0:
                raise ParamValue(self, 'enclosure', '>= 0')
        else:
            enclosure = None

        # Parse the slots
        slots = []
        if slot:
            for s in slot.split(','):
                # Make sure the slot is valid
                if s == '*':
                    # We're removing them all
                    s = None
                else:
                    try:
                        s = int(s)
                    except:
                        raise ParamType(self, 'slot', 'integer')

                    if s < 0:
                        raise ParamValue(self, 'slot', '>= 0')

                    if s in slots:
                        raise ParamError(self, 'slot',
                                         f'"{s}" is listed twice')

                # Looks good
                slots.append(s)

        scope_ids = []
        for scope_mapping in scope_mappings:
            for slot in slots:
                # Check that the controller configuration exists for the scope
                query = """
					scope_map.id FROM storage_controller,scope_map
					WHERE storage_controller.scope_map_id = scope_map.id
					AND scope_map.scope = %s
					AND scope_map.appliance_id <=> %s
					AND scope_map.os_id <=> %s
					AND scope_map.environment_id <=> %s
					AND scope_map.node_id <=> %s
				"""
                values = list(scope_mapping)

                # 0 might be valid so need to check for None
                if adapter is not None:
                    query += " AND storage_controller.adapter = %s"
                    values.append(adapter)

                if enclosure is not None:
                    query += " AND storage_controller.enclosure = %s"
                    values.append(enclosure)

                if slot is not None:
                    query += " AND storage_controller.slot = %s"
                    values.append(slot)

                rows = self.db.select(query, values)
                if not rows:
                    if adapter is None:
                        adapter = '*'
                    if enclosure is None:
                        enclosure = '*'
                    if slot is None:
                        slot = '*'

                    raise CommandError(
                        self, f'disk specification for "{adapter}/'
                        f'{enclosure}/{slot}" doesn\'t exist')

                scope_ids.extend(flatten(rows))

        # Controller disk specifications existed for all the scope mappings,
        # so delete them.
        # Note: We just delete the scope mapping, the ON DELETE CASCADE takes
        # care of removing the storage_controller table entries for us.
        self.db.execute('delete from scope_map where id in %s', (scope_ids, ))
Exemplo n.º 12
0
	def run(self, params, args):
		# Get the scope and make sure the args are valid
		scope, = self.fillParams([('scope', 'global')])
		scope_mappings = self.getScopeMappings(args, scope)

		# Now validate the params
		adapter, enclosure, slot, hotspare, raidlevel, arrayid, options = self.fillParams([
			('adapter', None),
			('enclosure', None),
			('slot', None),
			('hotspare', None),
			('raidlevel', None),
			('arrayid', None, True),
			('options', '')
		])

		# Gotta have either a hotspare list or a slot list
		if not hotspare and not slot:
			raise ParamRequired(self, ['slot', 'hotspare'])

		# Non-global arrays need a raid level
		if arrayid != 'global' and not raidlevel:
			raise ParamRequired(self, 'raidlevel')

		# Make sure the adapter is an integer greater than 0, if it exists
		if adapter:
			try:
				adapter = int(adapter)
			except:
				raise ParamType(self, 'adapter', 'integer')

			if adapter < 0:
				raise ParamValue(self, 'adapter', '>= 0')
		else:
			adapter = -1

		# Make sure the enclosure is an integer greater than 0, if it exists
		if enclosure:
			try:
				enclosure = int(enclosure)
			except:
				raise ParamType(self, 'enclosure', 'integer')

			if enclosure < 0:
				raise ParamValue(self, 'enclosure', '>= 0')
		else:
			enclosure = -1

		# Parse the slots
		slots = []
		if slot:
			for s in slot.split(','):
				# Make sure the slot is valid
				if s == '*':
					# Represent '*' in the database as '-1'
					s = -1
				else:
					try:
						s = int(s)
					except:
						raise ParamType(self, 'slot', 'integer')

					if s < 0:
						raise ParamValue(self, 'slot', '>= 0')

					if s in slots:
						raise ParamError(
							self, 'slot', f'"{s}" is listed twice'
						)

				# Needs to be unique in the scope
				for scope_mapping in scope_mappings:
					# Check that the route is unique for the scope
					if self.db.count("""
						(storage_controller.id)
						FROM storage_controller,scope_map
						WHERE storage_controller.scope_map_id = scope_map.id
						AND storage_controller.adapter = %s
						AND storage_controller.enclosure = %s
						AND storage_controller.slot = %s
						AND scope_map.scope = %s
						AND scope_map.appliance_id <=> %s
						AND scope_map.os_id <=> %s
						AND scope_map.environment_id <=> %s
						AND scope_map.node_id <=> %s
					""", (adapter, enclosure, s, *scope_mapping)) != 0:
		 				raise CommandError(
							self,
							f'disk specification for "{adapter}/'
							f'{enclosure}/{s}" already exists'
						)

				# Looks good
				slots.append(s)

		# Parse the hotspares
		hotspares = []
		if hotspare:
			for h in hotspare.split(','):
				# Make sure the hotspare is valid
				try:
					h = int(h)
				except:
					raise ParamType(self, 'hotspare', 'integer')

				if h < 0:
					raise ParamValue(self, 'hotspare', '>= 0')

				if h in hotspares:
					raise ParamError(
						self, 'hotspare', f'"{h}" is listed twice'
					)

				if h in slots:
					raise ParamError(
						self, 'hotspare', f'"{h}" is listed in slots'
					)

				# Needs to be unique in the scope
				for scope_mapping in scope_mappings:
					# Check that the route is unique for the scope
					if self.db.count("""
						(storage_controller.id)
						FROM storage_controller,scope_map
						WHERE storage_controller.scope_map_id = scope_map.id
						AND storage_controller.adapter = %s
						AND storage_controller.enclosure = %s
						AND storage_controller.slot = %s
						AND scope_map.scope = %s
						AND scope_map.appliance_id <=> %s
						AND scope_map.os_id <=> %s
						AND scope_map.environment_id <=> %s
						AND scope_map.node_id <=> %s
					""", (adapter, enclosure, h, *scope_mapping)) != 0:
		 				raise CommandError(
							self,
							f'disk specification for "{adapter}/'
							f'{enclosure}/{h}" already exists'
						)

				# Looks good
				hotspares.append(h)

		# Check the arrayid
		if arrayid not in {'global', '*'}:
			try:
				arrayid = int(arrayid)
			except:
				raise ParamType(self, 'arrayid', 'integer')

			if arrayid < 1:
				raise ParamValue(self, 'arrayid', '>= 1')

		if arrayid == 'global' and len(hotspares) == 0:
			raise ParamError(self, 'arrayid', 'is "global" with no hotspares')

		# Special encodings for arrayid
		if arrayid == 'global':
			arrayid = -1
		elif arrayid == '*':
			arrayid = -2

		# Everything is valid, add the data for each scope_mapping
		for scope_mapping in scope_mappings:
			# Add the slots
			for slot in slots:
				# First add the scope mapping
				self.db.execute("""
					INSERT INTO scope_map(
						scope, appliance_id, os_id, environment_id, node_id
					)
					VALUES (%s, %s, %s, %s, %s)
				""", scope_mapping)

				# Then add the slot controller entry
				self.db.execute("""
					INSERT INTO storage_controller(
						scope_map_id, adapter, enclosure, slot,
						raidlevel, arrayid, options
					)
					VALUES (LAST_INSERT_ID(), %s, %s, %s, %s, %s, %s)
				""", (adapter, enclosure, slot, raidlevel, arrayid, options))

			# And add the hotspares
			for hotspare in hotspares:
				# First add the scope mapping
				self.db.execute("""
					INSERT INTO scope_map(
						scope, appliance_id, os_id, environment_id, node_id
					)
					VALUES (%s, %s, %s, %s, %s)
				""", scope_mapping)

				# Then add the hotspare controller entry
				self.db.execute("""
					INSERT INTO storage_controller(
						scope_map_id, adapter, enclosure, slot,
						raidlevel, arrayid, options
					)
					VALUES (LAST_INSERT_ID(), %s, %s, %s, '-1', %s, %s)
				""", (adapter, enclosure, hotspare, arrayid, options))
Exemplo n.º 13
0
    def run(self, params, args):
        # Get the scope and make sure the args are valid
        scope, = self.fillParams([('scope', 'global')])
        scope_mappings = self.getScopeMappings(args, scope)

        # Now validate the params
        (name, table_type, chain, action, service, protocol, input_network,
         output_network, flags, comment) = self.fillParams([
             ('rulename', None), ('table', 'filter'), ('chain', None, True),
             ('action', None, True), ('service', None, True),
             ('protocol', None, True), ('network', None),
             ('output-network', None), ('flags', None), ('comment', None)
         ])

        # Generate a random firewall rule name if needed
        if not name:
            name = str(uuid.uuid1())

        # Make sure table is a valid choice
        if table_type not in {'filter', 'raw', 'mangle', 'nat'}:
            raise ParamError(self, 'table', 'is not valid')

        # Catch any blank parameters in chain, action, service, and protocol
        if not chain:
            raise ParamRequired(self, 'chain')

        if not action:
            raise ParamRequired(self, 'action')

        if not service:
            raise ParamRequired(self, 'service')

        if not protocol:
            raise ParamRequired(self, 'protocol')

        # Uppercase chain and action
        chain = chain.upper()
        action = action.upper()

        # Convert our networks to subnet ids
        input_network = blank_str_to_None(input_network)
        if input_network:
            rows = self.db.select('id from subnets where name=%s',
                                  (input_network, ))

            if not rows:
                raise CommandError(
                    self, f'"{input_network}" is not a valid network')

            in_subnet_id = rows[0][0]
        else:
            in_subnet_id = None

        output_network = blank_str_to_None(output_network)
        if output_network:
            rows = self.db.select('id from subnets where name = %s',
                                  (output_network, ))

            if not rows:
                raise CommandError(
                    self, f'"{output_network}" is not a valid network')

            out_subnet_id = rows[0][0]
        else:
            out_subnet_id = None

        # Normalize the service sting by stripping whitespace and lowercasing it
        service = re.sub(r'\s+', '', service).lower()

        # Make sure the service string is valid
        if not re.fullmatch(
                r"""
			all 				# 'all'
			|				# OR
			(?:
				\d+(?::\d+)?		# a port number with optional ':N' range
				|			# OR
				[a-z]+			# a service name
			)
			(?:
				,			# zero or more comma-seperated repetitions
				(?:			# of the above pattern
					\d+(?::\d+)?
					|
					[a-z]+
				)
			)*
		""", service, re.VERBOSE):
            raise CommandError(
                self, f'"{service}" is not a valid service specification')

        # Make sure blank strings are None for flags and comment
        flags = blank_str_to_None(flags)
        comment = blank_str_to_None(comment)

        for scope_mapping in scope_mappings:
            # Check that the rule name is unique for the scope
            if self.db.count(
                    """
		 		(firewall_rules.id) FROM firewall_rules,scope_map
				WHERE firewall_rules.scope_map_id = scope_map.id
				AND firewall_rules.name = %s
				AND scope_map.scope = %s
				AND scope_map.appliance_id <=> %s
				AND scope_map.os_id <=> %s
				AND scope_map.environment_id <=> %s
				AND scope_map.node_id <=> %s
			""", (name, *scope_mapping)) != 0:
                raise CommandError(self, f'rule named "{name}" already exists')

            # And that the rule is unique for the scope
            if self.db.count(
                    """
		 		(firewall_rules.id) FROM firewall_rules,scope_map
				WHERE firewall_rules.scope_map_id = scope_map.id
				AND firewall_rules.table_type = %s
				AND firewall_rules.chain = %s
				AND firewall_rules.action = %s
				AND firewall_rules.service = %s
				AND firewall_rules.protocol = %s
				AND firewall_rules.in_subnet_id <=> %s
				AND firewall_rules.out_subnet_id <=> %s
				AND firewall_rules.flags <=>%s
				AND scope_map.scope = %s
				AND scope_map.appliance_id <=> %s
				AND scope_map.os_id <=> %s
				AND scope_map.environment_id <=> %s
				AND scope_map.node_id <=> %s
			""", (table_type, chain, action, service, protocol, in_subnet_id,
            out_subnet_id, flags, *scope_mapping)) != 0:
                raise CommandError(self, 'firewall rule already exists')

        # Everything looks good, add the new rules
        for scope_mapping in scope_mappings:
            # First add the scope mapping for the new rule
            self.db.execute(
                """
				INSERT INTO scope_map(
					scope, appliance_id, os_id, environment_id, node_id
				)
				VALUES (%s, %s, %s, %s, %s)
			""", scope_mapping)

            # Then add the rule itself
            self.db.execute(
                """
				INSERT INTO firewall_rules(
					scope_map_id, name, table_type, chain, action, service,
					protocol, in_subnet_id, out_subnet_id, flags, comment
				)
				VALUES (LAST_INSERT_ID(), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
			""", (name, table_type, chain, action, service, protocol, in_subnet_id,
            out_subnet_id, flags, comment))
Exemplo n.º 14
0
    def doParams(self):

        (service, network, outnetwork, chain, action, protocol, flags, comment,
         table, rulename) = self.fillParams([
             ('service', None, True),
             ('network', None),
             ('output-network', None),
             ('chain', None, True),
             ('action', None, True),
             ('protocol', None, True),
             ('flags', None),
             ('comment', None),
             ('table', 'filter'),
             ('rulename', None),
         ])

        if not network and not outnetwork:
            raise ParamRequired(self, ('network', 'output-network'))

        if table not in ['filter', 'raw', 'mangle', 'nat']:
            raise ParamError(self, 'table', 'is not valid')

        #
        # check if the network exists
        #
        if network == 'all':
            network = 0
        elif network:
            rows = self.db.select('id from subnets where name = %s',
                                  (network, ))

            if len(rows) == 0:
                raise CommandError(
                    self,
                    'network "%s" not in the database. Run "stack list network" to get a list of valid networks.'
                    % network)

            network = rows[0][0]
        elif network == "":
            network = None

        if outnetwork == 'all':
            outnetwork = 0
        elif outnetwork:
            rows = self.db.select('id from subnets where name = %s',
                                  (outnetwork, ))

            if len(rows) == 0:
                raise CommandError(
                    self,
                    'output-network "%s" not in the database. Run "stack list network" to get a list of valid networks.'
                    % outnetwork)

            outnetwork = rows[0][0]
        elif outnetwork == "":
            outnetwork = None

        self.serviceCheck(service)

        action = action.upper()
        chain = chain.upper()

        # Make sure empty strings are None
        if protocol == "":
            protocol = None

        if flags == "":
            flags = None

        if comment == "":
            comment = None

        if not rulename:
            rulename = str(uuid.uuid1())

        return (service, network, outnetwork, chain, action, protocol, flags,
                comment, table, rulename)
Exemplo n.º 15
0
	def run(self, params, args):
		if not len(args):
			raise ArgRequired(self, 'host')

		cmd, debug, force_imp = self.fillParams([
			('command', None, True),
			('debug', False),
			('method', None)
		])
		host_errors = []
		self.debug = self.str2bool(debug)
		impl_output = namedtuple('output', 'out debug success')

		self.loadImplementation()

		# The first implementation is ipmi by default
		# but can be forced by the method parameter
		# If this is set, only that implementation will be run
		if force_imp:
			if force_imp not in self.impl_list:
				raise ParamError(self, 'method', f'{force_imp} not found as a valid implementation')
			imp_names = [force_imp]

		# Otherwise use all the implementations
		else:

			# Gather all set power implmentations besides ipmi and ssh
			imp_names  = [imp for imp in self.impl_list if imp not in ['ssh', 'ipmi']]

			# Add ipmi to be the first implementation used
			if 'ipmi' in self.impl_list:
				imp_names.insert(0, 'ipmi')

			# Add ssh to be the last implementation used
			if 'ssh' in self.impl_list:
				imp_names.append('ssh')

		if cmd not in ['on', 'off', 'reset', 'status']:
			raise ParamError(self, 'command', 'must be "on", "off", "reset", or "status"')

		for host in self.getHostnames(args):

			# Flag for if an implementation has
			# successfully run. Set to true if an
			# implementation returns success in its output
			imp_success = False
			self.beginOutput()

			# Iterate through each implementation
			# if one succeeds, we are done with the command
			for imp in imp_names:
				imp_msg = self.runImplementation(imp, [host, cmd, impl_output])
				if imp_msg.out:
					self.addOutput(host, imp_msg.out)
				if self.debug:

					# Output debug information if the parameter was set
					if not imp_msg.success and imp_msg.debug:
						self.addOutput(host, f'Failed to set power via {imp}: "{imp_msg.debug}"')

					# Handle if an implementation fails but has no debug information
					elif not imp_msg.success:
						self.addOutput(host, f'Failed to set power via {imp}')
					elif imp_msg.success:
						self.addOutput(host, f'Successfully set power via {imp}')

				# We don't need to run anymore implementations
				# now that one has succeeded for this host
				if imp_msg.success:
					imp_success = True
					self.mq_publish(host, cmd)
					break
			if self.debug and not imp_success:
				self.addOutput(host, f'Could not set power cmd {cmd} on host {host}')
			self.endOutput(padChar='', trimOwner=True)