diff --git a/octane/commands/enable_release.py b/octane/commands/enable_release.py new file mode 100644 index 00000000..117044c8 --- /dev/null +++ b/octane/commands/enable_release.py @@ -0,0 +1,70 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from cliff import command +from fuelclient.client import APIClient +from octane.handlers import backup_restore +from octane import magic_consts +from octane.util import fuel_client + +LOG = logging.getLogger(__name__) + + +def enable_release(release_id, context): + release_url = "/releases/{0}".format(release_id) + with fuel_client.set_auth_context(context): + data = APIClient.get_request(release_url) + state = data.get('state') + if state == magic_consts.RELEASE_STATUS_MANAGED: + data['state'] = magic_consts.RELEASE_STATUS_ENABLED + APIClient.put_request(release_url, data) + else: + exc_msg = ("Cannot enable release {0}: has status {1}, not {2}" + .format(release_id, + state, + magic_consts.RELEASE_STATUS_MANAGED)) + raise Exception(exc_msg) + + +class EnableReleaseCommand(command.Command): + + def get_parser(self, *args, **kwargs): + parser = super(EnableReleaseCommand, self).get_parser(*args, **kwargs) + parser.add_argument( + "--id", + type=str, + action="store", + dest="release_id", + required=True, + help="ID of the release to enable.") + parser.add_argument( + "--admin-password", + type=str, + action="store", + dest="admin_password", + required=True, + help="Fuel admin password") + return parser + + def get_context(self, parsed_args): + return backup_restore.NailgunCredentialsContext( + password=parsed_args.admin_password, + user="admin" + ) + + def take_action(self, parsed_args): + assert parsed_args.release_id + assert parsed_args.admin_password + enable_release(parsed_args.release_id, + self.get_context(parsed_args)) diff --git a/octane/magic_consts.py b/octane/magic_consts.py index 7f4b5c83..00c3c98f 100644 --- a/octane/magic_consts.py +++ b/octane/magic_consts.py @@ -80,3 +80,5 @@ OSD_REPOS_UPDATE = [ COBBLER_DROP_VERSION = "7.0" MIRRORS_EXTRA_DIRS = ["ubuntu-full", "mos-ubuntu"] +RELEASE_STATUS_ENABLED = "available" +RELEASE_STATUS_MANAGED = "manageonly" diff --git a/octane/tests/test_enable_release.py b/octane/tests/test_enable_release.py new file mode 100644 index 00000000..d6494cc0 --- /dev/null +++ b/octane/tests/test_enable_release.py @@ -0,0 +1,68 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import pytest + +from octane.commands.enable_release import enable_release +from octane import magic_consts + + +@pytest.mark.parametrize("release_id,password", + [('1', 'test_pass'), + ('1', ''), + ('', '')]) +def test_parser(mocker, octane_app, release_id, password): + command = "enable-release" + get_context_mock = mocker.patch( + "octane.commands.enable_release.EnableReleaseCommand.get_context") + context_mock = mocker.patch( + "octane.handlers.backup_restore.NailgunCredentialsContext") + get_context_mock.return_value = context_mock + enable_release_mock = mocker.patch( + "octane.commands.enable_release.enable_release") + params = [command, "--id", release_id, "--admin-password", password] + if release_id and password: + octane_app.run(params) + enable_release_mock.assert_called_once_with(release_id, + context_mock) + else: + with pytest.raises(AssertionError): + octane_app.run(params) + + +@pytest.mark.parametrize("release_id,data", [ + (1, {'state': 'manageonly', }), + (1, {'state': 'available', }), + (1, {'state': 'unavailable', }), + (1, {'nostate': '', }), +]) +def test_enable_release(mocker, release_id, data): + release_url = "/releases/{0}".format(release_id) + context_class_mock = mocker.patch( + "octane.handlers.backup_restore.NailgunCredentialsContext") + context_mock = context_class_mock() + set_auth_context_mock = mocker.patch( + "octane.util.fuel_client.set_auth_context") + get_request_mock = mocker.patch( + "fuelclient.client.APIClient.get_request") + put_request_mock = mocker.patch( + "fuelclient.client.APIClient.put_request") + get_request_mock.return_value = data + + if data.get("state") == magic_consts.RELEASE_STATUS_MANAGED: + enable_release(release_id, context_mock) + set_auth_context_mock.assert_called_once_with(context_mock) + expected_data = {'state': magic_consts.RELEASE_STATUS_ENABLED} + put_request_mock.assert_called_once_with(release_url, expected_data) + else: + with pytest.raises(Exception): + enable_release(release_id, context_mock) diff --git a/setup.cfg b/setup.cfg index 98a1dda4..dc84f7c5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,6 +40,7 @@ octane = fuel-repo-backup = octane.commands.backup:BackupRepoCommand fuel-repo-restore = octane.commands.restore:RestoreRepoCommand update-bootstrap-centos = octane.commands.update_bootstrap:UpdateCentos + enable-release = octane.commands.enable_release:EnableReleaseCommand octane.handlers.upgrade = controller = octane.handlers.upgrade.controller:ControllerUpgrade compute = octane.handlers.upgrade.compute:ComputeUpgrade