Merge "Add 'subcloud deploy delete' command to dcmanager"
This commit is contained in:
commit
32065bcc68
@ -1791,6 +1791,37 @@ Response Example
|
|||||||
:language: json
|
:language: json
|
||||||
|
|
||||||
|
|
||||||
|
************************************
|
||||||
|
Delete Subcloud Deploy Files
|
||||||
|
************************************
|
||||||
|
|
||||||
|
.. rest_method:: DELETE /v1.0/subcloud-deploy
|
||||||
|
|
||||||
|
**Normal response codes**
|
||||||
|
|
||||||
|
200
|
||||||
|
|
||||||
|
**Error response codes**
|
||||||
|
|
||||||
|
badRequest (400), unauthorized (401), forbidden (403), notFound (404),
|
||||||
|
HTTPUnprocessableEntity (422), internalServerError (500),
|
||||||
|
serviceUnavailable (503)
|
||||||
|
|
||||||
|
**Request parameters**
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- release: release_uri
|
||||||
|
- deployment_files: delete_subcloud_deployment_files
|
||||||
|
- prestage_images: delete_subcloud_deploy_prestage_images
|
||||||
|
|
||||||
|
Request Example
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. literalinclude:: samples/subcloud-deploy/subcloud-deploy-delete-request.json
|
||||||
|
:language: json
|
||||||
|
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
Phased Subcloud Deploy
|
Phased Subcloud Deploy
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -239,6 +239,20 @@ default_instance_action:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
delete_subcloud_deploy_prestage_images:
|
||||||
|
description: |
|
||||||
|
The flag to indicate the deployment manager prestage images
|
||||||
|
file to be deleted.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
delete_subcloud_deployment_files:
|
||||||
|
description: |
|
||||||
|
The flag to indicate the deploy playbook, deploy overrides,
|
||||||
|
deploy chart files to be deleted.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
deploy_config:
|
deploy_config:
|
||||||
description: |
|
description: |
|
||||||
The content of a file containing the resource definitions describing
|
The content of a file containing the resource definitions describing
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"release": 23.09,
|
||||||
|
"prestage_images": false,
|
||||||
|
"deployment_files": false
|
||||||
|
}
|
@ -149,3 +149,44 @@ class SubcloudDeployController(object):
|
|||||||
filename = filename.replace(prefix, '', 1)
|
filename = filename.replace(prefix, '', 1)
|
||||||
deploy_dicts.update({f: filename})
|
deploy_dicts.update({f: filename})
|
||||||
return dict(subcloud_deploy=deploy_dicts)
|
return dict(subcloud_deploy=deploy_dicts)
|
||||||
|
|
||||||
|
@index.when(method='DELETE', template='json')
|
||||||
|
def delete(self, release=None):
|
||||||
|
"""Delete the subcloud deploy files.
|
||||||
|
|
||||||
|
:param release: release version
|
||||||
|
"""
|
||||||
|
policy.authorize(subcloud_deploy_policy.POLICY_ROOT % "delete", {},
|
||||||
|
restcomm.extract_credentials_for_policy())
|
||||||
|
|
||||||
|
is_prestage_images = request.params.get('prestage_images', '').lower() == 'true'
|
||||||
|
is_deployment_files = request.params.get('deployment_files', '').lower() == 'true'
|
||||||
|
|
||||||
|
dir_path = os.path.join(dccommon_consts.DEPLOY_DIR, utils.get_sw_version(release))
|
||||||
|
if not os.path.isdir(dir_path):
|
||||||
|
pecan.abort(httpclient.NOT_FOUND,
|
||||||
|
_("Directory not found: %s" % dir_path))
|
||||||
|
try:
|
||||||
|
file_options = []
|
||||||
|
if is_prestage_images:
|
||||||
|
file_options.append(consts.DEPLOY_PRESTAGE)
|
||||||
|
|
||||||
|
if is_deployment_files:
|
||||||
|
file_options.extend([consts.DEPLOY_OVERRIDES, consts.DEPLOY_CHART,
|
||||||
|
consts.DEPLOY_PLAYBOOK])
|
||||||
|
|
||||||
|
if not (is_deployment_files or is_prestage_images):
|
||||||
|
file_options.extend(consts.DEPLOY_COMMON_FILE_OPTIONS)
|
||||||
|
|
||||||
|
for file_option in file_options:
|
||||||
|
prefix = file_option + '_'
|
||||||
|
file_name = utils.get_filename_by_prefix(dir_path, prefix)
|
||||||
|
if file_name:
|
||||||
|
os.remove(os.path.join(dir_path, file_name))
|
||||||
|
else:
|
||||||
|
LOG.warning('%s file not present' % file_option)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
pecan.abort(httpclient.INTERNAL_SERVER_ERROR,
|
||||||
|
_("Failed to delete file: %s" % e))
|
||||||
|
return None
|
||||||
|
@ -36,6 +36,21 @@ subcloud_deploy_rules = [
|
|||||||
'path': '/v1.0/subcloud-deploy/{release}'
|
'path': '/v1.0/subcloud-deploy/{release}'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=POLICY_ROOT % 'delete',
|
||||||
|
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
|
||||||
|
description="Delete subcloud deploy files.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'DELETE',
|
||||||
|
'path': '/v1.0/subcloud-deploy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'method': 'DELETE',
|
||||||
|
'path': '/v1.0/subcloud-deploy/{release}'
|
||||||
|
}
|
||||||
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
|
from os import path as os_path
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
import six
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
import webtest
|
import webtest
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ from dcmanager.tests import utils
|
|||||||
|
|
||||||
from tsconfig.tsconfig import SW_VERSION
|
from tsconfig.tsconfig import SW_VERSION
|
||||||
|
|
||||||
FAKE_SOFTWARE_VERSION = '21.12'
|
FAKE_SOFTWARE_VERSION = '22.12'
|
||||||
FAKE_TENANT = utils.UUID1
|
FAKE_TENANT = utils.UUID1
|
||||||
FAKE_ID = '1'
|
FAKE_ID = '1'
|
||||||
FAKE_URL = '/v1.0/subcloud-deploy'
|
FAKE_URL = '/v1.0/subcloud-deploy'
|
||||||
@ -40,6 +42,7 @@ FAKE_HEADERS = {'X-Tenant-Id': FAKE_TENANT, 'X_ROLE': 'admin,member,reader',
|
|||||||
FAKE_DEPLOY_PLAYBOOK_PREFIX = consts.DEPLOY_PLAYBOOK + '_'
|
FAKE_DEPLOY_PLAYBOOK_PREFIX = consts.DEPLOY_PLAYBOOK + '_'
|
||||||
FAKE_DEPLOY_OVERRIDES_PREFIX = consts.DEPLOY_OVERRIDES + '_'
|
FAKE_DEPLOY_OVERRIDES_PREFIX = consts.DEPLOY_OVERRIDES + '_'
|
||||||
FAKE_DEPLOY_CHART_PREFIX = consts.DEPLOY_CHART + '_'
|
FAKE_DEPLOY_CHART_PREFIX = consts.DEPLOY_CHART + '_'
|
||||||
|
FAKE_PRESTAGE_IMAGES_PREFIX = consts.DEPLOY_PRESTAGE + '_'
|
||||||
FAKE_DEPLOY_PLAYBOOK_FILE = 'deployment-manager.yaml'
|
FAKE_DEPLOY_PLAYBOOK_FILE = 'deployment-manager.yaml'
|
||||||
FAKE_DEPLOY_OVERRIDES_FILE = 'deployment-manager-overrides-subcloud.yaml'
|
FAKE_DEPLOY_OVERRIDES_FILE = 'deployment-manager-overrides-subcloud.yaml'
|
||||||
FAKE_DEPLOY_CHART_FILE = 'deployment-manager.tgz'
|
FAKE_DEPLOY_CHART_FILE = 'deployment-manager.tgz'
|
||||||
@ -48,6 +51,21 @@ FAKE_DEPLOY_FILES = {
|
|||||||
FAKE_DEPLOY_OVERRIDES_PREFIX: FAKE_DEPLOY_OVERRIDES_FILE,
|
FAKE_DEPLOY_OVERRIDES_PREFIX: FAKE_DEPLOY_OVERRIDES_FILE,
|
||||||
FAKE_DEPLOY_CHART_PREFIX: FAKE_DEPLOY_CHART_FILE,
|
FAKE_DEPLOY_CHART_PREFIX: FAKE_DEPLOY_CHART_FILE,
|
||||||
}
|
}
|
||||||
|
FAKE_DEPLOY_DELETE_FILES = {
|
||||||
|
FAKE_DEPLOY_PLAYBOOK_PREFIX: '/opt/platform/deploy/22.12/deployment-manager.yaml',
|
||||||
|
FAKE_DEPLOY_OVERRIDES_PREFIX:
|
||||||
|
'/opt/platform/deploy/22.12/deployment-manager-overrides-subcloud.yaml',
|
||||||
|
FAKE_DEPLOY_CHART_PREFIX: '/opt/platform/deploy/22.12/deployment-manager.tgz',
|
||||||
|
FAKE_PRESTAGE_IMAGES_PREFIX: '/opt/platform/deploy/22.12/prestage_images.yml'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_filename_by_prefix_side_effect(dir_path, prefix):
|
||||||
|
filename = FAKE_DEPLOY_FILES.get(prefix)
|
||||||
|
if filename:
|
||||||
|
return prefix + FAKE_DEPLOY_FILES.get(prefix)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class TestSubcloudDeploy(testroot.DCManagerApiTest):
|
class TestSubcloudDeploy(testroot.DCManagerApiTest):
|
||||||
@ -269,3 +287,127 @@ class TestSubcloudDeploy(testroot.DCManagerApiTest):
|
|||||||
f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1/install_values.yml')
|
f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1/install_values.yml')
|
||||||
self.assertEqual(deploy_config,
|
self.assertEqual(deploy_config,
|
||||||
f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_deploy_config.yml')
|
f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_deploy_config.yml')
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
def test_subcloud_deploy_delete_directory_not_found(self,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
|
||||||
|
mock_get_sw_version.return_value = '21.12'
|
||||||
|
url = FAKE_URL + '?prestage_images=' + \
|
||||||
|
str(False) + '&deployment_files=' + str(False)
|
||||||
|
mock_path_isdir.side_effect = lambda x: True \
|
||||||
|
if x == '/opt/platform/deploy/22.12' else False
|
||||||
|
six.assertRaisesRegex(self, webtest.app.AppError, "404 *",
|
||||||
|
self.app.delete, url,
|
||||||
|
headers=FAKE_HEADERS)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
def test_subcloud_deploy_delete_internal_server_error(self,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
mock_path_isdir.side_effect = lambda x: True \
|
||||||
|
if x == '/opt/platform/deploy/22.12' else False
|
||||||
|
six.assertRaisesRegex(self, webtest.app.AppError, "500 *",
|
||||||
|
self.app.delete, FAKE_URL,
|
||||||
|
headers=FAKE_HEADERS)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||||
|
@mock.patch.object(os, 'remove')
|
||||||
|
def test_subcloud_deploy_delete_with_release(self, mock_os_remove,
|
||||||
|
mock_get_filename_by_prefix,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
|
||||||
|
mock_os_remove.return_value = None
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
|
||||||
|
mock_get_filename_by_prefix.side_effect = \
|
||||||
|
get_filename_by_prefix_side_effect
|
||||||
|
mock_path_isdir.return_value = True
|
||||||
|
url = FAKE_URL + '/' + FAKE_SOFTWARE_VERSION + \
|
||||||
|
'?prestage_images=' + str(False) + '&deployment_files=' + str(False)
|
||||||
|
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||||
|
@mock.patch.object(os, 'remove')
|
||||||
|
def test_subcloud_deploy_delete_without_release(self, mock_os_remove,
|
||||||
|
mock_get_filename_by_prefix,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
|
||||||
|
mock_os_remove.return_value = None
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
url = FAKE_URL + '?prestage_images=' + \
|
||||||
|
str(True) + '&deployment_files=' + str(True)
|
||||||
|
mock_get_filename_by_prefix.side_effect = \
|
||||||
|
get_filename_by_prefix_side_effect
|
||||||
|
mock_path_isdir.return_value = True
|
||||||
|
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||||
|
@mock.patch.object(os, 'remove')
|
||||||
|
def test_subcloud_deploy_delete_deployment_files(self, mock_os_remove,
|
||||||
|
mock_get_filename_by_prefix,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
mock_os_remove.return_value = None
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
url = FAKE_URL + '?prestage_images=' + \
|
||||||
|
str(False) + '&deployment_files=' + str(True)
|
||||||
|
mock_get_filename_by_prefix.side_effect = \
|
||||||
|
get_filename_by_prefix_side_effect
|
||||||
|
mock_path_isdir.side_effect = lambda x: True \
|
||||||
|
if x == '/opt/platform/deploy/22.12' else False
|
||||||
|
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||||
|
@mock.patch.object(os, 'remove')
|
||||||
|
def test_subcloud_deploy_delete_prestage_images(self, mock_os_remove,
|
||||||
|
mock_get_filename_by_prefix,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
mock_os_remove.return_value = None
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
url = FAKE_URL + '?prestage_images=' + \
|
||||||
|
str(True) + '&deployment_files=' + str(False)
|
||||||
|
mock_get_filename_by_prefix.side_effect = \
|
||||||
|
get_filename_by_prefix_side_effect
|
||||||
|
mock_path_isdir.side_effect = lambda x: True \
|
||||||
|
if x == '/opt/platform/deploy/22.12' else False
|
||||||
|
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
|
||||||
|
@mock.patch.object(os_path, 'isdir')
|
||||||
|
@mock.patch.object(dutils, 'get_sw_version')
|
||||||
|
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||||
|
@mock.patch.object(os, 'remove')
|
||||||
|
def test_subcloud_deploy_delete_with_both_parameters(self, mock_os_remove,
|
||||||
|
mock_get_filename_by_prefix,
|
||||||
|
mock_get_sw_version,
|
||||||
|
mock_path_isdir):
|
||||||
|
mock_os_remove.return_value = None
|
||||||
|
mock_get_sw_version.return_value = '22.12'
|
||||||
|
url = FAKE_URL + '?prestage_images=' + \
|
||||||
|
str(True) + '&deployment_files=' + str(True)
|
||||||
|
mock_get_filename_by_prefix.side_effect = \
|
||||||
|
get_filename_by_prefix_side_effect
|
||||||
|
mock_path_isdir.side_effect = lambda x: True \
|
||||||
|
if x == '/opt/platform/deploy/22.12' else False
|
||||||
|
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
Loading…
Reference in New Issue
Block a user