Fix Terraform infra-driver instantiate rollback
This patch fixes instantiate rollback operation fails for Terraform infra-driver. The main fixes are as follows: - Change it to use "InstantiateVnfRequest" instead of "instantiatedVnfInfo". This is for bug fixes. - Organized the conditions for call of terminate function. This is because terminate operation fails depending on the timing of the failure. Also, functional test for instantiate rollback operation is not implemented in current Terraform infra-driver, so add it. Closes-Bug: #2040338 Change-Id: Id22a77da5825edabfa5358ea68df0cf92bc9c17f
This commit is contained in:
parent
bd5dcda608
commit
f40a63e49c
@ -99,7 +99,24 @@ class Terraform():
|
||||
|
||||
def instantiate_rollback(self, req, inst, grant_req, grant, vnfd):
|
||||
'''Calls terminate'''
|
||||
self.terminate(req, inst, grant_req, grant, vnfd)
|
||||
vim_conn_info = inst_utils.select_vim_info(inst.vimConnectionInfo)
|
||||
tf_dir_path = req.additionalParams.get('tf_dir_path')
|
||||
tf_var_path = req.additionalParams.get('tf_var_path')
|
||||
working_dir = self._get_tf_vnfpkg(
|
||||
inst.id, grant_req.vnfdId, tf_dir_path)
|
||||
|
||||
# NOTE: Checks the terraform.tfstate file state to call
|
||||
# the terminate function. The reason is as follows.
|
||||
# - For fails terraform apply command, the size of
|
||||
# the terraform.tfstate file is 0.
|
||||
# - For fails before terraform apply command,
|
||||
# terraform.tfstate file does not exist.
|
||||
tfstate_file = f"{working_dir}/terraform.tfstate"
|
||||
if os.path.exists(tfstate_file):
|
||||
if os.path.getsize(tfstate_file) != 0:
|
||||
self._terminate(vim_conn_info, working_dir, tf_var_path)
|
||||
else:
|
||||
shutil.rmtree(working_dir)
|
||||
|
||||
def change_vnfpkg(self, req, inst, grant_req, grant, vnfd):
|
||||
'''Calls Terraform Apply and replicates new files'''
|
||||
|
@ -13,12 +13,21 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
|
||||
class SampleScript(object):
|
||||
class FailScript(object):
|
||||
"""Define error method for each operation
|
||||
|
||||
For example:
|
||||
|
||||
def instantiate_start(self):
|
||||
if os.path.exists('/tmp/instantiate_start')
|
||||
raise Exception('test instantiate_start error')
|
||||
"""
|
||||
|
||||
def __init__(self, req, inst, grant_req, grant, csar_dir):
|
||||
self.req = req
|
||||
@ -27,17 +36,12 @@ class SampleScript(object):
|
||||
self.grant = grant
|
||||
self.csar_dir = csar_dir
|
||||
|
||||
def instantiate_start(self):
|
||||
pass
|
||||
def _fail(self, method):
|
||||
if os.path.exists(f'/tmp/{method}'):
|
||||
raise Exception(f'test {method} error')
|
||||
|
||||
def instantiate_end(self):
|
||||
pass
|
||||
|
||||
def terminate_start(self):
|
||||
pass
|
||||
|
||||
def terminate_end(self):
|
||||
pass
|
||||
def __getattr__(self, name):
|
||||
return functools.partial(self._fail, name)
|
||||
|
||||
|
||||
def main():
|
||||
@ -50,11 +54,8 @@ def main():
|
||||
grant = script_dict['grant_response']
|
||||
csar_dir = script_dict['tmp_csar_dir']
|
||||
|
||||
script = SampleScript(req, inst, grant_req, grant, csar_dir)
|
||||
try:
|
||||
getattr(script, operation)()
|
||||
except AttributeError:
|
||||
raise Exception("{} is not included in the script.".format(operation))
|
||||
script = FailScript(req, inst, grant_req, grant, csar_dir)
|
||||
getattr(script, operation)()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -333,4 +333,55 @@ class VnfLcmTerraformTest(base_v2.BaseVnfLcmTerraformV2Test):
|
||||
self.assertEqual(404, resp.status_code)
|
||||
self.check_package_usage(self.basic_pkg, state='NOT_IN_USE')
|
||||
|
||||
# TODO(yasufum) consider to add a test for instantiate_rollback here.
|
||||
def test_instantiate_rollback(self):
|
||||
"""Test rollback operation for instantiation.
|
||||
|
||||
* About LCM operations:
|
||||
This test includes the following operations.
|
||||
- 1. Create VNF instance
|
||||
- 2. Instantiate VNF => FAILED_TEMP
|
||||
- 3. Show VNF instance
|
||||
- 4. Rollback instantiate
|
||||
- 5. Show VNF instance
|
||||
- 6. Delete a VNF instance
|
||||
"""
|
||||
|
||||
# 1. Create VNF instance
|
||||
create_req = tf_paramgen.create_req_by_vnfd_id(self.basic_vnfd_id)
|
||||
resp, body = self.create_vnf_instance(create_req)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.check_resp_headers_in_create(resp)
|
||||
inst_id = body['id']
|
||||
|
||||
# 2. Instantiate VNF => FAILED_TEMP
|
||||
self.put_fail_file('instantiate_end')
|
||||
instantiate_req = tf_paramgen.instantiate_req()
|
||||
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.check_resp_headers_in_operation_task(resp)
|
||||
|
||||
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||
self.wait_lcmocc_failed_temp(lcmocc_id)
|
||||
self.rm_fail_file('instantiate_end')
|
||||
|
||||
# 3. Show VNF instance
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.assertEqual('NOT_INSTANTIATED', body['instantiationState'])
|
||||
|
||||
# 4. Rollback instantiate
|
||||
resp, body = self.rollback_lcmocc(lcmocc_id)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.wait_lcmocc_rolled_back(lcmocc_id)
|
||||
|
||||
# 5. Show VNF instance
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.assertEqual('NOT_INSTANTIATED', body['instantiationState'])
|
||||
|
||||
# 6. Delete a VNF instance
|
||||
resp, body = self.delete_vnf_instance(inst_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
self.check_resp_headers_in_delete(resp)
|
||||
|
@ -166,8 +166,10 @@ class TestTerraform(base.BaseTestCase):
|
||||
f"/var/lib/tacker/terraform/{inst.id}",
|
||||
inst.instantiatedVnfInfo.metadata['tf_var_path'])
|
||||
|
||||
@mock.patch.object(terraform.Terraform, '_get_tf_vnfpkg')
|
||||
@mock.patch.object(terraform.Terraform, '_terminate')
|
||||
def test_instantiate_rollback(self, mock_instantiate_rollback):
|
||||
def test_instantiate_rollback(self, mock_instantiate_rollback,
|
||||
mock_working_dir):
|
||||
'''Verifies instantiate_rollback is called once'''
|
||||
|
||||
req = objects.InstantiateVnfRequest.from_dict(_instantiate_req_example)
|
||||
@ -190,19 +192,57 @@ class TestTerraform(base.BaseTestCase):
|
||||
)
|
||||
|
||||
grant_req = objects.GrantRequestV1(
|
||||
operation=fields.LcmOperationType.INSTANTIATE
|
||||
operation=fields.LcmOperationType.INSTANTIATE,
|
||||
vnfdId=SAMPLE_VNFD_ID
|
||||
)
|
||||
|
||||
grant = objects.GrantV1()
|
||||
|
||||
# Execute
|
||||
self.driver.instantiate_rollback(req, inst, grant_req,
|
||||
grant, self.vnfd_2)
|
||||
# Create a temporary directory
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Create the tfstate content
|
||||
provider = "provider[\"registry.terraform.io/hashicorp/aws\"]"
|
||||
tfstate_content = {
|
||||
"version": 4,
|
||||
"terraform_version": "1.4.4",
|
||||
"serial": 4,
|
||||
"lineage": "5745b992-04a2-5811-2e02-19d64f6f4b44",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_instance",
|
||||
"name": "vdu1",
|
||||
"provider": provider
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_subnet",
|
||||
"name": "hoge-subnet01",
|
||||
"provider": provider
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Set the desired return value for _get_tf_vnfpkg
|
||||
mock_working_dir.return_value = f"{temp_dir}/{inst.id}"
|
||||
os.mkdir(mock_working_dir())
|
||||
|
||||
# Write the tfstate content to a temporary file
|
||||
tfstate_file_path = os.path.join(mock_working_dir(),
|
||||
'terraform.tfstate')
|
||||
with open(tfstate_file_path, "w") as tfstate_file:
|
||||
json.dump(tfstate_content, tfstate_file)
|
||||
|
||||
# Execute
|
||||
self.driver.instantiate_rollback(req, inst, grant_req,
|
||||
grant, self.vnfd_2)
|
||||
|
||||
# Verify _terminate is called once
|
||||
mock_instantiate_rollback.assert_called_once_with(
|
||||
req.vimConnectionInfo["vim1"],
|
||||
f"/var/lib/tacker/terraform/{inst.id}",
|
||||
inst.instantiatedVnfInfo.metadata['tf_var_path'])
|
||||
f"{temp_dir}/{inst.id}",
|
||||
req.additionalParams.get('tf_var_path'))
|
||||
|
||||
@mock.patch.object(terraform.Terraform, '_get_tf_vnfpkg')
|
||||
@mock.patch.object(terraform.Terraform, '_generate_provider_tf')
|
||||
|
Loading…
Reference in New Issue
Block a user