Add two plugins related commands into fuel2
* fuel2 plugins install <path> * fuel2 plugins remove <name> <version> DocImpact Change-Id: Id166eacad0ffe8b9f6fd98519aaa15246a9c1956 Closes-Bug: #1668253
This commit is contained in:
parent
4d739ecc04
commit
b765ac3814
|
@ -18,6 +18,48 @@ from fuelclient.commands import base
|
|||
class PluginsMixIn(object):
|
||||
entity_name = 'plugins'
|
||||
|
||||
@staticmethod
|
||||
def add_plugin_file_argument(parser):
|
||||
parser.add_argument(
|
||||
'file',
|
||||
type=str,
|
||||
help='Path to plugin file to install'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_plugin_name_argument(parser):
|
||||
parser.add_argument(
|
||||
'name',
|
||||
type=str,
|
||||
help='Name of plugin to remove'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_plugin_version_argument(parser):
|
||||
parser.add_argument(
|
||||
'version',
|
||||
type=str,
|
||||
help='Version of plugin to remove'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_plugin_ids_argument(parser):
|
||||
parser.add_argument(
|
||||
'ids',
|
||||
type=int,
|
||||
nargs='*',
|
||||
metavar='plugin-id',
|
||||
help='Synchronise only plugins with specified ids'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_plugin_install_force_argument(parser):
|
||||
parser.add_argument(
|
||||
'-f', '--force',
|
||||
action='store_true',
|
||||
help='Used for reinstall plugin with the same version'
|
||||
)
|
||||
|
||||
|
||||
class PluginsList(PluginsMixIn, base.BaseListCommand):
|
||||
"""Show list of all available plugins."""
|
||||
|
@ -34,16 +76,42 @@ class PluginsSync(PluginsMixIn, base.BaseCommand):
|
|||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(PluginsSync, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'ids',
|
||||
type=int,
|
||||
nargs='*',
|
||||
metavar='plugin-id',
|
||||
help='Synchronise only plugins with specified ids')
|
||||
|
||||
self.add_plugin_ids_argument(parser)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ids = parsed_args.ids if len(parsed_args.ids) > 0 else None
|
||||
self.client.sync(ids=ids)
|
||||
self.app.stdout.write("Plugins were successfully synchronized.\n")
|
||||
|
||||
|
||||
class PluginInstall(PluginsMixIn, base.BaseCommand):
|
||||
"""Install plugin archive and register in API service."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(PluginInstall, self).get_parser(prog_name)
|
||||
self.add_plugin_file_argument(parser)
|
||||
self.add_plugin_install_force_argument(parser)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.client.install(parsed_args.file, force=parsed_args.force)
|
||||
self.app.stdout.write(
|
||||
"Plugin {0} was successfully installed.\n".format(parsed_args.file)
|
||||
)
|
||||
|
||||
|
||||
class PluginRemove(PluginsMixIn, base.BaseCommand):
|
||||
"""Remove the plugin package, and update data in API service."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(PluginRemove, self).get_parser(prog_name)
|
||||
self.add_plugin_name_argument(parser)
|
||||
self.add_plugin_version_argument(parser)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.client.remove(parsed_args.name, parsed_args.version)
|
||||
self.app.stdout.write(
|
||||
"Plugin {0} was successfully removed.\n".format(parsed_args.name)
|
||||
)
|
||||
|
|
|
@ -336,6 +336,10 @@ class Plugins(base.BaseObject):
|
|||
:return: Plugins information
|
||||
:rtype: dict
|
||||
"""
|
||||
if not utils.file_exists(plugin_path):
|
||||
raise error.BadDataException(
|
||||
"No such plugin file: {0}".format(plugin_path)
|
||||
)
|
||||
plugin = cls.make_obj_by_file(plugin_path)
|
||||
|
||||
name = plugin.name_from_file(plugin_path)
|
||||
|
|
|
@ -25,6 +25,7 @@ from fuelclient.objects.plugins import Plugins
|
|||
from fuelclient.objects.plugins import PluginV1
|
||||
from fuelclient.objects.plugins import PluginV2
|
||||
from fuelclient.tests.unit.v1 import base
|
||||
from fuelclient import utils
|
||||
|
||||
|
||||
@patch('fuelclient.objects.plugins.raise_error_if_not_master')
|
||||
|
@ -220,9 +221,11 @@ class TestPluginsObject(base.UnitTestCase):
|
|||
get_mock.assert_called_once_with(self.name, self.version)
|
||||
del_mock.assert_called_once_with('plugins/123')
|
||||
|
||||
@patch.object(utils, 'file_exists', return_value=True)
|
||||
@patch.object(Plugins, 'register')
|
||||
@patch.object(Plugins, 'make_obj_by_file')
|
||||
def test_install(self, make_obj_by_file_mock, register_mock):
|
||||
def test_install(self, make_obj_by_file_mock, register_mock,
|
||||
file_exists_mock):
|
||||
plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock)
|
||||
register_mock.return_value = {'id': 1}
|
||||
self.plugin.install(self.path)
|
||||
|
@ -230,6 +233,7 @@ class TestPluginsObject(base.UnitTestCase):
|
|||
plugin_obj.install.assert_called_once_with(self.path, force=False)
|
||||
register_mock.assert_called_once_with(
|
||||
'retrieved_name', 'retrieved_version', force=False)
|
||||
file_exists_mock.assert_called_once_with(self.path)
|
||||
|
||||
@patch.object(Plugins, 'unregister')
|
||||
@patch.object(Plugins, 'make_obj_by_name')
|
||||
|
|
|
@ -15,16 +15,19 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
import tempfile
|
||||
|
||||
from fuelclient.tests.unit.v2.cli import test_engine
|
||||
from fuelclient.tests.utils import fake_plugin
|
||||
|
||||
|
||||
class TestPluginsCommand(test_engine.BaseCLITest):
|
||||
"""Tests for fuel2 node * commands."""
|
||||
"""Tests for fuel2 plugins * commands."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestPluginsCommand, self).setUp()
|
||||
self.name = 'fuel_plugin'
|
||||
self.version = '1.0.0'
|
||||
|
||||
get_fake_plugins = fake_plugin.get_fake_plugins
|
||||
|
||||
|
@ -57,3 +60,25 @@ class TestPluginsCommand(test_engine.BaseCLITest):
|
|||
|
||||
self.m_get_client.assert_called_once_with('plugins', mock.ANY)
|
||||
self.m_client.sync.assert_called_once_with(ids=ids)
|
||||
|
||||
def exec_install(self, ext='rpm', force=False):
|
||||
path = tempfile.mkstemp(suffix='.{}'.format(ext))[1]
|
||||
args = 'plugins install {0} {1}'.format(path,
|
||||
'--force' if force else '')
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('plugins', mock.ANY)
|
||||
self.m_client.install.assert_called_once_with(path, force=force)
|
||||
|
||||
def test_plugin_install(self):
|
||||
self.exec_install()
|
||||
|
||||
def test_plugin_install_with_force(self):
|
||||
self.exec_install(force=True)
|
||||
|
||||
def test_plugin_remove(self):
|
||||
args = 'plugins remove {0} {1}'.format(self.name, self.version)
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('plugins', mock.ANY)
|
||||
self.m_client.remove.assert_called_once_with(self.name, self.version)
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
# 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 json
|
||||
|
||||
from mock import mock
|
||||
|
||||
import fuelclient
|
||||
from fuelclient.cli import error
|
||||
from fuelclient.tests.unit.v2.lib import test_api
|
||||
from fuelclient.tests import utils
|
||||
|
||||
|
@ -63,3 +67,104 @@ class TestPluginsFacade(test_api.BaseLibTest):
|
|||
self.client.sync(ids=ids)
|
||||
self.assertTrue(matcher.called)
|
||||
self.assertEqual(ids, matcher.last_request.json()['ids'])
|
||||
|
||||
|
||||
class TestPluginInstallFacade(TestPluginsFacade):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPluginInstallFacade, self).setUp()
|
||||
|
||||
self.m_exec = mock.patch.object(fuelclient.utils, 'exec_cmd')
|
||||
self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER',
|
||||
True)
|
||||
self.m_meta = mock.patch.object(fuelclient.utils,
|
||||
'glob_and_parse_yaml',
|
||||
return_value=self.fake_plugins)
|
||||
|
||||
self.m_file_exists = mock.patch.object(fuelclient.utils,
|
||||
'file_exists',
|
||||
return_value=True)
|
||||
|
||||
def exec_install(self, force=False):
|
||||
path = '/path/to/plugin.rpm'
|
||||
|
||||
post_matcher = self.m_request.post(self.res_uri, json={})
|
||||
get_matcher = self.m_request.get(self.res_uri, json={})
|
||||
put_matcher = None
|
||||
|
||||
fake_plugin = self.fake_plugins[0]
|
||||
if force:
|
||||
put_uri = '/api/{version}/plugins/{id}'.format(
|
||||
version=self.version,
|
||||
id=fake_plugin['id'])
|
||||
put_matcher = self.m_request.put(put_uri, json={})
|
||||
post_matcher = self.m_request.post(self.res_uri, json={
|
||||
'message': json.dumps({'id': fake_plugin['id']})
|
||||
}, status_code=409)
|
||||
m_name = mock.patch.object(fuelclient.objects.plugins.PluginV2,
|
||||
'name_from_file',
|
||||
return_value=fake_plugin['name'])
|
||||
m_version = mock.patch.object(fuelclient.objects.plugins.PluginV2,
|
||||
'version_from_file',
|
||||
return_value=fake_plugin['version'])
|
||||
|
||||
with m_name, m_version, self.m_is_master, self.m_meta, self.m_exec,\
|
||||
self.m_file_exists:
|
||||
self.client.install(path, force)
|
||||
|
||||
self.assertTrue(get_matcher.called)
|
||||
self.assertTrue(post_matcher.called)
|
||||
self.assertEqual(fake_plugin,
|
||||
json.loads(post_matcher.last_request.body))
|
||||
if force:
|
||||
self.assertTrue(put_matcher.called)
|
||||
self.assertEqual(fake_plugin,
|
||||
json.loads(put_matcher.last_request.body))
|
||||
|
||||
def test_install_plugin(self):
|
||||
|
||||
self.exec_install()
|
||||
|
||||
def test_install_plugin_force(self):
|
||||
self.exec_install(True)
|
||||
|
||||
def test_install_plugin_fail_not_master(self):
|
||||
self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER',
|
||||
False)
|
||||
self.assertRaises(error.WrongEnvironmentError, self.exec_install)
|
||||
|
||||
def test_install_plugin_fail_file_not_exists(self):
|
||||
self.m_file_exists = mock.patch.object(fuelclient.utils,
|
||||
'file_exists',
|
||||
return_value=False)
|
||||
self.assertRaises(error.BadDataException, self.exec_install)
|
||||
|
||||
|
||||
class TestPluginRemoveFacade(TestPluginsFacade):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPluginRemoveFacade, self).setUp()
|
||||
|
||||
self.m_exec = mock.patch.object(fuelclient.utils, 'exec_cmd')
|
||||
self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER',
|
||||
True)
|
||||
|
||||
def exec_remove(self):
|
||||
fake_plugin = self.fake_plugins[0]
|
||||
expected_uri = '/api/{version}/plugins/{id}'.format(
|
||||
version=self.version, id=fake_plugin['id'])
|
||||
del_matcher = self.m_request.delete(expected_uri, json={})
|
||||
get_matcher = self.m_request.get(self.res_uri, json=self.fake_plugins)
|
||||
with self.m_is_master, self.m_exec:
|
||||
self.client.remove(fake_plugin['name'], fake_plugin['version'])
|
||||
self.assertTrue(get_matcher.called)
|
||||
self.assertTrue(del_matcher.called)
|
||||
self.assertIsNone(del_matcher.last_request.body)
|
||||
|
||||
def test_remove_plugin(self):
|
||||
self.exec_remove()
|
||||
|
||||
def test_remove_plugin_fail_not_master(self):
|
||||
self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER',
|
||||
False)
|
||||
self.assertRaises(error.WrongEnvironmentError, self.exec_remove)
|
||||
|
|
|
@ -53,6 +53,24 @@ class PluginsClient(base_v1.BaseV1Client):
|
|||
|
||||
self._entity_wrapper.sync(plugin_ids=ids)
|
||||
|
||||
def install(self, plugin_path, force=False):
|
||||
"""Install plugin archive and register in API service.
|
||||
|
||||
:param plugin_path: Path to plugin file
|
||||
:type plugin_path: str
|
||||
:param force: Update existent plugin even if it is not updatable
|
||||
:type force: bool
|
||||
"""
|
||||
return self._entity_wrapper.install(plugin_path, force=force)
|
||||
|
||||
def remove(self, plugin_name, plugin_version):
|
||||
"""Remove the plugin package, and update data in API service.
|
||||
|
||||
:param str plugin_name: Name of plugin to remove
|
||||
:param str plugin_version: Version of plugin to remove
|
||||
"""
|
||||
return self._entity_wrapper.remove(plugin_name, plugin_version)
|
||||
|
||||
|
||||
def get_client(connection):
|
||||
return PluginsClient(connection)
|
||||
|
|
|
@ -103,7 +103,9 @@ fuelclient =
|
|||
openstack-config_execute=fuelclient.commands.openstack_config:OpenstackConfigExecute
|
||||
openstack-config_list=fuelclient.commands.openstack_config:OpenstackConfigList
|
||||
openstack-config_upload=fuelclient.commands.openstack_config:OpenstackConfigUpload
|
||||
plugins_install=fuelclient.commands.plugins:PluginInstall
|
||||
plugins_list=fuelclient.commands.plugins:PluginsList
|
||||
plugins_remove=fuelclient.commands.plugins:PluginRemove
|
||||
plugins_sync=fuelclient.commands.plugins:PluginsSync
|
||||
release_component_list=fuelclient.commands.release:ReleaseComponentList
|
||||
release_list=fuelclient.commands.release:ReleaseList
|
||||
|
|
Loading…
Reference in New Issue