2015-12-31 04:10:59 +00:00
|
|
|
import subprocess
|
|
|
|
import os
|
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class Terraform:
|
|
|
|
def __init__(self, targets=None, state='terraform.tfstate', variables=None):
|
|
|
|
self.targets = [] if targets is None else targets
|
|
|
|
self.variables = dict() if variables is None else variables
|
2015-12-31 07:15:51 +00:00
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
self.state_filename = state
|
|
|
|
self.state_data = dict()
|
2015-12-31 04:34:35 +00:00
|
|
|
self.parallelism = 50
|
2015-12-31 04:10:59 +00:00
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
def apply(self, targets=None, variables=None, **kargs):
|
2015-12-31 06:48:26 +00:00
|
|
|
"""
|
|
|
|
refer to https://terraform.io/docs/commands/apply.html
|
2016-02-25 09:22:11 +00:00
|
|
|
:param variables: variables in dict type
|
|
|
|
:param targets: targets in list
|
|
|
|
:returns return_code, stdout, stderr
|
2015-12-31 06:48:26 +00:00
|
|
|
"""
|
2015-12-31 04:10:59 +00:00
|
|
|
variables = self.variables if variables is None else variables
|
|
|
|
targets = self.targets if targets is None else targets
|
|
|
|
|
|
|
|
parameters = []
|
|
|
|
parameters += self._generate_targets(targets)
|
|
|
|
parameters += self._generate_var_string(variables)
|
2016-02-25 09:22:11 +00:00
|
|
|
parameters += self._gen_param_string(kargs)
|
|
|
|
|
2015-12-31 04:10:59 +00:00
|
|
|
parameters = \
|
2016-02-25 09:22:11 +00:00
|
|
|
['terraform', 'apply', '-state=%s' % self.state_filename] + parameters
|
2015-12-31 04:10:59 +00:00
|
|
|
|
|
|
|
cmd = ' '.join(parameters)
|
|
|
|
return self._run_cmd(cmd)
|
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
def _gen_param_string(self, kargs):
|
|
|
|
params = []
|
|
|
|
for key, value in kargs.items():
|
|
|
|
params += ['%s=%s' % (key, value)]
|
|
|
|
return params
|
|
|
|
|
2015-12-31 04:10:59 +00:00
|
|
|
def _run_cmd(self, cmd):
|
|
|
|
log.debug('command: ' + cmd)
|
2015-12-31 07:15:51 +00:00
|
|
|
|
2015-12-31 04:10:59 +00:00
|
|
|
p = subprocess.Popen(
|
|
|
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
|
|
|
out, err = p.communicate()
|
|
|
|
ret_code = p.returncode
|
|
|
|
log.debug('output: ' + out)
|
2015-12-31 07:15:51 +00:00
|
|
|
|
2015-12-31 04:10:59 +00:00
|
|
|
if ret_code == 0:
|
|
|
|
log.debug('error: ' + err)
|
2016-02-25 09:22:11 +00:00
|
|
|
self.read_state_file()
|
2015-12-31 04:10:59 +00:00
|
|
|
return ret_code, out, err
|
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
def destroy(self, targets=None, variables=None, **kwargs):
|
2015-12-31 04:10:59 +00:00
|
|
|
variables = self.variables if variables is None else variables
|
|
|
|
targets = self.targets if targets is None else targets
|
|
|
|
|
|
|
|
parameters = []
|
|
|
|
parameters += self._generate_targets(targets)
|
|
|
|
parameters += self._generate_var_string(variables)
|
2015-12-31 07:15:51 +00:00
|
|
|
|
2015-12-31 04:10:59 +00:00
|
|
|
parameters = \
|
2016-02-25 09:22:11 +00:00
|
|
|
['terraform', 'destroy', '-force', '-state=%s' % self.state_filename] + \
|
2015-12-31 04:10:59 +00:00
|
|
|
parameters
|
|
|
|
cmd = ' '.join(parameters)
|
|
|
|
return self._run_cmd(cmd)
|
|
|
|
|
|
|
|
def refresh(self, targets=None, variables=None):
|
|
|
|
variables = self.variables if variables is None else variables
|
|
|
|
targets = self.targets if targets is None else targets
|
|
|
|
|
|
|
|
parameters = []
|
|
|
|
parameters += self._generate_targets(targets)
|
|
|
|
parameters += self._generate_var_string(variables)
|
|
|
|
parameters = \
|
2016-02-25 09:22:11 +00:00
|
|
|
['terraform', 'refresh', '-state=%s' % self.state_filename] + \
|
2015-12-31 04:10:59 +00:00
|
|
|
parameters
|
|
|
|
cmd = ' '.join(parameters)
|
|
|
|
return self._run_cmd(cmd)
|
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
def read_state_file(self):
|
|
|
|
"""
|
|
|
|
read .tfstate file
|
|
|
|
:return: states file in dict type
|
|
|
|
"""
|
|
|
|
if os.path.exists(self.state_filename):
|
|
|
|
with open(self.state_filename) as f:
|
2015-12-31 04:10:59 +00:00
|
|
|
json_data = json.load(f)
|
|
|
|
self.state_data = json_data
|
|
|
|
log.debug("state_data=%s" % str(self.state_data))
|
|
|
|
return json_data
|
|
|
|
|
|
|
|
return dict()
|
|
|
|
|
|
|
|
def is_any_aws_instance_alive(self):
|
|
|
|
self.refresh()
|
2016-02-25 09:22:11 +00:00
|
|
|
if not os.path.exists(self.state_filename):
|
2015-12-31 04:10:59 +00:00
|
|
|
log.debug("can't find %s " % self.state_data)
|
|
|
|
return False
|
|
|
|
|
2016-02-25 09:22:11 +00:00
|
|
|
self.read_state_file()
|
2015-12-31 04:10:59 +00:00
|
|
|
try:
|
|
|
|
main_module = self._get_main_module()
|
|
|
|
for resource_key, info in main_module['resources'].items():
|
|
|
|
if 'aws_instance' in resource_key:
|
|
|
|
log.debug("%s is found when read state" % resource_key)
|
|
|
|
return True
|
|
|
|
log.debug("no aws_instance found in resource key")
|
|
|
|
return False
|
|
|
|
except KeyError as err:
|
|
|
|
log.debug(str(err))
|
|
|
|
return False
|
|
|
|
except TypeError as err:
|
|
|
|
log.debug(str(err))
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _get_main_module(self):
|
|
|
|
return self.state_data['modules'][0]
|
|
|
|
|
|
|
|
def get_aws_instances(self):
|
|
|
|
instances = dict()
|
|
|
|
|
|
|
|
try:
|
|
|
|
main_module = self._get_main_module()
|
|
|
|
for resource_key, info in main_module['resources'].items():
|
|
|
|
if 'aws_instance' in resource_key:
|
|
|
|
instances[resource_key] = info
|
|
|
|
except KeyError:
|
|
|
|
return instances
|
|
|
|
except TypeError:
|
|
|
|
return instances
|
|
|
|
|
|
|
|
return instances
|
|
|
|
|
|
|
|
def get_aws_instance(self, resource_name):
|
|
|
|
"""
|
|
|
|
:param resource_name:
|
|
|
|
name of terraform resource, make source count is attached
|
|
|
|
:return: return None if not exist, dict type if exist
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
return self.get_aws_instances()[resource_name]
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_output_value(self, output_name):
|
2016-02-25 09:22:11 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
:param output_name:
|
|
|
|
:return:
|
|
|
|
"""
|
2015-12-31 04:10:59 +00:00
|
|
|
try:
|
|
|
|
main_module = self._get_main_module()
|
|
|
|
return main_module['outputs'][output_name]
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _generate_var_string(d):
|
|
|
|
str_t = []
|
|
|
|
for k, v in d.iteritems():
|
|
|
|
str_t += ['-var'] + ["%s=%s" % (k, v)]
|
|
|
|
|
|
|
|
return str_t
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _generate_targets(targets):
|
|
|
|
str_t = []
|
|
|
|
for t in targets:
|
|
|
|
str_t += ['-target=%s' % t]
|
|
|
|
return str_t
|
|
|
|
|
|
|
|
|
|
|
|
|