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
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
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
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}"
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"]