Skip to content

Instantly share code, notes, and snippets.

@AnyISalIn
Last active December 9, 2019 03:23
Show Gist options
  • Select an option

  • Save AnyISalIn/7a66c5d08228da0402d19fa3eea6614c to your computer and use it in GitHub Desktop.

Select an option

Save AnyISalIn/7a66c5d08228da0402d19fa3eea6614c to your computer and use it in GitHub Desktop.
TerraformWrapper
import delegator
import os
import json
from service import TerraformManagerService
class Provider:
def __init__(self, config):
self.config = config
class Template:
def __init__(self, providers, resources, outputs, datasources, variables, user_variables):
self.providers = providers
self.resources = resources
self.outputs = outputs
self.datasources = datasources
self.variables = variables
self.user_variables = variables
class Instance:
def __init__(self, name, template, variables=None):
self.name = name
self.template = template
self.variables = variables or dict()
self.states = None
self.status = None
self.terraform_service = TerraformManagerService()
self.shell_output = None
@property
def path(self):
return self.terraform_service.plan_template_dir.joinpath(self.name)
def init(self):
self.status = 'INITIALIZATION'
self.generate_plan_files()
init_cmd = self.terraform_service.init()
cmd = delegator.run(' '.join(init_cmd), cwd=str(self.path))
self.shell_output = cmd.err or cmd.out
if cmd.return_code != 0:
self.status = 'INITIALIZATION_ERROR'
else:
self.status = 'INITIALIZATION_SUCCEED'
self.graph()
def generate_plan_files(self):
if not os.path.exists(self.path):
os.mkdir(self.path)
with open(os.path.join(self.path, 'providers.tf'), 'wb') as f:
data = '\n'.join([_.config for _ in self.template.providers])
f.write(data.encode())
with open(os.path.join(self.path, 'resources.tf'), 'wb') as f:
f.write(self.template.resources.encode())
with open(os.path.join(self.path, 'outputs.tf'), 'wb') as f:
f.write(self.template.outputs.encode())
with open(os.path.join(self.path, 'variables.tf'), 'wb') as f:
f.write(self.template.variables.encode())
with open(os.path.join(self.path, 'datasources.tf'), 'wb') as f:
f.write(self.template.datasources.encode())
def build_variables(self):
for variable in self.variables:
yield f'''-var "{variable['key']}={variable['value']}"'''
def apply(self):
self.init()
self.status = 'APPLYING'
variables_args = ' '.join(list(self.build_variables()))
apply_cmd = ' '.join(self.terraform_service.apply(variables_args, str(self.path)))
cmd = delegator.run(f'{apply_cmd}', cwd=str(self.path))
self.shell_output = cmd.err or cmd.out
if cmd.return_code != 0:
self.status = 'APPLY_ERROR'
else:
self.status = 'APPLY_SUCCEED'
def destroy(self):
self.status = 'DESTROYING'
destroy_cmd = ' '.join(self.terraform_service.destroy())
cmd = delegator.run(f'{destroy_cmd}', cwd=str(self.path))
if cmd.return_code == 0:
shutil.rmtree(str(self.path))
return
self.shell_output = cmd.err
self.status = 'DESTROY_ERROR'
raise CommandExecuteError
def show(self):
show_cmd = ' '.join(self.terraform_service.show())
cmd = delegator.run(f'{show_cmd}', cwd=str(self.path))
if cmd.return_code == 0:
self.states = json.loads(cmd.out)
return self.states
self.shell_output = cmd.err
raise CommandExecuteError
def refresh(self):
refresh_cmd = ' '.join(self.terraform_service.refresh())
self.status = 'SYNCING'
cmd = delegator.run(f'{refresh_cmd}', cwd=str(self.path))
if cmd.return_code == 0:
self.shell_output = cmd.out
self.status = 'SYNC_SUCCEED'
return self.show()
self.shell_output = cmd.err
self.status = 'SYNC_ERROR'
raise CommandExecuteError
def graph(self):
graph_cmd = ' '.join(self.terraform_service.graph())
cmd = delegator.run(f'{graph_cmd}', cwd=str(self.path))
self.graph_output = cmd.out
return self.graph_output
def plan(self):
self.generate_plan_files()
variables_args = ' '.join(list(self.build_variables()))
plan_cmd = ' '.join(self.terraform_service.plan(variables_args))
cmd = delegator.run(f'{plan_cmd}', cwd=str(self.path))
self.shell_output = cmd.out
return self.shell_output
def __repr__(self):
return f'<Instance {self.path}>'
import pathlib
class TerraformManagerService(object):
def __init__(self, terraform_bin=None, plan_template_dir=None):
self.terraform_bin = terraform_bin or '/usr/local/bin/terraform'
self.plan_template_dir = pathlib.Path(plan_template_dir or '/Users/anyisalin/codes/terraform_test/instances')
def validate(self, *args):
return [self.terraform_bin, 'validate'] + list(args)
def apply(self, *args):
return [self.terraform_bin, 'apply', '-auto-approve'] + list(args)
def init(self, *args):
return [self.terraform_bin, 'init'] + list(args)
def show(self, *args):
return [self.terraform_bin, 'show', '-json'] + list(args)
def refresh(self, *args):
return [self.terraform_bin, 'refresh'] + list(args)
def destroy(self, *args):
return [self.terraform_bin, 'destroy', '-auto-approve'] + list(args)
def graph(self, *args):
return [self.terraform_bin, 'graph'] + list(args)
def plan(self, *args):
return [self.terraform_bin, 'plan'] + list(args)
from models import Template, Instance, Provider
from service import TerraformManagerService
provider = '''
provider "openstack" {
region = "RegionOne"
insecure = "true"
}
'''
resources = '''
resource "openstack_compute_instance_v2" "terraform" {
name = "${var.vm_name}"
image_name = "${var.image}"
flavor_name = "${var.flavor}"
key_pair = "terraform"
security_groups = ["terraform"]
network {
uuid = "${var.network}"
}
}
'''
variables = '''
variable "image" {
default = "Ubuntu 16.04"
}
variable "flavor" {
default = "m1.small"
}
variable "ssh_key_file" {
default = "~/.ssh/id_rsa"
}
variable "ssh_user_name" {
default = "ubuntu"
}
variable "pool" {
default = "Public"
}
variable "network" {
default = "f5a2c66a-f465-4578-ac96-676c4e767f8d"
}
variable "vm_name" {
default = "terraform"
}
'''
datasources = ''
outputs = ''
openstack_provider = Provider(config=provider)
template = Template(providers=[openstack_provider],
resources=resources,
datasources=datasources,
outputs=outputs,
variables=variables,
user_variables=[
{'key': 'vm_name', 'default': 'test', 'required': False}
]
)
instance = Instance(name='instance-test', template=template, variables=[{'key': 'vm_name', 'value': 'instance1'}])
instance.init()
instance.apply()
instance.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment