def create_variables_template(*, write_output: bool = False) -> bool:
    """
    Writes an exemplary JSON file to the current directory.

    :param write_output: Whether to write informational messages to STDOUT and STDERR.
    :return: Whether the creation succeeded.
    """

    filename = "template.json"
    example = [
        Variable(key="key1", value="value1").to_json(),
        Variable(key="key2", value="value2").to_json()
    ]
    try:
        with open(filename, "w") as file:
            file.write(json.dumps(example, indent=2))
        if write_output:
            print(f"Successfully created {filename}.")
        return True
    except:
        if write_output:
            # yapf: disable
            print((
                f"Error: something went wrong while writing the {filename} file. Ensure you have "
                "permission to write files in the current working directory."
            ), file=sys.stderr)
            # yapf: enable
        return False
Beispiel #2
0
def test_validity() -> None:
    for key in ["", "  ", "  test  ", "a bad key", "another-bad-key@"]:
        assert not Variable(key=key, value="").is_valid

    for category in ["Terraform", "environment", "ENV", "TF"]:
        assert not Variable(key="test", value="", category=category).is_valid

    for key in ["a-good-key", "Some_Other_Key", "YET_1_ANOTHER_KEY_86"]:
        for category in ["terraform", "env"]:
            assert Variable(key=key, value="", category=category).is_valid
Beispiel #3
0
def test_configure_variables(mocker: MockerFixture) -> None:
    for success in [True, False]:
        _mock_sys_argv_arguments(mocker)
        test_variable = Variable(key="key", value="value")
        fail_mock: MagicMock = _mock_cli_fail(mocker)
        parse_mock: MagicMock = mocker.patch(
            "terraform_manager.__main__.cli_handlers.parse_variables",
            return_value=[test_variable])
        configure_mock: MagicMock = mocker.patch(
            "terraform_manager.entities.terraform.Terraform.configure_variables",
            return_value=success)
        _mock_fetch_workspaces(mocker, [_test_workspace1])

        variables_file = "test.json"
        _mock_parsed_arguments(
            mocker, _arguments({"configure_variables": variables_file}))
        _mock_get_group_arguments(mocker)

        main()

        parse_mock.assert_called_once_with(variables_file, write_output=True)
        configure_mock.assert_called_once_with([test_variable])
        if success:
            fail_mock.assert_not_called()
        else:
            fail_mock.assert_called_once()
def _get_existing_variables(
        base_url: str,
        headers: Dict[str, str],
        workspace: Workspace,
        *,
        write_output: bool = False) -> Optional[Dict[str, Variable]]:
    """
    Fetches the variables for a given workspaces. This method will eagerly exit and return None if
    anything unexpected is encountered. This is done prophylactically as the ensuing update/create
    operations hinge on the successful completion of this method.

    :param base_url: A URL fragment onto which a path will be appended to construct the Terraform
                     API endpoint.
    :param headers: The headers to provide in the API HTTP request to fetch the variables.
    :param workspace: The workspace for which variables will be fetched.
    :param write_output: Whether to print a tabulated result of the patch operations to STDOUT.
    :return: A dictionary mapping variable IDs to variables, or None if an error occurred.
    """
    def write_parse_error(json_object: Any) -> None:
        if write_output:
            print(
                f"Warning: a variable was not successfully parsed from {json.dumps(json_object)}",
                file=sys.stderr)

    # yapf: disable
    response = safe_http_request(
        lambda: throttle(lambda: requests.get(
            f"{base_url}/workspaces/{workspace.workspace_id}/vars",
            headers=headers
        ))
    )
    # yapf: enable

    variables = {}
    if response.status_code == 200:
        body = response.json()
        if "data" in body and isinstance(body["data"], list):
            for obj in body["data"]:
                if isinstance(obj,
                              dict) and "id" in obj and "attributes" in obj:
                    variable_id = obj["id"]
                    variable = Variable.from_json(obj["attributes"])
                    if variable is not None:
                        variables[variable_id] = variable
                    else:
                        write_parse_error(obj)
                        return None
                else:
                    write_parse_error(obj)
                    return None
        else:
            write_parse_error(response.json())
            return None
    else:
        if write_output:
            print(
                f'Error: failed to get the existing variables for workspace "{workspace.name}".',
                file=sys.stderr)
        return None
    return variables
Beispiel #5
0
def test_deserialization() -> None:
    variable = Variable.from_json(_test_json)
    assert variable.key == _test_json["key"]
    assert variable.value == _test_json["value"]
    assert variable.description == _test_json["description"]
    assert variable.sensitive == _test_json["sensitive"]
    assert variable.category == _test_json["category"]
    assert variable.hcl == _test_json["hcl"]
def test_create_variables_template(mocker: MockerFixture) -> None:
    for write in [True, False]:
        file_handle_mock: MagicMock = mocker.patch("builtins.open")
        print_mock: MagicMock = mocker.patch("builtins.print")
        expected_templated_variables = [
            Variable(key="key1", value="value1").to_json(),
            Variable(key="key2", value="value2").to_json()
        ]
        expected_template_contents = json.dumps(expected_templated_variables,
                                                indent=2)

        assert create_variables_template(write_output=write)
        file_handle_mock.assert_called_once_with("template.json", "w")
        file_handle_mock.return_value.__enter__().write\
            .assert_called_once_with(expected_template_contents)
        if write:
            print_mock.assert_called_once_with(
                f"Successfully created template.json.")
        else:
            print_mock.assert_not_called()
def test_configure_variables_invalid(mocker: MockerFixture) -> None:
    print_mock: MagicMock = mocker.patch("builtins.print")
    assert not configure_variables(
        TEST_TERRAFORM_DOMAIN,
        TEST_ORGANIZATION,
        workspaces=[_test_workspace],
        variables=[Variable(key=" a bad key ", value="")],
        write_output=True)
    print_mock.assert_called_once_with(
        "At least one variable is invalid, so no variables will be configured.",
        file=sys.stderr)
def test_parse_variables(mocker: MockerFixture) -> None:
    os_path_mock: MagicMock = mocker.patch("os.path.exists", return_value=True)
    file_handle_mock: MagicMock = mocker.patch("builtins.open")
    json_load_mock: MagicMock = mocker.patch("json.load",
                                             return_value=[_variable_json])

    filename = "test.json"
    parsed_variables = parse_variables(filename)

    assert parsed_variables == [Variable(key="key1", value="value1")]
    os_path_mock.assert_called_once_with(filename)
    file_handle_mock.assert_called_once_with(filename, "r")
    json_load_mock.assert_called_once()
def parse_variables(file_path_and_name: str,
                    write_output: bool = False) -> List[Variable]:
    """
    Parses Variable objects out of a given file.

    :param file_path_and_name: The path (relative to the current working directory) and filename of
                               the file containing the variables to configure.
    :param write_output: Whether to print a tabulated result of the patch operations to STDOUT.
    :return: A list of variables that were parsed from the given file, if any.
    """

    variables = []
    try:
        if os.path.exists(file_path_and_name):
            with open(file_path_and_name, "r") as file:
                variables_json = json.load(file)
            for obj in variables_json:
                variable = Variable.from_json(obj)
                if variable is not None:
                    variables.append(variable)
                else:
                    if write_output:
                        # yapf: disable
                        print((
                            "Warning: a variable was not successfully parsed from "
                            f"{file_path_and_name}. Its JSON is {json.dumps(obj)}"
                        ), file=sys.stderr)
                        # yapf: enable
            return variables
        else:
            raise ValueError(f"{file_path_and_name} does not exist.")
    except:
        if write_output:
            print(
                f"Error: unable to read and/or parse the {file_path_and_name} file into JSON.",
                file=sys.stderr)
        return variables
from tabulate import tabulate
from terraform_manager.entities.variable import Variable
from terraform_manager.entities.workspace import Workspace
from terraform_manager.terraform.variables import create_variables_template, parse_variables, \
    _get_existing_variables, _update_variables, _create_variables, configure_variables, \
    delete_variables

from tests.utilities.tooling import test_workspace, TEST_API_URL, TEST_TERRAFORM_DOMAIN, \
    TEST_ORGANIZATION

_variable_json: Dict[str, str] = {"key": "key1", "value": "value1"}

_test_workspace: Workspace = test_workspace()

_test_variable_id: str = "test1"
_test_variable: Variable = Variable(key="key", value="value")
_test_variable_api_json: Dict[str, List[Dict[str, Any]]] = {
    "data": [{
        "id": _test_variable_id,
        "type": "vars",
        "attributes": _test_variable.to_json()
    }]
}
_test_variables_with_ids: Dict[str, Variable] = {
    _test_variable_id: _test_variable
}

_test_variables_api_url: str = f"{TEST_API_URL}/workspaces/{_test_workspace.workspace_id}/vars"
_test_specific_variable_api_url: str = \
    f"{TEST_API_URL}/workspaces/{_test_workspace.workspace_id}/vars/{_test_variable_id}"
Beispiel #11
0
from typing import Dict, Any

from terraform_manager.entities.variable import Variable

_test_json: Dict[str, Any] = {
    "key": "key",
    "value": "value",
    "description": "",
    "sensitive": True,
    "category": "terraform",
    "hcl": False
}
_test_variable: Variable = Variable(key="key",
                                    value="value",
                                    description="",
                                    category="terraform",
                                    hcl=False,
                                    sensitive=True)


def test_serialization() -> None:
    assert _test_variable.to_json() == _test_json


def test_deserialization() -> None:
    variable = Variable.from_json(_test_json)
    assert variable.key == _test_json["key"]
    assert variable.value == _test_json["value"]
    assert variable.description == _test_json["description"]
    assert variable.sensitive == _test_json["sensitive"]
    assert variable.category == _test_json["category"]