Merge branch 'release/0.0.2'

This commit is contained in:
Freddy Tan 2016-02-25 17:38:12 +08:00
commit f99e58455e
11 changed files with 257 additions and 19 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.tfstate
*.tfstate.backup
*.pyc
*.egg-info
.idea

1
MANIFEST.in Normal file
View file

@ -0,0 +1 @@
include VERSION

9
README.md Normal file
View file

@ -0,0 +1,9 @@
## 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
## Installation
pip install git+https://github.com/beelit94/python-terraform.git@develop

1
VERSION Normal file
View file

@ -0,0 +1 @@
0.0.2

View file

@ -9,49 +9,63 @@ log = logging.getLogger(__name__)
class Terraform: class Terraform:
def __init__(self, targets=None, state='terraform.tfstate', variables=None): def __init__(self, targets=None, state='terraform.tfstate', variables=None):
self.targets = [] if targets is None else targets self.targets = [] if targets is None else targets
self.state = state
self.variables = dict() if variables is None else variables self.variables = dict() if variables is None else variables
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 variables = self.variables if variables is None else variables
targets = self.targets if targets is None else targets targets = self.targets if targets is None else targets
parameters = [] parameters = []
parameters += self._generate_targets(targets) parameters += self._generate_targets(targets)
parameters += self._generate_var_string(variables) parameters += self._generate_var_string(variables)
# hard code 30 for splunk aws limit on us-west-2 region, parameters += self._gen_param_string(kargs)
# todo move this to somewhere else
parameters += ['-parallelism=30']
parameters = \ parameters = \
['terraform', 'apply', '-state=%s' % self.state] + parameters ['terraform', 'apply', '-state=%s' % self.state_filename] + parameters
cmd = ' '.join(parameters) cmd = ' '.join(parameters)
return self._run_cmd(cmd) 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): def _run_cmd(self, cmd):
log.debug('command: ' + cmd) log.debug('command: ' + cmd)
p = subprocess.Popen( p = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate() out, err = p.communicate()
ret_code = p.returncode ret_code = p.returncode
log.debug('output: ' + out) log.debug('output: ' + out)
if ret_code == 0: if ret_code == 0:
log.debug('error: ' + err) log.debug('error: ' + err)
self.read_state() self.read_state_file()
return ret_code, out, err 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 variables = self.variables if variables is None else variables
targets = self.targets if targets is None else targets targets = self.targets if targets is None else targets
parameters = [] parameters = []
parameters += self._generate_targets(targets) parameters += self._generate_targets(targets)
parameters += self._generate_var_string(variables) parameters += self._generate_var_string(variables)
# hard code 19 for splunk aws limit on us-west-2 region,
# todo move parallelism?
parameters = \ parameters = \
['terraform', 'destroy', '-force', '-state=%s' % self.state] + \ ['terraform', 'destroy', '-force', '-state=%s' % self.state_filename] + \
parameters parameters
cmd = ' '.join(parameters) cmd = ' '.join(parameters)
return self._run_cmd(cmd) return self._run_cmd(cmd)
@ -64,15 +78,18 @@ class Terraform:
parameters += self._generate_targets(targets) parameters += self._generate_targets(targets)
parameters += self._generate_var_string(variables) parameters += self._generate_var_string(variables)
parameters = \ parameters = \
['terraform', 'refresh', '-state=%s' % self.state] + \ ['terraform', 'refresh', '-state=%s' % self.state_filename] + \
parameters parameters
cmd = ' '.join(parameters) cmd = ' '.join(parameters)
return self._run_cmd(cmd) return self._run_cmd(cmd)
def read_state(self, state=None): def read_state_file(self):
state = self.state if state is None else state """
if os.path.exists(state): read .tfstate file
with open(state) as f: :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) json_data = json.load(f)
self.state_data = json_data self.state_data = json_data
log.debug("state_data=%s" % str(self.state_data)) log.debug("state_data=%s" % str(self.state_data))
@ -82,11 +99,11 @@ class Terraform:
def is_any_aws_instance_alive(self): def is_any_aws_instance_alive(self):
self.refresh() 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) log.debug("can't find %s " % self.state_data)
return False return False
self.read_state() self.read_state_file()
try: try:
main_module = self._get_main_module() main_module = self._get_main_module()
for resource_key, info in main_module['resources'].items(): for resource_key, info in main_module['resources'].items():
@ -132,6 +149,11 @@ class Terraform:
return None return None
def get_output_value(self, output_name): def get_output_value(self, output_name):
"""
:param output_name:
:return:
"""
try: try:
main_module = self._get_main_module() main_module = self._get_main_module()
return main_module['outputs'][output_name] return main_module['outputs'][output_name]

104
release.py Normal file
View file

@ -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()

57
setup.py Normal file
View file

@ -0,0 +1,57 @@
"""
My Tool does one thing, and one thing well.
"""
from distutils.core import setup
import os
dependencies = []
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=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=['python_terraform'],
include_package_data=True,
package_data={},
zip_safe=False,
platforms='any',
install_requires=dependencies,
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',
]
)

24
test/test.tf Normal file
View file

@ -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"
// }
}

15
test/test_terraform.py Normal file
View file

@ -0,0 +1,15 @@
from python_terraform import Terraform
class TestTerraform:
def test_apply_and_destory(self):
tf = Terraform()
ret_code, out, err = tf.apply()
print out
print err
# assert ret_code, 0
ret_code, out, err = tf.destroy()
assert ret_code, 0

View file