169163334 - Abstracts terraform wrapper code

The terraform wrapper is now abstracted in to a utility class for
working with terraform. The terraform module was also updated to support
configurable keyvault servers. Logging for this new module was also
added, so the terraform output is seen on the console.
This commit is contained in:
Rob Gil 2020-01-16 12:51:20 -05:00
parent deead852b5
commit aa89505650
4 changed files with 88 additions and 39 deletions

View File

@ -4,64 +4,48 @@ import logging
import subprocess import subprocess
from utils.keyvault.secrets import SecretsClient from utils.keyvault.secrets import SecretsClient
from utils.terraform.wrapper import TFWrapper
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
PROCESS='terraform' PROCESS='terraform'
@click.group() @click.group()
@click.option('--keyvault', required=True, help="Specify the keyvault to operate on")
@click.pass_context @click.pass_context
def terraform(ctx): def terraform(ctx, keyvault):
pass ctx.ensure_object(dict)
ctx.obj['keyvault'] = keyvault
@click.command('plan') @click.command('plan')
@click.pass_context @click.pass_context
def plan(ctx): def plan(ctx):
keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") keyvault = SecretsClient(vault_url=ctx.obj['keyvault'])
# Set env variables for TF tf = TFWrapper(keyvault)
for secret in keyvault.list_secrets(): tf.plan()
name = 'TF_VAR_' + secret
val = keyvault.get_secret(secret)
#print(val)
os.environ[name] = val
env = os.environ.copy()
command = "{} {}".format(PROCESS, 'plan')
with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc:
for line in proc.stdout:
logging.info(line.decode("utf-8") )
@click.command('apply') @click.command('apply')
@click.pass_context @click.pass_context
def apply(ctx): def apply(ctx):
keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") keyvault = SecretsClient(vault_url=ctx.obj['keyvault'])
# Set env variables for TF tf = TFWrapper(keyvault)
for secret in keyvault.list_secrets(): tf.apply()
name = 'TF_VAR_' + secret
val = keyvault.get_secret(secret)
#print(val)
os.environ[name] = val
env = os.environ.copy()
command = "{} {}".format(PROCESS, 'apply -auto-approve')
with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc:
for line in proc.stdout:
logging.info(line.decode("utf-8") )
@click.command('destroy') @click.command('destroy')
@click.pass_context @click.pass_context
def destroy(ctx): def destroy(ctx):
keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") keyvault = SecretsClient(vault_url=ctx.obj['keyvault'])
# Set env variables for TF tf = TFWrapper(keyvault)
for secret in keyvault.list_secrets(): tf.destroy()
name = 'TF_VAR_' + secret
val = keyvault.get_secret(secret) @click.command('init')
#print(val) @click.pass_context
os.environ[name] = val def init(ctx):
env = os.environ.copy() keyvault = SecretsClient(vault_url=ctx.obj['keyvault'])
command = "{} {}".format(PROCESS, 'destroy') tf = TFWrapper(keyvault)
with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: tf.init()
for line in proc.stdout:
logging.info(line.decode("utf-8") )
terraform.add_command(plan) terraform.add_command(plan)
terraform.add_command(apply) terraform.add_command(apply)
terraform.add_command(destroy) terraform.add_command(destroy)
terraform.add_command(init)

View File

@ -49,6 +49,10 @@ loggers:
level: DEBUG level: DEBUG
handlers: [console] handlers: [console]
propogate: yes propogate: yes
utils.terraform.wrapper:
level: DEBUG
handlers: [console]
propogate: yes
commands: commands:
level: INFO level: INFO
handlers: [console] handlers: [console]

View File

@ -0,0 +1,61 @@
import os
import logging
import subprocess
logger = logging.getLogger(__name__)
class TFWrapper:
"""
Command wrapper for terraform that injects secrets
from keyvault in to environment variables which
can then be used by terraform
"""
def __init__(self, keyvault: object):
self.keyvault = keyvault
self.env = ''
self.terraform_path = 'terraform'
self._set_env()
def _set_env(self):
# Prefix variables with TF_VAR_
for secret in self.keyvault.list_secrets():
name = 'TF_VAR_' + secret
val = self.keyvault.get_secret(secret)
os.environ[name] = val
# Set the environment with new vars
self.env = os.environ.copy()
return None
def _run_tf(self, option: str):
try:
command = '{} {}'.format(self.terraform_path, option)
with subprocess.Popen(command, env=self.env, stdout=subprocess.PIPE, shell=True) as proc:
for line in proc.stdout:
logging.info(line.decode("utf-8"))
except Exception as e:
print(e)
def plan(self):
"""
terraform plan
"""
self._run_tf(option='plan')
def init(self):
"""
terraform init
"""
self._run_tf(option='init')
def apply(self):
"""
terraform apply
"""
self._run_tf(option='apply -auto-approve')
def destroy(self):
"""
terraform destroy
"""
self._run_tf(option='destroy')