summaryrefslogtreecommitdiff
path: root/nova/api/openstack/compute/plugins/v3/baremetal_nodes.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/api/openstack/compute/plugins/v3/baremetal_nodes.py')
-rw-r--r--nova/api/openstack/compute/plugins/v3/baremetal_nodes.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/nova/api/openstack/compute/plugins/v3/baremetal_nodes.py b/nova/api/openstack/compute/plugins/v3/baremetal_nodes.py
new file mode 100644
index 0000000000..3582e88090
--- /dev/null
+++ b/nova/api/openstack/compute/plugins/v3/baremetal_nodes.py
@@ -0,0 +1,173 @@
+# Copyright (c) 2013 NTT DOCOMO, INC.
+# Copyright 2014 IBM Corporation.
+# All Rights Reserved.
+#
+# 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.
+
+"""The bare-metal admin extension."""
+
+from oslo.config import cfg
+from oslo.utils import importutils
+import webob
+
+from nova.api.openstack import extensions
+from nova.api.openstack import wsgi
+from nova.i18n import _
+
+ironic_client = importutils.try_import('ironicclient.client')
+
+CONF = cfg.CONF
+ALIAS = "os-baremetal-nodes"
+authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
+
+node_fields = ['id', 'cpus', 'local_gb', 'memory_mb', 'pm_address',
+ 'pm_user', 'service_host', 'terminal_port', 'instance_uuid']
+
+node_ext_fields = ['uuid', 'task_state', 'updated_at', 'pxe_config_path']
+
+interface_fields = ['id', 'address', 'datapath_id', 'port_no']
+
+CONF.import_opt('api_version',
+ 'nova.virt.ironic.driver',
+ group='ironic')
+CONF.import_opt('api_endpoint',
+ 'nova.virt.ironic.driver',
+ group='ironic')
+CONF.import_opt('admin_username',
+ 'nova.virt.ironic.driver',
+ group='ironic')
+CONF.import_opt('admin_password',
+ 'nova.virt.ironic.driver',
+ group='ironic')
+CONF.import_opt('admin_tenant_name',
+ 'nova.virt.ironic.driver',
+ group='ironic')
+CONF.import_opt('compute_driver', 'nova.virt.driver')
+
+
+def _interface_dict(interface_ref):
+ d = {}
+ for f in interface_fields:
+ d[f] = interface_ref.get(f)
+ return d
+
+
+def _get_ironic_client():
+ """return an Ironic client."""
+ # TODO(NobodyCam): Fix insecure setting
+ kwargs = {'os_username': CONF.ironic.admin_username,
+ 'os_password': CONF.ironic.admin_password,
+ 'os_auth_url': CONF.ironic.admin_url,
+ 'os_tenant_name': CONF.ironic.admin_tenant_name,
+ 'os_service_type': 'baremetal',
+ 'os_endpoint_type': 'public',
+ 'insecure': 'true',
+ 'ironic_url': CONF.ironic.api_endpoint}
+ icli = ironic_client.get_client(CONF.ironic.api_version, **kwargs)
+ return icli
+
+
+def _no_ironic_proxy(cmd):
+ raise webob.exc.HTTPBadRequest(
+ explanation=_("Command Not supported. Please use Ironic "
+ "command %(cmd)s to perform this "
+ "action.") % {'cmd': cmd})
+
+
+class BareMetalNodeController(wsgi.Controller):
+ """The Bare-Metal Node API controller for the OpenStack API."""
+
+ def _node_dict(self, node_ref):
+ d = {}
+ for f in node_fields:
+ d[f] = node_ref.get(f)
+ for f in node_ext_fields:
+ d[f] = node_ref.get(f)
+ return d
+
+ @extensions.expected_errors(404)
+ def index(self, req):
+ context = req.environ['nova.context']
+ authorize(context)
+ nodes = []
+ # proxy command to Ironic
+ icli = _get_ironic_client()
+ ironic_nodes = icli.node.list(detail=True)
+ for inode in ironic_nodes:
+ node = {'id': inode.uuid,
+ 'interfaces': [],
+ 'host': 'IRONIC MANAGED',
+ 'task_state': inode.provision_state,
+ 'cpus': inode.properties['cpus'],
+ 'memory_mb': inode.properties['memory_mb'],
+ 'disk_gb': inode.properties['local_gb']}
+ nodes.append(node)
+ return {'nodes': nodes}
+
+ @extensions.expected_errors(404)
+ def show(self, req, id):
+ context = req.environ['nova.context']
+ authorize(context)
+ # proxy command to Ironic
+ icli = _get_ironic_client()
+ inode = icli.node.get(id)
+ iports = icli.node.list_ports(id)
+ node = {'id': inode.uuid,
+ 'interfaces': [],
+ 'host': 'IRONIC MANAGED',
+ 'task_state': inode.provision_state,
+ 'cpus': inode.properties['cpus'],
+ 'memory_mb': inode.properties['memory_mb'],
+ 'disk_gb': inode.properties['local_gb'],
+ 'instance_uuid': inode.instance_uuid}
+ for port in iports:
+ node['interfaces'].append({'address': port.address})
+ return {'node': node}
+
+ @extensions.expected_errors(400)
+ def create(self, req, body):
+ _no_ironic_proxy("port-create")
+
+ @extensions.expected_errors(400)
+ def delete(self, req, id):
+ _no_ironic_proxy("port-create")
+
+ @wsgi.action('add_interface')
+ @extensions.expected_errors(400)
+ def _add_interface(self, req, id, body):
+ _no_ironic_proxy("port-create")
+
+ @wsgi.action('remove_interface')
+ @extensions.expected_errors(400)
+ def _remove_interface(self, req, id, body):
+ _no_ironic_proxy("port-delete")
+
+
+class BareMetalNodes(extensions.V3APIExtensionBase):
+ """Admin-only bare-metal node administration."""
+
+ name = "BareMetalNodes"
+ alias = ALIAS
+ version = 1
+
+ def get_resources(self):
+ resource = [extensions.ResourceExtension(ALIAS,
+ BareMetalNodeController(),
+ member_actions={"action": "POST"})]
+ return resource
+
+ def get_controller_extensions(self):
+ """It's an abstract function V3APIExtensionBase and the extension
+ will not be loaded without it.
+ """
+ return []