1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Terraform: add workspace support for switching and removing workspaces (#43489)

From terraform documentation:
```
The persistent data stored in the backend belongs to a workspace. Initially the backend has only one workspace, called "default", and thus there is only one Terraform state associated with that configuration.

Certain backends support multiple named workspaces, allowing multiple states to be associated with a single configuration. The configuration still has only one backend, but multiple distinct instances of that configuration to be deployed without configuring a new backend or changing authentication credentials.
```

This patch introduces the `workspace` parameter in the terraform module. The module will select
the workspace is it does not exists, or simply select it if it exists.

Fixes #43134

Add 'purge_workspace' parameter and handle the workspace context

The `purge_workspace` parameter allows to remove a workspace when asking for state = absent.
It allows to leave a clean state file without empty workspaces if the parameter is true.

Also adding the support of a workspace context that allows to restore the workspace
when that was active when the module started.
This commit is contained in:
Rémi REY 2018-08-02 15:37:26 +02:00 committed by Ryan Brown
parent 09ae1ec308
commit 0461620b2d

View file

@ -38,6 +38,21 @@ options:
- The path to the root of the Terraform directory with the
vars.tf/main.tf/etc to use.
required: true
workspace:
description:
- The terraform workspace to work with.
required: false
default: default
version_added: 2.7
purge_workspace:
description:
- Only works with state = absent
- If true, the workspace will be deleted after the "terraform destroy" action.
- The 'default' workspace will not be deleted.
required: false
default: false
type: bool
version_added: 2.7
plan_file:
description:
- The path to an existing Terraform plan file to apply. If this is not
@ -166,6 +181,43 @@ def init_plugins(bin_path, project_path):
module.fail_json(msg="Failed to initialize Terraform modules:\r\n{0}".format(err))
def get_workspace_context(bin_path, project_path):
workspace_ctx = {"current": "default", "all": []}
command = [bin_path, 'workspace', 'list']
rc, out, err = module.run_command(command, cwd=project_path)
if rc != 0:
module.fail_json(msg="Failed to list Terraform workspaces:\r\n{0}".format(err))
for item in out.split('\n'):
stripped_item = item.strip()
if not stripped_item:
continue
elif stripped_item.startswith('* '):
workspace_ctx["current"] = stripped_item.replace('* ', '')
else:
workspace_ctx["all"].append(stripped_item)
return workspace_ctx
def _workspace_cmd(bin_path, project_path, action, workspace):
command = [bin_path, 'workspace', action, workspace]
rc, out, err = module.run_command(command, cwd=project_path)
if rc != 0:
module.fail_json(msg="Failed to {0} workspace:\r\n{1}".format(action, err))
return rc, out, err
def create_workspace(bin_path, project_path, workspace):
_workspace_cmd(bin_path, project_path, 'new', workspace)
def select_workspace(bin_path, project_path, workspace):
_workspace_cmd(bin_path, project_path, 'select', workspace)
def remove_workspace(bin_path, project_path, workspace):
_workspace_cmd(bin_path, project_path, 'delete', workspace)
def build_plan(bin_path, project_path, variables_args, state_file, targets, plan_path=None):
if plan_path is None:
f, plan_path = tempfile.mkstemp(suffix='.tfplan')
@ -198,6 +250,8 @@ def main():
argument_spec=dict(
project_path=dict(required=True, type='path'),
binary_path=dict(type='path'),
workspace=dict(required=False, type='str', default='default'),
purge_workspace=dict(type='bool', default=False),
state=dict(default='present', choices=['present', 'absent', 'planned']),
variables=dict(type='dict'),
variables_file=dict(type='path'),
@ -206,7 +260,7 @@ def main():
targets=dict(type='list', default=[]),
lock=dict(type='bool', default=True),
lock_timeout=dict(type='int',),
force_init=dict(type='bool', default=False)
force_init=dict(type='bool', default=False),
),
required_if=[('state', 'planned', ['plan_file'])],
supports_check_mode=True,
@ -214,6 +268,8 @@ def main():
project_path = module.params.get('project_path')
bin_path = module.params.get('binary_path')
workspace = module.params.get('workspace')
purge_workspace = module.params.get('purge_workspace')
state = module.params.get('state')
variables = module.params.get('variables') or {}
variables_file = module.params.get('variables_file')
@ -229,6 +285,13 @@ def main():
if force_init:
init_plugins(command[0], project_path)
workspace_ctx = get_workspace_context(command[0], project_path)
if workspace_ctx["current"] != workspace:
if workspace not in workspace_ctx["all"]:
create_workspace(command[0], project_path, workspace)
else:
select_workspace(command[0], project_path, workspace)
variables_args = []
for k, v in variables.items():
variables_args.extend([
@ -300,7 +363,13 @@ def main():
else:
outputs = json.loads(outputs_text)
module.exit_json(changed=changed, state=state, outputs=outputs, stdout=out, stderr=err, command=' '.join(command))
# Restore the Terraform workspace found when running the module
if workspace_ctx["current"] != workspace:
select_workspace(command[0], project_path, workspace_ctx["current"])
if state == 'absent' and workspace != 'default' and purge_workspace is True:
remove_workspace(command[0], project_path, workspace)
module.exit_json(changed=changed, state=state, workspace=workspace, outputs=outputs, stdout=out, stderr=err, command=' '.join(command))
if __name__ == '__main__':