예제 #1
0
    def apply(next_in_line, env, *args, **kwargs):
        if local_file_path:
            try:
                with open(local_file_path, "r") as local_file:
                    # the lock is released when the file gets closed on leaving
                    # the with statement
                    fcntl.flock(local_file.fileno(), fcntl.LOCK_SH)
                    original_content = local_file.read()
            except EnvironmentError as e:
                raise error("Unable to read {0}: {1}".format(
                    local_file_path, e.strerror)) from e
            env.corosync_conf_data = original_content

        result_of_next = next_in_line(env, *args, **kwargs)

        if local_file_path and env.corosync_conf_data != original_content:
            try:
                with open(local_file_path, "w") as local_file:
                    # the lock is released when the file gets closed on leaving
                    # the with statement
                    fcntl.flock(local_file.fileno(), fcntl.LOCK_EX)
                    local_file.write(env.corosync_conf_data)
            except EnvironmentError as e:
                raise error("Unable to write {0}: {1}".format(
                    local_file_path, e.strerror)) from e
        return result_of_next
예제 #2
0
    def apply(next_in_line, env, *args, **kwargs):
        if filename:
            touch_cib_file(filename)
            try:
                with open(filename, mode="r") as cib_file:
                    # the lock is released when the file gets closed on leaving
                    # the with statement
                    fcntl.flock(cib_file.fileno(), fcntl.LOCK_SH)
                    original_content = cib_file.read()
            except EnvironmentError as e:
                raise error("Cannot read cib file '{0}': '{1}'".format(
                    filename, str(e))) from e
            env.cib_data = original_content

        result_of_next = next_in_line(env, *args, **kwargs)

        if filename and env.cib_data != original_content:
            try:
                with open(filename, mode="w") as cib_file:
                    # the lock is released when the file gets closed on leaving
                    # the with statement
                    fcntl.flock(cib_file.fileno(), fcntl.LOCK_EX)
                    cib_file.write(env.cib_data)
            except EnvironmentError as e:
                raise error("Cannot write cib file '{0}': '{1}'".format(
                    filename, str(e))) from e

        return result_of_next
예제 #3
0
파일: dr.py 프로젝트: kmalyjur/pcs
def status(
    lib: Any,
    argv: Sequence[str],
    modifiers: InputModifiers,
) -> None:
    """
    Options:
      * --full - show full details, node attributes and failcount
      * --hide-inactive - hide inactive resources
      * --request-timeout - HTTP timeout for node authorization check
    """
    modifiers.ensure_only_supported(
        "--full",
        "--hide-inactive",
        "--request-timeout",
    )
    if argv:
        raise CmdLineInputError()

    status_list_raw = lib.dr.status_all_sites_plaintext(
        hide_inactive_resources=modifiers.get("--hide-inactive"),
        verbose=modifiers.get("--full"),
    )
    try:
        status_list = [
            dto.from_dict(DrSiteStatusDto, status_raw)
            for status_raw in status_list_raw
        ]
    except (KeyError, TypeError, ValueError) as e:
        raise error(
            "Unable to communicate with pcsd, received response:\n"
            f"{status_list_raw}"
        ) from e

    has_errors = False
    plaintext_parts = []
    for site_status in status_list:
        plaintext_parts.append(
            "--- {local_remote} cluster - {role} site ---".format(
                local_remote=("Local" if site_status.local_site else "Remote"),
                role=site_status.site_role.capitalize(),
            )
        )
        if site_status.status_successfully_obtained:
            plaintext_parts.append(site_status.status_plaintext.strip())
            plaintext_parts.extend(["", ""])
        else:
            has_errors = True
            plaintext_parts.extend(
                ["Error: Unable to get status of the cluster from any node", ""]
            )
    print("\n".join(plaintext_parts).strip())
    if has_errors:
        raise error("Unable to get status of all sites")
예제 #4
0
파일: dr.py 프로젝트: kmalyjur/pcs
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) as e:
        raise error(
            "Unable to communicate with pcsd, received response:\n"
            f"{config_raw}"
        ) from e

    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))
예제 #5
0
파일: middleware.py 프로젝트: zht750808/pcs
    def apply(next_in_line, env, *args, **kwargs):
        if local_file_path:
            try:
                env.corosync_conf_data = open(local_file_path).read()
            except EnvironmentError as e:
                raise error("Unable to read {0}: {1}".format(
                    local_file_path, e.strerror)) from e

        result_of_next = next_in_line(env, *args, **kwargs)

        if local_file_path:
            try:
                file = open(local_file_path, "w")
                file.write(env.corosync_conf_data)
                file.close()
            except EnvironmentError as e:
                raise error("Unable to write {0}: {1}".format(
                    local_file_path, e.strerror)) from e
        return result_of_next
예제 #6
0
파일: command.py 프로젝트: zht750808/pcs
def remove(lib, argv, modifiers):
    """
    Options:
      * -f - CIB file
    """
    modifiers.ensure_only_supported("-f")
    if len(argv) != 2:
        raise CmdLineInputError()
    ticket, resource_id = argv
    if not lib.constraint_ticket.remove(ticket, resource_id):
        raise error("no matching ticket constraint found")
예제 #7
0
파일: middleware.py 프로젝트: zht750808/pcs
    def apply(next_in_line, env, *args, **kwargs):
        if filename:
            touch_cib_file(filename)
            try:
                with open(filename, mode="r") as cib_file:
                    original_content = cib_file.read()
            except EnvironmentError as e:
                raise error("Cannot read cib file '{0}': '{1}'".format(
                    filename, str(e))) from e
            env.cib_data = original_content

        result_of_next = next_in_line(env, *args, **kwargs)

        if filename and env.cib_data != original_content:
            try:
                with open(filename, mode="w") as cib_file:
                    cib_file.write(env.cib_data)
            except EnvironmentError as e:
                raise error("Cannot write cib file '{0}': '{1}'".format(
                    filename, str(e))) from e

        return result_of_next
예제 #8
0
파일: status.py 프로젝트: kmalyjur/pcs
def print_pcsd_daemon_status(lib, modifiers):
    """
    Commandline options:
      * --request-timeout - HTTP timeout for node authorization check or when
        not running under root to call local pcsd
    """
    print("PCSD Status:")
    if os.getuid() == 0:
        pcsd_status_cmd(lib, [],
                        modifiers.get_subset("--request-timeout"),
                        dont_exit=True)
    else:
        err_msgs, exitcode, std_out, dummy_std_err = utils.call_local_pcsd(
            ["status", "pcsd"], [])
        if err_msgs:
            for msg in err_msgs:
                print(msg)
        if exitcode == 0:
            print(std_out)
        else:
            raise error("Unable to get PCSD status")
예제 #9
0
def get_capabilities_definition():
    """
    Read and parse capabilities file

    The point is to return all data in python structures for further processing.
    """
    filename = os.path.join(settings.pcsd_exec_location, "capabilities.xml")
    try:
        with open(filename, mode="r") as file_:
            capabilities_xml = xml_fromstring(file_.read())
    except (EnvironmentError, etree.XMLSyntaxError,
            etree.DocumentInvalid) as e:
        raise error(
            "Cannot read capabilities definition file '{0}': '{1}'".format(
                filename, str(e))) from e
    capabilities = []
    for feat_xml in capabilities_xml.findall(".//capability"):
        feat = dict(feat_xml.attrib)
        desc = feat_xml.find("./description")
        # dedent and strip remove indentation in the XML file
        feat["description"] = "" if desc is None else dedent(desc.text).strip()
        capabilities.append(feat)
    return capabilities
예제 #10
0
 def flush(modified_env):
     if not is_mocked_environment:
         return
     if not modified_env:
         # TODO now this would not happen
         # for more information see comment in
         # pcs.cli.common.lib_wrapper.lib_env_to_cli_env
         raise output.error("Error during library communication")
     try:
         key_file.write(modified_env["key_file"]["content"],
                        can_overwrite=True)
         config_file.write(modified_env["config_file"]["content"],
                           can_overwrite=True)
     # TODO write custom error handling, do not use pcs.lib specific code
     # and LibraryError
     except pcs_file.RawFileError as e:
         raise LibraryError(
             ReportItem.error(
                 reports.messages.FileIoError(
                     e.metadata.file_type_code,
                     e.action,
                     e.reason,
                     file_path=e.metadata.path,
                 ))) from e
예제 #11
0
def middleware_config(config_path, key_path):
    if config_path and not key_path:
        raise output.error("When --booth-conf is specified, "
                           "--booth-key must be specified as well")
    if key_path and not config_path:
        raise output.error("When --booth-key is specified, "
                           "--booth-conf must be specified as well")
    is_mocked_environment = config_path and key_path

    if is_mocked_environment:
        config_file = pcs_file.RawFile(
            metadata.for_file_type(file_type_codes.BOOTH_CONFIG, config_path))
        key_file = pcs_file.RawFile(
            metadata.for_file_type(file_type_codes.BOOTH_KEY, key_path))

    def create_booth_env():
        try:
            config_data = config_file.read() if config_file.exists() else None
            key_data = key_file.read() if key_file.exists() else None
        # TODO write custom error handling, do not use pcs.lib specific code
        # and LibraryError
        except pcs_file.RawFileError as e:
            raise LibraryError(
                ReportItem.error(
                    reports.messages.FileIoError(
                        e.metadata.file_type_code,
                        e.action,
                        e.reason,
                        file_path=e.metadata.path,
                    ))) from e
        return {
            "config_data": config_data,
            "key_data": key_data,
            "key_path": key_path,
        }

    def flush(modified_env):
        if not is_mocked_environment:
            return
        if not modified_env:
            # TODO now this would not happen
            # for more information see comment in
            # pcs.cli.common.lib_wrapper.lib_env_to_cli_env
            raise output.error("Error during library communication")
        try:
            key_file.write(modified_env["key_file"]["content"],
                           can_overwrite=True)
            config_file.write(modified_env["config_file"]["content"],
                              can_overwrite=True)
        # TODO write custom error handling, do not use pcs.lib specific code
        # and LibraryError
        except pcs_file.RawFileError as e:
            raise LibraryError(
                ReportItem.error(
                    reports.messages.FileIoError(
                        e.metadata.file_type_code,
                        e.action,
                        e.reason,
                        file_path=e.metadata.path,
                    ))) from e

    def apply(next_in_line, env, *args, **kwargs):
        env.booth = create_booth_env() if is_mocked_environment else {}
        result_of_next = next_in_line(env, *args, **kwargs)
        if is_mocked_environment:
            flush(env.booth["modified_env"])
        return result_of_next

    return apply
예제 #12
0
파일: app.py 프로젝트: kmalyjur/pcs
def main(argv=None):
    # pylint: disable=global-statement
    # pylint: disable=too-many-branches
    # pylint: disable=too-many-locals
    # pylint: disable=too-many-statements
    if completion.has_applicable_environment(os.environ):
        print(
            completion.make_suggestions(
                os.environ, usage.generate_completion_tree_from_usage()))
        sys.exit()

    argv = argv if argv else sys.argv[1:]
    utils.subprocess_setup()
    global filename, usefile
    utils.pcs_options = {}

    # we want to support optional arguments for --wait, so if an argument
    # is specified with --wait (ie. --wait=30) then we use them
    waitsecs = None
    new_argv = []
    for arg in argv:
        if arg.startswith("--wait="):
            tempsecs = arg.replace("--wait=", "")
            if tempsecs:
                waitsecs = tempsecs
                arg = "--wait"
        new_argv.append(arg)
    argv = new_argv

    try:
        if "--" in argv:
            pcs_options, argv = getopt.gnu_getopt(argv,
                                                  parse_args.PCS_SHORT_OPTIONS,
                                                  parse_args.PCS_LONG_OPTIONS)
        else:
            # DEPRECATED
            # TODO remove
            # We want to support only the -- version
            (
                args_without_negative_nums,
                args_filtered_out,
            ) = parse_args.filter_out_non_option_negative_numbers(argv)
            if args_filtered_out:
                options_str = "', '".join(args_filtered_out)
                deprecation_warning(
                    f"Using '{options_str}' without '--' is deprecated, those "
                    "parameters will be considered position independent "
                    "options in future pcs versions")
            pcs_options, dummy_argv = getopt.gnu_getopt(
                args_without_negative_nums,
                parse_args.PCS_SHORT_OPTIONS,
                parse_args.PCS_LONG_OPTIONS,
            )
            argv = parse_args.filter_out_options(argv)
    except getopt.GetoptError as err:
        error(str(err))
        print_to_stderr(usage.main())
        sys.exit(1)

    full = False
    for option, dummy_value in pcs_options:
        if option == "--full":
            full = True
            break

    for opt, val in pcs_options:
        if not opt in utils.pcs_options:
            utils.pcs_options[opt] = val
        else:
            # If any options are a list then they've been entered twice which
            # isn't valid
            utils.err("%s can only be used once" % opt)

        if opt in ("-h", "--help"):
            if not argv:
                print(usage.main())
                sys.exit()
            else:
                argv = [argv[0], "help"] + argv[1:]
        elif opt == "-f":
            usefile = True
            filename = val
            utils.usefile = usefile
            utils.filename = filename
        elif opt == "--corosync_conf":
            settings.corosync_conf_file = val
        elif opt == "--version":
            print(settings.pcs_version)
            if full:
                print(" ".join(
                    sorted([
                        feat["id"]
                        for feat in capabilities.get_pcs_capabilities()
                    ])))
            sys.exit()
        elif opt == "--fullhelp":
            usage.full_usage()
            sys.exit()
        elif opt == "--wait":
            utils.pcs_options[opt] = waitsecs
        elif opt == "--request-timeout":
            request_timeout_valid = False
            try:
                timeout = int(val)
                if timeout > 0:
                    utils.pcs_options[opt] = timeout
                    request_timeout_valid = True
            except ValueError:
                pass
            if not request_timeout_valid:
                utils.err(("'{0}' is not a valid --request-timeout value, use "
                           "a positive integer").format(val))

    # initialize logger
    logging.getLogger("pcs")

    if (os.getuid() != 0) and (argv and argv[0] != "help") and not usefile:
        _non_root_run(argv)
    cmd_map = {
        "resource": resource.resource_cmd,
        "cluster": cluster.cluster_cmd,
        "stonith": stonith.stonith_cmd,
        "property": prop.property_cmd,
        "constraint": constraint.constraint_cmd,
        "acl": acl.acl_cmd,
        "status": status.status_cmd,
        "config": config.config_cmd,
        "pcsd": pcsd.pcsd_cmd,
        "node": node.node_cmd,
        "quorum": quorum.quorum_cmd,
        "qdevice": qdevice.qdevice_cmd,
        "alert": alert.alert_cmd,
        "booth": booth.booth_cmd,
        "host": host.host_cmd,
        "client": client.client_cmd,
        "dr": dr.dr_cmd,
        "tag": tag.tag_cmd,
        "help": lambda lib, argv, modifiers: print(usage.main()),
    }
    try:
        routing.create_router(cmd_map, [])(utils.get_library_wrapper(), argv,
                                           utils.get_input_modifiers())
    except LibraryError as e:
        if e.output:
            sys.stderr.write(e.output)
            sys.exit(1)
        process_library_reports(e.args)
    except errors.CmdLineInputError:
        if argv and argv[0] in cmd_map:
            usage.show(argv[0], [])
        else:
            print_to_stderr(usage.main())
        sys.exit(1)
예제 #13
0
파일: stonith.py 프로젝트: CtrlZmaster/pcs
def stonith_create(lib, argv, modifiers):
    """
    Options:
      * --before - specified resource inside a group before which new resource
        will be placed inside the group
      * --after - specified resource inside a group after which new resource
        will be placed inside the group
      * --group - specifies group in which resource will be created
      * --force - allow not existing agent, invalid operations or invalid
        instance attributes
      * --disabled - created resource will be disabled
      * --no-default-ops - do not add default operations
      * --wait
      * -f - CIB file
    """
    modifiers.ensure_only_supported(
        "--before",
        "--after",
        "--group",
        "--force",
        "--disabled",
        "--no-default-ops",
        "--wait",
        "-f",
    )
    if modifiers.is_specified("--before") and modifiers.is_specified(
            "--after"):
        raise error("you cannot specify both --before and --after{0}".format(
            "" if modifiers.
            is_specified("--group") else " and you have to specify --group"))

    if not modifiers.is_specified("--group"):
        if modifiers.is_specified("--before"):
            raise error("you cannot use --before without --group")
        if modifiers.is_specified("--after"):
            raise error("you cannot use --after without --group")

    if len(argv) < 2:
        raise CmdLineInputError()

    stonith_id = argv[0]
    stonith_type = argv[1]

    parts = parse_create_args(argv[2:])

    settings = dict(
        allow_absent_agent=modifiers.get("--force"),
        allow_invalid_operation=modifiers.get("--force"),
        allow_invalid_instance_attributes=modifiers.get("--force"),
        ensure_disabled=modifiers.get("--disabled"),
        use_default_operations=not modifiers.get("--no-default-ops"),
        wait=modifiers.get("--wait"),
    )

    if not modifiers.get("--group"):
        lib.stonith.create(
            stonith_id,
            stonith_type,
            parts["op"],
            parts["meta"],
            parts["options"],
            **settings,
        )
    else:
        deprecation_warning(
            "Option to group stonith resource is deprecated and will be "
            "removed in a future release.")
        adjacent_resource_id = None
        put_after_adjacent = False
        if modifiers.get("--after"):
            adjacent_resource_id = modifiers.get("--after")
            put_after_adjacent = True
        if modifiers.get("--before"):
            adjacent_resource_id = modifiers.get("--before")
            put_after_adjacent = False

        lib.stonith.create_in_group(
            stonith_id,
            stonith_type,
            modifiers.get("--group"),
            parts["op"],
            parts["meta"],
            parts["options"],
            adjacent_resource_id=adjacent_resource_id,
            put_after_adjacent=put_after_adjacent,
            **settings,
        )