def run_module() -> None:
    module_args = _module_args()

    result: Dict[str, Any] = dict(
        changed=False,
    )
    # supports_check_mode=True is okay we just collecting data
    # and therefore no extra mechanism to address check_mode=true
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    params: Params = Params(copy.deepcopy(module.params))
    func_run_command = functools.partial(AnsibleModule.run_command, module)
    func_log = logging.CachingLogger(module.log)

    try:
        registration_info: SpireAgentRegistrationInfo = SpireAgentRegistrationInfo(
            run_command=func_run_command,
            log_func=func_log,
            spire_server_install_dir=module.params.get("spire_server_install_dir"),
            spire_agent_spiffe_ids=module.params.get("spire_agent_spiffe_id"),
            spire_agent_attestation_types=module.params.get("spire_agent_attestation_type"),
            spire_agent_serial_numbers=module.params.get("spire_agent_serial_number"),
            spire_server_registration_uds_path=module.params.get("spire_server_registration_uds_path"),
        )

        entry_data_list: List[AgentRegistrationEntry] = registration_info.find_registrations()
        AgentRegistrationEntry.to_ansible_result_registration_entry
        result["spire_agent_registrations"] = [
            AgentRegistrationEntry.to_ansible_result_registration_entry(e)
            for e in entry_data_list
        ]

        result["debug_msg"] = str(func_log.messages)

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg=f"Exception while running module:{func_log.messages}", exception=e)
예제 #2
0
def run_module() -> None:
    module_args = _module_args()

    # TODO check if check_mode does make any sens?
    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    params: Params = Params(copy.deepcopy(module.params))
    func_run_command = RunCommand(module)

    func_log = logging.CachingLogger(module.log)

    try:
        dirs: AgentDirs = AgentDirs(
            config_dir=module.params["spire_agent_config_dir"],
            data_dir=module.params["spire_agent_data_dir"],
            install_dir=module.params["spire_agent_install_dir"],
            log_dir=module.params["spire_agent_log_dir"],
            service_dir=module.params["spire_agent_service_dir"],
            service_name=module.params["spire_agent_service_name"],
        )
        agent_info: SpireAgentInfo = SpireAgentInfo(
            run_command=func_run_command,
            log_func=func_log,
            dirs=dirs,
            socket_path=module.params["spire_agent_socket_path"],
            service_scope=module.params["spire_agent_service_scope"],
            expected_version=None  # TODO not needed remove me
        )
        state_snapshot: AgentStateSnapshot = AgentStateSnapshot(agent_info)
        result = {
            "changed":
            False,
            **state_snapshot.to_ansible_result(), "debug_msg":
            str(func_log.messages)
        }
        module.exit_json(**result)
    except Exception as e:
        module.fail_json(
            msg=f"Exception while running module:{func_log.messages}",
            exception=e)
예제 #3
0
def test_entries_having_same_identity(
        test_case: str, params: Dict[str, Union[List[str], str, bool]],
        entries: List[RegistrationEntry],
        expected: List[RegistrationEntry]) -> None:
    actual = entries_having_same_identity(Params(params), entries)
    assert actual == expected, f"case failed: {test_case}"
예제 #4
0
def test_need_change(test_case: str, params: Dict[str, Union[List[str], str,
                                                             bool]],
                     entry: Dict[str, Union[List[str],
                                            str]], expected: bool) -> None:
    actual = need_change(Params(params), RegistrationEntry(entry))
    assert actual == expected, f"case failed: {test_case}"
예제 #5
0
def run_module() -> None:
    module_args = _module_args()

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    params: Params = Params(copy.deepcopy(module.params))
    func_run_command = RunCommand(module)
    func_log = logging.CachingLogger(module.log)

    try:
        assert_not_handling_check_mode_since_action_reponsibility(module)
        server_dirs = ServerDirs.from_ansible_src(
            value_lookup_func=module.params.get)
        server_info: SpireServerInfo = _server_info_from_module_params(
            run_command=func_run_command,
            log_func=func_log,
            server_dirs=server_dirs,
            params=params)
        state_snapshot = ServerStateSnapshot(server_info)
        current_state: StateOfServer = state_snapshot.get_state_of_server()
        expected_state: StateOfServer = StateOfServer.from_task_args(params)
        changed = False
        func_log(
            f"state-of-server: actual={current_state}, expected={expected_state}"
        )
        if expected_state.need_change(current_state):
            changed = True
            func_log(f"Change expected:state={expected_state.state}")
            service = systemd.SpireComponentService(
                service_name=module.params["spire_server_service_name"],
                scope=systemd.Scope.by_name(
                    module.params["spire_server_service_scope"]),
                run_command=func_run_command,
                log_func=func_log)
            if expected_state.state == State.absent:
                service.teardown_service()
                dir_keys = [
                    "spire_server_config_dir",
                    "spire_server_data_dir",
                    "spire_server_install_dir",
                    # "spire_server_service_dir"
                ]
                for dir_key in dir_keys:
                    dir_value: str = module.params.get(dir_key)
                    if dir_keys is not None and not dir_value.isspace():
                        shutil.rmtree(dir_value.strip())
                log_dir: str = module.params.get("spire_server_log_dir")
                if log_dir is not None and pathlib.Path(
                        log_dir.strip()) != pathlib.Path("/var/log"):
                    shutil.rmtree(log_dir)
            else:
                if expected_state.need_srv_installation_change(current_state):
                    if SubStateServiceInstallation.not_installed == expected_state.substate_service_installation:
                        service.teardown_service()
                    else:
                        # all service related file are created by the ansible-action.
                        # we just make sure the service as been installed (file as been copied)
                        # This does not assess the runtime viability of the service
                        server_info.assert_spire_component_and_srv_are_installed(
                        )
                        if expected_state.substate_service_installation == SubStateServiceInstallation.enabled:
                            service.enable()
                        if expected_state.substate_service_status == SubStateServiceStatus.stopped:
                            service.stop()
                        else:  # started or healthy
                            service.start()
                            if expected_state.substate_service_status == SubStateServiceStatus.healthy:
                                timeout = module.params[
                                    "spire_server_healthiness_probe_timeout_seconds"]
                                healthcheck = healthchecks.CheckServer(
                                    run_command=func_run_command,
                                    file_spire_server_bin=server_info.
                                    get_executable_path(),
                                    readiness_probe_timeout_seconds=timeout,
                                    registration_uds_path=module.params[
                                        "spire_server_registration_uds_path"])
                                healthcheck.wait_for_readiness()

            server_info = _server_info_from_module_params(
                run_command=func_run_command,
                log_func=func_log,
                server_dirs=server_dirs,
                params=params)
            state_snapshot = spire_server_info_cmd.ServerStateSnapshot(
                server_info)
        current_state = state_snapshot.get_state_of_server()
        func_log(f"issues = {state_snapshot.get_all_issues()}")
        result = {
            "changed":
            changed,
            **current_state.to_ansible_return_data(),
            "info":
            state_snapshot.to_ansible_result(),
            "debug_msg":
            func_log.messages,
        }
        module.exit_json(**result)
    except Exception as e:
        print(func_log.messages)
        module.fail_json(
            msg=f"Exception while running module:{str(e)}",
            exception=e,
            debug_msg=func_log.messages,
        )
예제 #6
0
def run_module() -> None:
    module_args = _module_args()

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    params: Params = Params(copy.deepcopy(module.params))
    func_run_command = RunCommand(module)
    func_log = logging.CachingLogger(module.log)

    try:
        assert_not_handling_check_mode_since_action_reponsibility(module)

        dirs: AgentDirs = AgentDirs(
            config_dir=module.params["spire_agent_config_dir"],
            data_dir=module.params["spire_agent_data_dir"],
            log_dir=module.params["spire_agent_log_dir"],
            service_dir=module.params["spire_agent_service_dir"],
            install_dir=module.params["spire_agent_install_dir"],
            service_name=module.params["spire_agent_service_name"],
        )
        agent_info: SpireAgentInfo = SpireAgentInfo(
            run_command=func_run_command,
            log_func=func_log,
            dirs=dirs,
            socket_path=module.params["spire_agent_socket_path"],
            service_scope=module.params["spire_agent_service_scope"],
        )
        state_snapshot = spire_agent_info_cmd.AgentStateSnapshot(agent_info)
        current_state: StateOfAgent = state_snapshot.get_state_of_agent()
        expected_state: StateOfAgent = StateOfAgent.from_task_args(params)
        if expected_state.need_change(current_state):
            func_log(f"Change expected:state={expected_state.state}")
            service = systemd.SpireComponentService(
                service_name=module.params["spire_agent_service_name"],
                scope=systemd.Scope.by_name(
                    module.params["spire_agent_service_scope"]),
                run_command=func_run_command,
                log_func=func_log)
            if expected_state.state == State.absent:
                service.teardown_service()
                dir_keys = [
                    "spire_agent_config_dir",
                    "spire_agent_data_dir",
                    "spire_agent_install_dir",
                    # "spire_agent_service_dir"
                ]
                for dir_key in dir_keys:
                    dir_value: str = module.params.get(dir_key)
                    if dir_keys is not None and not dir_value.isspace():
                        shutil.rmtree(dir_value.strip())
                log_dir: str = module.params.get("spire_agent_log_dir")
                if log_dir is not None and pathlib.Path(
                        log_dir.strip()) != pathlib.Path("/var/log"):
                    shutil.rmtree(log_dir)
            else:
                if expected_state.need_srv_installation_change(current_state):
                    if SubStateServiceInstallation.not_installed == expected_state.substate_service_installation:
                        service.teardown_service()
                    else:
                        # all service related file are created by the ansible-action.
                        # we just make sure the service as been installed (file as been copied)
                        # This does not assess the runtime viability of the service
                        agent_info.assert_agent_and_srv_are_installed()
                        if expected_state.substate_service_installation == SubStateServiceInstallation.enabled:
                            service.enable()
                        if expected_state.substate_service_status == SubStateServiceStatus.stopped:
                            if expected_state.substate_agent_registered == SubStateAgentRegistered.yes:
                                # registration is a collaborative job between agent and server.
                                # we do not have access to the server from here.
                                # we however know that an healthy agent must have a valid registration
                                # So our strategy to ensure registration is to:
                                #   - starts the agent
                                #   - wait for its healthiness
                                #   - and and stop it
                                service.start()
                                timeout = module.params[
                                    "spire_agent_healthiness_probe_timeout_seconds"]
                                healthcheck = healthchecks.CheckAgent(
                                    run_command=func_run_command,
                                    file_spire_agent_bin=dirs.path_executable,
                                    readiness_probe_timeout_seconds=timeout,
                                    socket_path=module.
                                    params["spire_agent_socket_path"])
                                healthcheck.wait_for_readiness()
                            service.stop()
                        else:  # started or healthy
                            service.start()
                            if expected_state.substate_service_status == SubStateServiceStatus.healthy:
                                timeout = module.params[
                                    "spire_agent_healthiness_probe_timeout_seconds"]
                                healthcheck = healthchecks.CheckAgent(
                                    run_command=func_run_command,
                                    file_spire_agent_bin=dirs.path_executable,
                                    readiness_probe_timeout_seconds=timeout,
                                    socket_path=module.
                                    params["spire_agent_socket_path"])
                                healthcheck.wait_for_readiness()

        agent_info.reset_computed_base_state()
        state_snapshot = spire_agent_info_cmd.AgentStateSnapshot(agent_info)
        current_state = state_snapshot.get_state_of_agent()
        func_log(f"issues = {state_snapshot.get_issues_issues()}")
        result = {
            "changed":
            False,
            **current_state.to_ansible_return_data(),
            "debug_msg":
            func_log.messages,
        }
        module.exit_json(**result)
    except Exception as e:
        module.fail_json(
            msg=f"Exception while running module:{str(e)}",
            exception=e,
            debug_msg=func_log.messages,
        )
def run_module() -> None:
    module_args = _module_args()

    result = dict(
        state='absent',
        changed=False,
    )

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    params: Params = Params(copy.deepcopy(module.params))
    func_run_command = functools.partial(AnsibleModule.run_command, module)
    func_log = logging.CachingLogger(module.log)

    try:
        show_outcome: SpireServerEntryShowOutcome = spire_server_entry_cmd.cmd_server_entry_show(
            func_run_command,
            func_log,
            params,
        )

        if show_outcome.exec_failed():
            msg = f"""
                    Fail to execute <entry show> cmd:
                        parse_error={show_outcome.parse_error}
                        rc={show_outcome.rc}
                        stdout={show_outcome.stdout}
                        stderr={show_outcome.stderr}
                        entries={show_outcome.entries}
                    """
            raise RuntimeError(msg)

        if show_outcome.parsing_failed():
            msg = f"""
                    Fail to parse <entry show> output:
                        parse_error={show_outcome.parse_error}
                        rc={show_outcome.rc}
                        stdout={show_outcome.stdout}
                        stderr={show_outcome.stderr}
                        entries={show_outcome.entries}
                    """
            raise RuntimeError(msg)

        # identity_params = params["identity_args"]
        actual_list = spire_server_entry_cmd.entries_having_same_identity(
            params, show_outcome.entries)
        if len(actual_list) > 1:
            module.fail_json(
                msg=
                f'Cannot handle more than one identified corresponding entries: {actual_list}'
            )
        actual: RegistrationEntry = RegistrationEntry() if len(
            actual_list) == 0 else actual_list[0]
        need_change = spire_server_entry_cmd.need_change(params, actual)
        if need_change:
            debug_msg = f"""
                need_change={need_change}
                params={params}
                actual={actual}
                actual_list={actual_list}
                entries={show_outcome.entries}
                """
            func_log(debug_msg)

        state = module.params['state']
        result["state"] = state
        result["changed"] = need_change

        if need_change:
            if not module.check_mode:
                if state == "absent":
                    # TODO actual is entry not a Param so merging is not type safe intro actual.to_params()
                    # or params.to_entry(..) because it is the command being built
                    # so command data format is needed which is entry data
                    merged = {**actual, **params}
                    spire_server_entry_cmd.cmd_server_entry_delete(
                        func_run_command, func_log, merged)
                if state == "present":
                    if not actual:
                        spire_server_entry_cmd.cmd_server_entry_create(
                            func_run_command, func_log, params)
                    else:
                        # TODO actual is entry not a Param so merging is not type safe
                        merged = {**actual, **params}
                        spire_server_entry_cmd.cmd_server_entry_update(
                            func_run_command, func_log, merged)
        result["debug_msg"] = str(func_log.messages)
        module.exit_json(**result)
    except Exception as e:
        module.fail_json(
            msg=f"Exception while running module:{func_log.messages}",
            exception=str(e))