diff --git a/.bumpversion.cfg b/.bumpversion.cfg index df6bc15..3de0e74 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.8.4 +current_version = 0.8.5 commit = True tag = False diff --git a/.travis.yml b/.travis.yml index c5bd4f8..9843ea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,10 @@ language: python python: - '2.7' - '3.5' +- '3.6' before_install: sudo apt-get install unzip before_script: - - export TFVER=0.8.1 + - export TFVER=0.9.5 - export TFURL=https://releases.hashicorp.com/terraform/ - TFURL+=$TFVER - TFURL+="/terraform_" diff --git a/README.md b/README.md index 68a6e7a..dae478f 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,27 @@ python-terraform is a python module provide a wrapper of `terraform` command lin pip install python-terraform ## Usage -####For any terraform command +#### For any terraform command from python_terraform import Terraform t = Terraform() return_code, stdout, stderr = t.(*arguments, **options) + +**Note**: method name same as reserved keyword like `import` won't be accepted by python interpreter, +to be able to call the method, you could call cmd_name by adding `_cmd` after command name, for example, +`import` here could be called by + + from python_terraform import Terraform + t = Terraform() + return_code, stdout, stderr = t.import_cmd(*arguments, **options) + +or just call cmd method directly + + from python_terraform import Terraform + t = Terraform() + return_code, stdout, stderr = t.cmd(, *arguments, **options) -####For any argument +#### For any argument simply pass the string to arguments of the method, for example, terraform apply target_dir @@ -24,7 +38,7 @@ simply pass the string to arguments of the method, for example, terraform import aws_instance.foo i-abcd1234 --> .import('aws_instance.foo', 'i-abcd1234') -####For any options +#### For any options * dash to underscore @@ -60,6 +74,15 @@ simply pass the string to arguments of the method, for example, --> tf.apply(var={'a':'b', 'c':'d'}) * if an option with None as value, it won't be used +#### Terraform Output + +By default, stdout and stderr are captured and returned. This causes the application to appear to hang. To print terraform output in real time, provide the `capture_output` option with any value other than `None`. This will cause the output of terraform to be printed to the terminal in real time. The value of `stdout` and `stderr` below will be `None`. + + + from python_terraform import Terraform + t = Terraform() + return_code, stdout, stderr = t.(capture_output=False) + ## Examples ### Have a test.tf file under folder "/home/test" #### 1. apply with variables a=b, c=d, refresh=false, no color in the output @@ -98,15 +121,6 @@ In python-terraform: tf = terraform(working_dir='/home/test') tf.fmt(diff=True) -# Terraform Output - -By default, stdout and stderr are captured and returned. This causes the application to appear to hang. To print terraform output in real time, provide the `capture_output` option with any value other than `None`. This will cause the output of terraform to be printed to the terminal in real time. The value of `stdout` and `stderr` below will be `None`. - - - from python_terraform import Terraform - t = Terraform() - return_code, stdout, stderr = t.(capture_output=False) - ## default values for apply/plan/destroy command, assign with following default value to make diff --git a/python_terraform/__init__.py b/python_terraform/__init__.py index 769350e..fe0d3d3 100644 --- a/python_terraform/__init__.py +++ b/python_terraform/__init__.py @@ -33,8 +33,9 @@ class Terraform(object): variables=None, parallelism=None, var_file=None, - terraform_bin_path=None): - """ + terraform_bin_path=None, + is_env_vars_included=True): + """ :param working_dir: the folder of the working folder, if not given, will be current working folder :param targets: list of target @@ -47,7 +48,10 @@ class Terraform(object): :param var_file: passed as value of -var-file option, could be string or list, list stands for multiple -var-file option :param terraform_bin_path: binary path of terraform + :type is_env_vars_included: bool + :param is_env_vars_included: included env variables when calling terraform cmd """ + self.is_env_vars_included = is_env_vars_included self.working_dir = working_dir self.state = state self.targets = [] if targets is None else targets @@ -64,8 +68,11 @@ class Terraform(object): def __getattr__(self, item): def wrapper(*args, **kwargs): + cmd_name = str(item) + if cmd_name.endswith('_cmd'): + cmd_name = cmd_name[:-4] logging.debug('called with %r and %r' % (args, kwargs)) - return self.cmd(item, *args, **kwargs) + return self.cmd(cmd_name, *args, **kwargs) return wrapper @@ -222,9 +229,12 @@ class Terraform(object): working_folder = self.working_dir if self.working_dir else None - p = subprocess.Popen(cmd_string, stdout=stdout, - stderr=stderr, shell=True, - cwd=working_folder) + environ_vars = {} + if self.is_env_vars_included: + environ_vars = os.environ.copy() + + p = subprocess.Popen(cmd_string, stdout=stdout, stderr=stderr, shell=True, + cwd=working_folder, env=environ_vars) out, err = p.communicate() ret_code = p.returncode log.debug('output: {o}'.format(o=out)) diff --git a/setup.py b/setup.py index 02e6aa1..e2011fe 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ except IOError: setup( name=module_name, - version='0.8.4', + version='0.8.5', url='https://github.com/beelit94/python-terraform', license='MIT', author='Freddy Tan', diff --git a/test/test_terraform.py b/test/test_terraform.py index eacb781..0a2487d 100644 --- a/test/test_terraform.py +++ b/test/test_terraform.py @@ -1,3 +1,7 @@ +try: + from cStringIO import StringIO # Python 2 +except ImportError: + from io import StringIO from python_terraform import * import pytest import os @@ -6,6 +10,9 @@ import re import shutil logging.basicConfig(level=logging.DEBUG) +root_logger = logging.getLogger() +# ch = logging.StreamHandler(sys.stdout) +# root_logger.addHandler(ch) current_path = os.path.dirname(os.path.realpath(__file__)) STRING_CASES = [ @@ -23,11 +30,20 @@ STRING_CASES = [ ] CMD_CASES = [ - ['method', 'expected_output'], + ['method', 'expected_output', 'expected_ret_code', 'expected_logs'], [ [ lambda x: x.cmd('plan', 'var_to_output', no_color=IsFlagged, var={'test_var': 'test'}) , - "doesn't need to do anything" + "doesn't need to do anything", + 0, + '' + ], + # try import aws instance + [ + lambda x: x.cmd('import', 'aws_instance.foo', 'i-abcd1234', no_color=IsFlagged), + '', + 1, + 'command: terraform import -no-color aws_instance.foo i-abcd1234' ] ] ] @@ -47,6 +63,19 @@ def fmt_test_file(request): return +@pytest.fixture() +def string_logger(request): + log_stream = StringIO() + handler = logging.StreamHandler(log_stream) + root_logger.addHandler(handler) + + def td(): + root_logger.removeHandler(handler) + + request.addfinalizer(td) + return log_stream + + class TestTerraform(object): def teardown_method(self, method): """ teardown any state that was previously setup with a setup_method @@ -73,11 +102,14 @@ class TestTerraform(object): assert s in result @pytest.mark.parametrize(*CMD_CASES) - def test_cmd(self, method, expected_output): + def test_cmd(self, method, expected_output, expected_ret_code, expected_logs, string_logger): tf = Terraform(working_dir=current_path) ret, out, err = method(tf) + logs = str(string_logger.getvalue()) + logs = logs.replace('\n', '') assert expected_output in out - assert ret == 0 + assert expected_ret_code == ret + assert expected_logs in logs @pytest.mark.parametrize( ("folder", "variables", "var_files", "expected_output", "options"), @@ -161,3 +193,10 @@ class TestTerraform(object): tf = Terraform(working_dir=current_path, variables={'test_var': 'test'}) ret, out, err = tf.fmt(diff=True) assert ret == 0 + + def test_import(self, string_logger): + tf = Terraform(working_dir=current_path) + tf.import_cmd('aws_instance.foo', 'i-abc1234', no_color=IsFlagged) + logs = string_logger.getvalue() + print(logs) + assert 'command: terraform import -no-color aws_instance.foo i-abc1234' in logs diff --git a/test/vars_require_input/main.tf b/test/vars_require_input/main.tf index 43e8e65..d3eaed3 100644 --- a/test/vars_require_input/main.tf +++ b/test/vars_require_input/main.tf @@ -10,11 +10,11 @@ variable "list" { variable "map" { default = {} - type = "map" + type = "map" } resource "aws_instance" "bar" { foo = "${var.ami}" bar = "${join(",", var.list)}" baz = "${join(",", keys(var.map))}" -} \ No newline at end of file +} diff --git a/tox.ini b/tox.ini index 9d0b810..1f9a9cd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ # content of: tox.ini , put in same dir as setup.py [tox] -envlist = py27, py35 +envlist = py27, py35, py36 [testenv] deps=pytest commands=py.test test @@ -8,4 +8,5 @@ commands=py.test test [travis] python = 2.7: py27 - 3.5: py35 \ No newline at end of file + 3.5: py35 + 3.6: py36 \ No newline at end of file