Add support for OpenStack Ironic actions

This patch adds support for all supported Ironic v1 API
actions via Mistral.

Implements: blueprint ironic-actions
Change-Id: Ib84caf28b7fe9f08bbaa8502b012132dff5dba58
This commit is contained in:
Dan Prince 2015-11-30 14:12:19 -05:00
parent d9736d2881
commit 0eddd11d80
8 changed files with 123 additions and 1 deletions

View File

@ -24,5 +24,6 @@ def all_generators():
generators.NeutronActionGenerator,
generators.CinderActionGenerator,
generators.CeilometerActionGenerator,
generators.TroveActionGenerator
generators.TroveActionGenerator,
generators.IronicActionGenerator
]

View File

@ -54,3 +54,8 @@ class CeilometerActionGenerator(base.OpenStackActionGenerator):
class TroveActionGenerator(base.OpenStackActionGenerator):
action_namespace = "trove"
base_action_class = actions.TroveAction
class IronicActionGenerator(base.OpenStackActionGenerator):
action_namespace = "ironic"
base_action_class = actions.IronicAction

View File

@ -16,6 +16,7 @@ from ceilometerclient.v2 import client as ceilometerclient
from cinderclient.v2 import client as cinderclient
from glanceclient.v2 import client as glanceclient
from heatclient.v1 import client as heatclient
from ironicclient.v1 import client as ironicclient
from keystoneclient import httpclient
from keystoneclient.v3 import client as keystoneclient
from neutronclient.v2_0 import client as neutronclient
@ -268,3 +269,24 @@ class TroveAction(base.OpenStackAction):
@classmethod
def _get_fake_client(cls):
return cls._client_class()
class IronicAction(base.OpenStackAction):
_client_class = ironicclient.Client
def _get_client(self):
ctx = context.ctx()
LOG.debug("Ironic action security context: %s" % ctx)
ironic_endpoint = keystone_utils.get_endpoint_for_project('ironic')
return self._client_class(
ironic_endpoint.url,
token=ctx.auth_token,
region_name=ironic_endpoint.region
)
@classmethod
def _get_fake_client(cls):
return cls._client_class("http://127.0.0.1:6385/")

View File

@ -869,5 +869,46 @@
"configuration_parameters_get_parameter": "configuration_parameters.get_parameter",
"configuration_parameters_parameters_by_version": "configuration_parameters.parameters_by_version",
"configuration_parameters_get_parameter_by_version": "configuration_parameters.get_parameter_by_version"
},
"ironic": {
"_comment": "It uses ironicclient.v1.",
"chassis_create": "chassis.create",
"chassis_delete": "chassis.delete",
"chassis_get": "chassis.get",
"chassis_list": "chassis.list",
"chassis_list_nodes": "chassis.list_nodes",
"chassis_update": "chassis.update",
"driver_delete": "driver.delete",
"driver_get": "driver.get",
"driver_get_vendor_passthru_methods": "driver.get_vendor_passthru_methods",
"driver_list": "driver.list",
"driver_properties": "driver.properties",
"driver_update": "driver.update",
"driver_vendor_passthru": "driver.vendor_passthru",
"node_create": "node.create",
"node_delete": "node.delete",
"node_get": "node.get",
"node_get_boot_device": "node.get_boot_device",
"node_get_by_instance_uuid": "node.get_by_instance_uuid",
"node_get_console": "node.get_console",
"node_get_supported_boot_devices": "node.get_supported_boot_devices",
"node_get_vendor_passthru_methods": "node.get_vendor_passthru_methods",
"node_list": "node.list",
"node_list_ports": "node.list_ports",
"node_set_boot_device": "node.set_boot_device",
"node_set_console_mode": "node.set_console_mode",
"node_set_maintenance": "node.set_maintenance",
"node_set_power_state": "node.set_power_state",
"node_set_provision_state": "node.set_provision_state",
"node_states": "node.states",
"node_update": "node.update",
"node_validate": "node.validate",
"node_vendor_passthru": "node.vendor_passthru",
"port_create": "port.create",
"port_delete": "port.delete",
"port_get": "port.get",
"port_get_by_address": "port.get_by_address",
"port_list": "port.list",
"port_update": "port.update"
}
}

View File

@ -0,0 +1,32 @@
# Copyright 2015 - AT&T Services, Inc.
#
# 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.
from mistral.actions.openstack.action_generator import generators
from mistral.actions.openstack import actions
from mistral.tests.unit import base
class IronicGeneratorTest(base.BaseTest):
def test_generator(self):
action_name = "ironic.node_list"
generator = generators.IronicActionGenerator
action_classes = generator.create_actions()
action = self._assert_single_item(
action_classes,
name=action_name
)
self.assertIsNotNone(generator)
self.assertTrue(issubclass(action['class'], actions.IronicAction))
self.assertEqual("node.list", action['class'].client_method_name)

View File

@ -114,3 +114,15 @@ class OpenStackActionTest(base.BaseTestCase):
self.assertTrue(mocked().instances.get.called)
mocked().instances.get.assert_called_once_with(instance="1234-abcd")
@mock.patch.object(actions.IronicAction, '_get_client')
def test_ironic_action(self, mocked):
method_name = "node.get"
action_class = actions.IronicAction
action_class.client_method_name = method_name
params = {'node': '1234-abcd'}
action = action_class(**params)
action.run()
self.assertTrue(mocked().node.get.called)
mocked().node.get.assert_called_once_with(node="1234-abcd")

View File

@ -29,6 +29,7 @@ python-keystoneclient!=1.8.0,>=1.6.0
python-neutronclient>=2.6.0
python-novaclient!=2.33.0,>=2.29.0
python-troveclient>=1.2.0
python-ironicclient>=0.8.0
PyYAML>=3.1.0
requests>=2.8.1
retrying!=1.3.0,>=1.2.3 # Apache-2.0

View File

@ -30,6 +30,8 @@ from novaclient import client as novaclient
from novaclient.openstack.common.apiclient import base as nova_base
from troveclient import base as trove_base
from troveclient.v1 import client as troveclient
from ironicclient.common import base as ironic_base
from ironicclient.v1 import client as ironicclient
# TODO(nmakhotkin): Find a rational way to do it for neutron.
# TODO(nmakhotkin): Implement recursive way of searching for managers
@ -62,6 +64,7 @@ BASE_NOVA_MANAGER = nova_base.HookableMixin
BASE_KEYSTONE_MANAGER = keystone_base.Manager
BASE_CINDER_MANAGER = cinder_base.HookableMixin
BASE_TROVE_MANAGER = trove_base.Manager
BASE_IRONIC_MANAGER = ironic_base.Manager
def get_parser():
parser = argparse.ArgumentParser(
@ -138,6 +141,9 @@ def get_cinder_client(**kwargs):
def get_trove_client(**kwargs):
return troveclient.Client('username', 'password')
def get_ironic_client(**kwargs):
return ironicclient.Client("http://127.0.0.1:6385/")
CLIENTS = {
'nova': get_nova_client,
'heat': get_heat_client,
@ -146,6 +152,7 @@ CLIENTS = {
'keystone': get_keystone_client,
'glance': get_glance_client,
'trove' : get_trove_client,
'ironic' : get_ironic_client,
# 'neutron': get_nova_client
}
BASE_MANAGERS = {
@ -156,6 +163,7 @@ BASE_MANAGERS = {
'keystone': BASE_KEYSTONE_MANAGER,
'glance': None,
'trove': BASE_TROVE_MANAGER,
'ironic': BASE_IRONIC_MANAGER,
# 'neutron': BASE_NOVA_MANAGER
}
NAMESPACES = {