Skip to content

Commit 9afa4e1

Browse files
committed
Merge branch 'release/0.9.1'
2 parents d23f85a + 3c9ea8b commit 9afa4e1

File tree

7 files changed

+221
-29
lines changed

7 files changed

+221
-29
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.9.0
2+
current_version = 0.9.1
33
commit = True
44
tag = False
55

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# Changelog
2+
## [0.9.1]
3+
1. [#10] log handler error on Linux environment
4+
1. [#11] Fix reading state file for remote state and support backend config for
5+
init command
26
## [0.9.0]
37
### Fixed
48
1. [#12] Output function doesn't accept parameter 'module'

python_terraform/__init__.py

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@
1010

1111
from python_terraform.tfstate import Tfstate
1212

13+
try: # Python 2.7+
14+
from logging import NullHandler
15+
except ImportError:
16+
class NullHandler(logging.Handler):
17+
def emit(self, record):
18+
pass
19+
1320
log = logging.getLogger(__name__)
21+
log.addHandler(NullHandler())
1422

1523

1624
class IsFlagged:
@@ -76,7 +84,8 @@ def wrapper(*args, **kwargs):
7684

7785
return wrapper
7886

79-
def apply(self, dir_or_plan=None, input=False, no_color=IsFlagged, **kwargs):
87+
def apply(self, dir_or_plan=None, input=False, no_color=IsFlagged,
88+
**kwargs):
8089
"""
8190
refer to https://terraform.io/docs/commands/apply.html
8291
no-color is flagged by default
@@ -122,7 +131,7 @@ def destroy(self, dir_or_plan=None, force=IsFlagged, **kwargs):
122131

123132
def plan(self, dir_or_plan=None, detailed_exitcode=IsFlagged, **kwargs):
124133
"""
125-
refert to https://www.terraform.io/docs/commands/plan.html
134+
refer to https://www.terraform.io/docs/commands/plan.html
126135
:param detailed_exitcode: Return a detailed exit code when the command exits.
127136
:param dir_or_plan: relative path to plan/folder
128137
:param kwargs: options
@@ -134,6 +143,32 @@ def plan(self, dir_or_plan=None, detailed_exitcode=IsFlagged, **kwargs):
134143
args = self._generate_default_args(dir_or_plan)
135144
return self.cmd('plan', *args, **options)
136145

146+
def init(self, dir_or_plan=None, backend_config=None,
147+
reconfigure=IsFlagged, backend=True, **kwargs):
148+
"""
149+
refer to https://www.terraform.io/docs/commands/init.html
150+
151+
By default, this assumes you want to use backend config, and tries to
152+
init fresh. The flags -reconfigure and -backend=true are default.
153+
154+
:param dir_or_plan: relative path to the folder want to init
155+
:param backend_config: a dictionary of backend config options. eg.
156+
t = Terraform()
157+
t.init(backend_config={'access_key': 'myaccesskey',
158+
'secret_key': 'mysecretkey', 'bucket': 'mybucketname'})
159+
:param reconfigure: whether or not to force reconfiguration of backend
160+
:param backend: whether or not to use backend settings for init
161+
:param kwargs: options
162+
:return: ret_code, stdout, stderr
163+
"""
164+
options = kwargs
165+
options['backend_config'] = backend_config
166+
options['reconfigure'] = reconfigure
167+
options['backend'] = backend
168+
options = self._generate_default_options(options)
169+
args = self._generate_default_args(dir_or_plan)
170+
return self.cmd('init', *args, **options)
171+
137172
def generate_cmd_string(self, cmd, *args, **kwargs):
138173
"""
139174
for any generate_cmd_string doesn't written as public method of terraform
@@ -161,35 +196,40 @@ def generate_cmd_string(self, cmd, *args, **kwargs):
161196
cmds = cmd.split()
162197
cmds = [self.terraform_bin_path] + cmds
163198

164-
for k, v in kwargs.items():
165-
if '_' in k:
166-
k = k.replace('_', '-')
199+
for option, value in kwargs.items():
200+
if '_' in option:
201+
option = option.replace('_', '-')
167202

168-
if type(v) is list:
169-
for sub_v in v:
170-
cmds += ['-{k}={v}'.format(k=k, v=sub_v)]
203+
if type(value) is list:
204+
for sub_v in value:
205+
cmds += ['-{k}={v}'.format(k=option, v=sub_v)]
171206
continue
172207

173-
# right now we assume only variables will be passed as dict
174-
# since map type sent in string won't work, create temp var file for
175-
# variables, and clean it up later
176-
if type(v) is dict:
177-
filename = self.temp_var_files.create(v)
178-
cmds += ['-var-file={0}'.format(filename)]
179-
continue
208+
if type(value) is dict:
209+
if 'backend-config' in option:
210+
for bk, bv in value.items():
211+
cmds += ['-backend-config={k}={v}'.format(k=bk, v=bv)]
212+
continue
213+
214+
# since map type sent in string won't work, create temp var file for
215+
# variables, and clean it up later
216+
else:
217+
filename = self.temp_var_files.create(value)
218+
cmds += ['-var-file={0}'.format(filename)]
219+
continue
180220

181221
# simple flag,
182-
if v is IsFlagged:
183-
cmds += ['-{k}'.format(k=k)]
222+
if value is IsFlagged:
223+
cmds += ['-{k}'.format(k=option)]
184224
continue
185225

186-
if v is None or v is IsNotFlagged:
226+
if value is None or value is IsNotFlagged:
187227
continue
188228

189-
if type(v) is bool:
190-
v = 'true' if v else 'false'
229+
if type(value) is bool:
230+
value = 'true' if value else 'false'
191231

192-
cmds += ['-{k}={v}'.format(k=k, v=v)]
232+
cmds += ['-{k}={v}'.format(k=option, v=value)]
193233

194234
cmds += args
195235
return cmds
@@ -274,14 +314,20 @@ def read_state_file(self, file_path=None):
274314
:return: states file in dict type
275315
"""
276316

277-
if not file_path:
278-
file_path = self.state
317+
working_dir = self.working_dir or ''
318+
319+
file_path = file_path or self.state or ''
279320

280321
if not file_path:
281-
file_path = 'terraform.tfstate'
322+
backend_path = os.path.join(file_path, '.terraform',
323+
'terraform.tfstate')
324+
325+
if os.path.exists(os.path.join(working_dir, backend_path)):
326+
file_path = backend_path
327+
else:
328+
file_path = os.path.join(file_path, 'terraform.tfstate')
282329

283-
if self.working_dir:
284-
file_path = os.path.join(self.working_dir, file_path)
330+
file_path = os.path.join(working_dir, file_path)
285331

286332
self.tfstate = Tfstate.load_file(file_path)
287333

@@ -297,7 +343,8 @@ def create(self, variables):
297343
with tempfile.NamedTemporaryFile('w+t', delete=False) as temp:
298344
log.debug('{0} is created'.format(temp.name))
299345
self.files.append(temp)
300-
log.debug('variables wrote to tempfile: {0}'.format(str(variables)))
346+
log.debug(
347+
'variables wrote to tempfile: {0}'.format(str(variables)))
301348
temp.write(json.dumps(variables))
302349
file_name = temp.name
303350

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
setup(
2222
name=module_name,
23-
version='0.9.0',
23+
version='0.9.1',
2424
url='https://github.com/beelit94/python-terraform',
2525
license='MIT',
2626
author='Freddy Tan',

test/test_terraform.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,13 @@ def teardown_method(self, method):
9292
""" teardown any state that was previously setup with a setup_method
9393
call.
9494
"""
95+
exclude = ['test_tfstate_file',
96+
'test_tfstate_file2',
97+
'test_tfstate_file3']
9598

9699
def purge(dir, pattern):
97100
for root, dirnames, filenames in os.walk(dir):
101+
dirnames[:] = [d for d in dirnames if d not in exclude]
98102
for filename in fnmatch.filter(filenames, pattern):
99103
f = os.path.join(root, filename)
100104
os.remove(f)
@@ -103,6 +107,7 @@ def purge(dir, pattern):
103107
shutil.rmtree(d)
104108

105109
purge('.', '*.tfstate')
110+
purge('.', '*.tfstate.backup')
106111
purge('.', '*.terraform')
107112
purge('.', FILE_PATH_WITH_SPACE_AND_SPACIAL_CHARS)
108113

@@ -166,6 +171,18 @@ def test_state_data(self):
166171
tf.read_state_file()
167172
assert tf.tfstate.modules[0]['path'] == ['root']
168173

174+
def test_state_default(self):
175+
cwd = os.path.join(current_path, 'test_tfstate_file2')
176+
tf = Terraform(working_dir=cwd)
177+
tf.read_state_file()
178+
assert tf.tfstate.modules[0]['path'] == ['default']
179+
180+
def test_state_default_backend(self):
181+
cwd = os.path.join(current_path, 'test_tfstate_file3')
182+
tf = Terraform(working_dir=cwd)
183+
tf.read_state_file()
184+
assert tf.tfstate.modules[0]['path'] == ['default_backend']
185+
169186
def test_pre_load_state_data(self):
170187
cwd = os.path.join(current_path, 'test_tfstate_file')
171188
tf = Terraform(working_dir=cwd, state='tfstate.test')
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"version": 3,
3+
"terraform_version": "0.7.10",
4+
"serial": 0,
5+
"lineage": "d03ecdf7-8be0-4593-a952-1d8127875119",
6+
"modules": [
7+
{
8+
"path": [
9+
"default"
10+
],
11+
"outputs": {},
12+
"resources": {
13+
"aws_instance.ubuntu-1404": {
14+
"type": "aws_instance",
15+
"depends_on": [],
16+
"primary": {
17+
"id": "i-84d10edb",
18+
"attributes": {
19+
"ami": "ami-9abea4fb",
20+
"associate_public_ip_address": "true",
21+
"availability_zone": "us-west-2b",
22+
"disable_api_termination": "false",
23+
"ebs_block_device.#": "0",
24+
"ebs_optimized": "false",
25+
"ephemeral_block_device.#": "0",
26+
"iam_instance_profile": "",
27+
"id": "i-84d10edb",
28+
"instance_state": "running",
29+
"instance_type": "t2.micro",
30+
"key_name": "",
31+
"monitoring": "false",
32+
"network_interface_id": "eni-46544f07",
33+
"private_dns": "ip-172-31-25-244.us-west-2.compute.internal",
34+
"private_ip": "172.31.25.244",
35+
"public_dns": "ec2-35-162-30-219.us-west-2.compute.amazonaws.com",
36+
"public_ip": "35.162.30.219",
37+
"root_block_device.#": "1",
38+
"root_block_device.0.delete_on_termination": "true",
39+
"root_block_device.0.iops": "100",
40+
"root_block_device.0.volume_size": "8",
41+
"root_block_device.0.volume_type": "gp2",
42+
"security_groups.#": "0",
43+
"source_dest_check": "true",
44+
"subnet_id": "subnet-d2c0f0a6",
45+
"tags.%": "0",
46+
"tenancy": "default",
47+
"vpc_security_group_ids.#": "1",
48+
"vpc_security_group_ids.619359045": "sg-9fc7dcfd"
49+
},
50+
"meta": {
51+
"schema_version": "1"
52+
},
53+
"tainted": false
54+
},
55+
"deposed": [],
56+
"provider": ""
57+
}
58+
},
59+
"depends_on": []
60+
}
61+
]
62+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"version": 3,
3+
"terraform_version": "0.7.10",
4+
"serial": 0,
5+
"lineage": "d03ecdf7-8be0-4593-a952-1d8127875119",
6+
"modules": [
7+
{
8+
"path": [
9+
"default_backend"
10+
],
11+
"outputs": {},
12+
"resources": {
13+
"aws_instance.ubuntu-1404": {
14+
"type": "aws_instance",
15+
"depends_on": [],
16+
"primary": {
17+
"id": "i-84d10edb",
18+
"attributes": {
19+
"ami": "ami-9abea4fb",
20+
"associate_public_ip_address": "true",
21+
"availability_zone": "us-west-2b",
22+
"disable_api_termination": "false",
23+
"ebs_block_device.#": "0",
24+
"ebs_optimized": "false",
25+
"ephemeral_block_device.#": "0",
26+
"iam_instance_profile": "",
27+
"id": "i-84d10edb",
28+
"instance_state": "running",
29+
"instance_type": "t2.micro",
30+
"key_name": "",
31+
"monitoring": "false",
32+
"network_interface_id": "eni-46544f07",
33+
"private_dns": "ip-172-31-25-244.us-west-2.compute.internal",
34+
"private_ip": "172.31.25.244",
35+
"public_dns": "ec2-35-162-30-219.us-west-2.compute.amazonaws.com",
36+
"public_ip": "35.162.30.219",
37+
"root_block_device.#": "1",
38+
"root_block_device.0.delete_on_termination": "true",
39+
"root_block_device.0.iops": "100",
40+
"root_block_device.0.volume_size": "8",
41+
"root_block_device.0.volume_type": "gp2",
42+
"security_groups.#": "0",
43+
"source_dest_check": "true",
44+
"subnet_id": "subnet-d2c0f0a6",
45+
"tags.%": "0",
46+
"tenancy": "default",
47+
"vpc_security_group_ids.#": "1",
48+
"vpc_security_group_ids.619359045": "sg-9fc7dcfd"
49+
},
50+
"meta": {
51+
"schema_version": "1"
52+
},
53+
"tainted": false
54+
},
55+
"deposed": [],
56+
"provider": ""
57+
}
58+
},
59+
"depends_on": []
60+
}
61+
]
62+
}

0 commit comments

Comments
 (0)