Skip to content

Commit 1023fb5

Browse files
authored
Add parallel argument to terraform gluescript command (#346)
Add --parallel to be able to control inner terraform -parallelism=N in plan and apply commit also include UT and e2e test. In particular the e2e test has a debug output showing the effect of the parallelism within terraform itself.
1 parent 8bc79ba commit 1023fb5

5 files changed

Lines changed: 88 additions & 6 deletions

File tree

scripts/qesap/lib/cmds.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,17 @@ def cmd_destroy(configure_data, base_project, dryrun=False, verbose=False):
165165
return cmd_terraform(configure_data, base_project, dryrun, workspace='default', destroy=True)
166166

167167

168-
def cmd_terraform(configure_data, base_project, dryrun, workspace='default', destroy=False):
168+
def cmd_terraform(configure_data, base_project, dryrun, workspace='default', destroy=False, parallel=None):
169169
""" Main executor for the deploy sub-command
170170
171171
Args:
172172
configure_data (obj): configuration structure
173173
base_project (str): base project path where to
174174
look for the Terraform files
175-
destroy (bool): destroy
176175
dryrun (bool): enable dryrun execution mode
176+
workspace (str): name of the workspace to activate before running the deployment
177+
destroy (bool): destroy
178+
parallel (int): value to use for argument --parallelism=n when call terraform plan and apply
177179
178180
Returns:
179181
Status: execution result, 0 means OK. It is mind to be used as script exit code
@@ -199,8 +201,11 @@ def cmd_terraform(configure_data, base_project, dryrun, workspace='default', des
199201
cmds.append(f"{terraform_common_cmd} init")
200202
if workspace != 'default':
201203
cmds.append(f"{terraform_common_cmd} workspace new {workspace}")
202-
cmds.append(f"{terraform_common_cmd} plan -out=plan.zip")
203-
cmds.append(f"{terraform_common_cmd} apply -auto-approve plan.zip")
204+
parallel_str = ''
205+
if parallel:
206+
parallel_str = f"-parallelism={parallel} "
207+
cmds.append(f"{terraform_common_cmd} plan {parallel_str}-out=plan.zip")
208+
cmds.append(f"{terraform_common_cmd} apply {parallel_str}-auto-approve plan.zip")
204209

205210
for command in cmds:
206211
command += ' -no-color'

scripts/qesap/qesap.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ def cli(command_line=None):
114114
dest='workspace',
115115
default='default',
116116
help="""Workspace to use in terraform commands. Defaults to 'default'""")
117+
parser_terraform.add_argument('-p',
118+
'--parallel',
119+
type=int,
120+
dest='parallel',
121+
help="""Set value for -parallelism for plan and apply""")
117122
parser_ansible = subparsers.add_parser('ansible', help="Run the Ansible part of the deployment")
118123
parser_ansible.add_argument('-d',
119124
'--destroy',
@@ -182,7 +187,8 @@ def main(command_line=None): # pylint: disable=too-many-return-statements
182187
parsed_args.basedir,
183188
parsed_args.dryrun,
184189
workspace=parsed_args.workspace,
185-
destroy=parsed_args.destroy
190+
destroy=parsed_args.destroy,
191+
parallel=parsed_args.parallel
186192
)
187193
if res != 0:
188194
print(res.msg) # should we use file=sys.stderr here?
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
resource "local_file" "foo" {
2+
# 10 is the default parallel level in terraform when not using -parallelism=N
3+
# so use it to maximise the difference in using or not using the argument
4+
count = 10
5+
content = "@${timestamp()} foo@"
6+
filename = "${path.module}/foo.${count.index}.bar"
7+
provisioner "local-exec" {
8+
command = "sleep 2 ; date +'%T %N'"
9+
}
10+
}

scripts/qesap/test/e2e/test.sh

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,47 @@ lines=$(cat "${THIS_LOG}" | wc -l)
375375
grep -E "SOMETHING INVALID" $THIS_LOG || test_die "Expected content not found in ${THIS_LOG}"
376376
rm terraform.*.log.txt
377377
rm "${TEST_PROVIDER}/main.tf"
378-
touch "${TEST_PROVIDER}/main.tf"
378+
379+
#######################################################################
380+
test_step "[${QESAP_CFG}] test parallel dryrun"
381+
382+
THIS_LOG="${QESAPROOT}/test_parallel.txt"
383+
reset_root
384+
cp main_local_many.tf "${TEST_PROVIDER}/main.tf"
385+
qesap.py --verbose -b ${QESAPROOT} -c ${QESAP_CFG} --dryrun terraform --parallel 1 |& tee "${THIS_LOG}"
386+
grep -E "plan.*-parallelism=1" ${THIS_LOG} || test_die "Missing argument -parallelism=1 in terraform plan"
387+
grep -E "apply.*-parallelism=1" ${THIS_LOG} || test_die "Missing argument -parallelism=1 in terraform apply"
388+
rm ${THIS_LOG}
389+
390+
#######################################################################
391+
test_step "[${QESAP_CFG}] test parallel"
392+
393+
# run reference test without parallel
394+
reset_root
395+
cp main_local_many.tf "${TEST_PROVIDER}/main.tf"
396+
qesap.py --verbose -b ${QESAPROOT} -c ${QESAP_CFG} terraform |& tee "${THIS_LOG}"
397+
grep local-exec ${THIS_LOG}
398+
for foofile in "${TEST_PROVIDER}"/foo.*; do
399+
printf "#${foofile} --> $(cat ${foofile})#\n"
400+
done
401+
count=$(grep -rhE "^@.*foo@" "${TEST_PROVIDER}" | sort -u | wc -l)
402+
[[ $count -eq 1 ]] || test_die "Not all the generated files has the same content. Count:${count}"
403+
404+
qesap.py --verbose -b ${QESAPROOT} -c ${QESAP_CFG} terraform -d
405+
rm ${THIS_LOG}
406+
407+
test_split
408+
409+
reset_root
410+
cp main_local_many.tf "${TEST_PROVIDER}/main.tf"
411+
qesap.py --verbose -b ${QESAPROOT} -c ${QESAP_CFG} terraform --parallel 1 |& tee "${THIS_LOG}"
412+
grep local-exec ${THIS_LOG}
413+
for foofile in "${TEST_PROVIDER}"/foo.*; do
414+
printf "#${foofile} --> $(cat ${foofile})#\n"
415+
done
416+
count=$(grep -rhE "^@.*foo@" "${TEST_PROVIDER}" | sort -u | wc -l)
417+
[[ $count -ne 1 ]] || test_die "All the generated files has the same content. Count:${count}"
418+
rm ${THIS_LOG}
379419

380420

381421
echo "#######################################################################"

scripts/qesap/test/unit/test_qesap_terraform.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,24 @@ def test_terraform_call_terraform_workspace_destroy(subprocess_run, args_helper,
252252
calls.append(mock.call(f"terraform -chdir={terraform_dir} workspace delete lucignolo -no-color"))
253253

254254
subprocess_run.assert_has_calls(calls)
255+
256+
257+
@mock.patch("lib.process_manager.subprocess_run")
258+
def test_terraform_call_terraform_parallel(subprocess_run, args_helper, config_yaml_sample):
259+
"""
260+
Command terraform calls 'terraform plan' and 'terraform apply' with -parallelism=n
261+
"""
262+
provider = 'mangiafuoco'
263+
conf = config_yaml_sample(provider)
264+
265+
args, terraform_dir, *_ = args_helper(provider, conf)
266+
args.extend(['terraform', '-p', '5'])
267+
subprocess_run.return_value = (0, [])
268+
assert main(args) == 0
269+
subprocess_run.assert_called()
270+
271+
calls = []
272+
calls.append(mock.call(f"terraform -chdir={terraform_dir} plan -parallelism=5 -out=plan.zip -no-color"))
273+
calls.append(mock.call(f"terraform -chdir={terraform_dir} apply -parallelism=5 -auto-approve plan.zip -no-color"))
274+
275+
subprocess_run.assert_has_calls(calls)

0 commit comments

Comments
 (0)