From f1c7a7e952e132e7bb0d8ec8a738804e0f2b2434 Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 31 Dec 2015 12:27:32 +0800 Subject: [PATCH 1/9] 1. move to package folder 2. fix setup.py --- setup.py | 52 +++++++++++++++++++++++++++ terraform.py => terraform/__init__.py | 0 2 files changed, 52 insertions(+) create mode 100644 setup.py rename terraform.py => terraform/__init__.py (100%) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fa99e73 --- /dev/null +++ b/setup.py @@ -0,0 +1,52 @@ +""" +My Tool does one thing, and one thing well. +""" +from distutils.core import setup +import os + +dependencies = [] +module_name = 'terraform' + + +setup( + name=module_name, + version="0.0.1", + url='https://github.com/beelit94/tsplk', + license='BSD', + author='Freddy Tan', + author_email='ftan@splunk.com', + description='My Tool does one thing, and one thing well.', + long_description=__doc__, + packages=[module_name], + include_package_data=True, + package_data={}, + zip_safe=False, + platforms='any', + install_requires=dependencies, + entry_points={ + # 'console_scripts': [ + # 'tsplk = %s.cli:main' % module_name, + # ], + }, + classifiers=[ + # As from http://pypi.python.org/pypi?%3Aaction=list_classifiers + # 'Development Status :: 1 - Planning', + # 'Development Status :: 2 - Pre-Alpha', + # 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', + # 'Development Status :: 5 - Production/Stable', + # 'Development Status :: 6 - Mature', + # 'Development Status :: 7 - Inactive', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: POSIX', + 'Operating System :: MacOS', + 'Operating System :: Unix', + 'Operating System :: Windows', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Libraries :: Python Modules', + ] +) diff --git a/terraform.py b/terraform/__init__.py similarity index 100% rename from terraform.py rename to terraform/__init__.py From 02a8de561878b0e3a99a5046ec8f337b19d6983a Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 31 Dec 2015 12:34:35 +0800 Subject: [PATCH 2/9] move test folder --- terraform/__init__.py | 5 ++--- test.tf => test/test.tf | 0 test_terraform.py => test/test_terraform.py | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename test.tf => test/test.tf (100%) rename test_terraform.py => test/test_terraform.py (100%) diff --git a/terraform/__init__.py b/terraform/__init__.py index 20b9fa6..d60ddd8 100644 --- a/terraform/__init__.py +++ b/terraform/__init__.py @@ -12,6 +12,7 @@ class Terraform: self.state = state self.variables = dict() if variables is None else variables self.state_data = None + self.parallelism = 50 def apply(self, targets=None, variables=None): variables = self.variables if variables is None else variables @@ -20,9 +21,7 @@ class Terraform: parameters = [] parameters += self._generate_targets(targets) parameters += self._generate_var_string(variables) - # hard code 30 for splunk aws limit on us-west-2 region, - # todo move this to somewhere else - parameters += ['-parallelism=30'] + parameters += ['-parallelism=%s' % self.parallelism] parameters = \ ['terraform', 'apply', '-state=%s' % self.state] + parameters diff --git a/test.tf b/test/test.tf similarity index 100% rename from test.tf rename to test/test.tf diff --git a/test_terraform.py b/test/test_terraform.py similarity index 100% rename from test_terraform.py rename to test/test_terraform.py From cc435e289d490c75b62281f6b5b65053d28fd2a5 Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 31 Dec 2015 14:48:26 +0800 Subject: [PATCH 3/9] 1. refactor setup.py 2. add doc --- README.md | 6 ++++++ setup.py | 9 ++------- terraform/__init__.py | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..f6903fa --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +## Introduction + +python-terraform is a python module provide a wrapper of `terraform` command line tool. +`terraform` is a tool made by Hashicorp, please refer to https://terraform.io/ + +## This project is not stable yet \ No newline at end of file diff --git a/setup.py b/setup.py index fa99e73..24fb6f5 100644 --- a/setup.py +++ b/setup.py @@ -11,11 +11,11 @@ module_name = 'terraform' setup( name=module_name, version="0.0.1", - url='https://github.com/beelit94/tsplk', + url='https://github.com/beelit94/python-terraform', license='BSD', author='Freddy Tan', author_email='ftan@splunk.com', - description='My Tool does one thing, and one thing well.', + description='This is a python module provide a wrapper of terraform command line tool', long_description=__doc__, packages=[module_name], include_package_data=True, @@ -23,11 +23,6 @@ setup( zip_safe=False, platforms='any', install_requires=dependencies, - entry_points={ - # 'console_scripts': [ - # 'tsplk = %s.cli:main' % module_name, - # ], - }, classifiers=[ # As from http://pypi.python.org/pypi?%3Aaction=list_classifiers # 'Development Status :: 1 - Planning', diff --git a/terraform/__init__.py b/terraform/__init__.py index d60ddd8..6eeb54e 100644 --- a/terraform/__init__.py +++ b/terraform/__init__.py @@ -15,6 +15,9 @@ class Terraform: self.parallelism = 50 def apply(self, targets=None, variables=None): + """ + refer to https://terraform.io/docs/commands/apply.html + """ variables = self.variables if variables is None else variables targets = self.targets if targets is None else targets From a0975baeb1afc518a56bd7f2c7d6dd1d07b11316 Mon Sep 17 00:00:00 2001 From: beelit94 Date: Thu, 31 Dec 2015 14:51:32 +0800 Subject: [PATCH 4/9] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 24fb6f5..30ab15b 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( url='https://github.com/beelit94/python-terraform', license='BSD', author='Freddy Tan', - author_email='ftan@splunk.com', + author_email='beelit94@gmail.com', description='This is a python module provide a wrapper of terraform command line tool', long_description=__doc__, packages=[module_name], From 7e2d95a77f19ed8578724927ece717a0c3a3c9fd Mon Sep 17 00:00:00 2001 From: beelit94 Date: Thu, 31 Dec 2015 14:57:23 +0800 Subject: [PATCH 5/9] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f6903fa..64cb5d5 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,7 @@ python-terraform is a python module provide a wrapper of `terraform` command line tool. `terraform` is a tool made by Hashicorp, please refer to https://terraform.io/ -## This project is not stable yet \ No newline at end of file +## This project is not stable yet + +## Installation + pip install git+https://github.com/beelit94/python-terraform.git@develop From 4ebdc607dc014408e2f2495cc5edb113d4a553e7 Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 31 Dec 2015 15:15:51 +0800 Subject: [PATCH 6/9] update --- .gitignore | 1 + terraform/__init__.py | 8 +++++--- test/__init__.py | 0 test/test_terraform.py | 20 ++++++++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 test/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/terraform/__init__.py b/terraform/__init__.py index 6eeb54e..7e534d2 100644 --- a/terraform/__init__.py +++ b/terraform/__init__.py @@ -9,8 +9,9 @@ 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.state = state self.variables = dict() if variables is None else variables + + self.state = state self.state_data = None self.parallelism = 50 @@ -33,11 +34,13 @@ class Terraform: def _run_cmd(self, cmd): log.debug('command: ' + cmd) + p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = p.communicate() ret_code = p.returncode log.debug('output: ' + out) + if ret_code == 0: log.debug('error: ' + err) self.read_state() @@ -50,8 +53,7 @@ class Terraform: parameters = [] parameters += self._generate_targets(targets) parameters += self._generate_var_string(variables) - # hard code 19 for splunk aws limit on us-west-2 region, - # todo move parallelism? + parameters = \ ['terraform', 'destroy', '-force', '-state=%s' % self.state] + \ parameters diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_terraform.py b/test/test_terraform.py index e69de29..00c4e02 100644 --- a/test/test_terraform.py +++ b/test/test_terraform.py @@ -0,0 +1,20 @@ +from terraform import Terraform + + +class TestTerraform: + def test_apply(self): + tf = Terraform() + + tf.apply() + + def test_refresh(self): + tf = Terraform() + + tf.refresh() + + def test_destroy(self): + tf = Terraform() + + tf.destroy() + + \ No newline at end of file From 4ef52dca4483d51ceb0561594091dc948b5c211a Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 25 Feb 2016 17:22:11 +0800 Subject: [PATCH 7/9] refactor --- .gitignore | 2 + VERSION | 1 + {terraform => python_terraform}/__init__.py | 48 ++++++++++++++------- setup.py | 16 +++++-- test/test.tf | 24 +++++++++++ test/test_terraform.py | 23 ++++------ 6 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 VERSION rename {terraform => python_terraform}/__init__.py (79%) diff --git a/.gitignore b/.gitignore index 7e99e36..aaa8228 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +*.tfstate +*.tfstate.backup *.pyc \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..8a9ecc2 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file diff --git a/terraform/__init__.py b/python_terraform/__init__.py similarity index 79% rename from terraform/__init__.py rename to python_terraform/__init__.py index 7e534d2..ce1a649 100644 --- a/terraform/__init__.py +++ b/python_terraform/__init__.py @@ -11,13 +11,16 @@ class Terraform: self.targets = [] if targets is None else targets self.variables = dict() if variables is None else variables - self.state = state - self.state_data = None + self.state_filename = state + self.state_data = dict() self.parallelism = 50 - def apply(self, targets=None, variables=None): + def apply(self, targets=None, variables=None, **kargs): """ refer to https://terraform.io/docs/commands/apply.html + :param variables: variables in dict type + :param targets: targets in list + :returns return_code, stdout, stderr """ variables = self.variables if variables is None else variables targets = self.targets if targets is None else targets @@ -25,13 +28,20 @@ class Terraform: parameters = [] parameters += self._generate_targets(targets) parameters += self._generate_var_string(variables) - parameters += ['-parallelism=%s' % self.parallelism] + parameters += self._gen_param_string(kargs) + parameters = \ - ['terraform', 'apply', '-state=%s' % self.state] + parameters + ['terraform', 'apply', '-state=%s' % self.state_filename] + parameters cmd = ' '.join(parameters) return self._run_cmd(cmd) + def _gen_param_string(self, kargs): + params = [] + for key, value in kargs.items(): + params += ['%s=%s' % (key, value)] + return params + def _run_cmd(self, cmd): log.debug('command: ' + cmd) @@ -43,10 +53,10 @@ class Terraform: if ret_code == 0: log.debug('error: ' + err) - self.read_state() + self.read_state_file() return ret_code, out, err - def destroy(self, targets=None, variables=None): + def destroy(self, targets=None, variables=None, **kwargs): variables = self.variables if variables is None else variables targets = self.targets if targets is None else targets @@ -55,7 +65,7 @@ class Terraform: parameters += self._generate_var_string(variables) parameters = \ - ['terraform', 'destroy', '-force', '-state=%s' % self.state] + \ + ['terraform', 'destroy', '-force', '-state=%s' % self.state_filename] + \ parameters cmd = ' '.join(parameters) return self._run_cmd(cmd) @@ -68,15 +78,18 @@ class Terraform: parameters += self._generate_targets(targets) parameters += self._generate_var_string(variables) parameters = \ - ['terraform', 'refresh', '-state=%s' % self.state] + \ + ['terraform', 'refresh', '-state=%s' % self.state_filename] + \ parameters cmd = ' '.join(parameters) return self._run_cmd(cmd) - def read_state(self, state=None): - state = self.state if state is None else state - if os.path.exists(state): - with open(state) as f: + 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: json_data = json.load(f) self.state_data = json_data log.debug("state_data=%s" % str(self.state_data)) @@ -86,11 +99,11 @@ class Terraform: def is_any_aws_instance_alive(self): self.refresh() - if not os.path.exists(self.state): + if not os.path.exists(self.state_filename): log.debug("can't find %s " % self.state_data) return False - self.read_state() + self.read_state_file() try: main_module = self._get_main_module() for resource_key, info in main_module['resources'].items(): @@ -136,6 +149,11 @@ class Terraform: return None def get_output_value(self, output_name): + """ + + :param output_name: + :return: + """ try: main_module = self._get_main_module() return main_module['outputs'][output_name] diff --git a/setup.py b/setup.py index 30ab15b..3c4bbe0 100644 --- a/setup.py +++ b/setup.py @@ -5,19 +5,29 @@ from distutils.core import setup import os dependencies = [] -module_name = 'terraform' +module_name = 'python-terraform' +def get_version(): + p = os.path.join(os.path.dirname( + os.path.abspath(__file__)), "VERSION") + with open(p) as f: + version = f.read() + version = version.strip() + if not version: + raise ValueError("could not read version") + return version + setup( name=module_name, - version="0.0.1", + version=get_version(), url='https://github.com/beelit94/python-terraform', license='BSD', author='Freddy Tan', author_email='beelit94@gmail.com', description='This is a python module provide a wrapper of terraform command line tool', long_description=__doc__, - packages=[module_name], + packages=['python_terraform'], include_package_data=True, package_data={}, zip_safe=False, diff --git a/test/test.tf b/test/test.tf index e69de29..6219dce 100644 --- a/test/test.tf +++ b/test/test.tf @@ -0,0 +1,24 @@ +variable "access_key" {} +variable "secret_key" {} + +provider "aws" { + access_key = "${var.access_key}" + secret_key = "${var.secret_key}" + region = "us-west-2" +} + +resource "aws_instance" "ubuntu-1404" { + ami = "ami-9abea4fb" + instance_type = "t2.micro" + security_groups = ["terraform-salty-splunk"] + tags { + Name = "python-terraform-test" + } +// key_name = "${aws_key_pair.key.key_name}" +// connection { +// type = "ssh" +// user = "ubuntu" +// key_file = "${var.key_path}" +// timeout = "10m" +// } +} \ No newline at end of file diff --git a/test/test_terraform.py b/test/test_terraform.py index 00c4e02..6fbdd32 100644 --- a/test/test_terraform.py +++ b/test/test_terraform.py @@ -1,20 +1,15 @@ -from terraform import Terraform +from python_terraform import Terraform class TestTerraform: - def test_apply(self): - tf = Terraform() - - tf.apply() + def test_apply_and_destory(self): + tf = Terraform() + ret_code, out, err = tf.apply() - def test_refresh(self): - tf = Terraform() + print out + print err + # assert ret_code, 0 - tf.refresh() + ret_code, out, err = tf.destroy() - def test_destroy(self): - tf = Terraform() - - tf.destroy() - - \ No newline at end of file + assert ret_code, 0 From cb835a5aa81cc7301b76c4c683b748f4fcc45d5d Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 25 Feb 2016 17:22:37 +0800 Subject: [PATCH 8/9] add release script --- release.py | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 release.py diff --git a/release.py b/release.py new file mode 100644 index 0000000..cc703cf --- /dev/null +++ b/release.py @@ -0,0 +1,104 @@ +import subprocess +import click +import os +from distutils.version import StrictVersion +import shutil +import re + + +def get_version(): + p = get_version_file_path() + with open(p) as f: + version = f.read() + version = version.strip() + if not version: + raise ValueError("could not read version") + return version + + +def write_version(version_tuple): + p = get_version_file_path() + with open(p, 'w+') as f: + f.write('.'.join([str(i) for i in version_tuple])) + + +def get_version_file_path(): + p = os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'VERSION') + return p + + +def release_patch(version_tuple): + patch_version = version_tuple[2] + 1 + new_version = version_tuple[:2] + (patch_version,) + click.echo('new version: %s' % str(new_version)) + write_version(new_version) + return new_version + + +def release_minor(version_tuple): + minor = version_tuple[1] + 1 + new_version = version_tuple[:1] + (minor, 0) + click.echo('new version: %s' % str(new_version)) + write_version(new_version) + return new_version + + +def release_major(version_tuple): + major = version_tuple[0] + 1 + new = (major, 0, 0) + click.echo('new version: %s' % str(new)) + write_version(new) + return new + + +@click.command() +@click.option('--release', '-r', type=click.Choice(['major', 'minor', 'patch']), default='patch') +@click.option('--url', prompt=True, default=lambda: os.environ.get('FURY_URL', '')) +def main(release, url): + version_tuple = StrictVersion(get_version()).version + click.echo('old version: %s' % str(version_tuple)) + + if release == 'major': + new_v = release_major(version_tuple) + elif release == 'minor': + new_v = release_minor(version_tuple) + else: + new_v = release_patch(version_tuple) + + new_v_s = '.'.join([str(i) for i in new_v]) + + os.chdir(os.path.dirname(os.path.abspath(__file__))) + subprocess.call("python setup.py sdist", shell=True) + + pkg_file = '' + for f in os.listdir('dist'): + r = re.compile(r'.*(%s\.tar\.gz)' % re.escape(new_v_s)) + result = r.match(f) + if result: + click.echo(f + ' is ready') + pkg_file = f + + break + + if not pkg_file: + raise ValueError + + this_folder = os.path.dirname(os.path.abspath(__file__)) + dist_folder = os.path.join(this_folder, 'dist') + pkg_file_name = pkg_file + pkg_file = os.path.join(dist_folder, pkg_file) + + shutil.move(pkg_file, this_folder) + shutil.rmtree(dist_folder) + os.remove('MANIFEST') + is_release = click.confirm('ready to release?') + + if is_release: + subprocess.call('curl -F package=@%s %s' % (pkg_file_name, url), + shell=True) + os.remove(pkg_file_name) + + +if __name__ == '__main__': + main() From 19b502f675c0d732ec952b330b32081084ccae34 Mon Sep 17 00:00:00 2001 From: Freddy Tan Date: Thu, 25 Feb 2016 17:38:05 +0800 Subject: [PATCH 9/9] release 0.0.2 to fury --- .gitignore | 4 +++- MANIFEST.in | 1 + VERSION | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 MANIFEST.in diff --git a/.gitignore b/.gitignore index aaa8228..db6d66b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.tfstate *.tfstate.backup -*.pyc \ No newline at end of file +*.pyc +*.egg-info +.idea \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..b1fc69e --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include VERSION \ No newline at end of file diff --git a/VERSION b/VERSION index 8a9ecc2..7bcd0e3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.0.2 \ No newline at end of file