Skip to content

Commit

Permalink
Merge pull request #219 from terrateamio/main
Browse files Browse the repository at this point in the history
Release v1
  • Loading branch information
orbitz authored Nov 21, 2023
2 parents 101cbc0 + a2312a2 commit d23fd4a
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 129 deletions.
176 changes: 47 additions & 129 deletions terrat_runner/work_apply.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,13 @@
import base64
import hashlib
import json
import logging
import os
import string
import tempfile

import cmd
import repo_config as rc
import requests_retry
import work_exec
import workflow_step
import workflow_step_terrateam_ssh_key_setup


def _load_plan(state, work_token, api_base_url, dir_path, workspace, plan_path):
res = requests_retry.get(api_base_url + '/v1/work-manifests/' + work_token + '/plans',
params={'path': dir_path, 'workspace': workspace})

if res.status_code != 200:
return (False, 'Could not load plan from backend')

plan_data = base64.b64decode(res.json()['data'])

try:
plan_data = json.loads(plan_data)

if plan_data['method'] == 'terrateam':
plan_data_encoded = plan_data['data']
plan_data_raw = base64.b64decode(plan_data_encoded)
logging.debug('APPLY : LOAD_PLAN : dir_path=%s : workspace=%s : md5=%s',
dir_path,
workspace,
hashlib.md5(plan_data_raw).hexdigest())

with open(plan_path, 'wb') as f:
f.write(plan_data_raw)

return (True, None)
elif plan_data['method'] == 'cmd':
tmpl_vars = {
'plan_dst_path': plan_path
}
fetch_cmd = [string.Template(s).safe_substitute(tmpl_vars) for s in plan_data['fetch']]
proc = cmd.run(state, {'cmd': fetch_cmd})
if proc.returncode != 0:
return (False, 'Failed to fetch plan, see action logs for more details')
if plan_data.get('delete'):
cmd.run(state, {'cmd': plan_data['delete']})
return (True, None)
else:
raise Exception('Unknown method')
except json.JSONDecodeError:
plan_data_raw = plan_data
logging.debug('APPLY : LOAD_PLAN : dir_path=%s : workspace=%s : md5=%s',
dir_path,
workspace,
hashlib.md5(plan_data_raw).hexdigest())

with open(plan_path, 'wb') as f:
f.write(plan_data_raw)

return (True, None)


class Exec(work_exec.ExecInterface):
def pre_hooks(self, state):
pre_hooks = rc.get_all_hooks(state.repo_config)['pre']
Expand Down Expand Up @@ -94,77 +38,51 @@ def exec(self, state, d):
workspace = d['workspace']
workflow_idx = d.get('workflow')

(success, output) = _load_plan(state,
state.work_token,
state.api_base_url,
path,
workspace,
os.path.join(tmpdir, 'plan'))

if not success:
outputs = [
{
'success': False,
'outputs': {'text': output},
'workflow_step': {
'type': 'init'
}
}
]
state = state._replace(failed=True)
result = {
'path': path,
'workspace': workspace,
'success': not state.failed,
'outputs': outputs,
}
return (state, result)
env = state.env.copy()
env['TERRATEAM_PLAN_FILE'] = os.path.join(tmpdir, 'plan')
env['TERRATEAM_DIR'] = path
env['TERRATEAM_WORKSPACE'] = workspace
env['TERRATEAM_TMPDIR'] = tmpdir

if workflow_idx is None:
workflow = rc.get_default_workflow(state.repo_config)
else:
env = state.env.copy()
env['TERRATEAM_PLAN_FILE'] = os.path.join(tmpdir, 'plan')
env['TERRATEAM_DIR'] = path
env['TERRATEAM_WORKSPACE'] = workspace
env['TERRATEAM_TMPDIR'] = tmpdir

if workflow_idx is None:
workflow = rc.get_default_workflow(state.repo_config)
else:
workflow = rc.get_workflow(state.repo_config, workflow_idx)

create_and_select_workspace = rc.get_create_and_select_workspace(
state.repo_config,
path)

logging.info('APPLY : CREATE_AND_SELECT_WORKSPACE : %s : %r',
path,
create_and_select_workspace)

logging.info('APPLY : CDKTF : %s : %r',
path,
workflow['cdktf'])

if not workflow['cdktf'] and create_and_select_workspace:
env['TF_WORKSPACE'] = workspace

env['TERRATEAM_TERRAFORM_VERSION'] = work_exec.determine_tf_version(
state.working_dir,
os.path.join(state.working_dir, path),
workflow['terraform_version'])

state = state._replace(env=env)

state = workflow_step.run_steps(
state._replace(working_dir=os.path.join(state.working_dir, path),
path=path,
workspace=workspace,
workflow=workflow),
workflow['apply'])

result = {
'path': path,
'workspace': workspace,
'success': not state.failed,
'outputs': state.outputs.copy(),
}

return (state, result)
workflow = rc.get_workflow(state.repo_config, workflow_idx)

create_and_select_workspace = rc.get_create_and_select_workspace(
state.repo_config,
path)

logging.info('APPLY : CREATE_AND_SELECT_WORKSPACE : %s : %r',
path,
create_and_select_workspace)

logging.info('APPLY : CDKTF : %s : %r',
path,
workflow['cdktf'])

if not workflow['cdktf'] and create_and_select_workspace:
env['TF_WORKSPACE'] = workspace

env['TERRATEAM_TERRAFORM_VERSION'] = work_exec.determine_tf_version(
state.working_dir,
os.path.join(state.working_dir, path),
workflow['terraform_version'])

state = state._replace(env=env)

state = workflow_step.run_steps(
state._replace(working_dir=os.path.join(state.working_dir, path),
path=path,
workspace=workspace,
workflow=workflow),
workflow['apply'])

result = {
'path': path,
'workspace': workspace,
'success': not state.failed,
'outputs': state.outputs.copy(),
}

return (state, result)
71 changes: 71 additions & 0 deletions terrat_runner/workflow_step_apply.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,67 @@
import base64
import hashlib
import json
import logging
import string

import cmd
import repo_config as rc
import requests_retry
import retry
import workflow
import workflow_step_terraform


def _load_plan(state, work_token, api_base_url, dir_path, workspace, plan_path):
res = requests_retry.get(api_base_url + '/v1/work-manifests/' + work_token + '/plans',
params={'path': dir_path, 'workspace': workspace})

if res.status_code != 200:
return (False, 'Could not load plan from backend')

plan_data = base64.b64decode(res.json()['data'])

try:
plan_data = json.loads(plan_data)

if plan_data['method'] == 'terrateam':
plan_data_encoded = plan_data['data']
plan_data_raw = base64.b64decode(plan_data_encoded)
logging.debug('APPLY : LOAD_PLAN : dir_path=%s : workspace=%s : md5=%s',
dir_path,
workspace,
hashlib.md5(plan_data_raw).hexdigest())

with open(plan_path, 'wb') as f:
f.write(plan_data_raw)

return (True, None)
elif plan_data['method'] == 'cmd':
tmpl_vars = {
'plan_dst_path': plan_path
}
fetch_cmd = [string.Template(s).safe_substitute(tmpl_vars) for s in plan_data['fetch']]
proc = cmd.run(state, {'cmd': fetch_cmd})
if proc.returncode != 0:
return (False, 'Failed to fetch plan, see action logs for more details')
if plan_data.get('delete'):
cmd.run(state, {'cmd': plan_data['delete']})
return (True, None)
else:
raise Exception('Unknown method')
except json.JSONDecodeError:
plan_data_raw = plan_data
logging.debug('APPLY : LOAD_PLAN : dir_path=%s : workspace=%s : md5=%s',
dir_path,
workspace,
hashlib.md5(plan_data_raw).hexdigest())

with open(plan_path, 'wb') as f:
f.write(plan_data_raw)

return (True, None)


def _test_success_update_config(config):
def _f(ret):
if ret.failed:
Expand All @@ -18,6 +76,19 @@ def run(state, config):
config['args'] = ['apply', '$TERRATEAM_PLAN_FILE']
config['output_key'] = 'apply'

(success, output) = _load_plan(state,
state.work_token,
state.api_base_url,
state.path,
state.workspace,
state.env['TERRATEAM_PLAN_FILE'])

if not success:
return workflow.Result(failed=True,
state=state,
workflow_step={'type': 'apply'},
outputs={'text': output})

retry_config = rc.get_retry(config)
tries = retry_config['enabled'] and retry_config['tries'] or 1
result = retry.run(
Expand Down

0 comments on commit d23fd4a

Please sign in to comment.