def alert_config_lines(lib): lines = ["Alerts:"] alert_list = lib.alert.get_all_alerts() if alert_list: for alert in alert_list: lines.extend(indent(_alert_to_str(alert), 1)) else: lines.append(" No alerts defined") return lines
def _resource_bundle_storage_to_text( storage_mappings: Sequence[CibResourceBundleStorageMappingDto], ) -> List[str]: if not storage_mappings: return [] output = [] for storage_mapping in storage_mappings: output.append(" ".join( _resource_bundle_storage_mapping_to_str(storage_mapping))) return ["Storage Mapping:"] + indent(output, indent_step=INDENT_STEP)
def _resource_operation_to_cmd( operations: Sequence[CibResourceOperationDto], ) -> List[str]: if not operations: return [] cmd = [] for op in operations: cmd.append("{name} {options}".format( name=op.name, options=_pairs_to_cmd(_resource_operation_to_pairs(op)), )) return ["op"] + indent(cmd, indent_step=INDENT_STEP)
def _resource_primitive_to_text( primitive_dto: CibResourcePrimitiveDto, ) -> List[str]: output = ( _resource_description_to_text(primitive_dto.description) + _nvset_to_text("Attributes", primitive_dto.instance_attributes) + _nvset_to_text("Meta Attributes", primitive_dto.meta_attributes) + _nvset_to_text("Utilization", primitive_dto.utilization)) if primitive_dto.operations: operation_lines: List[str] = [] for operation_dto in primitive_dto.operations: operation_lines.extend(_resource_operation_to_str(operation_dto)) output.extend(["Operations:"] + indent(operation_lines, indent_step=INDENT_STEP)) return [ "Resource: {res_id} ({res_type})".format( res_id=primitive_dto.id, res_type=_resource_agent_name_to_text(primitive_dto.agent_name), ) ] + indent(output, indent_step=INDENT_STEP)
def _date_dto_to_lines( rule_expr: CibRuleExpressionDto, with_ids: bool = False ) -> List[str]: # pylint: disable=too-many-branches operation = rule_expr.options.get("operation", None) if operation == "date_spec": heading_parts = ["Expression:"] if with_ids: heading_parts.append(f"(id:{rule_expr.id})") line_parts = ["Date Spec:"] if rule_expr.date_spec: line_parts.extend( format_name_value_list( sorted(rule_expr.date_spec.options.items()) ) ) if with_ids: line_parts.append(f"(id:{rule_expr.date_spec.id})") return [" ".join(heading_parts)] + indent([" ".join(line_parts)]) if operation == "in_range" and rule_expr.duration: heading_parts = ["Expression:", "date", "in_range"] if "start" in rule_expr.options: heading_parts.append(rule_expr.options["start"]) heading_parts.extend(["to", "duration"]) if with_ids: heading_parts.append(f"(id:{rule_expr.id})") lines = [" ".join(heading_parts)] line_parts = ["Duration:"] line_parts.extend( format_name_value_list(sorted(rule_expr.duration.options.items())) ) if with_ids: line_parts.append(f"(id:{rule_expr.duration.id})") lines.extend(indent([" ".join(line_parts)])) return lines return _simple_expr_to_lines(rule_expr, with_ids=with_ids)
def _resource_bundle_port_mappings_to_text( bundle_port_mappings: Sequence[CibResourceBundlePortMappingDto], ) -> List[str]: port_mappings = [ " ".join( _resource_bundle_network_port_mapping_to_str(port_mapping_dto)) for port_mapping_dto in bundle_port_mappings ] if port_mappings: return ["Port Mapping:"] + indent(port_mappings, indent_step=INDENT_STEP) return []
def _parsed_to_str(parsed): if isinstance(parsed, BoolExpr): str_args = [] for arg in parsed.children: str_args.extend(_parsed_to_str(arg).splitlines()) return "\n".join([f"{parsed.__class__.__name__} {parsed.operator}"] + indent(str_args)) parts = [parsed.__class__.__name__] for field in fields(parsed): value = getattr(parsed, field.name) if value is not None: parts.append(f"{field.name}={value}") return " ".join(parts)
def _resource_operation_to_str( operation_dto: CibResourceOperationDto, ) -> List[str]: lines = format_name_value_list([ pair for pair in _resource_operation_to_pairs(operation_dto) if pair[0] != "id" ]) # TODO: add support for meta and instance attributes once it is supported # by pcs return [ "{name}:{id}".format( name=operation_dto.name, id=format_optional(operation_dto.id, " {}"), ) ] + indent(lines, indent_step=INDENT_STEP)
def _resource_group_to_text( group_dto: CibResourceGroupDto, resources_facade: ResourcesConfigurationFacade, ) -> List[str]: output = (_resource_description_to_text(group_dto.description) + _nvset_to_text("Attributes", group_dto.instance_attributes) + _nvset_to_text("Meta Attributes", group_dto.meta_attributes)) for primitive_id in group_dto.member_ids: primitive_dto = resources_facade.get_primitive_dto(primitive_id) if primitive_dto is None: raise CmdLineInputError( f"Invalid data: group {group_dto.id} has no children") output.extend(_resource_primitive_to_text(primitive_dto)) return [f"Group: {group_dto.id}"] + indent(output, indent_step=INDENT_STEP)
def nvset_dto_to_lines(nvset: CibNvsetDto, with_ids: bool = False) -> List[str]: nvset_label = _nvset_type_to_label.get(nvset.type, "Options Set") heading_parts = [f"{nvset_label}: {nvset.id}"] if nvset.options: heading_parts.append(" ".join( format_name_value_list(sorted(nvset.options.items())))) lines = format_name_value_list( sorted([(nvpair.name, nvpair.value) for nvpair in nvset.nvpairs])) if nvset.rule: lines.extend( rule_expression_dto_to_lines(nvset.rule, with_ids=with_ids)) return [" ".join(heading_parts)] + indent(lines)
def config( lib: Any, argv: Sequence[str], modifiers: InputModifiers, ) -> None: """ Options: None """ modifiers.ensure_only_supported() if argv: raise CmdLineInputError() config_raw = lib.dr.get_config() try: config_dto = dto.from_dict(DrConfigDto, config_raw) except (KeyError, TypeError, ValueError): raise error("Unable to communicate with pcsd, received response:\n" f"{config_raw}") lines = ["Local site:"] lines.extend(indent(_config_site_lines(config_dto.local_site))) for site_dto in config_dto.remote_site_list: lines.append("Remote site:") lines.extend(indent(_config_site_lines(site_dto))) print("\n".join(lines))
def show_constraints_with_set(constraint_list, show_detail, indent_step=2): """ return list of console lines with info about constraints list of dict constraint_list see constraint in pcs/lib/exchange_formats.md bool with_id have to show id with options int indent_step is count of spaces for indenting Commandline options: no options """ return ["Resource Sets:"] + indent( [ constraint_with_sets(constraint, with_id=show_detail) for constraint in constraint_list ], indent_step=indent_step, )
def _rule_dto_to_lines(rule_expr: CibRuleExpressionDto, with_ids: bool = False) -> List[str]: in_effect_label = get_in_effect_label(rule_expr) heading_parts = [ "Rule{0}:".format(f" ({in_effect_label})" if in_effect_label else "") ] heading_parts.extend( format_name_value_list(sorted(rule_expr.options.items()))) if with_ids: heading_parts.append(f"(id:{rule_expr.id})") lines = [] for child in rule_expr.expressions: lines.extend(rule_expression_dto_to_lines(child, with_ids)) return [" ".join(heading_parts)] + indent(lines)
def _resource_clone_to_text( clone_dto: CibResourceCloneDto, resources_facade: ResourcesConfigurationFacade, ) -> List[str]: output = (_resource_description_to_text(clone_dto.description) + _nvset_to_text("Attributes", clone_dto.instance_attributes) + _nvset_to_text("Meta Attributes", clone_dto.meta_attributes)) primitive_dto = resources_facade.get_primitive_dto(clone_dto.member_id) group_dto = resources_facade.get_group_dto(clone_dto.member_id) if primitive_dto is not None: output.extend(_resource_primitive_to_text(primitive_dto)) elif group_dto is not None: output.extend(_resource_group_to_text(group_dto, resources_facade)) else: raise CmdLineInputError( f"Invalid data: clone {clone_dto.id} has no children") return [f"Clone: {clone_dto.id}"] + indent(output, indent_step=INDENT_STEP)
def tag_config( lib: Any, argv: Sequence[str], modifiers: InputModifiers, ) -> None: """ Options: * -f - CIB file """ modifiers.ensure_only_supported("-f") tag_list = lib.tag.config(argv) if not tag_list: print_to_stderr(" No tags defined") return lines = [] for tag in tag_list: lines.append(tag["tag_id"]) lines.extend(indent(tag["idref_list"])) print("\n".join(lines))
def _parsed_to_str(parsed): if isinstance(parsed, BoolExpr): str_args = [] for arg in parsed.children: str_args.extend(_parsed_to_str(arg).splitlines()) return "\n".join([f"{parsed.__class__.__name__} {parsed.operator}"] + indent(str_args)) parts = [parsed.__class__.__name__] for field in dataclasses.fields(parsed): value = getattr(parsed, field.name) if value is not None: if field.name in ("duration_parts", "date_parts"): parts.append(f"{field.name}=(\n ") parts.extend([f"{key}={val}" for key, val in value]) parts.append("\n)") else: parts.append(f"{field.name}={value}") return " ".join(parts)
def nvset_dto_to_lines(nvset: CibNvsetDto, nvset_label: str = "Options Set", with_ids: bool = False) -> List[str]: in_effect_label = get_in_effect_label(nvset.rule) if nvset.rule else None heading_parts = [ "{label}{in_effect}:{id}".format( label=nvset_label, in_effect=format_optional(in_effect_label, " ({})"), id=format_optional(nvset.id, " {}"), ) ] if nvset.options: heading_parts.append(" ".join( format_name_value_list(sorted(nvset.options.items())))) lines = format_name_value_list( sorted([(nvpair.name, nvpair.value) for nvpair in nvset.nvpairs])) if nvset.rule: lines.extend( rule_expression_dto_to_lines(nvset.rule, with_ids=with_ids)) return [" ".join(heading_parts)] + indent(lines)
def quorum_config_to_str(config): """ Commandline options: no options """ lines = [] lines.append("Options:") if "options" in config and config["options"]: lines.extend( indent([ "{n}: {v}".format(n=name, v=value) for name, value in sorted(config["options"].items()) ])) if "device" in config and config["device"]: lines.append("Device:") lines.extend( indent([ "{n}: {v}".format(n=name, v=value) for name, value in sorted(config["device"].get( "generic_options", {}).items()) ])) model_settings = [ "Model: {m}".format(m=config["device"].get("model", "")) ] model_settings.extend( indent([ "{n}: {v}".format(n=name, v=value) for name, value in sorted(config["device"].get( "model_options", {}).items()) ])) lines.extend(indent(model_settings)) heuristics_options = config["device"].get("heuristics_options", {}) if heuristics_options: heuristics_settings = ["Heuristics:"] heuristics_settings.extend( indent([ "{n}: {v}".format(n=name, v=value) for name, value in sorted(heuristics_options.items()) ])) lines.extend(indent(heuristics_settings)) return lines
def stonith_level_config_to_str(config): """ Commandline option: no options """ config_data = {} for level in config: if level["target_type"] not in config_data: config_data[level["target_type"]] = {} if level["target_value"] not in config_data[level["target_type"]]: config_data[level["target_type"]][level["target_value"]] = [] config_data[level["target_type"]][level["target_value"]].append(level) lines = [] for target_type in [ TARGET_TYPE_NODE, TARGET_TYPE_REGEXP, TARGET_TYPE_ATTRIBUTE, ]: if not target_type in config_data: continue for target_value in sorted(config_data[target_type].keys()): lines.append("Target{0}: {1}".format( " (regexp)" if target_type == TARGET_TYPE_REGEXP else "", "=".join(target_value) if target_type == TARGET_TYPE_ATTRIBUTE else target_value, )) level_lines = [] for target_level in sorted( config_data[target_type][target_value], key=lambda level: level["level"], ): level_lines.append("Level {level} - {devices}".format( level=target_level["level"], devices=",".join(target_level["devices"]), )) lines.extend(indent(level_lines)) return lines
def test_indent_list_of_lines(self): self.assertEqual( tools.indent(["first", "second"]), [" first", " second"] )
def _recipient_to_str(recipient): return [ "Recipient: {id} (value={value})".format( value=recipient["value"], id=recipient["id"] ) ] + indent(__description_attributes_to_str(recipient), 1)
def _config_show_cib_lines(lib): """ Commandline options: * -f - CIB file """ # update of pcs_options will change output of constraint show and # displaying resources and operations defaults utils.pcs_options["--full"] = 1 # get latest modifiers object after updating pcs_options modifiers = utils.get_input_modifiers() cib_dom = utils.get_cib_dom() resources_facade = ResourcesConfigurationFacade.from_resources_dto( lib.resource.get_configured_resources()) all_lines = [] all_lines.append("Resources:") all_lines.extend( smart_wrap_text( indent( resources_to_text(resources_facade.filter_stonith(False)), indent_step=INDENT_STEP, ))) all_lines.append("") all_lines.append("Stonith Devices:") all_lines.extend( smart_wrap_text( indent( resources_to_text(resources_facade.filter_stonith(True)), indent_step=INDENT_STEP, ))) all_lines.append("Fencing Levels:") levels_lines = stonith.stonith_level_config_to_str( lib.fencing_topology.get_config()) if levels_lines: all_lines.extend(indent(levels_lines, indent_step=2)) all_lines.append("") constraints_element = cib_dom.getElementsByTagName("constraints")[0] all_lines.extend( constraint.location_lines( constraints_element, showDetail=True, show_expired=True, verify_expiration=False, )) all_lines.extend( constraint_command.config_cmd( "Ordering Constraints:", lib.constraint_order.config, constraints_reports.order_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.config_cmd( "Colocation Constraints:", lib.constraint_colocation.config, constraints_reports.colocation_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.config_cmd( "Ticket Constraints:", lib.constraint_ticket.config, constraints_reports.ticket_plain, modifiers.get_subset("-f", "--full"), )) all_lines.append("") all_lines.extend(alert.alert_config_lines(lib)) all_lines.append("") all_lines.append("Resources Defaults:") all_lines.extend( indent( nvset_dto_list_to_lines( lib.cib_options.resource_defaults_config( evaluate_expired=False).meta_attributes, nvset_label="Meta Attrs", with_ids=modifiers.get("--full"), text_if_empty="No defaults set", ))) all_lines.append("Operations Defaults:") all_lines.extend( indent( nvset_dto_list_to_lines( lib.cib_options.operation_defaults_config( evaluate_expired=False).meta_attributes, nvset_label="Meta Attrs", with_ids=modifiers.get("--full"), text_if_empty="No defaults set", ))) all_lines.append("") all_lines.append("Cluster Properties:") properties = utils.get_set_properties() all_lines.extend( indent( [ "{0}: {1}".format(prop, val) for prop, val in sorted(properties.items()) ], indent_step=1, )) all_lines.append("") all_lines.append("Tags:") tags = lib.tag.config([]) if not tags: all_lines.append(" No tags defined") tag_lines = [] for tag in tags: tag_lines.append(tag["tag_id"]) tag_lines.extend(indent(tag["idref_list"])) all_lines.extend(indent(tag_lines, indent_step=1)) return all_lines
def _print_stonith_levels(lib): levels = stonith_level_config_to_str(lib.fencing_topology.get_config()) if levels: print("\nFencing Levels:") print("\n".join(indent(levels, 1)))
def _config_show_cib_lines(lib): """ Commandline options: * -f - CIB file """ # update of pcs_options will change output of constraint show utils.pcs_options["--full"] = 1 # get latest modifiers object after updating pcs_options modifiers = utils.get_input_modifiers() cib_xml = utils.get_cib() cib_etree = utils.get_cib_etree(cib_xml=cib_xml) cib_dom = utils.get_cib_dom(cib_xml=cib_xml) resource_lines = [] stonith_lines = [] for resource_el in cib_etree.find(".//resources"): is_stonith = ("class" in resource_el.attrib and resource_el.attrib["class"] == "stonith") resource_el_lines = resource.resource_node_lines(resource_el) if is_stonith: stonith_lines += resource_el_lines else: resource_lines += resource_el_lines all_lines = [] all_lines.append("Resources:") all_lines.extend(indent(resource_lines, indent_step=1)) all_lines.append("") all_lines.append("Stonith Devices:") all_lines.extend(indent(stonith_lines, indent_step=1)) all_lines.append("Fencing Levels:") levels_lines = stonith.stonith_level_config_to_str( lib.fencing_topology.get_config()) if levels_lines: all_lines.extend(indent(levels_lines, indent_step=2)) all_lines.append("") constraints_element = cib_dom.getElementsByTagName("constraints")[0] all_lines.extend( constraint.location_lines( constraints_element, showDetail=True, show_expired=True, verify_expiration=False, )) all_lines.extend( constraint_command.show( "Ordering Constraints:", lib.constraint_order.show, constraints_reports.order_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.show( "Colocation Constraints:", lib.constraint_colocation.show, constraints_reports.colocation_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.show( "Ticket Constraints:", lib.constraint_ticket.show, constraints_reports.ticket_plain, modifiers.get_subset("-f", "--full"), )) all_lines.append("") all_lines.extend(alert.alert_config_lines(lib)) all_lines.append("") all_lines.append("Resources Defaults:") all_lines.extend( indent(resource.show_defaults(cib_dom, "rsc_defaults"), indent_step=1)) all_lines.append("Operations Defaults:") all_lines.extend( indent(resource.show_defaults(cib_dom, "op_defaults"), indent_step=1)) all_lines.append("") all_lines.append("Cluster Properties:") properties = utils.get_set_properties() all_lines.extend( indent( [ "{0}: {1}".format(prop, val) for prop, val in sorted(properties.items()) ], indent_step=1, )) all_lines.append("") all_lines.append("Tags:") tags = lib.tag.config([]) if not tags: all_lines.append(" No tags defined") tag_lines = [] for tag in tags: tag_lines.append(tag["tag_id"]) tag_lines.extend(indent(tag["idref_list"])) all_lines.extend(indent(tag_lines, indent_step=1)) return all_lines
def _target_group_to_str(type_name, obj): return ["{0}: {1}".format(type_name.title(), obj.get("id"))] + indent( [" ".join(["Roles:"] + obj.get("role_list", []))] )
def format_resource_agent_metadata( metadata: resource_agent.dto.ResourceAgentMetadataDto, default_operations: List[CibResourceOperationDto], verbose: bool = False, ) -> List[str]: # pylint: disable=too-many-branches # pylint: disable=too-many-statements sub_section_indent = 2 wrapped_line_indent = 4 output = [] is_stonith = metadata.name.standard == "stonith" agent_name = (metadata.name.type if is_stonith else get_resource_agent_full_name(metadata.name)) if metadata.shortdesc: output.extend( format_with_indentation( "{agent_name} - {shortdesc}".format( agent_name=agent_name, shortdesc=metadata.shortdesc.replace("\n", " "), ), indentation=wrapped_line_indent, )) else: output.append(agent_name) if metadata.longdesc: output.append("") output.extend( format_with_indentation(metadata.longdesc.replace("\n", " "))) params = [] for param in metadata.parameters: if not verbose and (param.advanced or param.deprecated): continue param_title = [param.name] if param.deprecated_by: param_title.append("(deprecated by {})".format(", ".join( param.deprecated_by))) elif param.deprecated: param_title.append("(deprecated)") if param.required: param_title.append("(required)") if param.unique_group: if param.unique_group.startswith( resource_agent.const.DEFAULT_UNIQUE_GROUP_PREFIX): param_title.append("(unique)") else: param_title.append("(unique group: {})".format( param.unique_group)) desc = "" if param.longdesc: desc = param.longdesc.replace("\n", " ") if not desc and param.shortdesc: desc = param.shortdesc.replace("\n", " ") if not desc: desc = "No description available" if param.deprecated_desc: desc += "DEPRECATED: {param.deprecated_desc}" params.extend( format_with_indentation( "{}: {}".format(" ".join(param_title), desc), indentation=wrapped_line_indent, max_length_trim=sub_section_indent, )) if params: output.append("") if is_stonith: output.append("Stonith options:") else: output.append("Resource options:") output.extend(indent(params, sub_section_indent)) operations = [] for operation in default_operations: op_params = [f"interval={operation.interval}"] if operation.start_delay: op_params.append(f"start-delay={operation.start_delay}") if operation.timeout: op_params.append(f"timeout={operation.timeout}") if operation.role: op_params.append(f"role={operation.role}") # TODO: deal with depth aka OCF_CHECK_LEVEL operations.extend( format_with_indentation( "{name}: {params}".format(name=operation.name, params=" ".join(op_params)), indentation=wrapped_line_indent, max_length_trim=sub_section_indent, )) if operations: output.append("") output.append("Default operations:") output.extend(indent(operations, sub_section_indent)) return output
def full_cluster_status_plaintext( env: LibraryEnvironment, hide_inactive_resources: bool = False, verbose: bool = False, ) -> str: """ Return full cluster status as plaintext env -- LibraryEnvironment hide_inactive_resources -- if True, do not display non-running resources verbose -- if True, display more info """ # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements # validation if not env.is_cib_live and env.is_corosync_conf_live: raise LibraryError( ReportItem.error( reports.messages.LiveEnvironmentNotConsistent( [file_type_codes.CIB], [file_type_codes.COROSYNC_CONF], ) ) ) if env.is_cib_live and not env.is_corosync_conf_live: raise LibraryError( ReportItem.error( reports.messages.LiveEnvironmentNotConsistent( [file_type_codes.COROSYNC_CONF], [file_type_codes.CIB], ) ) ) # initialization runner = env.cmd_runner() report_processor = env.report_processor live = env.is_cib_live and env.is_corosync_conf_live is_sbd_running = False # load status, cib, corosync.conf status_text, warning_list = get_cluster_status_text( runner, hide_inactive_resources, verbose ) corosync_conf = None # If we are live on a remote node, we have no corosync.conf. # TODO Use the new file framework so the path is not exposed. if not live or os.path.exists(settings.corosync_conf_file): corosync_conf = env.get_corosync_conf() cib = env.get_cib() if verbose: ( ticket_status_text, ticket_status_stderr, ticket_status_retval, ) = get_ticket_status_text(runner) # get extra info if live if live: try: is_sbd_running = is_service_running(runner, get_sbd_service_name()) except LibraryError: pass local_services_status = _get_local_services_status(runner) if verbose and corosync_conf: node_name_list, node_names_report_list = get_existing_nodes_names( corosync_conf ) report_processor.report_list(node_names_report_list) node_reachability = _get_node_reachability( env.get_node_target_factory(), env.get_node_communicator(), report_processor, node_name_list, ) # check stonith configuration warning_list = list(warning_list) warning_list.extend(_stonith_warnings(cib, is_sbd_running)) # put it all together if report_processor.has_errors: raise LibraryError() cluster_name = ( corosync_conf.get_cluster_name() if corosync_conf else nvpair.get_value( "cluster_property_set", get_crm_config(cib), "cluster-name", "" ) ) parts = [] parts.append(f"Cluster name: {cluster_name}") if warning_list: parts.extend(["", "WARNINGS:"] + warning_list + [""]) parts.append(status_text) if verbose: parts.extend(["", "Tickets:"]) if ticket_status_retval != 0: ticket_warning_parts = [ "WARNING: Unable to get information about tickets" ] if ticket_status_stderr: ticket_warning_parts.extend( indent(ticket_status_stderr.splitlines()) ) parts.extend(indent(ticket_warning_parts)) else: parts.extend(indent(ticket_status_text.splitlines())) if live: if verbose and corosync_conf: parts.extend(["", "PCSD Status:"]) parts.extend( indent( _format_node_reachability(node_name_list, node_reachability) ) ) parts.extend(["", "Daemon Status:"]) parts.extend( indent(_format_local_services_status(local_services_status)) ) return "\n".join(parts)
def resource_agent_metadata_to_text( metadata: resource_agent.dto.ResourceAgentMetadataDto, default_operations: List[CibResourceOperationDto], verbose: bool = False, ) -> List[str]: # pylint: disable=too-many-branches output = [] _is_stonith = is_stonith(metadata.name) agent_name = (metadata.name.type if _is_stonith else get_resource_agent_full_name(metadata.name)) if metadata.shortdesc: output.extend( format_wrap_for_terminal( "{agent_name} - {shortdesc}".format( agent_name=agent_name, shortdesc=metadata.shortdesc.replace("\n", " "), ), )) else: output.append(agent_name) if metadata.longdesc: output.append("") output.extend( format_wrap_for_terminal(metadata.longdesc.replace("\n", " "), subsequent_indent=0)) params = [] for param in metadata.parameters: if not verbose and (param.advanced or param.deprecated): continue param_title = [param.name] if param.deprecated_by: param_title.append("(deprecated by {})".format(", ".join( param.deprecated_by))) elif param.deprecated: param_title.append("(deprecated)") if param.required: param_title.append("(required)") if param.unique_group: if param.unique_group.startswith( resource_agent.const.DEFAULT_UNIQUE_GROUP_PREFIX): param_title.append("(unique)") else: param_title.append("(unique group: {})".format( param.unique_group)) desc = "" if param.longdesc: desc = param.longdesc.replace("\n", " ") if not desc and param.shortdesc: desc = param.shortdesc.replace("\n", " ") if not desc: desc = "No description available" if param.deprecated_desc: desc += "DEPRECATED: {param.deprecated_desc}" params.append("{}: {}".format(" ".join(param_title), desc)) if params: output.append("") if _is_stonith: output.append("Stonith options:") else: output.append("Resource options:") output.extend(indent(params, indent_step=INDENT_STEP)) operations = [] for operation in default_operations: operations.extend(_resource_operation_to_str(operation)) if operations: output.append("") output.append("Default operations:") output.extend(indent(operations, indent_step=INDENT_STEP)) return output
def role_to_str(role): out = [] if role.get("description"): out.append("Description: {0}".format(role.get("description"))) out += map(_permission_to_str, role.get("permission_list", [])) return ["Role: {0}".format(role.get("id"))] + indent(out)
def _config_site_lines(site_dto: DrConfigSiteDto) -> List[str]: lines = [f"Role: {site_dto.site_role.capitalize()}"] if site_dto.node_list: lines.append("Nodes:") lines.extend(indent(sorted([node.name for node in site_dto.node_list]))) return lines