Fix issue of Content-Type of the v1 modify vnflcm

- Fix so that Content-Type of the v1 modify vnflcm request is
  "application/merge-patch+json".
- Fix so that as the same, Content-Type of all patch request is
  "application/merge-patch+json".
- Fix so that Accept of all patch request and put vnfpkgm request
  is "application/json".
- All patch request of above:
  - PATCH VNF LCM(V1)
  - PATCH VNF packages
  - PATCH VNF LCM(V2)
  - PATCH VNF FM
  - PATCH VNF PM(Modify a PM job)
  - PATCH VNF PM(Modify a PM threshold)

Closes-Bug: #2069701
Change-Id: Ia37312f1ba5560438970beffad432832d30d7d53
Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
Co-Authored-By: Takahiro Miyajima <fj6257jz@fujitsu.com>
This commit is contained in:
Yasufumi Ogawa 2024-06-21 20:46:26 +09:00 committed by Takahiro Miyajima
parent 940b7a5436
commit 046a136021
8 changed files with 268 additions and 3 deletions

@ -131,7 +131,11 @@ class HTTPClient(object):
content_type = kwargs.pop('content_type', None) or 'application/json'
headers = headers or {}
headers.setdefault('Accept', content_type)
accept = kwargs.pop('accept', None)
if accept:
headers.setdefault('Accept', f'application/{accept}')
else:
headers.setdefault('Accept', content_type)
if body:
headers.setdefault('Content-Type', content_type)
@ -284,7 +288,11 @@ class SessionClient(adapter.Adapter):
content_type = kwargs.pop('content_type', None) or 'application/json'
headers = kwargs.setdefault('headers', {})
headers.setdefault('Accept', content_type)
accept = kwargs.pop('accept', None)
if accept:
headers.setdefault('Accept', f'application/{accept}')
else:
headers.setdefault('Accept', content_type)
try:
kwargs.setdefault('data', kwargs.pop('body'))

@ -24,12 +24,14 @@ from unittest import mock
import ddt
import zipfile
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v1.vnfpkgm import vnf_package
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v1 import vnf_package_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
@ -515,6 +517,32 @@ class TestUploadVnfPackage(TestVnfPackage):
# check no fault response is received
self.assertNotCalled(m)
@ddt.data('path')
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_upload_vnf_package_check_content_type(self, method, mock_des):
path = None
if method == 'path':
zip_file, temp_dir = _create_zip()
path = zip_file
arglist, verifylist = self._get_arglist_and_verifylist(method, path)
parsed_args = self.check_parser(self.upload_vnf_package, arglist,
verifylist)
mock_des.return_value = {}
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(202, headers=headers), None)
self._mock_request_url_for_upload('PUT')
self.upload_vnf_package.take_action(parsed_args)
# Delete temporary folder
shutil.rmtree(temp_dir)
mock_req.assert_called_once_with(
f'/vnfpkgm/v1/vnf_packages/{self._vnf_package["id"]}'
'/package_content', 'PUT',
body=mock.ANY, headers=mock.ANY,
content_type='application/zip', accept='json')
def test_upload_vnf_package_with_conflict_error(self):
# Scenario in which vnf package is already in on-boarded state
zip_file, temp_dir = _create_zip()
@ -605,6 +633,37 @@ class TestUpdateVnfPackage(TestVnfPackage):
self.assertListItemsEqual(
vnf_package_fakes.get_vnf_package_data(fake_response), data)
@ddt.data((["--user-data", 'Test_key=Test_value'],
[('user_data', {'Test_key': 'Test_value'})]))
@ddt.unpack
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_take_action_check_content_type(
self, arglist, verifylist, mock_des):
vnf_package_obj = vnf_package_fakes.vnf_package_obj(
onboarded_state=True)
arglist.append(vnf_package_obj['id'])
verifylist.append(('vnf_package', vnf_package_obj['id']))
mock_des.return_value = {}
parsed_args = self.check_parser(self.update_vnf_package, arglist,
verifylist)
url = os.path.join(self.url, 'vnfpkgm/v1/vnf_packages',
vnf_package_obj['id'])
fake_response = vnf_package_fakes.get_fake_update_vnf_package_obj(
arglist)
self.requests_mock.register_uri('PATCH', url, json=fake_response,
headers=self.header)
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(200, headers=headers), None)
self.update_vnf_package.take_action(parsed_args)
mock_req.assert_called_once_with(
f'/vnfpkgm/v1/vnf_packages/{vnf_package_obj["id"]}', 'PATCH',
body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
def test_update_no_options(self):
self.assertRaises(base.ParserException, self.check_parser,
self.update_vnf_package, [], [])

@ -22,12 +22,14 @@ from unittest import mock
import ddt
from oslo_utils.fixture import uuidsentinel
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v1.vnflcm import vnflcm
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v1 import vnflcm_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
@ -659,6 +661,45 @@ class TestUpdateVnfLcm(TestVnfLcm):
self.assertEqual(expected_message, actual_message)
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_take_action_check_content_type(self, mock_des):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = ('./tackerclient/osc/v1/vnflcm/samples/'
'update_vnf_instance_param_sample.json')
arglist = [vnf_instance['id'], '--I', sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('I', sample_param_file)]
mock_des.return_value = {}
# command param
parsed_args = self.check_parser(
self.update_vnf_lcm, arglist, verifylist)
url = os.path.join(self.url, 'vnflcm/v1/vnf_instances',
vnf_instance['id'])
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json={})
sys.stdout = buffer = StringIO()
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(202, headers=headers), None)
self.update_vnf_lcm.take_action(parsed_args)
# check content_type
mock_req.assert_called_once_with(
f'/vnflcm/v1/vnf_instances/{vnf_instance["id"]}', 'PATCH',
body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
actual_message = buffer.getvalue().strip()
expected_message = f'Update vnf:{vnf_instance["id"]}'
self.assertEqual(expected_message, actual_message)
def test_take_action_param_file_not_exists(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = "./not_exists.json"

@ -19,12 +19,15 @@ import os
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnffm import vnffm_alarm
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnffm_alarm_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
class TestVnfFmAlarm(base.FixturedTestCase):
@ -262,6 +265,39 @@ class TestUpdateVnfFmAlarm(TestVnfFmAlarm):
self.assertEqual(expected_data, data)
@ddt.data('ACKNOWLEDGED')
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_take_action_check_content_type(self, ack_state, mock_des):
"""Check content type by test of take_action()"""
vnffm_alarm_obj = vnffm_alarm_fakes.vnf_fm_alarm_response(
None, 'update')
arg_list = ['--ack-state', ack_state, uuidsentinel.vnf_fm_alarm_id]
verify_list = [('ack_state', ack_state),
('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
mock_des.return_value = {}
# command param
parsed_args = self.check_parser(
self.update_vnf_fm_alarm, arg_list, verify_list)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnffm_alarm_obj)
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(200, headers=headers), None)
self.update_vnf_fm_alarm.take_action(parsed_args)
mock_req.assert_called_once_with(
f'/vnffm/v1/alarms/{uuidsentinel.vnf_fm_alarm_id}',
'PATCH', body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
@ddt.data('ACKNOWLEDGED')
def test_take_action_vnf_lcm_op_occ_id_not_found(self, ack_state):
"""Test if vnf-lcm-op-occ-id does not find"""

@ -18,12 +18,14 @@ import os
import sys
from unittest import mock
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc.v1.vnflcm import vnflcm
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v1 import test_vnflcm
from tackerclient.tests.unit.osc.v1 import vnflcm_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
@ -42,6 +44,50 @@ class TestVnfLcmV2(base.FixturedTestCase):
# check of other paths is omitted.
class TestUpdateVnfLcmV2(test_vnflcm.TestVnfLcm):
api_version = '2'
def setUp(self):
super(TestUpdateVnfLcmV2, self).setUp()
self.update_vnf_lcm = vnflcm.UpdateVnfLcm(
self.app, self.app_args, cmd_name='vnflcm modify')
def test_take_action_check_content_type(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = ('./tackerclient/osc/v1/vnflcm/samples/'
'update_vnf_instance_param_sample.json')
arglist = [vnf_instance['id'], '--I', sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('I', sample_param_file)]
# command param
parsed_args = self.check_parser(
self.update_vnf_lcm, arglist, verifylist)
url = os.path.join(self.url, 'vnflcm/v2/vnf_instances',
vnf_instance['id'])
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json={})
sys.stdout = buffer = StringIO()
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(202, headers=headers), None)
self.update_vnf_lcm.take_action(parsed_args)
# check content_type
mock_req.assert_called_once_with(
f'/vnflcm/v2/vnf_instances/{vnf_instance["id"]}', 'PATCH',
body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
actual_message = buffer.getvalue().strip()
expected_message = f'Update vnf:{vnf_instance["id"]}'
self.assertEqual(expected_message, actual_message)
class TestChangeVnfPkgVnfLcm(test_vnflcm.TestVnfLcm):
api_version = '2'

@ -21,12 +21,15 @@ from io import StringIO
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnfpm import vnfpm_job
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnfpm_job_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
class TestVnfPmJob(base.FixturedTestCase):
@ -378,6 +381,39 @@ class TestUpdateVnfPmJob(TestVnfPmJob):
vnfpm_job_obj, columns=columns)
self.assertEqual(expected_data, data)
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_take_action_check_content_type(self, mock_des):
"""Check content type by test of take_action()"""
param_file = ('./tackerclient/osc/v2/vnfpm/samples/'
'update_vnf_pm_job_param_sample.json')
arg_list = [uuidsentinel.vnf_pm_job_id, param_file]
verify_list = [
('vnf_pm_job_id', uuidsentinel.vnf_pm_job_id),
('request_file', param_file)
]
vnfpm_job_obj = vnfpm_job_fakes.vnf_pm_job_response(
None, 'update')
mock_des.return_value = {}
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_job, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', uuidsentinel.vnf_pm_job_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnfpm_job_obj)
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(200, headers=headers), None)
self.update_vnf_pm_job.take_action(parsed_args)
mock_req.assert_called_once_with(
f'/vnfpm/v2/pm_jobs/{uuidsentinel.vnf_pm_job_id}', 'PATCH',
body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
def test_take_action_vnf_pm_job_id_not_found(self):
"""Test if vnf-pm-job-id does not find"""

@ -21,12 +21,15 @@ from io import StringIO
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient import client as root_client
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnfpm import vnfpm_threshold
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnfpm_threshold_fakes
from tackerclient.tests.unit.test_cli10 import MyResp
from tackerclient.v1_0 import client as proxy_client
class TestVnfPmThreshold(base.FixturedTestCase):
@ -300,6 +303,38 @@ class TestUpdateVnfPmThreshold(TestVnfPmThreshold):
vnfpm_threshold_obj, columns=columns)
self.assertEqual(expected_data, data)
@mock.patch.object(proxy_client.ClientBase, 'deserialize')
def test_take_action_check_content_type(self, mock_des):
param_file = ('./tackerclient/osc/v2/vnfpm/samples/'
'update_vnf_pm_threshold_param_sample.json')
arg_list = [uuidsentinel.vnf_pm_threshold_id, param_file]
verify_list = [
('vnf_pm_threshold_id', uuidsentinel.vnf_pm_threshold_id),
('request_file', param_file)
]
vnfpm_threshold_obj = vnfpm_threshold_fakes.vnf_pm_threshold_response(
None, 'update')
mock_des.return_value = {}
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_threshold, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds',
uuidsentinel.vnf_pm_threshold_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnfpm_threshold_obj)
with mock.patch.object(root_client.HTTPClient,
'do_request') as mock_req:
headers = {'Content-Type': 'application/json'}
mock_req.return_value = (MyResp(200, headers=headers), None)
self.update_vnf_pm_threshold.take_action(parsed_args)
mock_req.assert_called_once_with(
f'/vnfpm/v2/thresholds/{uuidsentinel.vnf_pm_threshold_id}',
'PATCH', body=mock.ANY, headers=mock.ANY,
content_type='application/merge-patch+json', accept='json')
def test_take_action_vnf_pm_threshold_id_not_found(self):
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"update_vnf_pm_threshold_param_sample.json")

@ -182,6 +182,7 @@ class ClientBase(object):
self.retry_interval = 1
self.rel = None
self.params = None
self.accept = None
def _handle_fault_response(self, status_code, response_body):
# Create exception with HTTP status code and message
@ -237,7 +238,7 @@ class ClientBase(object):
resp, replybody = self.httpclient.do_request(
action, method, body=body, headers=headers,
content_type=self.content_type())
content_type=self.content_type(), accept=self.accept)
if 'application/zip' == resp.headers.get('Content-Type'):
self.format = 'zip'
@ -357,6 +358,8 @@ class ClientBase(object):
headers=headers, params=params)
def patch(self, action, body=None, headers=None, params=None):
self.format = 'merge-patch+json'
self.accept = 'json'
return self.retry_request("PATCH", action, body=body,
headers=headers, params=params)
@ -480,6 +483,7 @@ class VnfPackageClient(ClientBase):
body=json)
else:
self.format = 'zip'
self.accept = 'json'
return self.put('{base_path}/{id}/package_content'.format(
id=vnf_package,
base_path=self.vnfpackages_path),