def remove_levels_by_params( topology_el: _Element, level=None, # TODO create a special type, so that it cannot accept any string target_type: Optional[str] = None, target_value=None, devices: Optional[Iterable[str]] = None, # TODO remove, deprecated backward compatibility layer ignore_if_missing: bool = False, # TODO remove, deprecated backward compatibility layer validate_device_ids: bool = True, ) -> ReportItemList: """ Remove specified fencing level(s) topology_el -- etree element to remove the levels from int|string level -- level (index) of the fencing level to remove target_type -- the removed fencing level target value type mixed target_value -- the removed fencing level target value devices -- list of stonith devices of the removed fencing level ignore_if_missing -- when True, do not report if level not found """ # Do not ever remove a fencing-topology element, even if it is empty. There # may be ACLs set in pacemaker which allow "write" for fencing-level # elements (adding, changing and removing) but not fencing-topology # elements. In such a case, removing a fencing-topology element would cause # the whole change to be rejected by pacemaker with a "permission denied" # message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 report_list: ReportItemList = [] if target_type: report_list.extend(_validate_target_typewise(target_type)) if has_errors(report_list): return report_list if validate_device_ids and devices is not None: for device_id in devices: validate_id(device_id, description="stonith id", reporter=report_list) level_el_list = _find_level_elements(topology_el, level, target_type, target_value, devices) if not level_el_list: if ignore_if_missing: return report_list report_list.append( ReportItem.error( reports.messages.CibFencingLevelDoesNotExist( level, target_type, target_value, sorted(devices) if devices else [], ))) if has_errors(report_list): return report_list for el in level_el_list: el.getparent().remove(el) return report_list
def _validate_devices( reporter, resources_el, devices, force_device=False, allow_force=True ): if not devices: reporter.add( reports.required_option_is_missing(["stonith devices"]) ) invalid_devices = [] for dev in devices: errors = reporter.errors_count validate_id(dev, description="device id", reporter=reporter) if reporter.errors_count > errors: continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: reporter.add( reports.stonith_resources_do_not_exist( invalid_devices, ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR , None if force_device or not allow_force else report_codes.FORCE_STONITH_RESOURCE_DOES_NOT_EXIST ) )
def _validate_devices( reporter, resources_el, devices, force_device=False, allow_force=True ): if not devices: reporter.append( reports.required_option_is_missing(["stonith devices"]) ) invalid_devices = [] for dev in devices: errors = reporter.errors_count validate_id(dev, description="device id", reporter=reporter) if reporter.errors_count > errors: continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: reporter.append( reports.stonith_resources_do_not_exist( invalid_devices, ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR , None if force_device or not allow_force else report_codes.FORCE_STONITH_RESOURCE_DOES_NOT_EXIST ) )
def validate(option_dict): value = ValuePair.get(option_dict[option_name]) report_list = [] validate_id(value.normalized, option_name_for_report, report_list) if id_provider is not None and not report_list: report_list.extend(id_provider.book_ids(value.normalized)) return report_list
def _validate_devices(resources_el: _Element, devices, force_device=False, allow_force=True) -> ReportItemList: report_list: ReportItemList = [] if not devices: report_list.append( ReportItem.error( reports.messages.RequiredOptionsAreMissing(["stonith devices" ]))) invalid_devices = [] for dev in devices: validate_id_report_list: ReportItemList = [] validate_id(dev, description="device id", reporter=validate_id_report_list) report_list.extend(validate_id_report_list) if has_errors(validate_id_report_list): continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: report_list.append( ReportItem( severity=ReportItemSeverity( level=(ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR), force_code=(None if force_device or not allow_force else report_codes.FORCE), ), message=reports.messages.StonithResourcesDoNotExist( invalid_devices), )) return report_list
def _validate_value(self, value: ValuePair) -> ReportItemList: report_list: ReportItemList = [] validate_id(value.normalized, self._option_name_for_report, report_list) if self._id_provider is not None and not report_list: report_list.extend(self._id_provider.book_ids(value.normalized)) return report_list
def test_invalid_character(self): desc = "test id" info = { "id": "", "id_description": desc, "invalid_character": "", "is_first_char": False, } report = (severity.ERROR, report_codes.INVALID_ID_BAD_CHAR, info) info["id"] = "dum:my" info["invalid_character"] = ":" assert_raise_library_error(lambda: lib.validate_id("dum:my", desc), report) info["id"] = "dummy:" info["invalid_character"] = ":" assert_raise_library_error(lambda: lib.validate_id("dummy:", desc), report) info["id"] = "dum?my" info["invalid_character"] = "?" assert_raise_library_error(lambda: lib.validate_id("dum?my", desc), report) info["id"] = "dummy?" info["invalid_character"] = "?" assert_raise_library_error(lambda: lib.validate_id("dummy?", desc), report)
def _validate_devices(resources_el, devices, force_device=False, allow_force=True) -> ReportItemList: report_list: ReportItemList = [] if not devices: report_list.append( reports.required_options_are_missing(["stonith devices"])) invalid_devices = [] for dev in devices: validate_id_report_list: ReportItemList = [] validate_id(dev, description="device id", reporter=validate_id_report_list) report_list.extend(validate_id_report_list) if has_errors(validate_id_report_list): continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: report_list.append( reports.stonith_resources_do_not_exist( invalid_devices, ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR, None if force_device or not allow_force else report_codes.FORCE_STONITH_RESOURCE_DOES_NOT_EXIST)) return report_list
def validate(option_dict): value = ValuePair.get(option_dict[option_name]) report_list = [] validate_id(value.normalized, option_name_for_report, report_list) if id_provider is not None and not report_list: report_list.extend( id_provider.book_ids(value.normalized) ) return report_list
def validate_clone_id(clone_id: str, id_provider: IdProvider) -> ReportItemList: """ Validate that clone_id is a valid xml id and it is unique in the cib. clone_id -- identifier of clone element id_provider -- elements' ids generator """ report_list: ReportItemList = [] validate_id(clone_id, reporter=report_list) report_list.extend(id_provider.book_ids(clone_id)) return report_list
def validate_book_id(self, id_provider, id_description="id"): """ Book element_id in the id_provider, return True if success """ self._book_errors = [] validate_id(self._element_id, description=id_description, reporter=self._book_errors) if not self._book_errors: self._book_errors += id_provider.book_ids(self._element_id) return len(self._book_errors) < 1
def _validate_tag_id(tag_id: str, id_provider: IdProvider) -> ReportItemList: """ Validate that tag_id is an valid xml id an it is uniqe in the cib. tag_id -- identifier of new tag id_provider -- elements' ids generator """ report_list: ReportItemList = [] validate_id(tag_id, reporter=report_list) report_list.extend(id_provider.book_ids(tag_id)) return report_list
def validate_book_id(self, id_provider, id_description="id"): """ Book element_id in the id_provider, return True if success """ self._book_errors = [] validate_id( self._element_id, description=id_description, reporter=self._book_errors ) if not self._book_errors: self._book_errors += id_provider.book_ids(self._element_id) return len(self._book_errors) < 1
def test_invalid_empty(self): assert_raise_library_error( lambda: lib.validate_id("", "test id"), ( severity.ERROR, report_codes.INVALID_ID_IS_EMPTY, {"id_description": "test id",}, ), )
def test_invalid_empty(self): assert_raise_library_error( lambda: lib.validate_id("", "test id"), ( severity.ERROR, report_codes.EMPTY_ID, { "id": "", "id_description": "test id", } ) )
def test_invalid_first_character(self): desc = "test id" info = { "id": "", "id_description": desc, "invalid_character": "", "is_first_char": True, } report = (severity.ERROR, report_codes.INVALID_ID_BAD_CHAR, info) info["id"] = "0" info["invalid_character"] = "0" assert_raise_library_error(lambda: lib.validate_id("0", desc), report) info["id"] = "-" info["invalid_character"] = "-" assert_raise_library_error(lambda: lib.validate_id("-", desc), report) info["id"] = "." info["invalid_character"] = "." assert_raise_library_error(lambda: lib.validate_id(".", desc), report) info["id"] = ":" info["invalid_character"] = ":" assert_raise_library_error(lambda: lib.validate_id(":", desc), report) info["id"] = "0dummy" info["invalid_character"] = "0" assert_raise_library_error( lambda: lib.validate_id("0dummy", desc), report ) info["id"] = "-dummy" info["invalid_character"] = "-" assert_raise_library_error( lambda: lib.validate_id("-dummy", desc), report ) info["id"] = ".dummy" info["invalid_character"] = "." assert_raise_library_error( lambda: lib.validate_id(".dummy", desc), report ) info["id"] = ":dummy" info["invalid_character"] = ":" assert_raise_library_error( lambda: lib.validate_id(":dummy", desc), report )
def test_invalid_character(self): desc = "test id" info = { "id": "", "id_description": desc, "invalid_character": "", "is_first_char": False, } report = (severity.ERROR, report_codes.INVALID_ID, info) info["id"] = "dum:my" info["invalid_character"] = ":" assert_raise_library_error( lambda: lib.validate_id("dum:my", desc), report ) info["id"] = "dummy:" info["invalid_character"] = ":" assert_raise_library_error( lambda: lib.validate_id("dummy:", desc), report ) info["id"] = "dum?my" info["invalid_character"] = "?" assert_raise_library_error( lambda: lib.validate_id("dum?my", desc), report ) info["id"] = "dummy?" info["invalid_character"] = "?" assert_raise_library_error( lambda: lib.validate_id("dummy?", desc), report )
def create_in_group( env, resource_id, resource_agent_name, group_id, operation_list, meta_attributes, instance_attributes, allow_absent_agent=False, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, adjacent_resource_id=None, put_after_adjacent=False, wait=False, allow_not_suitable_command=False, ): # pylint: disable=too-many-arguments, too-many-locals """ Create resource in a cib and put it into defined group LibraryEnvironment env provides all for communication with externals string resource_id is identifier of resource string resource_agent_name contains name for the identification of agent string group_id is identificator for group to put primitive resource inside list of dict operation_list contains attributes for each entered operation dict meta_attributes contains attributes for primitive/meta_attributes bool allow_absent_agent is a flag for allowing agent that is not installed in a system bool allow_invalid_operation is a flag for allowing to use operations that are not listed in a resource agent metadata bool allow_invalid_instance_attributes is a flag for allowing to use instance attributes that are not listed in a resource agent metadata or for allowing to not use the instance_attributes that are required in resource agent metadata bool use_default_operations is a flag for stopping stopping of adding default cib operations (specified in a resource agent) bool ensure_disabled is flag that keeps resource in target-role "Stopped" string adjacent_resource_id identify neighbor of a newly created resource bool put_after_adjacent is flag to put a newly create resource befor/after adjacent resource mixed wait is flag for controlling waiting for pacemaker idle mechanism bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND """ resource_agent = get_agent( env.report_processor, env.cmd_runner(), resource_agent_name, allow_absent_agent, ) with resource_environment( env, wait, [resource_id], _ensure_disabled_after_wait( ensure_disabled or resource.common.are_meta_disabled(meta_attributes)) ) as resources_section: id_provider = IdProvider(resources_section) _check_special_cases(env, resource_agent, resources_section, resource_id, meta_attributes, instance_attributes, allow_not_suitable_command) primitive_element = resource.primitive.create( env.report_processor, resources_section, id_provider, resource_id, resource_agent, operation_list, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ) if ensure_disabled: resource.common.disable(primitive_element, id_provider) validate_id(group_id, "group name") resource.group.place_resource( resource.group.provide_group(resources_section, group_id), primitive_element, adjacent_resource_id, put_after_adjacent, )
def create( report_processor, resources_section, resource_id, resource_agent, raw_operation_list=None, meta_attributes=None, instance_attributes=None, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, resource_type="resource" ): """ Prepare all parts of primitive resource and append it into cib. report_processor is a tool for warning/info/error reporting etree.Element resources_section is place where new element will be appended string resource_id is id of new resource lib.resource_agent.CrmAgent resource_agent list of dict raw_operation_list specifies operations of resource dict meta_attributes specifies meta attributes of resource dict instance_attributes specifies instance attributes of resource bool allow_invalid_operation is flag for skipping validation of operations bool allow_invalid_instance_attributes is flag for skipping validation of instance_attributes bool use_default_operations is flag for completion operations with default actions specified in resource agent string resource_type -- describes the resource for reports """ if raw_operation_list is None: raw_operation_list = [] if meta_attributes is None: meta_attributes = {} if instance_attributes is None: instance_attributes = {} if does_id_exist(resources_section, resource_id): raise LibraryError(reports.id_already_exists(resource_id)) validate_id(resource_id, "{0} name".format(resource_type)) operation_list = prepare_operations( report_processor, raw_operation_list, resource_agent.get_cib_default_actions( necessary_only=not use_default_operations ), [operation["name"] for operation in resource_agent.get_actions()], allow_invalid=allow_invalid_operation, ) report_processor.process_list( resource_agent.validate_parameters( instance_attributes, parameters_type=resource_type, allow_invalid=allow_invalid_instance_attributes, ) ) return append_new( resources_section, resource_id, resource_agent.get_standard(), resource_agent.get_provider(), resource_agent.get_type(), instance_attributes=instance_attributes, meta_attributes=meta_attributes, operation_list=operation_list )
def check_new_id_applicable(tree, description, id): validate_id(id, description) validate_id_does_not_exist(tree, id)
def create( report_processor, resources_section, resource_id, resource_agent, raw_operation_list=None, meta_attributes=None, instance_attributes=None, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, ): """ Prepare all parts of primitive resource and append it into cib. report_processor is a tool for warning/info/error reporting etree.Element resources_section is place where new element will be appended string resource_id is id of new resource lib.resource_agent.CrmAgent resource_agent list of dict raw_operation_list specifies operations of resource dict meta_attributes specifies meta attributes of resource dict instance_attributes specifies instance attributes of resource bool allow_invalid_operation is flag for skipping validation of operations bool allow_invalid_instance_attributes is flag for skipping validation of instance_attributes bool use_default_operations is flag for completion operations with default actions specified in resource agent bool ensure_disabled is flag for completion meta_attributes with attribute causing disabling resource """ if raw_operation_list is None: raw_operation_list = [] if meta_attributes is None: meta_attributes = {} if instance_attributes is None: instance_attributes = {} if does_id_exist(resources_section, resource_id): raise LibraryError(reports.id_already_exists(resource_id)) validate_id(resource_id, "resource name") operation_list = prepare_operations( report_processor, raw_operation_list, resource_agent.get_cib_default_actions( necessary_only=not use_default_operations ), [operation["name"] for operation in resource_agent.get_actions()], allow_invalid=allow_invalid_operation, ) if ensure_disabled: meta_attributes = disable_meta(meta_attributes) report_processor.process_list( resource_agent.validate_parameters( instance_attributes, parameters_type="resource", allow_invalid=allow_invalid_instance_attributes, ) ) return append_new( resources_section, resource_id, resource_agent.get_standard(), resource_agent.get_provider(), resource_agent.get_type(), instance_attributes=instance_attributes, meta_attributes=meta_attributes, operation_list=operation_list )
def create_in_group( env, stonith_id, stonith_agent_name, group_id, operations, meta_attributes, instance_attributes, allow_absent_agent=False, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, adjacent_resource_id=None, put_after_adjacent=False, wait=False, ): # pylint: disable=too-many-arguments, too-many-locals """ Create stonith as resource in a cib and put it into defined group. LibraryEnvironment env provides all for communication with externals string stonith_id is an identifier of stonith resource string stonith_agent_name contains name for the identification of agent string group_id is identificator for group to put stonith inside list of dict operations contains attributes for each entered operation dict meta_attributes contains attributes for primitive/meta_attributes dict instance_attributes contains attributes for primitive/instance_attributes bool allow_absent_agent is a flag for allowing agent that is not installed in a system bool allow_invalid_operation is a flag for allowing to use operations that are not listed in a stonith agent metadata bool allow_invalid_instance_attributes is a flag for allowing to use instance attributes that are not listed in a stonith agent metadata or for allowing to not use the instance_attributes that are required in stonith agent metadata bool use_default_operations is a flag for stopping stopping of adding default cib operations (specified in a stonith agent) bool ensure_disabled is flag that keeps resource in target-role "Stopped" string adjacent_resource_id identify neighbor of a newly created stonith bool put_after_adjacent is flag to put a newly create resource befor/after adjacent stonith mixed wait is flag for controlling waiting for pacemaker idle mechanism """ stonith_agent = get_agent( env.report_processor, env.cmd_runner(), stonith_agent_name, allow_absent_agent, ) if stonith_agent.get_provides_unfencing(): meta_attributes["provides"] = "unfencing" with resource_environment( env, wait, [stonith_id], _ensure_disabled_after_wait( ensure_disabled or are_meta_disabled(meta_attributes), ), ) as resources_section: id_provider = IdProvider(resources_section) stonith_element = resource.primitive.create( env.report_processor, resources_section, id_provider, stonith_id, stonith_agent, operations, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ) if ensure_disabled: resource.common.disable(stonith_element, id_provider) validate_id(group_id, "group name") resource.group.place_resource( resource.group.provide_group(resources_section, group_id), stonith_element, adjacent_resource_id, put_after_adjacent, )
def create_in_group( env: LibraryEnvironment, stonith_id: str, stonith_agent_name: str, group_id: str, operations: Iterable[Mapping[str, str]], meta_attributes: Mapping[str, str], instance_attributes: Mapping[str, str], allow_absent_agent: bool = False, allow_invalid_operation: bool = False, allow_invalid_instance_attributes: bool = False, use_default_operations: bool = True, ensure_disabled: bool = False, adjacent_resource_id: Optional[str] = None, put_after_adjacent: bool = False, wait: WaitType = False, ): # pylint: disable=too-many-arguments, too-many-locals """ DEPRECATED Create stonith as resource in a cib and put it into defined group. env -- provides all for communication with externals stonith_id --an identifier of stonith resource stonith_agent_name -- contains name for the identification of agent group_id -- identificator for group to put stonith inside operations -- contains attributes for each entered operation meta_attributes -- contains attributes for primitive/meta_attributes instance_attributes -- contains attributes for primitive/instance_attributes allow_absent_agent -- a flag for allowing agent not installed in a system allow_invalid_operation -- a flag for allowing to use operations that are not listed in a stonith agent metadata allow_invalid_instance_attributes -- a flag for allowing to use instance attributes that are not listed in a stonith agent metadata or for allowing to not use the instance_attributes that are required in stonith agent metadata use_default_operations -- a flag for stopping of adding default cib operations (specified in a stonith agent) ensure_disabled -- flag that keeps resource in target-role "Stopped" adjacent_resource_id -- identify neighbor of a newly created stonith put_after_adjacent -- is flag to put a newly create resource befor/after adjacent stonith wait -- flag for controlling waiting for pacemaker idle mechanism """ runner = env.cmd_runner() agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor) stonith_agent = _get_agent_facade( env.report_processor, agent_factory, stonith_agent_name, allow_absent_agent, ) if stonith_agent.metadata.provides_unfencing: meta_attributes = dict(meta_attributes, provides="unfencing") with resource_environment( env, wait, [stonith_id], _ensure_disabled_after_wait( ensure_disabled or resource.common.are_meta_disabled(meta_attributes), ), ) as resources_section: id_provider = IdProvider(resources_section) adjacent_resource_element = None if adjacent_resource_id: try: adjacent_resource_element = get_element_by_id( get_root(resources_section), adjacent_resource_id) except ElementNotFound: # We cannot continue without adjacent element because # the validator might produce misleading reports if env.report_processor.report( ReportItem.error( reports.messages.IdNotFound( adjacent_resource_id, []))).has_errors: raise LibraryError() from None try: group_element = get_element_by_id(get_root(resources_section), group_id) except ElementNotFound: group_id_reports: List[ReportItem] = [] validate_id(group_id, description="group name", reporter=group_id_reports) env.report_processor.report_list(group_id_reports) group_element = resource.group.append_new(resources_section, group_id) stonith_element = resource.primitive.create( env.report_processor, resources_section, id_provider, stonith_id, stonith_agent, operations, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ) if ensure_disabled: resource.common.disable(stonith_element, id_provider) if env.report_processor.report_list( resource.validations.validate_move_resources_to_group( group_element, [stonith_element], adjacent_resource_element, )).has_errors: raise LibraryError() resource.hierarchy.move_resources_to_group( group_element, [stonith_element], adjacent_resource_element, put_after_adjacent, )
def create_in_group( env, resource_id, resource_agent_name, group_id, operations, meta_attributes, instance_attributes, allow_absent_agent=False, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, adjacent_resource_id=None, put_after_adjacent=False, wait=False, ): """ Create resource in a cib and put it into defined group LibraryEnvironment env provides all for communication with externals string resource_id is identifier of resource string resource_agent_name contains name for the identification of agent string group_id is identificator for group to put primitive resource inside list of dict operations contains attributes for each entered operation dict meta_attributes contains attributes for primitive/meta_attributes bool allow_absent_agent is a flag for allowing agent that is not installed in a system bool allow_invalid_operation is a flag for allowing to use operations that are not listed in a resource agent metadata bool allow_invalid_instance_attributes is a flag for allowing to use instance attributes that are not listed in a resource agent metadata or for allowing to not use the instance_attributes that are required in resource agent metadata bool use_default_operations is a flag for stopping stopping of adding default cib operations (specified in a resource agent) bool ensure_disabled is flag that keeps resource in target-role "Stopped" string adjacent_resource_id identify neighbor of a newly created resource bool put_after_adjacent is flag to put a newly create resource befor/after adjacent resource mixed wait is flag for controlling waiting for pacemaker iddle mechanism """ resource_agent = get_agent( env.report_processor, env.cmd_runner(), resource_agent_name, allow_absent_agent, ) with resource_environment( env, resource_id, wait, ensure_disabled or are_meta_disabled(meta_attributes), ) as resources_section: primitive_element = resource.primitive.create( env.report_processor, resources_section, resource_id, resource_agent, operations, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ensure_disabled, ) validate_id(group_id, "group name") resource.group.place_resource( resource.group.provide_group(resources_section, group_id), primitive_element, adjacent_resource_id, put_after_adjacent, )
def create( report_processor: ReportProcessor, resources_section, id_provider, resource_id, resource_agent, raw_operation_list=None, meta_attributes=None, instance_attributes=None, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, resource_type="resource", do_not_report_instance_attribute_server_exists=False # TODO remove this arg ): # pylint: disable=too-many-arguments """ Prepare all parts of primitive resource and append it into cib. report_processor is a tool for warning/info/error reporting etree.Element resources_section is place where new element will be appended IdProvider id_provider -- elements' ids generator string resource_id is id of new resource lib.resource_agent.CrmAgent resource_agent list of dict raw_operation_list specifies operations of resource dict meta_attributes specifies meta attributes of resource dict instance_attributes specifies instance attributes of resource bool allow_invalid_operation is flag for skipping validation of operations bool allow_invalid_instance_attributes is flag for skipping validation of instance_attributes bool use_default_operations is flag for completion operations with default actions specified in resource agent string resource_type -- describes the resource for reports bool do_not_report_instance_attribute_server_exists -- dirty fix due to suboptimal architecture, TODO: fix the architecture and remove the param """ if raw_operation_list is None: raw_operation_list = [] if meta_attributes is None: meta_attributes = {} if instance_attributes is None: instance_attributes = {} if does_id_exist(resources_section, resource_id): raise LibraryError(reports.id_already_exists(resource_id)) validate_id(resource_id, "{0} name".format(resource_type)) operation_list = prepare_operations( report_processor, raw_operation_list, resource_agent.get_cib_default_actions( necessary_only=not use_default_operations ), [operation["name"] for operation in resource_agent.get_actions()], allow_invalid=allow_invalid_operation, ) if report_processor.report_list( validate_resource_instance_attributes_create( resource_agent, instance_attributes, resources_section, force=allow_invalid_instance_attributes, do_not_report_instance_attribute_server_exists=( do_not_report_instance_attribute_server_exists ) ) ).has_errors: raise LibraryError() return append_new( resources_section, id_provider, resource_id, resource_agent.get_standard(), resource_agent.get_provider(), resource_agent.get_type(), instance_attributes=instance_attributes, meta_attributes=meta_attributes, operation_list=operation_list )
def create_in_group( env, resource_id, resource_agent_name, group_id, operation_list, meta_attributes, instance_attributes, allow_absent_agent=False, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, adjacent_resource_id=None, put_after_adjacent=False, wait=False, allow_not_suitable_command=False, ): # pylint: disable=too-many-arguments, too-many-locals """ Create resource in a cib and put it into defined group LibraryEnvironment env provides all for communication with externals string resource_id is identifier of resource string resource_agent_name contains name for the identification of agent string group_id is identificator for group to put primitive resource inside list of dict operation_list contains attributes for each entered operation dict meta_attributes contains attributes for primitive/meta_attributes bool allow_absent_agent is a flag for allowing agent that is not installed in a system bool allow_invalid_operation is a flag for allowing to use operations that are not listed in a resource agent metadata bool allow_invalid_instance_attributes is a flag for allowing to use instance attributes that are not listed in a resource agent metadata or for allowing to not use the instance_attributes that are required in resource agent metadata bool use_default_operations is a flag for stopping stopping of adding default cib operations (specified in a resource agent) bool ensure_disabled is flag that keeps resource in target-role "Stopped" string adjacent_resource_id identify neighbor of a newly created resource bool put_after_adjacent is flag to put a newly create resource befor/after adjacent resource mixed wait is flag for controlling waiting for pacemaker idle mechanism bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND """ resource_agent = get_agent( env.report_processor, env.cmd_runner(), resource_agent_name, allow_absent_agent, ) with resource_environment( env, wait, [resource_id], _ensure_disabled_after_wait( ensure_disabled or resource.common.are_meta_disabled(meta_attributes) ) ) as resources_section: id_provider = IdProvider(resources_section) _check_special_cases( env, resource_agent, resources_section, resource_id, meta_attributes, instance_attributes, allow_not_suitable_command ) primitive_element = resource.primitive.create( env.report_processor, resources_section, id_provider, resource_id, resource_agent, operation_list, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ) if ensure_disabled: resource.common.disable(primitive_element, id_provider) validate_id(group_id, "group name") resource.group.place_resource( resource.group.provide_group(resources_section, group_id), primitive_element, adjacent_resource_id, put_after_adjacent, )
def test_invalid_first_character(self): desc = "test id" info = { "id": "", "id_description": desc, "invalid_character": "", "is_first_char": True, } report = (severity.ERROR, report_codes.INVALID_ID, info) info["id"] = "0" info["invalid_character"] = "0" assert_raise_library_error( lambda: lib.validate_id("0", desc), report ) info["id"] = "-" info["invalid_character"] = "-" assert_raise_library_error( lambda: lib.validate_id("-", desc), report ) info["id"] = "." info["invalid_character"] = "." assert_raise_library_error( lambda: lib.validate_id(".", desc), report ) info["id"] = ":" info["invalid_character"] = ":" assert_raise_library_error( lambda: lib.validate_id(":", desc), report ) info["id"] = "0dummy" info["invalid_character"] = "0" assert_raise_library_error( lambda: lib.validate_id("0dummy", desc), report ) info["id"] = "-dummy" info["invalid_character"] = "-" assert_raise_library_error( lambda: lib.validate_id("-dummy", desc), report ) info["id"] = ".dummy" info["invalid_character"] = "." assert_raise_library_error( lambda: lib.validate_id(".dummy", desc), report ) info["id"] = ":dummy" info["invalid_character"] = ":" assert_raise_library_error( lambda: lib.validate_id(":dummy", desc), report )
def test_valid(self): self.assertEqual(None, lib.validate_id("dummy")) self.assertEqual(None, lib.validate_id("DUMMY")) self.assertEqual(None, lib.validate_id("dUmMy")) self.assertEqual(None, lib.validate_id("dummy0")) self.assertEqual(None, lib.validate_id("dum0my")) self.assertEqual(None, lib.validate_id("dummy-")) self.assertEqual(None, lib.validate_id("dum-my")) self.assertEqual(None, lib.validate_id("dummy.")) self.assertEqual(None, lib.validate_id("dum.my")) self.assertEqual(None, lib.validate_id("_dummy")) self.assertEqual(None, lib.validate_id("dummy_")) self.assertEqual(None, lib.validate_id("dum_my"))
def create_in_group( env, stonith_id, stonith_agent_name, group_id, operations, meta_attributes, instance_attributes, allow_absent_agent=False, allow_invalid_operation=False, allow_invalid_instance_attributes=False, use_default_operations=True, ensure_disabled=False, adjacent_resource_id=None, put_after_adjacent=False, wait=False, ): # pylint: disable=too-many-arguments, too-many-locals """ Create stonith as resource in a cib and put it into defined group. LibraryEnvironment env provides all for communication with externals string stonith_id is an identifier of stonith resource string stonith_agent_name contains name for the identification of agent string group_id is identificator for group to put stonith inside list of dict operations contains attributes for each entered operation dict meta_attributes contains attributes for primitive/meta_attributes dict instance_attributes contains attributes for primitive/instance_attributes bool allow_absent_agent is a flag for allowing agent that is not installed in a system bool allow_invalid_operation is a flag for allowing to use operations that are not listed in a stonith agent metadata bool allow_invalid_instance_attributes is a flag for allowing to use instance attributes that are not listed in a stonith agent metadata or for allowing to not use the instance_attributes that are required in stonith agent metadata bool use_default_operations is a flag for stopping stopping of adding default cib operations (specified in a stonith agent) bool ensure_disabled is flag that keeps resource in target-role "Stopped" string adjacent_resource_id identify neighbor of a newly created stonith bool put_after_adjacent is flag to put a newly create resource befor/after adjacent stonith mixed wait is flag for controlling waiting for pacemaker idle mechanism """ stonith_agent = get_agent( env.report_processor, env.cmd_runner(), stonith_agent_name, allow_absent_agent, ) if stonith_agent.get_provides_unfencing(): meta_attributes["provides"] = "unfencing" with resource_environment( env, wait, [stonith_id], _ensure_disabled_after_wait( ensure_disabled or are_meta_disabled(meta_attributes), ) ) as resources_section: id_provider = IdProvider(resources_section) stonith_element = resource.primitive.create( env.report_processor, resources_section, id_provider, stonith_id, stonith_agent, operations, meta_attributes, instance_attributes, allow_invalid_operation, allow_invalid_instance_attributes, use_default_operations, ) if ensure_disabled: resource.common.disable(stonith_element, id_provider) validate_id(group_id, "group name") resource.group.place_resource( resource.group.provide_group(resources_section, group_id), stonith_element, adjacent_resource_id, put_after_adjacent, )
def create( report_processor: reports.ReportProcessor, resources_section: _Element, id_provider: IdProvider, resource_id: str, resource_agent_facade: ResourceAgentFacade, raw_operation_list: Optional[Iterable[ResourceOperationIn]] = None, meta_attributes: Optional[Mapping[str, str]] = None, instance_attributes: Optional[Mapping[str, str]] = None, allow_invalid_operation: bool = False, allow_invalid_instance_attributes: bool = False, use_default_operations: bool = True, resource_type: str = "resource", # TODO remove this arg do_not_report_instance_attribute_server_exists: bool = False, ): # pylint: disable=too-many-arguments # pylint: disable=too-many-locals """ Prepare all parts of primitive resource and append it into cib. report_processor -- a tool for warning/info/error reporting resources_section -- a place where the new resource will be appended id_provider -- elements' ids generator resource_id -- id of the new resource resource_agent_facade -- resource agent raw_operation_list -- specifies operations of the resource meta_attributes -- specifies meta attributes of the resource instance_attributes -- specifies instance attributes of the resource allow_invalid_operation -- flag for skipping validation of operations allow_invalid_instance_attributes -- flag for skipping validation of instance_attributes use_default_operations -- flag for completion operations with default actions specified in resource agent resource_type -- describes the resource for reports do_not_report_instance_attribute_server_exists -- dirty fix due to suboptimal architecture, TODO: fix the architecture and remove the param """ if raw_operation_list is None: raw_operation_list = [] if meta_attributes is None: meta_attributes = {} if instance_attributes is None: instance_attributes = {} filtered_raw_operation_list = [] for op in raw_operation_list: filtered_raw_operation_list.append( {name: "" if value is None else value for name, value in op.items()} ) if does_id_exist(resources_section, resource_id): raise LibraryError( reports.ReportItem.error( reports.messages.IdAlreadyExists(resource_id) ) ) validate_id(resource_id, "{0} name".format(resource_type)) agent_metadata = resource_agent_facade.metadata operation_list = prepare_operations( report_processor, filtered_raw_operation_list, get_default_operations( agent_metadata, necessary_only=not use_default_operations ), [operation.name for operation in agent_metadata.actions], are_new_role_names_supported(resources_section), allow_invalid=allow_invalid_operation, ) report_items = validate_resource_instance_attributes_create( resource_agent_facade, instance_attributes, resources_section, force=allow_invalid_instance_attributes, ) # TODO remove this "if", see pcs.lib.cib.remote_node.create for details if do_not_report_instance_attribute_server_exists: for report_item in report_items: if isinstance(report_item.message, reports.messages.InvalidOptions): report_msg = cast( reports.messages.InvalidOptions, report_item.message ) report_item.message = reports.messages.InvalidOptions( report_msg.option_names, sorted( [ value for value in report_msg.allowed if value != "server" ] ), report_msg.option_type, report_msg.allowed_patterns, ) report_processor.report_list(report_items) if report_processor.has_errors: raise LibraryError() return append_new( resources_section, id_provider, resource_id, agent_metadata.name.standard, agent_metadata.name.provider, agent_metadata.name.type, instance_attributes=instance_attributes, meta_attributes=meta_attributes, operation_list=operation_list, )