diff --git a/doc/source/man/index.rst b/doc/source/man/index.rst index 38dc6cad5e..46f5c17ff0 100644 --- a/doc/source/man/index.rst +++ b/doc/source/man/index.rst @@ -30,8 +30,6 @@ Reference nova-api-metadata nova-api-os-compute nova-api - nova-baremetal-deploy-helper - nova-baremetal-manage nova-cert nova-compute nova-conductor diff --git a/doc/source/man/nova-baremetal-deploy-helper.rst b/doc/source/man/nova-baremetal-deploy-helper.rst deleted file mode 100644 index 838c3dd85d..0000000000 --- a/doc/source/man/nova-baremetal-deploy-helper.rst +++ /dev/null @@ -1,52 +0,0 @@ -============================ -nova-baremetal-deploy-helper -============================ - ------------------------------------------------------------------- -Writes images to a bare-metal node and switch it to instance-mode ------------------------------------------------------------------- - -:Author: openstack@lists.openstack.org -:Date: 2012-10-17 -:Copyright: OpenStack Foundation -:Version: 2013.1 -:Manual section: 1 -:Manual group: cloud computing - -SYNOPSIS -======== - - nova-baremetal-deploy-helper - -DESCRIPTION -=========== - -This is a service which should run on nova-compute host when using the -baremetal driver. During a baremetal node's first boot, -nova-baremetal-deploy-helper works in conjunction with diskimage-builder's -"deploy" ramdisk to write an image from glance onto the baremetal node's disks -using iSCSI. After that is complete, nova-baremetal-deploy-helper switches the -PXE config to reference the kernel and ramdisk which correspond to the running -image. - -OPTIONS -======= - - **General options** - -FILES -======== - -* /etc/nova/nova.conf -* /etc/nova/rootwrap.conf -* /etc/nova/rootwrap.d/ - -SEE ALSO -======== - -* `OpenStack Nova `__ - -BUGS -==== - -* Nova bugs are managed at Launchpad `Bugs : Nova `__ diff --git a/doc/source/man/nova-baremetal-manage.rst b/doc/source/man/nova-baremetal-manage.rst deleted file mode 100644 index 6dc6d164d6..0000000000 --- a/doc/source/man/nova-baremetal-manage.rst +++ /dev/null @@ -1,67 +0,0 @@ -===================== -nova-baremetal-manage -===================== - ------------------------------------------------------- -Manage bare-metal DB in OpenStack Nova ------------------------------------------------------- - -:Author: openstack@lists.openstack.org -:Date: 2012-10-17 -:Copyright: OpenStack Foundation -:Version: 2013.1 -:Manual section: 1 -:Manual group: cloud computing - -SYNOPSIS -======== - - nova-baremetal-manage [] - -DESCRIPTION -=========== - -nova-baremetal-manage manages bare-metal DB schema. - -OPTIONS -======= - -The standard pattern for executing a nova-baremetal-manage command is: -``nova-baremetal-manage []`` - -Run without arguments to see a list of available command categories: -``nova-baremetal-manage`` - -Categories are db. Detailed descriptions are below. - -You can also run with a category argument such as "db" to see a list of all commands in that category: -``nova-baremetal-manage db`` - -These sections describe the available categories and arguments for nova-baremetal-manage. - -Bare-Metal DB -~~~~~~~~~~~~~ - -``nova-baremetal-manage db version`` - - Print the current database version. - -``nova-baremetal-manage db sync`` - - Sync the database up to the most recent version. This is the standard way to create the db as well. - -FILES -======== - -/etc/nova/nova.conf: get location of bare-metal DB - -SEE ALSO -======== - -* `OpenStack Nova `__ - -BUGS -==== - -* Nova bugs are managed at Launchpad `Bugs : Nova `__ - diff --git a/nova/api/openstack/compute/contrib/baremetal_nodes.py b/nova/api/openstack/compute/contrib/baremetal_nodes.py index a50f4b4afd..3f9f710c4a 100644 --- a/nova/api/openstack/compute/contrib/baremetal_nodes.py +++ b/nova/api/openstack/compute/contrib/baremetal_nodes.py @@ -15,7 +15,6 @@ """The bare-metal admin extension with Ironic Proxy.""" -import netaddr from oslo.config import cfg from oslo.utils import importutils import webob @@ -23,10 +22,8 @@ import webob from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil -from nova import exception from nova.i18n import _ from nova.openstack.common import log as logging -from nova.virt.baremetal import db ironic_client = importutils.try_import('ironicclient.client') @@ -80,14 +77,6 @@ def _make_interface_elem(elem): elem.set(f) -def _use_ironic(): - # TODO(lucasagomes): This switch this should also be deleted as - # part of the Nova Baremetal removal effort. At that point, any - # code that checks it should assume True, the False case should be - # removed, and this API will only/always proxy to Ironic. - return 'ironic' in CONF.compute_driver - - def _get_ironic_client(): """return an Ironic client.""" # TODO(NobodyCam): Fix insecure setting @@ -110,20 +99,6 @@ def _no_ironic_proxy(cmd): "action.") % {'cmd': cmd}) -def is_valid_mac(address): - """Verify the format of a MAC address.""" - - class mac_dialect(netaddr.mac_eui48): - word_fmt = '%.02x' - word_sep = ':' - - try: - na = netaddr.EUI(address, dialect=mac_dialect) - except Exception: - return False - return str(na) == address.lower() - - class NodeTemplate(xmlutil.TemplateBuilder): def construct(self): node_elem = xmlutil.TemplateElement('node', selector='node') @@ -149,13 +124,6 @@ class NodesTemplate(xmlutil.TemplateBuilder): return xmlutil.MasterTemplate(root, 1) -class InterfaceTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('interface', selector='interface') - _make_interface_elem(root) - return xmlutil.MasterTemplate(root, 1) - - class BareMetalNodeController(wsgi.Controller): """The Bare-Metal Node API controller for the OpenStack API. @@ -182,161 +150,54 @@ class BareMetalNodeController(wsgi.Controller): context = req.environ['nova.context'] authorize(context) nodes = [] - if _use_ironic(): - # 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) - else: - # use nova baremetal - nodes_from_db = db.bm_node_get_all(context) - for node_from_db in nodes_from_db: - try: - ifs = db.bm_interface_get_all_by_bm_node_id( - context, node_from_db['id']) - except exception.NodeNotFound: - ifs = [] - node = self._node_dict(node_from_db) - node['interfaces'] = [_interface_dict(i) for i in ifs] - nodes.append(node) - return {'nodes': nodes} - - @wsgi.serializers(xml=NodeTemplate) - def show(self, req, id): - context = req.environ['nova.context'] - authorize(context) - if _use_ironic(): - # proxy command to Ironic - icli = _get_ironic_client() - inode = icli.node.get(id) - iports = icli.node.list_ports(id) + # 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'], - 'instance_uuid': inode.instance_uuid} - for port in iports: - node['interfaces'].append({'address': port.address}) - else: - # use nova baremetal - try: - node = db.bm_node_get(context, id) - except exception.NodeNotFound: - raise webob.exc.HTTPNotFound() - try: - ifs = db.bm_interface_get_all_by_bm_node_id(context, id) - except exception.NodeNotFound: - ifs = [] - node = self._node_dict(node) - node['interfaces'] = [_interface_dict(i) for i in ifs] + 'disk_gb': inode.properties['local_gb']} + nodes.append(node) + return {'nodes': nodes} + + @wsgi.serializers(xml=NodeTemplate) + 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} @wsgi.serializers(xml=NodeTemplate) def create(self, req, body): - if _use_ironic(): - _no_ironic_proxy("node-create") - - context = req.environ['nova.context'] - authorize(context) - values = body['node'].copy() - prov_mac_address = values.pop('prov_mac_address', None) - if (prov_mac_address is not None - and not is_valid_mac(prov_mac_address)): - raise webob.exc.HTTPBadRequest( - explanation=_("Must specify address " - "in the form of xx:xx:xx:xx:xx:xx")) - node = db.bm_node_create(context, values) - node = self._node_dict(node) - if prov_mac_address: - if_id = db.bm_interface_create(context, - bm_node_id=node['id'], - address=prov_mac_address, - datapath_id=None, - port_no=None) - if_ref = db.bm_interface_get(context, if_id) - node['interfaces'] = [_interface_dict(if_ref)] - else: - node['interfaces'] = [] - return {'node': node} + _no_ironic_proxy("port-create") def delete(self, req, id): - if _use_ironic(): - _no_ironic_proxy("node-delete") + _no_ironic_proxy("port-create") - context = req.environ['nova.context'] - authorize(context) - try: - db.bm_node_destroy(context, id) - except exception.NodeNotFound: - raise webob.exc.HTTPNotFound() - return webob.Response(status_int=202) - - def _check_node_exists(self, context, node_id): - try: - db.bm_node_get(context, node_id) - except exception.NodeNotFound: - raise webob.exc.HTTPNotFound() - - @wsgi.serializers(xml=InterfaceTemplate) @wsgi.action('add_interface') def _add_interface(self, req, id, body): - if _use_ironic(): - _no_ironic_proxy("port-create") + _no_ironic_proxy("port-create") - context = req.environ['nova.context'] - authorize(context) - self._check_node_exists(context, id) - body = body['add_interface'] - address = body['address'] - datapath_id = body.get('datapath_id') - port_no = body.get('port_no') - if not is_valid_mac(address): - raise webob.exc.HTTPBadRequest( - explanation=_("Must specify address " - "in the form of xx:xx:xx:xx:xx:xx")) - if_id = db.bm_interface_create(context, - bm_node_id=id, - address=address, - datapath_id=datapath_id, - port_no=port_no) - if_ref = db.bm_interface_get(context, if_id) - return {'interface': _interface_dict(if_ref)} - - @wsgi.response(202) @wsgi.action('remove_interface') def _remove_interface(self, req, id, body): - if _use_ironic(): - _no_ironic_proxy("port-delete") - - context = req.environ['nova.context'] - authorize(context) - self._check_node_exists(context, id) - body = body['remove_interface'] - if_id = body.get('id') - address = body.get('address') - if not if_id and not address: - raise webob.exc.HTTPBadRequest( - explanation=_("Must specify id or address")) - ifs = db.bm_interface_get_all_by_bm_node_id(context, id) - for i in ifs: - if if_id and if_id != i['id']: - continue - if address and address != i['address']: - continue - db.bm_interface_destroy(context, i['id']) - return webob.Response(status_int=202) - raise webob.exc.HTTPNotFound() + _no_ironic_proxy("port-delete") class Baremetal_nodes(extensions.ExtensionDescriptor): diff --git a/nova/cmd/baremetal_deploy_helper.py b/nova/cmd/baremetal_deploy_helper.py deleted file mode 100644 index dc6e961b1a..0000000000 --- a/nova/cmd/baremetal_deploy_helper.py +++ /dev/null @@ -1,376 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Starter script for Bare-Metal Deployment Service.""" - - -import cgi -import os -import Queue -import re -import socket -import stat -import sys -import threading -import time -from wsgiref import simple_server - -from oslo.utils import excutils -from oslo.utils import units - -from nova import config -from nova import context as nova_context -from nova.i18n import _ -from nova import objects -from nova.openstack.common import log as logging -from nova.openstack.common import processutils -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import db -from nova.virt.disk import api as disk - - -QUEUE = Queue.Queue() -LOG = logging.getLogger(__name__) - - -class BareMetalDeployException(Exception): - pass - - -# All functions are called from deploy() directly or indirectly. -# They are split for stub-out. - -def discovery(portal_address, portal_port): - """Do iSCSI discovery on portal.""" - utils.execute('iscsiadm', - '-m', 'discovery', - '-t', 'st', - '-p', '%s:%s' % (portal_address, portal_port), - run_as_root=True, - check_exit_code=[0]) - - -def login_iscsi(portal_address, portal_port, target_iqn): - """Login to an iSCSI target.""" - utils.execute('iscsiadm', - '-m', 'node', - '-p', '%s:%s' % (portal_address, portal_port), - '-T', target_iqn, - '--login', - run_as_root=True, - check_exit_code=[0]) - # Ensure the login complete - time.sleep(10) - - -def logout_iscsi(portal_address, portal_port, target_iqn): - """Logout from an iSCSI target.""" - utils.execute('iscsiadm', - '-m', 'node', - '-p', '%s:%s' % (portal_address, portal_port), - '-T', target_iqn, - '--logout', - run_as_root=True, - check_exit_code=[0]) - - -def make_partitions(dev, root_mb, swap_mb, ephemeral_mb): - """Create partitions for root, ephemeral and swap on a disk device.""" - # Lead in with 1MB to allow room for the partition table itself, otherwise - # the way sfdisk adjusts doesn't shift the partition up to compensate, and - # we lose the space. - # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/raring/util-linux/ - # raring/view/head:/fdisk/sfdisk.c#L1940 - if ephemeral_mb: - stdin_command = ('1,%d,83;\n,%d,82;\n,%d,83;\n0,0;\n' % - (ephemeral_mb, swap_mb, root_mb)) - else: - stdin_command = ('1,%d,83;\n,%d,82;\n0,0;\n0,0;\n' % - (root_mb, swap_mb)) - utils.execute('sfdisk', '-uM', dev, process_input=stdin_command, - run_as_root=True, - attempts=3, - check_exit_code=[0]) - # avoid "device is busy" - time.sleep(10) - - -def is_block_device(dev): - """Check whether a device is block or not.""" - s = os.stat(dev) - return stat.S_ISBLK(s.st_mode) - - -def dd(src, dst): - """Execute dd from src to dst.""" - utils.execute('dd', - 'if=%s' % src, - 'of=%s' % dst, - 'bs=1M', - 'oflag=direct', - run_as_root=True, - check_exit_code=[0]) - - -def mkswap(dev, label='swap1'): - """Execute mkswap on a device.""" - utils.execute('mkswap', - '-L', label, - dev, - run_as_root=True, - check_exit_code=[0]) - - -def mkfs_ephemeral(dev, label="ephemeral0"): - # TODO(jogo) support non-default mkfs options as well - disk.mkfs("default", label, dev) - - -def block_uuid(dev): - """Get UUID of a block device.""" - out, _ = utils.execute('blkid', '-s', 'UUID', '-o', 'value', dev, - run_as_root=True, - check_exit_code=[0]) - return out.strip() - - -def switch_pxe_config(path, root_uuid): - """Switch a pxe config from deployment mode to service mode.""" - with open(path) as f: - lines = f.readlines() - root = 'UUID=%s' % root_uuid - rre = re.compile(r'\$\{ROOT\}') - dre = re.compile('^default .*$') - with open(path, 'w') as f: - for line in lines: - line = rre.sub(root, line) - line = dre.sub('default boot', line) - f.write(line) - - -def notify(address, port): - """Notify a node that it becomes ready to reboot.""" - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect((address, port)) - s.send('done') - finally: - s.close() - - -def get_dev(address, port, iqn, lun): - """Returns a device path for given parameters.""" - dev = "/dev/disk/by-path/ip-%s:%s-iscsi-%s-lun-%s" \ - % (address, port, iqn, lun) - return dev - - -def get_image_mb(image_path): - """Get size of an image in Megabyte.""" - mb = units.Mi - image_byte = os.path.getsize(image_path) - # round up size to MB - image_mb = int((image_byte + mb - 1) / mb) - return image_mb - - -def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, image_path, - preserve_ephemeral): - """Creates partitions and write an image to the root partition. - - :param preserve_ephemeral: If True, no filesystem is written to the - ephemeral block device, preserving whatever content it had (if the - partition table has not changed). - """ - def raise_exception(msg): - LOG.error(msg) - raise BareMetalDeployException(msg) - - if ephemeral_mb: - ephemeral_part = "%s-part1" % dev - swap_part = "%s-part2" % dev - root_part = "%s-part3" % dev - else: - root_part = "%s-part1" % dev - swap_part = "%s-part2" % dev - - if not is_block_device(dev): - raise_exception(_("parent device '%s' not found") % dev) - make_partitions(dev, root_mb, swap_mb, ephemeral_mb) - if not is_block_device(root_part): - raise_exception(_("root device '%s' not found") % root_part) - if not is_block_device(swap_part): - raise_exception(_("swap device '%s' not found") % swap_part) - if ephemeral_mb and not is_block_device(ephemeral_part): - raise_exception(_("ephemeral device '%s' not found") % ephemeral_part) - dd(image_path, root_part) - mkswap(swap_part) - if ephemeral_mb and not preserve_ephemeral: - mkfs_ephemeral(ephemeral_part) - - try: - root_uuid = block_uuid(root_part) - except processutils.ProcessExecutionError: - with excutils.save_and_reraise_exception(): - LOG.error(_("Failed to detect root device UUID.")) - return root_uuid - - -def deploy(address, port, iqn, lun, image_path, pxe_config_path, - root_mb, swap_mb, ephemeral_mb, preserve_ephemeral=False): - """All-in-one function to deploy a node. - - :param preserve_ephemeral: If True, no filesystem is written to the - ephemeral block device, preserving whatever content it had (if the - partition table has not changed). - """ - dev = get_dev(address, port, iqn, lun) - image_mb = get_image_mb(image_path) - if image_mb > root_mb: - root_mb = image_mb - discovery(address, port) - login_iscsi(address, port, iqn) - try: - root_uuid = work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, - image_path, preserve_ephemeral) - except processutils.ProcessExecutionError as err: - with excutils.save_and_reraise_exception(): - # Log output if there was a error - LOG.error(_("Cmd : %s"), err.cmd) - LOG.error(_("StdOut : %r"), err.stdout) - LOG.error(_("StdErr : %r"), err.stderr) - finally: - logout_iscsi(address, port, iqn) - switch_pxe_config(pxe_config_path, root_uuid) - # Ensure the node started netcat on the port after POST the request. - time.sleep(3) - notify(address, 10000) - - -class Worker(threading.Thread): - """Thread that handles requests in queue.""" - - def __init__(self): - super(Worker, self).__init__() - self.setDaemon(True) - self.stop = False - self.queue_timeout = 1 - - def run(self): - while not self.stop: - try: - # Set timeout to check self.stop periodically - (node_id, params) = QUEUE.get(block=True, - timeout=self.queue_timeout) - except Queue.Empty: - pass - else: - # Requests comes here from BareMetalDeploy.post() - LOG.info(_('start deployment for node %(node_id)s, ' - 'params %(params)s'), - {'node_id': node_id, 'params': params}) - context = nova_context.get_admin_context() - try: - db.bm_node_update(context, node_id, - {'task_state': baremetal_states.DEPLOYING}) - deploy(**params) - except Exception: - LOG.exception(_('deployment to node %s failed'), node_id) - db.bm_node_update(context, node_id, - {'task_state': baremetal_states.DEPLOYFAIL}) - else: - LOG.info(_('deployment to node %s done'), node_id) - db.bm_node_update(context, node_id, - {'task_state': baremetal_states.DEPLOYDONE}) - - -class BareMetalDeploy(object): - """WSGI server for bare-metal deployment.""" - - def __init__(self): - self.worker = Worker() - self.worker.start() - - def __call__(self, environ, start_response): - method = environ['REQUEST_METHOD'] - if method == 'POST': - return self.post(environ, start_response) - else: - start_response('501 Not Implemented', - [('Content-type', 'text/plain')]) - return 'Not Implemented' - - def post(self, environ, start_response): - LOG.info(_("post: environ=%s"), environ) - inpt = environ['wsgi.input'] - length = int(environ.get('CONTENT_LENGTH', 0)) - - x = inpt.read(length) - q = dict(cgi.parse_qsl(x)) - try: - node_id = q['i'] - deploy_key = q['k'] - address = q['a'] - port = q.get('p', '3260') - iqn = q['n'] - lun = q.get('l', '1') - err_msg = q.get('e') - except KeyError as e: - start_response('400 Bad Request', [('Content-type', 'text/plain')]) - return "parameter '%s' is not defined" % e - - if err_msg: - LOG.error(_('Deploy agent error message: %s'), err_msg) - - context = nova_context.get_admin_context() - d = db.bm_node_get(context, node_id) - - if d['deploy_key'] != deploy_key: - start_response('400 Bad Request', [('Content-type', 'text/plain')]) - return 'key is not match' - - params = {'address': address, - 'port': port, - 'iqn': iqn, - 'lun': lun, - 'image_path': d['image_path'], - 'pxe_config_path': d['pxe_config_path'], - 'root_mb': int(d['root_mb']), - 'swap_mb': int(d['swap_mb']), - 'ephemeral_mb': int(d['ephemeral_mb']), - 'preserve_ephemeral': d['preserve_ephemeral'], - } - # Restart worker, if needed - if not self.worker.isAlive(): - self.worker = Worker() - self.worker.start() - LOG.info(_("request is queued: node %(node_id)s, params %(params)s"), - {'node_id': node_id, 'params': params}) - QUEUE.put((node_id, params)) - # Requests go to Worker.run() - start_response('200 OK', [('Content-type', 'text/plain')]) - return '' - - -def main(): - config.parse_args(sys.argv) - logging.setup("nova") - global LOG - LOG = logging.getLogger('nova.virt.baremetal.deploy_helper') - objects.register_all() - app = BareMetalDeploy() - srv = simple_server.make_server('', 10000, app) - srv.serve_forever() diff --git a/nova/cmd/baremetal_manage.py b/nova/cmd/baremetal_manage.py deleted file mode 100644 index e8283221ec..0000000000 --- a/nova/cmd/baremetal_manage.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -# Interactive shell based on Django: -# -# Copyright (c) 2005, the Lawrence Journal-World -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of Django nor the names of its contributors may be -# used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -""" - CLI interface for nova bare-metal management. -""" - -import os -import sys - -from oslo.config import cfg -import six - -from nova import config -from nova.i18n import _ -from nova import objects -from nova.openstack.common import cliutils -from nova.openstack.common import log as logging -from nova import version -from nova.virt.baremetal.db import migration as bmdb_migration - -CONF = cfg.CONF - - -# Decorators for actions -def args(*args, **kwargs): - def _decorator(func): - func.__dict__.setdefault('args', []).insert(0, (args, kwargs)) - return func - return _decorator - - -class BareMetalDbCommands(object): - """Class for managing the bare-metal database.""" - - def __init__(self): - pass - - @args('--version', dest='version', metavar='', - help='Bare-metal Database version') - def sync(self, version=None): - """Sync the database up to the most recent version.""" - bmdb_migration.db_sync(version) - - def version(self): - """Print the current database version.""" - v = bmdb_migration.db_version() - print(v) - # return for unittest - return v - - -CATEGORIES = { - 'db': BareMetalDbCommands, -} - - -def methods_of(obj): - """Get all callable methods of an object that don't start with underscore. - - returns a list of tuples of the form (method_name, method) - """ - result = [] - for i in dir(obj): - if callable(getattr(obj, i)) and not i.startswith('_'): - result.append((i, getattr(obj, i))) - return result - - -def add_command_parsers(subparsers): - parser = subparsers.add_parser('bash-completion') - parser.add_argument('query_category', nargs='?') - - for category in CATEGORIES: - command_object = CATEGORIES[category]() - - parser = subparsers.add_parser(category) - parser.set_defaults(command_object=command_object) - - category_subparsers = parser.add_subparsers(dest='action') - - for (action, action_fn) in methods_of(command_object): - parser = category_subparsers.add_parser(action) - - action_kwargs = [] - for args, kwargs in getattr(action_fn, 'args', []): - action_kwargs.append(kwargs['dest']) - kwargs['dest'] = 'action_kwarg_' + kwargs['dest'] - parser.add_argument(*args, **kwargs) - - parser.set_defaults(action_fn=action_fn) - parser.set_defaults(action_kwargs=action_kwargs) - - parser.add_argument('action_args', nargs='*') - - -category_opt = cfg.SubCommandOpt('category', - title='Command categories', - help='Available categories', - handler=add_command_parsers) - - -def main(): - """Parse options and call the appropriate class/method.""" - CONF.register_cli_opt(category_opt) - try: - config.parse_args(sys.argv) - logging.setup("nova") - except cfg.ConfigFilesNotFoundError: - cfgfile = CONF.config_file[-1] if CONF.config_file else None - if cfgfile and not os.access(cfgfile, os.R_OK): - st = os.stat(cfgfile) - print(_("Could not read %s. Re-running with sudo") % cfgfile) - try: - os.execvp('sudo', ['sudo', '-u', '#%s' % st.st_uid] + sys.argv) - except Exception: - print(_('sudo failed, continuing as if nothing happened')) - - print(_('Please re-run nova-manage as root.')) - return(2) - - objects.register_all() - - if CONF.category.name == "version": - print(version.version_string_with_package()) - return(0) - - if CONF.category.name == "bash-completion": - if not CONF.category.query_category: - print(" ".join(CATEGORIES.keys())) - elif CONF.category.query_category in CATEGORIES: - fn = CATEGORIES[CONF.category.query_category] - command_object = fn() - actions = methods_of(command_object) - print(" ".join([k for (k, v) in actions])) - return(0) - - fn = CONF.category.action_fn - fn_args = [arg.decode('utf-8') for arg in CONF.category.action_args] - fn_kwargs = {} - for k in CONF.category.action_kwargs: - v = getattr(CONF.category, 'action_kwarg_' + k) - if v is None: - continue - if isinstance(v, six.string_types): - v = v.decode('utf-8') - fn_kwargs[k] = v - - # call the action with the remaining arguments - # check arguments - try: - cliutils.validate_args(fn, *fn_args, **fn_kwargs) - except cliutils.MissingArgs as e: - print(fn.__doc__) - print(e) - return(1) - try: - fn(*fn_args, **fn_kwargs) - return(0) - except Exception: - print(_("Command failed, please check log for more info")) - raise diff --git a/nova/tests/api/openstack/compute/contrib/test_baremetal_nodes.py b/nova/tests/api/openstack/compute/contrib/test_baremetal_nodes.py index 908e2b34c1..62a61afd69 100644 --- a/nova/tests/api/openstack/compute/contrib/test_baremetal_nodes.py +++ b/nova/tests/api/openstack/compute/contrib/test_baremetal_nodes.py @@ -20,10 +20,8 @@ from webob import exc from nova.api.openstack.compute.contrib import baremetal_nodes from nova.api.openstack import extensions from nova import context -from nova import exception from nova import test from nova.tests.virt.ironic import utils as ironic_utils -from nova.virt.baremetal import db CONF = cfg.CONF @@ -63,17 +61,6 @@ def fake_node_ext_status(**updates): return node -def fake_interface(**updates): - interface = { - 'id': 1, - 'address': '11:11:11:11:11:11', - 'datapath_id': 2, - 'port_no': 3, - } - if updates: - interface.update(updates) - return interface - FAKE_IRONIC_CLIENT = ironic_utils.FakeClient() @@ -89,302 +76,8 @@ class BareMetalNodesTest(test.NoDBTestCase): self.controller = baremetal_nodes.BareMetalNodeController(self.ext_mgr) self.request = FakeRequest(self.context) - def _test_create(self, node, ext_status=False): - response = node.copy() - del response['pm_password'] - response['instance_uuid'] = None - self.mox.StubOutWithMock(db, 'bm_node_create') - db.bm_node_create(self.context, node).AndReturn(response) - self.ext_mgr.is_loaded('os-baremetal-ext-status').AndReturn(ext_status) - self.mox.ReplayAll() - res_dict = self.controller.create(self.request, {'node': node}) - self.assertEqual({'node': response}, res_dict) - - def _test_show(self, node, ext_status=False): - interfaces = [fake_interface(id=1, address='11:11:11:11:11:11'), - fake_interface(id=2, address='22:22:22:22:22:22'), - ] - node.update(interfaces=interfaces) - response = node.copy() - del response['pm_password'] - self.mox.StubOutWithMock(db, 'bm_node_get') - self.mox.StubOutWithMock(db, 'bm_interface_get_all_by_bm_node_id') - db.bm_node_get(self.context, node['id']).AndReturn(node) - db.bm_interface_get_all_by_bm_node_id(self.context, node['id']).\ - AndReturn(interfaces) - self.ext_mgr.is_loaded('os-baremetal-ext-status').AndReturn(ext_status) - self.mox.ReplayAll() - res_dict = self.controller.show(self.request, node['id']) - self.assertEqual({'node': response}, res_dict) - self.assertEqual(2, len(res_dict['node']['interfaces'])) - - def _test_show_no_interfaces(self, ext_status=False): - node_id = 1 - node = {'id': node_id} - self.mox.StubOutWithMock(db, 'bm_node_get') - self.mox.StubOutWithMock(db, 'bm_interface_get_all_by_bm_node_id') - db.bm_node_get(self.context, node_id).AndReturn(node) - db.bm_interface_get_all_by_bm_node_id(self.context, node_id).\ - AndRaise(exception.NodeNotFound(node_id=node_id)) - self.ext_mgr.is_loaded('os-baremetal-ext-status').AndReturn(ext_status) - self.mox.ReplayAll() - res_dict = self.controller.show(self.request, node_id) - self.assertEqual(node_id, res_dict['node']['id']) - self.assertEqual(0, len(res_dict['node']['interfaces'])) - - def _test_index(self, ext_status=False): - nodes = [{'id': 1}, - {'id': 2}, - ] - interfaces = [{'id': 1, 'address': '11:11:11:11:11:11'}, - {'id': 2, 'address': '22:22:22:22:22:22'}, - ] - self.mox.StubOutWithMock(db, 'bm_node_get_all') - self.mox.StubOutWithMock(db, 'bm_interface_get_all_by_bm_node_id') - db.bm_node_get_all(self.context).AndReturn(nodes) - db.bm_interface_get_all_by_bm_node_id(self.context, 1).\ - AndRaise(exception.NodeNotFound(node_id=1)) - for n in nodes: - self.ext_mgr.is_loaded('os-baremetal-ext-status').\ - AndReturn(ext_status) - db.bm_interface_get_all_by_bm_node_id(self.context, 2).\ - AndReturn(interfaces) - self.mox.ReplayAll() - res_dict = self.controller.index(self.request) - self.assertEqual(2, len(res_dict['nodes'])) - self.assertEqual([], res_dict['nodes'][0]['interfaces']) - self.assertEqual(2, len(res_dict['nodes'][1]['interfaces'])) - - def test_create(self): - node = fake_node(id=100) - self._test_create(node) - - def test_create_ext_status(self): - node = fake_node_ext_status(id=100) - self._test_create(node, ext_status=True) - - def test_create_with_prov_mac_address(self): - node = { - 'service_host': "host", - 'cpus': 8, - 'memory_mb': 8192, - 'local_gb': 128, - 'pm_address': "10.1.2.3", - 'pm_user': "pm_user", - 'pm_password': "pm_pass", - 'terminal_port': 8000, - 'interfaces': [], - } - intf = { - 'address': '1a:B2:3C:4d:e5:6f', - 'datapath_id': None, - 'id': None, - 'port_no': None, - } - - request = node.copy() - request['prov_mac_address'] = intf['address'] - - db_node = node.copy() - db_node['id'] = 100 - - response = node.copy() - response.update(id=db_node['id'], - instance_uuid=None, - interfaces=[intf]) - del response['pm_password'] - - self.mox.StubOutWithMock(db, 'bm_node_create') - self.mox.StubOutWithMock(db, 'bm_interface_create') - self.mox.StubOutWithMock(db, 'bm_interface_get') - db.bm_node_create(self.context, node).AndReturn(db_node) - self.ext_mgr.is_loaded('os-baremetal-ext-status').AndReturn(False) - db.bm_interface_create(self.context, - bm_node_id=db_node['id'], - address=intf['address'], - datapath_id=intf['datapath_id'], - port_no=intf['port_no']).AndReturn(1000) - db.bm_interface_get(self.context, 1000).AndReturn(intf) - self.mox.ReplayAll() - res_dict = self.controller.create(self.request, {'node': request}) - self.assertEqual({'node': response}, res_dict) - - def test_create_with_invalid_prov_mac_address(self): - node = { - 'service_host': "host", - 'cpus': 8, - 'memory_mb': 8192, - 'local_gb': 128, - 'pm_address': "10.1.2.3", - 'pm_user': "pm_user", - 'pm_password': "pm_pass", - 'terminal_port': 8000, - 'prov_mac_address': 'INVALID!!', - } - self.assertRaises(exc.HTTPBadRequest, - self.controller.create, - self.request, {'node': node}) - - def test_delete(self): - self.mox.StubOutWithMock(db, 'bm_node_destroy') - db.bm_node_destroy(self.context, 1) - self.mox.ReplayAll() - self.controller.delete(self.request, 1) - - def test_delete_node_not_found(self): - self.mox.StubOutWithMock(db, 'bm_node_destroy') - db.bm_node_destroy(self.context, 1).\ - AndRaise(exception.NodeNotFound(node_id=1)) - self.mox.ReplayAll() - self.assertRaises( - exc.HTTPNotFound, - self.controller.delete, - self.request, - 1) - - def test_index(self): - self._test_index() - - def test_index_ext_status(self): - self._test_index(ext_status=True) - - def test_show(self): - node = fake_node(id=1) - self._test_show(node) - - def test_show_ext_status(self): - node = fake_node_ext_status(id=1) - self._test_show(node, ext_status=True) - - def test_show_no_interfaces(self): - self._test_show_no_interfaces() - - def test_show_no_interfaces_ext_status(self): - self._test_show_no_interfaces(ext_status=True) - - def test_add_interface(self): - node_id = 1 - address = '11:22:33:ab:cd:ef' - body = {'add_interface': {'address': address}} - self.mox.StubOutWithMock(db, 'bm_node_get') - self.mox.StubOutWithMock(db, 'bm_interface_create') - self.mox.StubOutWithMock(db, 'bm_interface_get') - db.bm_node_get(self.context, node_id) - db.bm_interface_create(self.context, - bm_node_id=node_id, - address=address, - datapath_id=None, - port_no=None).\ - AndReturn(12345) - db.bm_interface_get(self.context, 12345).\ - AndReturn({'id': 12345, 'address': address}) - self.mox.ReplayAll() - res_dict = self.controller._add_interface(self.request, node_id, body) - self.assertEqual(12345, res_dict['interface']['id']) - self.assertEqual(address, res_dict['interface']['address']) - - def test_add_interface_invalid_address(self): - node_id = 1 - body = {'add_interface': {'address': ''}} - self.mox.StubOutWithMock(db, 'bm_node_get') - db.bm_node_get(self.context, node_id) - self.mox.ReplayAll() - self.assertRaises(exc.HTTPBadRequest, - self.controller._add_interface, - self.request, - node_id, - body) - - def test_remove_interface(self): - node_id = 1 - interfaces = [{'id': 1}, - {'id': 2}, - {'id': 3}, - ] - body = {'remove_interface': {'id': 2}} - self.mox.StubOutWithMock(db, 'bm_node_get') - self.mox.StubOutWithMock(db, 'bm_interface_get_all_by_bm_node_id') - self.mox.StubOutWithMock(db, 'bm_interface_destroy') - db.bm_node_get(self.context, node_id) - db.bm_interface_get_all_by_bm_node_id(self.context, node_id).\ - AndReturn(interfaces) - db.bm_interface_destroy(self.context, 2) - self.mox.ReplayAll() - self.controller._remove_interface(self.request, node_id, body) - - def test_remove_interface_by_address(self): - node_id = 1 - interfaces = [{'id': 1, 'address': '11:11:11:11:11:11'}, - {'id': 2, 'address': '22:22:22:22:22:22'}, - {'id': 3, 'address': '33:33:33:33:33:33'}, - ] - self.mox.StubOutWithMock(db, 'bm_node_get') - self.mox.StubOutWithMock(db, 'bm_interface_get_all_by_bm_node_id') - self.mox.StubOutWithMock(db, 'bm_interface_destroy') - db.bm_node_get(self.context, node_id) - db.bm_interface_get_all_by_bm_node_id(self.context, node_id).\ - AndReturn(interfaces) - db.bm_interface_destroy(self.context, 2) - self.mox.ReplayAll() - body = {'remove_interface': {'address': '22:22:22:22:22:22'}} - self.controller._remove_interface(self.request, node_id, body) - - def test_remove_interface_no_id_no_address(self): - node_id = 1 - self.mox.StubOutWithMock(db, 'bm_node_get') - db.bm_node_get(self.context, node_id) - self.mox.ReplayAll() - body = {'remove_interface': {}} - self.assertRaises(exc.HTTPBadRequest, - self.controller._remove_interface, - self.request, - node_id, - body) - - def test_add_interface_node_not_found(self): - node_id = 1 - self.mox.StubOutWithMock(db, 'bm_node_get') - db.bm_node_get(self.context, node_id).\ - AndRaise(exception.NodeNotFound(node_id=node_id)) - self.mox.ReplayAll() - body = {'add_interface': {'address': '11:11:11:11:11:11'}} - self.assertRaises(exc.HTTPNotFound, - self.controller._add_interface, - self.request, - node_id, - body) - - def test_remove_interface_node_not_found(self): - node_id = 1 - self.mox.StubOutWithMock(db, 'bm_node_get') - db.bm_node_get(self.context, node_id).\ - AndRaise(exception.NodeNotFound(node_id=node_id)) - self.mox.ReplayAll() - body = {'remove_interface': {'address': '11:11:11:11:11:11'}} - self.assertRaises(exc.HTTPNotFound, - self.controller._remove_interface, - self.request, - node_id, - body) - - def test_is_valid_mac(self): - self.assertFalse(baremetal_nodes.is_valid_mac(None)) - self.assertTrue(baremetal_nodes.is_valid_mac("52:54:00:cf:2d:31")) - self.assertTrue(baremetal_nodes.is_valid_mac(u"52:54:00:cf:2d:31")) - self.assertFalse(baremetal_nodes.is_valid_mac("127.0.0.1")) - self.assertFalse(baremetal_nodes.is_valid_mac("not:a:mac:address")) - self.assertFalse(baremetal_nodes.is_valid_mac("52-54-00-cf-2d-31")) - self.assertFalse(baremetal_nodes.is_valid_mac("5254.00cf.2d31")) - self.assertFalse(baremetal_nodes.is_valid_mac("52:54:0:cf:2d:31")) - self.assertFalse(baremetal_nodes.is_valid_mac("aa bb cc dd ee ff")) - self.assertTrue(baremetal_nodes.is_valid_mac("AA:BB:CC:DD:EE:FF")) - self.assertFalse(baremetal_nodes.is_valid_mac("AA BB CC DD EE FF")) - self.assertFalse(baremetal_nodes.is_valid_mac("AA-BB-CC-DD-EE-FF")) - @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list') def test_index_ironic(self, mock_list): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') - properties = {'cpus': 2, 'memory_mb': 1024, 'local_gb': 20} node = ironic_utils.get_test_node(properties=properties) mock_list.return_value = [node] @@ -404,8 +97,6 @@ class BareMetalNodesTest(test.NoDBTestCase): @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list_ports') @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get') def test_show_ironic(self, mock_get, mock_list_ports): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') - properties = {'cpus': 1, 'memory_mb': 512, 'local_gb': 10} node = ironic_utils.get_test_node(properties=properties) port = ironic_utils.get_test_port() @@ -429,8 +120,6 @@ class BareMetalNodesTest(test.NoDBTestCase): @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list_ports') @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get') def test_show_ironic_no_interfaces(self, mock_get, mock_list_ports): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') - properties = {'cpus': 1, 'memory_mb': 512, 'local_gb': 10} node = ironic_utils.get_test_node(properties=properties) mock_get.return_value = node @@ -442,25 +131,21 @@ class BareMetalNodesTest(test.NoDBTestCase): mock_list_ports.assert_called_once_with(node.uuid) def test_create_ironic_not_supported(self): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') self.assertRaises(exc.HTTPBadRequest, self.controller.create, self.request, {'node': object()}) def test_delete_ironic_not_supported(self): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') self.assertRaises(exc.HTTPBadRequest, self.controller.delete, self.request, 'fake-id') def test_add_interface_ironic_not_supported(self): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') self.assertRaises(exc.HTTPBadRequest, self.controller._add_interface, self.request, 'fake-id', 'fake-body') def test_remove_interface_ironic_not_supported(self): - CONF.set_override('compute_driver', 'nova.virt.ironic.driver') self.assertRaises(exc.HTTPBadRequest, self.controller._remove_interface, self.request, 'fake-id', 'fake-body') diff --git a/nova/tests/db/test_migrations.py b/nova/tests/db/test_migrations.py index b7319433a6..666e825a5a 100644 --- a/nova/tests/db/test_migrations.py +++ b/nova/tests/db/test_migrations.py @@ -27,9 +27,8 @@ which allows testing against all 3 databases (sqlite in memory, mysql, pg) in a properly configured unit test environment. For the opportunistic testing you need to set up db's named 'openstack_citest' -and 'openstack_baremetal_citest' with user 'openstack_citest' and password -'openstack_citest' on localhost. The test will then use that db and u/p combo -to run the tests. +with user 'openstack_citest' and password 'openstack_citest' on localhost. The +test will then use that db and u/p combo to run the tests. For postgres on Ubuntu this can be done with the following commands:: @@ -37,8 +36,6 @@ For postgres on Ubuntu this can be done with the following commands:: | postgres=# create user openstack_citest with createdb login password | 'openstack_citest'; | postgres=# create database openstack_citest with owner openstack_citest; -| postgres=# create database openstack_baremetal_citest with owner -| openstack_citest; """ @@ -60,7 +57,6 @@ from nova.openstack.common import log as logging from nova.openstack.common import processutils from nova import test from nova import utils -import nova.virt.baremetal.db.sqlalchemy.migrate_repo LOG = logging.getLogger(__name__) @@ -111,8 +107,7 @@ def get_pgsql_connection_info(conn_pieces): class CommonTestsMixIn(object): - """These tests are shared between TestNovaMigrations and - TestBaremetalMigrations. + """Base class for migration tests. BaseMigrationTestCase is effectively an abstract class, meant to be derived from and not directly tested against; that's why these `test_` methods need @@ -889,144 +884,6 @@ class TestNovaMigrations(BaseWalkMigrationTestCase, CommonTestsMixIn): ['host']])) -class TestBaremetalMigrations(BaseWalkMigrationTestCase, CommonTestsMixIn): - """Test sqlalchemy-migrate migrations.""" - USER = "openstack_citest" - PASSWD = "openstack_citest" - DATABASE = "openstack_baremetal_citest" - - def __init__(self, *args, **kwargs): - super(TestBaremetalMigrations, self).__init__(*args, **kwargs) - - self.DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__), - '../virt/baremetal/test_baremetal_migrations.conf') - # Test machines can set the NOVA_TEST_MIGRATIONS_CONF variable - # to override the location of the config file for migration testing - self.CONFIG_FILE_PATH = os.environ.get( - 'BAREMETAL_TEST_MIGRATIONS_CONF', - self.DEFAULT_CONFIG_FILE) - self.MIGRATE_FILE = \ - nova.virt.baremetal.db.sqlalchemy.migrate_repo.__file__ - self.REPOSITORY = repository.Repository( - os.path.abspath(os.path.dirname(self.MIGRATE_FILE))) - - def setUp(self): - super(TestBaremetalMigrations, self).setUp() - - if self.migration is None: - self.migration = __import__('nova.virt.baremetal.db.migration', - globals(), locals(), ['db_initial_version'], -1) - self.INIT_VERSION = self.migration.db_initial_version() - if self.migration_api is None: - temp = __import__('nova.virt.baremetal.db.sqlalchemy.migration', - globals(), locals(), ['versioning_api'], -1) - self.migration_api = temp.versioning_api - - def _pre_upgrade_002(self, engine): - data = [{'id': 1, 'key': 'fake-key', 'image_path': '/dev/null', - 'pxe_config_path': '/dev/null/', 'root_mb': 0, 'swap_mb': 0}] - table = oslodbutils.get_table(engine, 'bm_deployments') - engine.execute(table.insert(), data) - return data - - def _check_002(self, engine, data): - self.assertRaises(sqlalchemy.exc.NoSuchTableError, - oslodbutils.get_table, engine, 'bm_deployments') - - def _post_downgrade_004(self, engine): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - self.assertNotIn(u'instance_name', [c.name for c in bm_nodes.columns]) - - def _check_005(self, engine, data): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - columns = [c.name for c in bm_nodes.columns] - self.assertNotIn(u'prov_vlan_id', columns) - self.assertNotIn(u'registration_status', columns) - - def _pre_upgrade_006(self, engine): - nodes = oslodbutils.get_table(engine, 'bm_nodes') - ifs = oslodbutils.get_table(engine, 'bm_interfaces') - # node 1 has two different addresses in bm_nodes and bm_interfaces - engine.execute(nodes.insert(), - [{'id': 1, - 'prov_mac_address': 'aa:aa:aa:aa:aa:aa'}]) - engine.execute(ifs.insert(), - [{'id': 101, - 'bm_node_id': 1, - 'address': 'bb:bb:bb:bb:bb:bb'}]) - # node 2 has one same address both in bm_nodes and bm_interfaces - engine.execute(nodes.insert(), - [{'id': 2, - 'prov_mac_address': 'cc:cc:cc:cc:cc:cc'}]) - engine.execute(ifs.insert(), - [{'id': 201, - 'bm_node_id': 2, - 'address': 'cc:cc:cc:cc:cc:cc'}]) - - def _check_006(self, engine, data): - ifs = oslodbutils.get_table(engine, 'bm_interfaces') - rows = ifs.select().\ - where(ifs.c.bm_node_id == 1).\ - execute().\ - fetchall() - self.assertEqual(len(rows), 2) - rows = ifs.select().\ - where(ifs.c.bm_node_id == 2).\ - execute().\ - fetchall() - self.assertEqual(len(rows), 1) - self.assertEqual(rows[0]['address'], 'cc:cc:cc:cc:cc:cc') - - def _post_downgrade_006(self, engine): - ifs = oslodbutils.get_table(engine, 'bm_interfaces') - rows = ifs.select().where(ifs.c.bm_node_id == 1).execute().fetchall() - self.assertEqual(len(rows), 1) - self.assertEqual(rows[0]['address'], 'bb:bb:bb:bb:bb:bb') - - rows = ifs.select().where(ifs.c.bm_node_id == 2).execute().fetchall() - self.assertEqual(len(rows), 0) - - def _check_007(self, engine, data): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - columns = [c.name for c in bm_nodes.columns] - self.assertNotIn(u'prov_mac_address', columns) - - def _check_008(self, engine, data): - self.assertRaises(sqlalchemy.exc.NoSuchTableError, - oslodbutils.get_table, engine, 'bm_pxe_ips') - - def _post_downgrade_008(self, engine): - oslodbutils.get_table(engine, 'bm_pxe_ips') - - def _pre_upgrade_010(self, engine): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - data = [{'id': 10, 'prov_mac_address': 'cc:cc:cc:cc:cc:cc'}] - engine.execute(bm_nodes.insert(), data) - - return data - - def _check_010(self, engine, data): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - self.assertIn('preserve_ephemeral', bm_nodes.columns) - - default = engine.execute( - sqlalchemy.select([bm_nodes.c.preserve_ephemeral]) - .where(bm_nodes.c.id == data[0]['id']) - ).scalar() - self.assertEqual(default, False) - - bm_nodes.delete().where(bm_nodes.c.id == data[0]['id']).execute() - - def _post_downgrade_010(self, engine): - bm_nodes = oslodbutils.get_table(engine, 'bm_nodes') - self.assertNotIn('preserve_ephemeral', bm_nodes.columns) - - def _skippable_migrations(self): - # NOTE(danms): This is deprecated code, soon to be removed, so don't - # obsess about tests here. - return range(1, 100) - - class ProjectTestCase(test.NoDBTestCase): def test_all_migrations_have_downgrade(self): diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.json.tpl deleted file mode 100644 index fbc9e5b8d1..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.json.tpl +++ /dev/null @@ -1,5 +0,0 @@ -{ - "add_interface": { - "address": "%(address)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.xml.tpl deleted file mode 100644 index abbbe895b2..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-req.xml.tpl +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.json.tpl deleted file mode 100644 index 268b41f084..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.json.tpl +++ /dev/null @@ -1,8 +0,0 @@ -{ - "interface": { - "id": %(interface_id)s, - "address": "aa:aa:aa:aa:aa:aa", - "datapath_id": null, - "port_no": null - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.xml.tpl deleted file mode 100644 index e5d34f92bd..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-add-interface-resp.xml.tpl +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.json.tpl deleted file mode 100644 index 389517ed74..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.json.tpl +++ /dev/null @@ -1,12 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pm_password": "pm_pass", - "terminal_port": 8000 - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.xml.tpl deleted file mode 100644 index a06b8d73fe..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-req.xml.tpl +++ /dev/null @@ -1,10 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.json.tpl deleted file mode 100644 index 7ab03b01bb..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.json.tpl +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": { - "cpus": 8, - "id": %(node_id)s, - "instance_uuid": null, - "interfaces": [], - "local_gb": 128, - "memory_mb": 8192, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pxe_config_path": null, - "service_host": "host", - "task_state": null, - "terminal_port": 8000, - "updated_at": null, - "uuid": "%(node_uuid)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.xml.tpl deleted file mode 100644 index db5c04ad26..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-resp.xml.tpl +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.json.tpl deleted file mode 100644 index 458aa12822..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.json.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pm_password": "pm_pass", - "prov_mac_address": "%(address)s", - "terminal_port": 8000 - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.xml.tpl deleted file mode 100644 index 2c7273709e..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-req.xml.tpl +++ /dev/null @@ -1,11 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.json.tpl deleted file mode 100644 index d1722d534d..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.json.tpl +++ /dev/null @@ -1,25 +0,0 @@ -{ - "node": { - "cpus": 8, - "id": %(node_id)s, - "instance_uuid": null, - "interfaces": [ - { - "address": "%(address)s", - "datapath_id": null, - "id": %(interface_id)s, - "port_no": null - } - ], - "local_gb": 128, - "memory_mb": 8192, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pxe_config_path": null, - "service_host": "host", - "task_state": null, - "terminal_port": 8000, - "updated_at": null, - "uuid": "%(node_uuid)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.xml.tpl deleted file mode 100644 index 800011c817..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-create-with-address-resp.xml.tpl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.json.tpl deleted file mode 100644 index 31fed860ae..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.json.tpl +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": [ - { - "cpus": 8, - "id": %(node_id)s, - "instance_uuid": null, - "interfaces": [ - { - "address": "%(address)s", - "datapath_id": null, - "id": %(interface_id)s, - "port_no": null - } - ], - "local_gb": 128, - "memory_mb": 8192, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pxe_config_path": null, - "service_host": "host", - "task_state": null, - "terminal_port": 8000, - "updated_at": null, - "uuid": "%(node_uuid)s" - } - ] -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.xml.tpl deleted file mode 100644 index ea50deed32..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-list-resp.xml.tpl +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.json.tpl deleted file mode 100644 index eb76a91401..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.json.tpl +++ /dev/null @@ -1,5 +0,0 @@ -{ - "remove_interface": { - "address": "%(address)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.xml.tpl deleted file mode 100644 index 089c94e86f..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-remove-interface-req.xml.tpl +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.json.tpl deleted file mode 100644 index d1722d534d..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.json.tpl +++ /dev/null @@ -1,25 +0,0 @@ -{ - "node": { - "cpus": 8, - "id": %(node_id)s, - "instance_uuid": null, - "interfaces": [ - { - "address": "%(address)s", - "datapath_id": null, - "id": %(interface_id)s, - "port_no": null - } - ], - "local_gb": 128, - "memory_mb": 8192, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pxe_config_path": null, - "service_host": "host", - "task_state": null, - "terminal_port": 8000, - "updated_at": null, - "uuid": "%(node_uuid)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.xml.tpl deleted file mode 100644 index 800011c817..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-ext-status/baremetal-node-show-resp.xml.tpl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.json.tpl deleted file mode 100644 index fbc9e5b8d1..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.json.tpl +++ /dev/null @@ -1,5 +0,0 @@ -{ - "add_interface": { - "address": "%(address)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.xml.tpl deleted file mode 100644 index abbbe895b2..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-req.xml.tpl +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.json.tpl deleted file mode 100644 index 268b41f084..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.json.tpl +++ /dev/null @@ -1,8 +0,0 @@ -{ - "interface": { - "id": %(interface_id)s, - "address": "aa:aa:aa:aa:aa:aa", - "datapath_id": null, - "port_no": null - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.xml.tpl deleted file mode 100644 index e5d34f92bd..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-add-interface-resp.xml.tpl +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.json.tpl deleted file mode 100644 index 389517ed74..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.json.tpl +++ /dev/null @@ -1,12 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pm_password": "pm_pass", - "terminal_port": 8000 - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.xml.tpl deleted file mode 100644 index a06b8d73fe..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-req.xml.tpl +++ /dev/null @@ -1,10 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.json.tpl deleted file mode 100644 index 855b671502..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.json.tpl +++ /dev/null @@ -1,14 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "terminal_port": 8000, - "instance_uuid": null, - "id": %(node_id)s, - "interfaces": [] - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.xml.tpl deleted file mode 100644 index 15d0640c9e..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-resp.xml.tpl +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.json.tpl deleted file mode 100644 index 458aa12822..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.json.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "pm_password": "pm_pass", - "prov_mac_address": "%(address)s", - "terminal_port": 8000 - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.xml.tpl deleted file mode 100644 index 2c7273709e..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-req.xml.tpl +++ /dev/null @@ -1,11 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.json.tpl deleted file mode 100644 index dae8d4373e..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.json.tpl +++ /dev/null @@ -1,19 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "terminal_port": 8000, - "instance_uuid": null, - "id": %(node_id)s, - "interfaces": [{ - "id": %(interface_id)s, - "address": "%(address)s", - "datapath_id": null, - "port_no": null - }] - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.xml.tpl deleted file mode 100644 index b036a1d472..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-create-with-address-resp.xml.tpl +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.json.tpl deleted file mode 100644 index a38bdf6d7f..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.json.tpl +++ /dev/null @@ -1,19 +0,0 @@ -{ - "nodes": [{ - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "terminal_port": 8000, - "instance_uuid": null, - "id": %(node_id)s, - "interfaces": [{ - "id": %(interface_id)s, - "address": "%(address)s", - "datapath_id": null, - "port_no": null - }] - }] -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.xml.tpl deleted file mode 100644 index 5bb51d4be3..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-list-resp.xml.tpl +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.json.tpl deleted file mode 100644 index eb76a91401..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.json.tpl +++ /dev/null @@ -1,5 +0,0 @@ -{ - "remove_interface": { - "address": "%(address)s" - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.xml.tpl deleted file mode 100644 index 089c94e86f..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-remove-interface-req.xml.tpl +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.json.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.json.tpl deleted file mode 100644 index dae8d4373e..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.json.tpl +++ /dev/null @@ -1,19 +0,0 @@ -{ - "node": { - "service_host": "host", - "cpus": 8, - "memory_mb": 8192, - "local_gb": 128, - "pm_address": "10.1.2.3", - "pm_user": "pm_user", - "terminal_port": 8000, - "instance_uuid": null, - "id": %(node_id)s, - "interfaces": [{ - "id": %(interface_id)s, - "address": "%(address)s", - "datapath_id": null, - "port_no": null - }] - } -} diff --git a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.xml.tpl b/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.xml.tpl deleted file mode 100644 index 7fc10026e2..0000000000 --- a/nova/tests/integrated/api_samples/os-baremetal-nodes/baremetal-node-show-resp.xml.tpl +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 0ee3cc2967..c064bbc605 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -66,7 +66,6 @@ from nova.tests.integrated import api_samples_test_base from nova.tests.integrated import integrated_helpers from nova.tests.objects import test_network from nova.tests import utils as test_utils -from nova.tests.virt.baremetal.db import base as bm_db_base from nova import utils from nova.volume import cinder @@ -138,6 +137,8 @@ class ApiSamplesTrap(ApiSampleTestBaseV2): # removed) soon. do_not_approve_additions = [] do_not_approve_additions.append('os-create-server-ext') + do_not_approve_additions.append('os-baremetal-ext-status') + do_not_approve_additions.append('os-baremetal-nodes') tests = self._get_extensions_tested() extensions = self._get_extensions() @@ -2952,120 +2953,6 @@ class CellsCapacitySampleXmlTest(CellsCapacitySampleJsonTest): ctype = 'xml' -class BareMetalNodesJsonTest(ApiSampleTestBaseV2, bm_db_base.BMDBTestCase): - extension_name = ('nova.api.openstack.compute.contrib.baremetal_nodes.' - 'Baremetal_nodes') - - def _get_subs(self): - subs = {} - return subs - - def _create_node(self): - response = self._do_post("os-baremetal-nodes", - "baremetal-node-create-req", - {}) - subs = self._get_subs() - subs.update({'node_id': '(?P\d+)'}) - return self._verify_response("baremetal-node-create-resp", subs, - response, 200) - - def _create_node_with_address(self): - address = '12:34:56:78:90:ab' - req_subs = {'address': address} - response = self._do_post("os-baremetal-nodes", - "baremetal-node-create-with-address-req", - req_subs) - subs = self._get_subs() - subs.update({'node_id': '(?P\d+)', - 'interface_id': '\d+', - 'address': address, - }) - self._verify_response("baremetal-node-create-with-address-resp", - subs, response, 200) - - def test_create_node(self): - self._create_node() - - def test_create_node_with_address(self): - self._create_node_with_address() - - def test_list_nodes(self): - node_id = self._create_node() - interface_id = self._add_interface(node_id) - response = self._do_get('os-baremetal-nodes') - subs = self._get_subs() - subs.update({'node_id': node_id, - 'interface_id': interface_id, - 'address': 'aa:aa:aa:aa:aa:aa', - }) - self._verify_response('baremetal-node-list-resp', subs, - response, 200) - - def test_show_node(self): - node_id = self._create_node() - interface_id = self._add_interface(node_id) - response = self._do_get('os-baremetal-nodes/%s' % node_id) - subs = self._get_subs() - subs.update({'node_id': node_id, - 'interface_id': interface_id, - 'address': 'aa:aa:aa:aa:aa:aa', - }) - self._verify_response('baremetal-node-show-resp', subs, response, 200) - - def test_delete_node(self): - node_id = self._create_node() - response = self._do_delete("os-baremetal-nodes/%s" % node_id) - self.assertEqual(response.status_code, 202) - - def _add_interface(self, node_id): - response = self._do_post("os-baremetal-nodes/%s/action" % node_id, - "baremetal-node-add-interface-req", - {'address': 'aa:aa:aa:aa:aa:aa'}) - subs = {'interface_id': r'(?P\d+)'} - return self._verify_response("baremetal-node-add-interface-resp", subs, - response, 200) - - def test_add_interface(self): - node_id = self._create_node() - self._add_interface(node_id) - - def test_remove_interface(self): - node_id = self._create_node() - self._add_interface(node_id) - response = self._do_post("os-baremetal-nodes/%s/action" % node_id, - "baremetal-node-remove-interface-req", - {'address': 'aa:aa:aa:aa:aa:aa'}) - self.assertEqual(response.status_code, 202) - self.assertEqual(response.content, "") - - -class BareMetalNodesXmlTest(BareMetalNodesJsonTest): - ctype = 'xml' - - -class BareMetalExtStatusJsonTest(BareMetalNodesJsonTest): - extension_name = ('nova.api.openstack.compute.contrib.' - 'baremetal_ext_status.Baremetal_ext_status') - - def _get_flags(self): - f = super(BareMetalExtStatusJsonTest, self)._get_flags() - f['osapi_compute_extension'] = CONF.osapi_compute_extension[:] - # BareMetalExtStatus extension also needs BareMetalNodes to be loaded. - f['osapi_compute_extension'].append( - 'nova.api.openstack.compute.contrib.baremetal_nodes.' - 'Baremetal_nodes') - return f - - def _get_subs(self): - vanilla_regexes = self._get_regexes() - subs = {'node_uuid': vanilla_regexes['uuid']} - return subs - - -class BareMetalExtStatusXmlTest(BareMetalExtStatusJsonTest): - ctype = 'xml' - - class BlockDeviceMappingV2BootJsonTest(ServersSampleBase): extension_name = ('nova.api.openstack.compute.contrib.' 'block_device_mapping_v2_boot.' diff --git a/nova/tests/virt/baremetal/__init__.py b/nova/tests/virt/baremetal/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/tests/virt/baremetal/db/__init__.py b/nova/tests/virt/baremetal/db/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/tests/virt/baremetal/db/base.py b/nova/tests/virt/baremetal/db/base.py deleted file mode 100644 index 499eee32ad..0000000000 --- a/nova/tests/virt/baremetal/db/base.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Bare-metal DB test base class.""" - -from oslo.config import cfg - -from nova import context as nova_context -from nova import test -from nova.virt.baremetal.db import migration as bm_migration -from nova.virt.baremetal.db.sqlalchemy import session as bm_session - -_DB_CACHE = None - -CONF = cfg.CONF -CONF.import_opt('sql_connection', - 'nova.virt.baremetal.db.sqlalchemy.session', - group='baremetal') - - -class Database(test.Database): - - def post_migrations(self): - pass - - -class BMDBTestCase(test.TestCase): - - def setUp(self): - super(BMDBTestCase, self).setUp() - self.flags(sql_connection='sqlite://', group='baremetal') - global _DB_CACHE - if not _DB_CACHE: - _DB_CACHE = Database(bm_session, bm_migration, - sql_connection=CONF.baremetal.sql_connection, - sqlite_db=None, - sqlite_clean_db=None) - self.useFixture(_DB_CACHE) - self.context = nova_context.get_admin_context() diff --git a/nova/tests/virt/baremetal/db/test_bm_interface.py b/nova/tests/virt/baremetal/db/test_bm_interface.py deleted file mode 100644 index 400be60c72..0000000000 --- a/nova/tests/virt/baremetal/db/test_bm_interface.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -""" -Bare-metal DB testcase for BareMetalInterface -""" - -from oslo.db import exception as db_exc - -from nova import exception -from nova.tests.virt.baremetal.db import base -from nova.virt.baremetal import db - - -class BareMetalInterfaceTestCase(base.BMDBTestCase): - - def test_unique_address(self): - pif1_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11', - '0x1', 1) - self.assertRaises(db_exc.DBError, - db.bm_interface_create, - self.context, 2, '11:11:11:11:11:11', '0x2', 2) - # succeed after delete pif1 - db.bm_interface_destroy(self.context, pif1_id) - pif2_id = db.bm_interface_create(self.context, 2, '11:11:11:11:11:11', - '0x2', 2) - self.assertIsNotNone(pif2_id) - - def test_unique_vif_uuid(self): - pif1_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11', - '0x1', 1) - pif2_id = db.bm_interface_create(self.context, 2, '22:22:22:22:22:22', - '0x2', 2) - db.bm_interface_set_vif_uuid(self.context, pif1_id, 'AAAA') - self.assertRaises(exception.NovaException, - db.bm_interface_set_vif_uuid, - self.context, pif2_id, 'AAAA') - - def test_vif_not_found(self): - pif_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11', - '0x1', 1) - self.assertRaises(exception.NovaException, - db.bm_interface_set_vif_uuid, - self.context, pif_id + 1, 'AAAA') diff --git a/nova/tests/virt/baremetal/db/test_bm_node.py b/nova/tests/virt/baremetal/db/test_bm_node.py deleted file mode 100644 index 0235430927..0000000000 --- a/nova/tests/virt/baremetal/db/test_bm_node.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -""" -Bare-Metal DB testcase for BareMetalNode -""" - -from nova import exception -from nova.tests.virt.baremetal.db import base -from nova.tests.virt.baremetal.db import utils -from nova.virt.baremetal import db - - -class BareMetalNodesTestCase(base.BMDBTestCase): - - def _create_nodes(self): - nodes = [ - utils.new_bm_node(pm_address='0', service_host="host1", - memory_mb=100000, cpus=100, local_gb=10000), - utils.new_bm_node(pm_address='1', service_host="host2", - instance_uuid='A', - memory_mb=100000, cpus=100, local_gb=10000), - utils.new_bm_node(pm_address='2', service_host="host2", - memory_mb=1000, cpus=1, local_gb=1000), - utils.new_bm_node(pm_address='3', service_host="host2", - memory_mb=1000, cpus=2, local_gb=1000), - utils.new_bm_node(pm_address='4', service_host="host2", - memory_mb=2000, cpus=1, local_gb=1000), - utils.new_bm_node(pm_address='5', service_host="host2", - memory_mb=2000, cpus=2, local_gb=1000), - ] - self.ids = [] - for n in nodes: - ref = db.bm_node_create(self.context, n) - self.ids.append(ref['id']) - - def test_get_all(self): - r = db.bm_node_get_all(self.context) - self.assertEqual(r, []) - - self._create_nodes() - - r = db.bm_node_get_all(self.context) - self.assertEqual(len(r), 6) - - def test_get(self): - self._create_nodes() - - r = db.bm_node_get(self.context, self.ids[0]) - self.assertEqual(r['pm_address'], '0') - - r = db.bm_node_get(self.context, self.ids[1]) - self.assertEqual(r['pm_address'], '1') - - self.assertRaises( - exception.NodeNotFound, - db.bm_node_get, - self.context, -1) - - def test_get_by_service_host(self): - self._create_nodes() - - r = db.bm_node_get_all(self.context, service_host=None) - self.assertEqual(len(r), 6) - - r = db.bm_node_get_all(self.context, service_host="host1") - self.assertEqual(len(r), 1) - self.assertEqual(r[0]['pm_address'], '0') - - r = db.bm_node_get_all(self.context, service_host="host2") - self.assertEqual(len(r), 5) - pmaddrs = [x['pm_address'] for x in r] - self.assertIn('1', pmaddrs) - self.assertIn('2', pmaddrs) - self.assertIn('3', pmaddrs) - self.assertIn('4', pmaddrs) - self.assertIn('5', pmaddrs) - - r = db.bm_node_get_all(self.context, service_host="host3") - self.assertEqual(r, []) - - def test_get_associated(self): - self._create_nodes() - - r = db.bm_node_get_associated(self.context, service_host=None) - self.assertEqual(len(r), 1) - self.assertEqual(r[0]['pm_address'], '1') - - r = db.bm_node_get_unassociated(self.context, service_host=None) - self.assertEqual(len(r), 5) - pmaddrs = [x['pm_address'] for x in r] - self.assertIn('0', pmaddrs) - self.assertIn('2', pmaddrs) - self.assertIn('3', pmaddrs) - self.assertIn('4', pmaddrs) - self.assertIn('5', pmaddrs) - - def test_destroy(self): - self._create_nodes() - - db.bm_node_destroy(self.context, self.ids[0]) - - self.assertRaises( - exception.NodeNotFound, - db.bm_node_get, - self.context, self.ids[0]) - - r = db.bm_node_get_all(self.context) - self.assertEqual(len(r), 5) - - def test_destroy_with_interfaces(self): - self._create_nodes() - - if_a_id = db.bm_interface_create(self.context, self.ids[0], - 'aa:aa:aa:aa:aa:aa', None, None) - if_b_id = db.bm_interface_create(self.context, self.ids[0], - 'bb:bb:bb:bb:bb:bb', None, None) - if_x_id = db.bm_interface_create(self.context, self.ids[1], - '11:22:33:44:55:66', None, None) - - db.bm_node_destroy(self.context, self.ids[0]) - - self.assertRaises( - exception.NovaException, - db.bm_interface_get, - self.context, if_a_id) - - self.assertRaises( - exception.NovaException, - db.bm_interface_get, - self.context, if_b_id) - - # Another node's interface is not affected - if_x = db.bm_interface_get(self.context, if_x_id) - self.assertEqual(self.ids[1], if_x['bm_node_id']) - - self.assertRaises( - exception.NodeNotFound, - db.bm_node_get, - self.context, self.ids[0]) - - r = db.bm_node_get_all(self.context) - self.assertEqual(len(r), 5) - - def test_find_free(self): - self._create_nodes() - fn = db.bm_node_find_free(self.context, 'host2') - self.assertEqual(fn['pm_address'], '2') - - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=500, cpus=2, local_gb=100) - self.assertEqual(fn['pm_address'], '3') - - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=1001, cpus=1, local_gb=1000) - self.assertEqual(fn['pm_address'], '4') - - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=2000, cpus=1, local_gb=1000) - self.assertEqual(fn['pm_address'], '4') - - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=2000, cpus=2, local_gb=1000) - self.assertEqual(fn['pm_address'], '5') - - # check memory_mb - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=2001, cpus=2, local_gb=1000) - self.assertIsNone(fn) - - # check cpus - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=2000, cpus=3, local_gb=1000) - self.assertIsNone(fn) - - # check local_gb - fn = db.bm_node_find_free(self.context, 'host2', - memory_mb=2000, cpus=2, local_gb=1001) - self.assertIsNone(fn) diff --git a/nova/tests/virt/baremetal/db/utils.py b/nova/tests/virt/baremetal/db/utils.py deleted file mode 100644 index 6faeb13d84..0000000000 --- a/nova/tests/virt/baremetal/db/utils.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Bare-metal test utils.""" - -from nova import test -from nova.virt.baremetal.db.sqlalchemy import models as bm_models - - -def new_bm_node(**kwargs): - h = bm_models.BareMetalNode() - h.id = kwargs.pop('id', None) - h.uuid = kwargs.pop('uuid', None) - h.service_host = kwargs.pop('service_host', None) - h.instance_uuid = kwargs.pop('instance_uuid', None) - h.cpus = kwargs.pop('cpus', 1) - h.memory_mb = kwargs.pop('memory_mb', 1024) - h.local_gb = kwargs.pop('local_gb', 64) - h.pm_address = kwargs.pop('pm_address', '192.168.1.1') - h.pm_user = kwargs.pop('pm_user', 'ipmi_user') - h.pm_password = kwargs.pop('pm_password', 'ipmi_password') - h.task_state = kwargs.pop('task_state', None) - h.terminal_port = kwargs.pop('terminal_port', 8000) - if len(kwargs) > 0: - raise test.TestingException("unknown field: %s" - % ','.join(kwargs.keys())) - return h - - -def new_bm_interface(**kwargs): - x = bm_models.BareMetalInterface() - x.id = kwargs.pop('id', None) - x.bm_node_id = kwargs.pop('bm_node_id', None) - x.address = kwargs.pop('address', None) - x.datapath_id = kwargs.pop('datapath_id', None) - x.port_no = kwargs.pop('port_no', None) - x.vif_uuid = kwargs.pop('vif_uuid', None) - if len(kwargs) > 0: - raise test.TestingException("unknown field: %s" - % ','.join(kwargs.keys())) - return x diff --git a/nova/tests/virt/baremetal/test_baremetal_migrations.conf b/nova/tests/virt/baremetal/test_baremetal_migrations.conf deleted file mode 100644 index 92681b41b3..0000000000 --- a/nova/tests/virt/baremetal/test_baremetal_migrations.conf +++ /dev/null @@ -1,24 +0,0 @@ -[unit_tests] -# Set up any number of databases to test concurrently. -# The "name" used in the test is the config variable key. - -sqlite=sqlite:// -#sqlitefile=sqlite:///test_baremetal_migrations_utils.db -#mysql=mysql+mysqldb://user:pass@localhost/test_baremetal_migrations_utils -#postgresql=postgresql+psycopg2://user:pass@localhost/test_migrations_utils - -[migration_dbs] -# Migration DB details are listed separately as they can't be connected to -# concurrently. These databases can't be the same as above - -# Note, sqlite:// is in-memory and unique each time it is spawned. -# However file sqlite's are not unique. - -sqlite=sqlite:// -#sqlitefile=sqlite:///test_baremetal_migrations.db -#mysql=mysql+mysqldb://user:pass@localhost/test_baremetal_migrations -#postgresql=postgresql+psycopg2://user:pass@localhost/test_baremetal_migrations - -[walk_style] -snake_walk=yes -downgrade=yes diff --git a/nova/tests/virt/baremetal/test_driver.py b/nova/tests/virt/baremetal/test_driver.py deleted file mode 100644 index 0824908ae8..0000000000 --- a/nova/tests/virt/baremetal/test_driver.py +++ /dev/null @@ -1,541 +0,0 @@ -# coding=utf-8 - -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright (c) 2011 University of Southern California / ISI -# 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. - -"""Tests for the base baremetal driver class.""" - -import mock -import mox -from oslo.config import cfg - -from nova.compute import flavors -from nova.compute import power_state -from nova.compute import task_states -from nova import db as main_db -from nova import exception -from nova import objects -from nova.openstack.common import jsonutils -from nova import test -from nova.tests.image import fake as fake_image -from nova.tests import utils -from nova.tests.virt.baremetal.db import base as bm_db_base -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import db -from nova.virt.baremetal import driver as bm_driver -from nova.virt.baremetal import fake -from nova.virt import fake as fake_virt - - -CONF = cfg.CONF - -COMMON_FLAGS = dict( - firewall_driver='nova.virt.baremetal.fake.FakeFirewallDriver', - host='test_host', -) - -BAREMETAL_FLAGS = dict( - driver='nova.virt.baremetal.fake.FakeDriver', - flavor_extra_specs=['cpu_arch:x86_64', 'test_spec:test_value'], - power_manager='nova.virt.baremetal.fake.FakePowerManager', - vif_driver='nova.virt.baremetal.fake.FakeVifDriver', - volume_driver='nova.virt.baremetal.fake.FakeVolumeDriver', - group='baremetal', -) - - -class BareMetalDriverNoDBTestCase(test.NoDBTestCase): - - def setUp(self): - super(BareMetalDriverNoDBTestCase, self).setUp() - self.flags(**COMMON_FLAGS) - self.flags(**BAREMETAL_FLAGS) - self.driver = bm_driver.BareMetalDriver(None) - - def test_validate_driver_loading(self): - self.assertIsInstance(self.driver.driver, fake.FakeDriver) - self.assertIsInstance(self.driver.vif_driver, fake.FakeVifDriver) - self.assertIsInstance(self.driver.volume_driver, fake.FakeVolumeDriver) - self.assertIsInstance(self.driver.firewall_driver, - fake.FakeFirewallDriver) - - def test_driver_capabilities(self): - self.assertTrue(self.driver.capabilities['has_imagecache']) - self.assertFalse(self.driver.capabilities['supports_recreate']) - - -class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase): - - def setUp(self): - super(BareMetalDriverWithDBTestCase, self).setUp() - self.flags(**COMMON_FLAGS) - self.flags(**BAREMETAL_FLAGS) - - fake_image.stub_out_image_service(self.stubs) - self.context = utils.get_test_admin_context() - self.driver = bm_driver.BareMetalDriver(fake_virt.FakeVirtAPI()) - self.addCleanup(fake_image.FakeImageService_reset) - - def _create_node(self, node_info=None, nic_info=None, ephemeral=True): - result = {} - if node_info is None: - node_info = bm_db_utils.new_bm_node( - id=123, - service_host='test_host', - cpus=2, - memory_mb=2048, - ) - if nic_info is None: - nic_info = [ - {'address': '01:23:45:67:89:01', 'datapath_id': '0x1', - 'port_no': 1}, - {'address': '01:23:45:67:89:02', 'datapath_id': '0x2', - 'port_no': 2}, - ] - result['node_info'] = node_info - result['nic_info'] = nic_info - result['node'] = db.bm_node_create(self.context, node_info) - - for nic in nic_info: - db.bm_interface_create( - self.context, - result['node']['id'], - nic['address'], - nic['datapath_id'], - nic['port_no'], - ) - if ephemeral: - result['instance'] = utils.get_test_instance() - else: - flavor = utils.get_test_flavor(options={'ephemeral_gb': 0}) - result['instance'] = utils.get_test_instance(flavor=flavor) - result['instance']['node'] = result['node']['uuid'] - result['spawn_params'] = dict( - admin_password='test_pass', - block_device_info=None, - context=self.context, - image_meta=utils.get_test_image_info( - None, result['instance']), - injected_files=[('/fake/path', 'hello world')], - instance=result['instance'], - network_info=utils.get_test_network_info(), - ) - result['destroy_params'] = dict( - context=self.context, - instance=result['instance'], - network_info=result['spawn_params']['network_info'], - block_device_info=result['spawn_params']['block_device_info'], - ) - - instance = objects.Instance._from_db_object( - self.context, objects.Instance(), result['instance']) - instance.node = result['node']['uuid'] - - result['rebuild_params'] = dict( - context=self.context, - instance=instance, - image_meta=utils.get_test_image_info(None, result['instance']), - injected_files=[('/fake/path', 'hello world')], - admin_password='test_pass', - bdms={}, - detach_block_devices=self.mox.CreateMockAnything(), - attach_block_devices=self.mox.CreateMockAnything(), - network_info=result['spawn_params']['network_info'], - block_device_info=result['spawn_params']['block_device_info'], - ) - - return result - - def test_spawn_ok(self): - node = self._create_node() - self.driver.spawn(**node['spawn_params']) - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.ACTIVE) - self.assertEqual(row['instance_uuid'], node['instance']['uuid']) - self.assertEqual(row['instance_name'], node['instance']['hostname']) - instance = main_db.instance_get_by_uuid(self.context, - node['instance']['uuid']) - self.assertEqual(instance['default_ephemeral_device'], '/dev/sda1') - - def test_set_default_ephemeral_device(self): - instance = objects.Instance(context=self.context) - instance.system_metadata = flavors.save_flavor_info( - {}, flavors.get_default_flavor()) - instance.system_metadata['instance_type_ephemeral_gb'] = 1 - with mock.patch.object(instance, 'save') as mock_save: - self.driver._set_default_ephemeral_device(instance) - mock_save.assert_called_once_with() - self.assertEqual('/dev/sda1', instance.default_ephemeral_device) - - def test_spawn_no_ephemeral_ok(self): - node = self._create_node(ephemeral=False) - self.driver.spawn(**node['spawn_params']) - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.ACTIVE) - self.assertEqual(row['instance_uuid'], node['instance']['uuid']) - self.assertEqual(row['instance_name'], node['instance']['hostname']) - instance = main_db.instance_get_by_uuid(self.context, - node['instance']['uuid']) - self.assertIsNone(instance['default_ephemeral_device']) - - def _test_rebuild(self, ephemeral): - node = self._create_node(ephemeral=ephemeral) - self.driver.spawn(**node['spawn_params']) - after_spawn = db.bm_node_get(self.context, node['node']['id']) - - instance = node['rebuild_params']['instance'] - instance.task_state = task_states.REBUILDING - instance.save(expected_task_state=[None]) - self.driver.rebuild(preserve_ephemeral=ephemeral, - **node['rebuild_params']) - after_rebuild = db.bm_node_get(self.context, node['node']['id']) - - self.assertEqual(after_rebuild['task_state'], baremetal_states.ACTIVE) - self.assertEqual(after_rebuild['preserve_ephemeral'], ephemeral) - self.assertEqual(after_spawn['instance_uuid'], - after_rebuild['instance_uuid']) - - def test_rebuild_ok(self): - self._test_rebuild(ephemeral=False) - - def test_rebuild_preserve_ephemeral(self): - self._test_rebuild(ephemeral=True) - - def test_macs_from_nic_for_instance(self): - node = self._create_node() - expected = set([nic['address'] for nic in node['nic_info']]) - self.assertEqual( - expected, self.driver.macs_for_instance(node['instance'])) - - def test_macs_for_instance_after_spawn(self): - node = self._create_node() - self.driver.spawn(**node['spawn_params']) - - expected = set([nic['address'] for nic in node['nic_info']]) - self.assertEqual( - expected, self.driver.macs_for_instance(node['instance'])) - - def test_macs_for_instance(self): - node = self._create_node() - expected = set(['01:23:45:67:89:01', '01:23:45:67:89:02']) - self.assertEqual( - expected, self.driver.macs_for_instance(node['instance'])) - - def test_macs_for_instance_no_interfaces(self): - # Nodes cannot boot with no MACs, so we raise an error if that happens. - node = self._create_node(nic_info=[]) - self.assertRaises(exception.NovaException, - self.driver.macs_for_instance, node['instance']) - - def test_spawn_node_already_associated(self): - node = self._create_node() - db.bm_node_update(self.context, node['node']['id'], - {'instance_uuid': '1234-5678'}) - - self.assertRaises(exception.NovaException, - self.driver.spawn, **node['spawn_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertIsNone(row['task_state']) - - def test_spawn_node_in_use(self): - node = self._create_node() - - self.driver.spawn(**node['spawn_params']) - self.assertRaises(exception.NovaException, - self.driver.spawn, **node['spawn_params']) - - def test_spawn_node_not_found(self): - node = self._create_node() - db.bm_node_update(self.context, node['node']['id'], - {'uuid': 'hide-this-node'}) - - self.assertRaises(exception.NovaException, - self.driver.spawn, **node['spawn_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertIsNone(row['task_state']) - - def test_spawn_fails(self): - node = self._create_node() - - self.mox.StubOutWithMock(fake.FakePowerManager, 'activate_node') - fake.FakePowerManager.activate_node().AndRaise(test.TestingException) - self.mox.ReplayAll() - - self.assertRaises(test.TestingException, - self.driver.spawn, **node['spawn_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.DELETED) - - def test_spawn_prepared(self): - node = self._create_node() - - def update_2prepared(context, node, instance, state): - row = db.bm_node_get(context, node['id']) - self.assertEqual(row['task_state'], baremetal_states.BUILDING) - db.bm_node_update( - context, node['id'], - {'task_state': baremetal_states.PREPARED}) - - self.mox.StubOutWithMock(fake.FakeDriver, 'activate_node') - self.mox.StubOutWithMock(bm_driver, '_update_state') - - bm_driver._update_state( - self.context, - mox.IsA(node['node']), - node['instance'], - baremetal_states.PREPARED).WithSideEffects(update_2prepared) - fake.FakeDriver.activate_node( - self.context, - mox.IsA(node['node']), - node['instance']).AndRaise(test.TestingException) - bm_driver._update_state( - self.context, - mox.IsA(node['node']), - node['instance'], - baremetal_states.ERROR).AndRaise(test.TestingException) - self.mox.ReplayAll() - - self.assertRaises(test.TestingException, - self.driver.spawn, **node['spawn_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.PREPARED) - - def test_spawn_fails_to_cleanup(self): - node = self._create_node() - - self.mox.StubOutWithMock(fake.FakePowerManager, 'activate_node') - self.mox.StubOutWithMock(fake.FakePowerManager, 'deactivate_node') - fake.FakePowerManager.deactivate_node().AndReturn(None) - fake.FakePowerManager.activate_node().AndRaise(test.TestingException) - fake.FakePowerManager.deactivate_node().AndRaise(test.TestingException) - self.mox.ReplayAll() - - self.assertRaises(test.TestingException, - self.driver.spawn, **node['spawn_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.ERROR) - - def test_spawn_destroy_images_on_deploy(self): - node = self._create_node() - self.driver.driver.destroy_images = mock.MagicMock() - self.driver.spawn(**node['spawn_params']) - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.ACTIVE) - self.assertEqual(row['instance_uuid'], node['instance']['uuid']) - self.assertEqual(row['instance_name'], node['instance']['hostname']) - instance = main_db.instance_get_by_uuid(self.context, - node['instance']['uuid']) - self.assertIsNotNone(instance) - self.assertEqual(1, self.driver.driver.destroy_images.call_count) - - def test_destroy_ok(self): - node = self._create_node() - self.driver.spawn(**node['spawn_params']) - self.driver.destroy(**node['destroy_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.DELETED) - self.assertIsNone(row['instance_uuid']) - self.assertIsNone(row['instance_name']) - - def test_destroy_fails(self): - node = self._create_node() - - self.mox.StubOutWithMock(fake.FakePowerManager, 'deactivate_node') - fake.FakePowerManager.deactivate_node().AndReturn(None) - fake.FakePowerManager.deactivate_node().AndRaise(test.TestingException) - self.mox.ReplayAll() - - self.driver.spawn(**node['spawn_params']) - self.assertRaises(test.TestingException, - self.driver.destroy, **node['destroy_params']) - - row = db.bm_node_get(self.context, node['node']['id']) - self.assertEqual(row['task_state'], baremetal_states.ERROR) - self.assertEqual(row['instance_uuid'], node['instance']['uuid']) - - def test_get_available_resources(self): - node = self._create_node() - - resources = self.driver.get_available_resource(node['node']['uuid']) - self.assertEqual(resources['memory_mb'], - node['node_info']['memory_mb']) - self.assertEqual(resources['memory_mb_used'], 0) - self.assertEqual(resources['supported_instances'], - '[["x86_64", "baremetal", "hvm"]]') - self.assertEqual(resources['stats'], - '{"cpu_arch": "x86_64", "baremetal_driver": ' - '"nova.virt.baremetal.fake.FakeDriver", ' - '"test_spec": "test_value"}') - - self.driver.spawn(**node['spawn_params']) - resources = self.driver.get_available_resource(node['node']['uuid']) - self.assertEqual(resources['memory_mb_used'], - node['node_info']['memory_mb']) - - self.driver.destroy(**node['destroy_params']) - resources = self.driver.get_available_resource(node['node']['uuid']) - self.assertEqual(resources['memory_mb_used'], 0) - stats = jsonutils.loads(resources['stats']) - self.assertEqual(stats['test_spec'], 'test_value') - - def test_get_available_nodes(self): - self.assertEqual(0, len(self.driver.get_available_nodes())) - self.assertEqual(0, len(self.driver.get_available_nodes(refresh=True))) - - node1 = self._create_node() - self.assertEqual(1, len(self.driver.get_available_nodes())) - - node1['instance']['hostname'] = 'test-host-1' - self.driver.spawn(**node1['spawn_params']) - self.assertEqual(1, len(self.driver.get_available_nodes())) - self.assertEqual([node1['node']['uuid']], - self.driver.get_available_nodes()) - - def test_list_instances(self): - self.assertEqual([], self.driver.list_instances()) - - node1 = self._create_node() - self.assertEqual([], self.driver.list_instances()) - - node_info = bm_db_utils.new_bm_node( - id=456, - service_host='test_host', - cpus=2, - memory_mb=2048, - ) - nic_info = [ - {'address': 'cc:cc:cc', 'datapath_id': '0x1', - 'port_no': 1}, - {'address': 'dd:dd:dd', 'datapath_id': '0x2', - 'port_no': 2}, - ] - node2 = self._create_node(node_info=node_info, nic_info=nic_info) - self.assertEqual([], self.driver.list_instances()) - - node1['instance']['hostname'] = 'test-host-1' - node2['instance']['hostname'] = 'test-host-2' - - self.driver.spawn(**node1['spawn_params']) - self.assertEqual(['test-host-1'], - self.driver.list_instances()) - - self.driver.spawn(**node2['spawn_params']) - self.assertEqual(['test-host-1', 'test-host-2'], - self.driver.list_instances()) - - self.driver.destroy(**node1['destroy_params']) - self.assertEqual(['test-host-2'], - self.driver.list_instances()) - - self.driver.destroy(**node2['destroy_params']) - self.assertEqual([], self.driver.list_instances()) - - def test_get_info_no_such_node(self): - node = self._create_node() - self.assertRaises(exception.InstanceNotFound, - self.driver.get_info, - node['instance']) - - def test_get_info_ok(self): - node = self._create_node() - db.bm_node_associate_and_update(self.context, node['node']['uuid'], - {'instance_uuid': node['instance']['uuid'], - 'instance_name': node['instance']['hostname'], - 'task_state': baremetal_states.ACTIVE}) - res = self.driver.get_info(node['instance']) - self.assertEqual(res['state'], power_state.RUNNING) - - def test_get_info_with_defunct_pm(self): - # test fix for bug 1178378 - node = self._create_node() - db.bm_node_associate_and_update(self.context, node['node']['uuid'], - {'instance_uuid': node['instance']['uuid'], - 'instance_name': node['instance']['hostname'], - 'task_state': baremetal_states.ACTIVE}) - - # fake the power manager and don't get a power state - self.mox.StubOutWithMock(fake.FakePowerManager, 'is_power_on') - fake.FakePowerManager.is_power_on().AndReturn(None) - self.mox.ReplayAll() - - res = self.driver.get_info(node['instance']) - # prior to the fix, returned power_state was SHUTDOWN - self.assertEqual(res['state'], power_state.NOSTATE) - self.mox.VerifyAll() - - def test_attach_volume(self): - connection_info = {'_fake_connection_info': None} - instance = utils.get_test_instance() - mountpoint = '/dev/sdd' - self.mox.StubOutWithMock(self.driver.volume_driver, 'attach_volume') - self.driver.volume_driver.attach_volume(connection_info, - instance, - mountpoint) - self.mox.ReplayAll() - self.driver.attach_volume(None, connection_info, instance, mountpoint) - - def test_detach_volume(self): - connection_info = {'_fake_connection_info': None} - instance = utils.get_test_instance() - mountpoint = '/dev/sdd' - self.mox.StubOutWithMock(self.driver.volume_driver, 'detach_volume') - self.driver.volume_driver.detach_volume(connection_info, - instance, - mountpoint) - self.mox.ReplayAll() - self.driver.detach_volume(connection_info, instance, mountpoint) - - def test_attach_block_devices(self): - connection_info_1 = {'_fake_connection_info_1': None} - connection_info_2 = {'_fake_connection_info_2': None} - block_device_mapping = [{'connection_info': connection_info_1, - 'mount_device': '/dev/sde'}, - {'connection_info': connection_info_2, - 'mount_device': '/dev/sdf'}] - block_device_info = {'block_device_mapping': block_device_mapping} - instance = utils.get_test_instance() - - self.mox.StubOutWithMock(self.driver, 'attach_volume') - self.driver.attach_volume(None, connection_info_1, instance, - '/dev/sde') - self.driver.attach_volume(None, connection_info_2, instance, - '/dev/sdf') - self.mox.ReplayAll() - self.driver._attach_block_devices(instance, block_device_info) - - def test_detach_block_devices(self): - connection_info_1 = {'_fake_connection_info_1': None} - connection_info_2 = {'_fake_connection_info_2': None} - block_device_mapping = [{'connection_info': connection_info_1, - 'mount_device': '/dev/sde'}, - {'connection_info': connection_info_2, - 'mount_device': '/dev/sdf'}] - block_device_info = {'block_device_mapping': block_device_mapping} - instance = utils.get_test_instance() - - self.mox.StubOutWithMock(self.driver, 'detach_volume') - self.driver.detach_volume(connection_info_1, instance, '/dev/sde') - self.driver.detach_volume(connection_info_2, instance, '/dev/sdf') - self.mox.ReplayAll() - self.driver._detach_block_devices(instance, block_device_info) diff --git a/nova/tests/virt/baremetal/test_iboot_pdu.py b/nova/tests/virt/baremetal/test_iboot_pdu.py deleted file mode 100644 index 3f99cf995e..0000000000 --- a/nova/tests/virt/baremetal/test_iboot_pdu.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2013 Red Hat Inc. -# 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. - -"""Test class for baremetal iBoot power manager.""" - -from nova import exception -from nova import test -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova.virt.baremetal import iboot_pdu - - -class BareMetalIbootPDUTestCase(test.TestCase): - - def setUp(self): - super(BareMetalIbootPDUTestCase, self).setUp() - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='192.168.1.254', - pm_user='foo', - pm_password='bar') - self.pm = iboot_pdu.IBootManager(node=self.node) - - def test_construct(self): - self.assertEqual(self.pm.address, '192.168.1.254') - self.assertEqual(self.pm.port, 9100) - self.assertEqual(self.pm.relay_id, 1) - self.assertEqual(self.pm.user, 'foo') - self.assertEqual(self.pm.password, 'bar') - - def test_construct_with_port_and_relay(self): - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='192.168.1.254:1234,8', - pm_user='foo', - pm_password='bar') - self.pm = iboot_pdu.IBootManager(node=self.node) - - self.assertEqual(self.pm.address, '192.168.1.254') - self.assertEqual(self.pm.port, 1234) - self.assertEqual(self.pm.relay_id, 8) - self.assertEqual(self.pm.user, 'foo') - self.assertEqual(self.pm.password, 'bar') - - def test_construct_with_invalid_port(self): - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='192.168.1.254:not_a_number', - pm_user='foo', - pm_password='bar') - self.assertRaises(exception.InvalidParameterValue, - iboot_pdu.IBootManager, node=self.node) - - def test_construct_with_relay_id(self): - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='192.168.1.254:1234,not_a_number', - pm_user='foo', - pm_password='bar') - self.assertRaises(exception.InvalidParameterValue, - iboot_pdu.IBootManager, node=self.node) - - def test_activate_node(self): - self.mox.StubOutWithMock(self.pm, '_create_connection') - self.mox.StubOutWithMock(self.pm, '_switch') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._create_connection().AndReturn(True) - self.pm._switch(1, True).AndReturn(True) - self.pm.is_power_on().AndReturn(True) - self.mox.ReplayAll() - - self.pm.activate_node() - self.mox.VerifyAll() - - def test_deactivate_node(self): - self.mox.StubOutWithMock(self.pm, '_create_connection') - self.mox.StubOutWithMock(self.pm, '_switch') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._create_connection().AndReturn(True) - self.pm.is_power_on().AndReturn(True) - self.pm._switch(1, False).AndReturn(True) - self.pm.is_power_on().AndReturn(False) - self.mox.ReplayAll() - - self.pm.deactivate_node() - self.mox.VerifyAll() - - def test_reboot_node(self): - self.mox.StubOutWithMock(self.pm, '_create_connection') - self.mox.StubOutWithMock(self.pm, '_switch') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._create_connection().AndReturn(True) - self.pm._switch(1, False).AndReturn(True) - self.pm._switch(1, True).AndReturn(True) - self.pm.is_power_on().AndReturn(True) - self.mox.ReplayAll() - - self.pm.reboot_node() - self.mox.VerifyAll() - - def test_is_power_on(self): - self.mox.StubOutWithMock(self.pm, '_create_connection') - self.mox.StubOutWithMock(self.pm, '_get_relay') - self.pm._create_connection().AndReturn(True) - self.pm._get_relay(1).AndReturn(True) - self.mox.ReplayAll() - - self.pm.is_power_on() - self.mox.VerifyAll() diff --git a/nova/tests/virt/baremetal/test_ipmi.py b/nova/tests/virt/baremetal/test_ipmi.py deleted file mode 100644 index 8872ab034c..0000000000 --- a/nova/tests/virt/baremetal/test_ipmi.py +++ /dev/null @@ -1,242 +0,0 @@ -# coding=utf-8 - -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Test class for baremetal IPMI power manager.""" - -import os -import stat -import tempfile - -from oslo.config import cfg - -from nova import test -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import ipmi -from nova.virt.baremetal import utils as bm_utils - -CONF = cfg.CONF - - -class BareMetalIPMITestCase(test.NoDBTestCase): - - def setUp(self): - super(BareMetalIPMITestCase, self).setUp() - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='fake-address', - pm_user='fake-user', - pm_password='fake-password') - self.ipmi = ipmi.IPMI(self.node) - - def test_construct(self): - self.assertEqual(self.ipmi.node_id, 123) - self.assertEqual(self.ipmi.address, 'fake-address') - self.assertEqual(self.ipmi.user, 'fake-user') - self.assertEqual(self.ipmi.password, 'fake-password') - - def test_make_password_file(self): - pw_file = ipmi._make_password_file(self.node['pm_password']) - try: - self.assertTrue(os.path.isfile(pw_file)) - self.assertEqual(os.stat(pw_file)[stat.ST_MODE] & 0o777, 0o600) - with open(pw_file, "r") as f: - pm_password = f.read() - self.assertEqual(pm_password, self.node['pm_password']) - finally: - os.unlink(pw_file) - - def test_make_empty_password_file(self): - pw_file = ipmi._make_password_file('') - try: - self.assertTrue(os.path.isfile(pw_file)) - self.assertEqual(os.stat(pw_file)[stat.ST_MODE] & 0o777, 0o600) - with open(pw_file, "rb") as f: - pm_password = f.read() - self.assertEqual(b"\0", pm_password) - finally: - os.unlink(pw_file) - - def test_exec_ipmitool(self): - pw_file = '/tmp/password_file' - - self.mox.StubOutWithMock(ipmi, '_make_password_file') - self.mox.StubOutWithMock(utils, 'execute') - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - ipmi._make_password_file(self.ipmi.password).AndReturn(pw_file) - args = [ - 'ipmitool', - '-I', 'lanplus', - '-H', self.ipmi.address, - '-U', self.ipmi.user, - '-f', pw_file, - 'A', 'B', 'C', - ] - utils.execute(*args, attempts=3).AndReturn(('', '')) - bm_utils.unlink_without_raise(pw_file).AndReturn(None) - self.mox.ReplayAll() - - self.ipmi._exec_ipmitool('A B C') - self.mox.VerifyAll() - - def test_is_power_on_ok(self): - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is on\n"]) - self.mox.ReplayAll() - - res = self.ipmi.is_power_on() - self.assertEqual(res, True) - self.mox.VerifyAll() - - def test_is_power_no_answer(self): - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Fake reply\n"]) - self.mox.ReplayAll() - - res = self.ipmi.is_power_on() - self.assertIsNone(res) - self.mox.VerifyAll() - - def test_power_already_on(self): - self.flags(ipmi_power_retry=0, group='baremetal') - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is on\n"]) - self.mox.ReplayAll() - - self.ipmi.state = baremetal_states.DELETED - self.ipmi._power_on() - self.mox.VerifyAll() - self.assertEqual(self.ipmi.state, baremetal_states.ACTIVE) - - def test_power_on_ok(self): - self.flags(ipmi_power_retry=0, group='baremetal') - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.ipmi._exec_ipmitool("power on").AndReturn([]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is on\n"]) - self.mox.ReplayAll() - - self.ipmi.state = baremetal_states.DELETED - self.ipmi._power_on() - self.mox.VerifyAll() - self.assertEqual(self.ipmi.state, baremetal_states.ACTIVE) - - def test_power_on_fail(self): - self.flags(ipmi_power_retry=0, group='baremetal') - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.ipmi._exec_ipmitool("power on").AndReturn([]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.mox.ReplayAll() - - self.ipmi.state = baremetal_states.DELETED - self.ipmi._power_on() - self.mox.VerifyAll() - self.assertEqual(self.ipmi.state, baremetal_states.ERROR) - - def test_power_on_max_retries(self): - self.flags(ipmi_power_retry=2, group='baremetal') - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.ipmi._exec_ipmitool("power on").AndReturn([]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.mox.ReplayAll() - - self.ipmi.state = baremetal_states.DELETED - self.ipmi._power_on() - self.mox.VerifyAll() - self.assertEqual(self.ipmi.state, baremetal_states.ERROR) - self.assertEqual(self.ipmi.retries, 3) - - def test_power_off_ok(self): - self.flags(ipmi_power_retry=0, group='baremetal') - self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool') - - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is on\n"]) - self.ipmi._exec_ipmitool("power off").AndReturn([]) - self.ipmi._exec_ipmitool("power status").AndReturn( - ["Chassis Power is off\n"]) - self.mox.ReplayAll() - - self.ipmi.state = baremetal_states.ACTIVE - self.ipmi._power_off() - self.mox.VerifyAll() - self.assertEqual(self.ipmi.state, baremetal_states.DELETED) - - def test_get_console_pid_path(self): - self.flags(terminal_pid_dir='/tmp', group='baremetal') - path = ipmi._get_console_pid_path(self.ipmi.node_id) - self.assertEqual(path, '/tmp/%s.pid' % self.ipmi.node_id) - - def test_console_pid(self): - fd, path = tempfile.mkstemp() - with os.fdopen(fd, 'w') as f: - f.write("12345\n") - - self.mox.StubOutWithMock(ipmi, '_get_console_pid_path') - ipmi._get_console_pid_path(self.ipmi.node_id).AndReturn(path) - self.mox.ReplayAll() - - pid = ipmi._get_console_pid(self.ipmi.node_id) - bm_utils.unlink_without_raise(path) - self.mox.VerifyAll() - self.assertEqual(pid, 12345) - - def test_console_pid_nan(self): - fd, path = tempfile.mkstemp() - with os.fdopen(fd, 'w') as f: - f.write("hello world\n") - - self.mox.StubOutWithMock(ipmi, '_get_console_pid_path') - ipmi._get_console_pid_path(self.ipmi.node_id).AndReturn(path) - self.mox.ReplayAll() - - pid = ipmi._get_console_pid(self.ipmi.node_id) - bm_utils.unlink_without_raise(path) - self.mox.VerifyAll() - self.assertIsNone(pid) - - def test_console_pid_file_not_found(self): - pid_path = ipmi._get_console_pid_path(self.ipmi.node_id) - - self.mox.StubOutWithMock(os.path, 'exists') - os.path.exists(pid_path).AndReturn(False) - self.mox.ReplayAll() - - pid = ipmi._get_console_pid(self.ipmi.node_id) - self.mox.VerifyAll() - self.assertIsNone(pid) diff --git a/nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py b/nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py deleted file mode 100644 index c42c04d86c..0000000000 --- a/nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py +++ /dev/null @@ -1,420 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Ilya Alekseyev -# -# 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 os -import tempfile -import time - -import mock -import mox -from oslo.utils import units - -from nova.cmd import baremetal_deploy_helper as bmdh -from nova.openstack.common import log as logging -from nova import test -from nova.tests.virt.baremetal.db import base as bm_db_base -from nova.virt.baremetal import db as bm_db - -bmdh.LOG = logging.getLogger('nova.virt.baremetal.deploy_helper') - -_PXECONF_DEPLOY = """ -default deploy - -label deploy -kernel deploy_kernel -append initrd=deploy_ramdisk -ipappend 3 - -label boot -kernel kernel -append initrd=ramdisk root=${ROOT} -""" - -_PXECONF_BOOT = """ -default boot - -label deploy -kernel deploy_kernel -append initrd=deploy_ramdisk -ipappend 3 - -label boot -kernel kernel -append initrd=ramdisk root=UUID=12345678-1234-1234-1234-1234567890abcdef -""" - - -class WorkerTestCase(bm_db_base.BMDBTestCase): - def setUp(self): - super(WorkerTestCase, self).setUp() - self.worker = bmdh.Worker() - # Make tearDown() fast - self.worker.queue_timeout = 0.1 - self.worker.start() - - def tearDown(self): - if self.worker.isAlive(): - self.worker.stop = True - self.worker.join(timeout=1) - super(WorkerTestCase, self).tearDown() - - def wait_queue_empty(self, timeout): - for _ in xrange(int(timeout / 0.1)): - if bmdh.QUEUE.empty(): - break - time.sleep(0.1) - - def test_run_calls_deploy(self): - """Check all queued requests are passed to deploy().""" - history = [] - - def fake_deploy(**params): - history.append(params) - - self.stubs.Set(bmdh, 'deploy', fake_deploy) - self.mox.StubOutWithMock(bm_db, 'bm_node_update') - # update is called twice inside Worker.run - for i in range(6): - bm_db.bm_node_update(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg()) - self.mox.ReplayAll() - - params_list = [{'fake1': ''}, {'fake2': ''}, {'fake3': ''}] - for (dep_id, params) in enumerate(params_list): - bmdh.QUEUE.put((dep_id, params)) - self.wait_queue_empty(1) - self.assertEqual(params_list, history) - self.mox.VerifyAll() - - def test_run_with_failing_deploy(self): - """Check a worker keeps on running even if deploy() raises - an exception. - """ - history = [] - - def fake_deploy(**params): - history.append(params) - # always fail - raise Exception('test') - - self.stubs.Set(bmdh, 'deploy', fake_deploy) - self.mox.StubOutWithMock(bm_db, 'bm_node_update') - # update is called twice inside Worker.run - for i in range(6): - bm_db.bm_node_update(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg()) - self.mox.ReplayAll() - - params_list = [{'fake1': ''}, {'fake2': ''}, {'fake3': ''}] - for (dep_id, params) in enumerate(params_list): - bmdh.QUEUE.put((dep_id, params)) - self.wait_queue_empty(1) - self.assertEqual(params_list, history) - self.mox.VerifyAll() - - -class PhysicalWorkTestCase(test.NoDBTestCase): - def setUp(self): - super(PhysicalWorkTestCase, self).setUp() - - def noop(*args, **kwargs): - pass - - self.stubs.Set(time, 'sleep', noop) - - def _deploy_mox(self): - self.mox.StubOutWithMock(bmdh, 'get_dev') - self.mox.StubOutWithMock(bmdh, 'get_image_mb') - self.mox.StubOutWithMock(bmdh, 'discovery') - self.mox.StubOutWithMock(bmdh, 'login_iscsi') - self.mox.StubOutWithMock(bmdh, 'logout_iscsi') - self.mox.StubOutWithMock(bmdh, 'make_partitions') - self.mox.StubOutWithMock(bmdh, 'is_block_device') - self.mox.StubOutWithMock(bmdh, 'dd') - self.mox.StubOutWithMock(bmdh, 'mkswap') - self.mox.StubOutWithMock(bmdh, 'block_uuid') - self.mox.StubOutWithMock(bmdh, 'switch_pxe_config') - self.mox.StubOutWithMock(bmdh, 'notify') - - def test_deploy_no_ephemeral(self): - address = '127.0.0.1' - port = 3306 - iqn = 'iqn.xyz' - lun = 1 - image_path = '/tmp/xyz/image' - pxe_config_path = '/tmp/abc/pxeconfig' - root_mb = 128 - swap_mb = 64 - ephemeral_mb = 0 - - dev = '/dev/fake' - root_part = '/dev/fake-part1' - swap_part = '/dev/fake-part2' - root_uuid = '12345678-1234-1234-12345678-12345678abcdef' - - self._deploy_mox() - - bmdh.get_dev(address, port, iqn, lun).AndReturn(dev) - bmdh.get_image_mb(image_path).AndReturn(1) # < root_mb - bmdh.discovery(address, port) - bmdh.login_iscsi(address, port, iqn) - bmdh.is_block_device(dev).AndReturn(True) - bmdh.make_partitions(dev, root_mb, swap_mb, ephemeral_mb) - bmdh.is_block_device(root_part).AndReturn(True) - bmdh.is_block_device(swap_part).AndReturn(True) - bmdh.dd(image_path, root_part) - bmdh.mkswap(swap_part) - bmdh.block_uuid(root_part).AndReturn(root_uuid) - bmdh.logout_iscsi(address, port, iqn) - bmdh.switch_pxe_config(pxe_config_path, root_uuid) - bmdh.notify(address, 10000) - self.mox.ReplayAll() - - bmdh.deploy(address, port, iqn, lun, image_path, pxe_config_path, - root_mb, swap_mb, ephemeral_mb) - - self.mox.VerifyAll() - - def test_deploy_with_ephemeral(self): - address = '127.0.0.1' - port = 3306 - iqn = 'iqn.xyz' - lun = 1 - image_path = '/tmp/xyz/image' - pxe_config_path = '/tmp/abc/pxeconfig' - root_mb = 128 - swap_mb = 64 - ephemeral_mb = 256 - - dev = '/dev/fake' - ephemeral_part = '/dev/fake-part1' - swap_part = '/dev/fake-part2' - root_part = '/dev/fake-part3' - root_uuid = '12345678-1234-1234-12345678-12345678abcdef' - - self._deploy_mox() - self.mox.StubOutWithMock(bmdh, 'mkfs_ephemeral') - - bmdh.get_dev(address, port, iqn, lun).AndReturn(dev) - bmdh.get_image_mb(image_path).AndReturn(1) # < root_mb - bmdh.discovery(address, port) - bmdh.login_iscsi(address, port, iqn) - bmdh.is_block_device(dev).AndReturn(True) - bmdh.make_partitions(dev, root_mb, swap_mb, ephemeral_mb) - bmdh.is_block_device(root_part).AndReturn(True) - bmdh.is_block_device(swap_part).AndReturn(True) - bmdh.is_block_device(ephemeral_part).AndReturn(True) - bmdh.dd(image_path, root_part) - bmdh.mkswap(swap_part) - bmdh.mkfs_ephemeral(ephemeral_part) - bmdh.block_uuid(root_part).AndReturn(root_uuid) - bmdh.logout_iscsi(address, port, iqn) - bmdh.switch_pxe_config(pxe_config_path, root_uuid) - bmdh.notify(address, 10000) - self.mox.ReplayAll() - - bmdh.deploy(address, port, iqn, lun, image_path, pxe_config_path, - root_mb, swap_mb, ephemeral_mb) - - self.mox.VerifyAll() - - def test_deploy_preserve_ephemeral(self): - address = '127.0.0.1' - port = 3306 - iqn = 'iqn.xyz' - lun = 1 - image_path = '/tmp/xyz/image' - pxe_config_path = '/tmp/abc/pxeconfig' - root_mb = 128 - swap_mb = 64 - ephemeral_mb = 128 - - dev = '/dev/fake' - ephemeral_part = '/dev/fake-part1' - swap_part = '/dev/fake-part2' - root_part = '/dev/fake-part3' - root_uuid = '12345678-1234-1234-12345678-12345678abcdef' - - self._deploy_mox() - self.mox.StubOutWithMock(bmdh, 'mkfs_ephemeral') - - bmdh.get_dev(address, port, iqn, lun).AndReturn(dev) - bmdh.get_image_mb(image_path).AndReturn(1) # < root_mb - bmdh.discovery(address, port) - bmdh.login_iscsi(address, port, iqn) - bmdh.is_block_device(dev).AndReturn(True) - bmdh.make_partitions(dev, root_mb, swap_mb, ephemeral_mb) - bmdh.is_block_device(root_part).AndReturn(True) - bmdh.is_block_device(swap_part).AndReturn(True) - bmdh.is_block_device(ephemeral_part).AndReturn(True) - bmdh.dd(image_path, root_part) - bmdh.mkswap(swap_part) - bmdh.block_uuid(root_part).AndReturn(root_uuid) - bmdh.logout_iscsi(address, port, iqn) - bmdh.switch_pxe_config(pxe_config_path, root_uuid) - bmdh.notify(address, 10000) - self.mox.ReplayAll() - - bmdh.deploy(address, port, iqn, lun, image_path, pxe_config_path, - root_mb, swap_mb, ephemeral_mb, True) - - self.mox.VerifyAll() - - def test_always_logout_iscsi(self): - """logout_iscsi() must be called once login_iscsi() is called.""" - address = '127.0.0.1' - port = 3306 - iqn = 'iqn.xyz' - lun = 1 - image_path = '/tmp/xyz/image' - pxe_config_path = '/tmp/abc/pxeconfig' - root_mb = 128 - swap_mb = 64 - ephemeral_mb = 256 - - dev = '/dev/fake' - - self.mox.StubOutWithMock(bmdh, 'get_dev') - self.mox.StubOutWithMock(bmdh, 'get_image_mb') - self.mox.StubOutWithMock(bmdh, 'discovery') - self.mox.StubOutWithMock(bmdh, 'login_iscsi') - self.mox.StubOutWithMock(bmdh, 'logout_iscsi') - self.mox.StubOutWithMock(bmdh, 'work_on_disk') - - class TestException(Exception): - pass - - bmdh.get_dev(address, port, iqn, lun).AndReturn(dev) - bmdh.get_image_mb(image_path).AndReturn(1) # < root_mb - bmdh.discovery(address, port) - bmdh.login_iscsi(address, port, iqn) - bmdh.work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, image_path, - False).AndRaise(TestException) - bmdh.logout_iscsi(address, port, iqn) - self.mox.ReplayAll() - - self.assertRaises(TestException, - bmdh.deploy, - address, port, iqn, lun, image_path, - pxe_config_path, root_mb, swap_mb, ephemeral_mb) - - -class WorkOnDiskTestCase(test.NoDBTestCase): - def setUp(self): - super(WorkOnDiskTestCase, self).setUp() - self.image_path = '/tmp/xyz/image' - self.root_mb = 128 - self.swap_mb = 64 - self.ephemeral_mb = 256 - self.dev = '/dev/fake' - self.ephemeral_part = '/dev/fake-part1' - self.swap_part = '/dev/fake-part2' - self.root_part = '/dev/fake-part3' - - self.m_ibd = mock.Mock() - self.m_mp = mock.Mock() - self.stubs.Set(bmdh, 'is_block_device', self.m_ibd) - self.stubs.Set(bmdh, 'make_partitions', self.m_mp) - - def test_no_parent_device(self): - self.m_ibd.return_value = False - self.assertRaises(bmdh.BareMetalDeployException, - bmdh.work_on_disk, - self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb, self.image_path, False) - self.m_ibd.assert_called_once_with(self.dev) - self.assertFalse(self.m_mp.called) - - def test_no_root_partition(self): - self.m_ibd.side_effect = [True, False] - calls = [mock.call(self.dev), - mock.call(self.root_part)] - self.assertRaises(bmdh.BareMetalDeployException, - bmdh.work_on_disk, - self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb, self.image_path, False) - self.assertEqual(self.m_ibd.call_args_list, calls) - self.m_mp.assert_called_once_with(self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb) - - def test_no_swap_partition(self): - self.m_ibd.side_effect = [True, True, False] - calls = [mock.call(self.dev), - mock.call(self.root_part), - mock.call(self.swap_part)] - self.assertRaises(bmdh.BareMetalDeployException, - bmdh.work_on_disk, - self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb, self.image_path, False) - self.assertEqual(self.m_ibd.call_args_list, calls) - self.m_mp.assert_called_once_with(self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb) - - def test_no_ephemeral_partition(self): - self.m_ibd.side_effect = [True, True, True, False] - calls = [mock.call(self.dev), - mock.call(self.root_part), - mock.call(self.swap_part), - mock.call(self.ephemeral_part)] - self.assertRaises(bmdh.BareMetalDeployException, - bmdh.work_on_disk, - self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb, self.image_path, False) - self.assertEqual(self.m_ibd.call_args_list, calls) - self.m_mp.assert_called_once_with(self.dev, self.root_mb, self.swap_mb, - self.ephemeral_mb) - - -class SwitchPxeConfigTestCase(test.NoDBTestCase): - def setUp(self): - super(SwitchPxeConfigTestCase, self).setUp() - (fd, self.fname) = tempfile.mkstemp() - os.write(fd, _PXECONF_DEPLOY) - os.close(fd) - - def tearDown(self): - os.unlink(self.fname) - super(SwitchPxeConfigTestCase, self).tearDown() - - def test_switch_pxe_config(self): - bmdh.switch_pxe_config(self.fname, - '12345678-1234-1234-1234-1234567890abcdef') - with open(self.fname, 'r') as f: - pxeconf = f.read() - self.assertEqual(pxeconf, _PXECONF_BOOT) - - -class OtherFunctionTestCase(test.NoDBTestCase): - def test_get_dev(self): - expected = '/dev/disk/by-path/ip-1.2.3.4:5678-iscsi-iqn.fake-lun-9' - actual = bmdh.get_dev('1.2.3.4', 5678, 'iqn.fake', 9) - self.assertEqual(expected, actual) - - def test_get_image_mb(self): - size = None - - def fake_getsize(path): - return size - - self.stubs.Set(os.path, 'getsize', fake_getsize) - size = 0 - self.assertEqual(bmdh.get_image_mb('x'), 0) - size = 1 - self.assertEqual(bmdh.get_image_mb('x'), 1) - size = units.Mi - self.assertEqual(bmdh.get_image_mb('x'), 1) - size = units.Mi + 1 - self.assertEqual(bmdh.get_image_mb('x'), 2) diff --git a/nova/tests/virt/baremetal/test_nova_baremetal_manage.py b/nova/tests/virt/baremetal/test_nova_baremetal_manage.py deleted file mode 100644 index cca8757db4..0000000000 --- a/nova/tests/virt/baremetal/test_nova_baremetal_manage.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Ilya Alekseyev -# -# 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 nova.cmd import baremetal_manage as bm_man -from nova.tests.virt.baremetal.db import base as bm_db_base - - -class BareMetalDbCommandsTestCase(bm_db_base.BMDBTestCase): - def setUp(self): - super(BareMetalDbCommandsTestCase, self).setUp() - self.commands = bm_man.BareMetalDbCommands() - - def test_sync_and_version(self): - self.commands.sync() - v = self.commands.version() - self.assertTrue(v > 0) diff --git a/nova/tests/virt/baremetal/test_pxe.py b/nova/tests/virt/baremetal/test_pxe.py deleted file mode 100644 index 98e9259e38..0000000000 --- a/nova/tests/virt/baremetal/test_pxe.py +++ /dev/null @@ -1,645 +0,0 @@ -# coding=utf-8 - -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Tests for baremetal pxe driver.""" - -import os - -import mox -from oslo.config import cfg -from oslo.db import exception as db_exc -from testtools import matchers - -from nova import exception -from nova import objects -from nova.tests.image import fake as fake_image -from nova.tests import utils -from nova.tests.virt.baremetal.db import base as bm_db_base -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import db -from nova.virt.baremetal import pxe -from nova.virt.baremetal import utils as bm_utils -from nova.virt.disk import api as disk_api -from nova.virt import fake as fake_virt - -CONF = cfg.CONF - -COMMON_FLAGS = dict( - firewall_driver='nova.virt.baremetal.fake.FakeFirewallDriver', - host='test_host', -) - -BAREMETAL_FLAGS = dict( - driver='nova.virt.baremetal.pxe.PXE', - flavor_extra_specs=['cpu_arch:test', 'test_spec:test_value'], - power_manager='nova.virt.baremetal.fake.FakePowerManager', - vif_driver='nova.virt.baremetal.fake.FakeVifDriver', - volume_driver='nova.virt.baremetal.fake.FakeVolumeDriver', - group='baremetal', -) - - -class BareMetalPXETestCase(bm_db_base.BMDBTestCase): - - def setUp(self): - super(BareMetalPXETestCase, self).setUp() - self.flags(**COMMON_FLAGS) - self.flags(**BAREMETAL_FLAGS) - self.driver = pxe.PXE(fake_virt.FakeVirtAPI()) - - fake_image.stub_out_image_service(self.stubs) - self.addCleanup(fake_image.FakeImageService_reset) - self.context = utils.get_test_admin_context() - self.test_block_device_info = None, - self.instance = utils.get_test_instance() - self.test_network_info = utils.get_test_network_info() - self.node_info = bm_db_utils.new_bm_node( - service_host='test_host', - cpus=4, - memory_mb=2048, - ) - self.nic_info = [ - {'address': '22:22:22:22:22:22', 'datapath_id': '0x1', - 'port_no': 1}, - {'address': '33:33:33:33:33:33', 'datapath_id': '0x2', - 'port_no': 2}, - ] - - def _create_node(self): - # File injection is off by default, but we should continue to test it - # until it is removed. - CONF.set_override('use_file_injection', True, 'baremetal') - self.node = db.bm_node_create(self.context, self.node_info) - for nic in self.nic_info: - db.bm_interface_create( - self.context, - self.node['id'], - nic['address'], - nic['datapath_id'], - nic['port_no'], - ) - self.instance['node'] = self.node['id'] - self.spawn_params = dict( - admin_password='test_pass', - block_device_info=self.test_block_device_info, - context=self.context, - image_meta=utils.get_test_image_info(None, - self.instance), - injected_files=[('/fake/path', 'hello world')], - instance=self.instance, - network_info=self.test_network_info, - ) - - -class PXEClassMethodsTestCase(BareMetalPXETestCase): - - def test_build_pxe_config(self): - args = { - 'deployment_id': 'aaa', - 'deployment_key': 'bbb', - 'deployment_iscsi_iqn': 'ccc', - 'deployment_aki_path': 'ddd', - 'deployment_ari_path': 'eee', - 'aki_path': 'fff', - 'ari_path': 'ggg', - 'network_info': self.test_network_info, - } - config = pxe.build_pxe_config(**args) - self.assertThat(config, matchers.StartsWith('default deploy')) - - # deploy bits are in the deploy section - start = config.index('label deploy') - end = config.index('label boot') - self.assertThat(config[start:end], matchers.MatchesAll( - matchers.Contains('kernel ddd'), - matchers.Contains('initrd=eee'), - matchers.Contains('deployment_id=aaa'), - matchers.Contains('deployment_key=bbb'), - matchers.Contains('iscsi_target_iqn=ccc'), - matchers.Not(matchers.Contains('kernel fff')), - )) - - # boot bits are in the boot section - start = config.index('label boot') - self.assertThat(config[start:], matchers.MatchesAll( - matchers.Contains('kernel fff'), - matchers.Contains('initrd=ggg'), - matchers.Not(matchers.Contains('kernel ddd')), - )) - - def test_build_pxe_network_config(self): - self.flags( - pxe_network_config=True, - group='baremetal', - ) - net = utils.get_test_network_info(1) - config = pxe.build_pxe_network_config(net) - self.assertIn('eth0:off', config) - self.assertNotIn('eth1', config) - - net = utils.get_test_network_info(2) - config = pxe.build_pxe_network_config(net) - self.assertIn('eth0:off', config) - self.assertIn('eth1:off', config) - - def test_build_network_config(self): - net = utils.get_test_network_info(1) - config = pxe.build_network_config(net) - self.assertIn('eth0', config) - self.assertNotIn('eth1', config) - - net = utils.get_test_network_info(2) - config = pxe.build_network_config(net) - self.assertIn('eth0', config) - self.assertIn('eth1', config) - - def test_build_network_config_dhcp(self): - self.flags( - net_config_template='$pybasedir/nova/virt/baremetal/' - 'net-dhcp.ubuntu.template', - group='baremetal', - ) - net = utils.get_test_network_info() - net[0]['network']['subnets'][0]['ips'][0]['address'] = '1.2.3.4' - config = pxe.build_network_config(net) - self.assertIn('iface eth0 inet dhcp', config) - self.assertNotIn('address 1.2.3.4', config) - - def test_build_network_config_static(self): - self.flags( - net_config_template='$pybasedir/nova/virt/baremetal/' - 'net-static.ubuntu.template', - group='baremetal', - ) - net = utils.get_test_network_info() - net[0]['network']['subnets'][0]['ips'][0]['address'] = '1.2.3.4' - config = pxe.build_network_config(net) - self.assertIn('iface eth0 inet static', config) - self.assertIn('address 1.2.3.4', config) - - def test_build_network_config_static_parameters(self): - self.flags(use_ipv6=True) - self.flags( - net_config_template='$pybasedir/nova/virt/baremetal/' - 'net-static.ubuntu.template', - group='baremetal' - ) - - net = utils.get_test_network_info() - net[0]['network']['subnets'][0]['cidr'] = '10.1.1.0/24' - net[0]['network']['subnets'][0]['gateway']['address'] = '10.1.1.1' - net[0]['network']['subnets'][0]['dns'][0]['address'] = '10.1.1.2' - net[0]['network']['subnets'][0]['dns'][1]['address'] = '10.1.1.3' - - net[0]['network']['subnets'][1]['cidr'] = 'fc00::/7' - net[0]['network']['subnets'][1]['ips'][0]['address'] = 'fc00::1' - net[0]['network']['subnets'][1]['gateway']['address'] = 'fc00::2' - config = pxe.build_network_config(net) - - self.assertIn('iface eth0 inet static', config) - self.assertIn('gateway 10.1.1.1', config) - self.assertIn('dns-nameservers 10.1.1.2 10.1.1.3', config) - - self.assertIn('iface eth0 inet6 static', config) - self.assertIn('address fc00::1', config) - self.assertIn('netmask 7', config) - self.assertIn('gateway fc00::2', config) - - def test_image_dir_path(self): - self.assertEqual( - os.path.join(CONF.instances_path, 'instance-00000001'), - pxe.get_image_dir_path(self.instance)) - - def test_image_file_path(self): - self.assertEqual( - os.path.join( - CONF.instances_path, 'instance-00000001', 'disk'), - pxe.get_image_file_path(self.instance)) - - def test_pxe_config_file_path(self): - self.instance['uuid'] = 'aaaa-bbbb-cccc' - self.assertEqual( - os.path.join(CONF.baremetal.tftp_root, - 'aaaa-bbbb-cccc', 'config'), - pxe.get_pxe_config_file_path(self.instance)) - - def test_pxe_mac_path(self): - self.assertEqual( - os.path.join(CONF.baremetal.tftp_root, - 'pxelinux.cfg', '01-23-45-67-89-ab'), - pxe.get_pxe_mac_path('23:45:67:89:AB')) - - def test_get_instance_deploy_ids(self): - self.instance['extra_specs'] = { - 'baremetal:deploy_kernel_id': 'aaaa', - 'baremetal:deploy_ramdisk_id': 'bbbb', - } - self.flags(deploy_kernel="fail", group='baremetal') - self.flags(deploy_ramdisk="fail", group='baremetal') - - self.assertEqual('aaaa', pxe.get_deploy_aki_id(self.instance)) - self.assertEqual('bbbb', pxe.get_deploy_ari_id(self.instance)) - - def test_get_default_deploy_ids(self): - self.instance['extra_specs'] = {} - self.flags(deploy_kernel="aaaa", group='baremetal') - self.flags(deploy_ramdisk="bbbb", group='baremetal') - - self.assertEqual('aaaa', pxe.get_deploy_aki_id(self.instance)) - self.assertEqual('bbbb', pxe.get_deploy_ari_id(self.instance)) - - def test_get_partition_sizes(self): - # default "kinda.big" instance - sizes = pxe.get_partition_sizes(self.instance) - self.assertEqual(40960, sizes[0]) - self.assertEqual(1024, sizes[1]) - - def test_swap_not_zero(self): - # override swap to 0 - flavor = utils.get_test_flavor(self.context) - flavor['swap'] = 0 - self.instance = utils.get_test_instance(self.context, flavor) - - sizes = pxe.get_partition_sizes(self.instance) - self.assertEqual(40960, sizes[0]) - self.assertEqual(1, sizes[1]) - - def test_get_tftp_image_info(self): - flavor = utils.get_test_flavor() - # Raises an exception when options are neither specified - # on the instance nor in configuration file - self.assertRaises(exception.NovaException, - pxe.get_tftp_image_info, - self.instance, flavor) - - # Test that other non-true values also raise an exception - self.flags(deploy_kernel='', deploy_ramdisk='', group='baremetal') - self.assertRaises(exception.NovaException, - pxe.get_tftp_image_info, - self.instance, flavor) - - # Even if the instance includes kernel_id and ramdisk_id, - # we still need deploy_kernel_id and deploy_ramdisk_id. - # If those aren't present in instance[], and not specified in - # config file, then we raise an exception. - self.instance['kernel_id'] = 'aaaa' - self.instance['ramdisk_id'] = 'bbbb' - self.assertRaises(exception.NovaException, - pxe.get_tftp_image_info, - self.instance, flavor) - - # If an instance doesn't specify deploy_kernel_id or deploy_ramdisk_id, - # but defaults are set in the config file, we should use those. - - # Here, we confirm both that all four values were set - # and that the proper paths are getting set for all of them - self.flags(deploy_kernel='cccc', deploy_ramdisk='dddd', - group='baremetal') - base = os.path.join(CONF.baremetal.tftp_root, self.instance['uuid']) - res = pxe.get_tftp_image_info(self.instance, flavor) - expected = { - 'kernel': ['aaaa', os.path.join(base, 'kernel')], - 'ramdisk': ['bbbb', os.path.join(base, 'ramdisk')], - 'deploy_kernel': ['cccc', os.path.join(base, 'deploy_kernel')], - 'deploy_ramdisk': ['dddd', - os.path.join(base, 'deploy_ramdisk')], - } - self.assertEqual(expected, res) - - # If deploy_kernel_id and deploy_ramdisk_id are specified on - # image extra_specs, this should override any default configuration. - # Note that it is passed on the 'instance' object, despite being - # inherited from the flavor_extra_specs table. - extra_specs = { - 'baremetal:deploy_kernel_id': 'eeee', - 'baremetal:deploy_ramdisk_id': 'ffff', - } - flavor['extra_specs'] = extra_specs - res = pxe.get_tftp_image_info(self.instance, flavor) - self.assertEqual('eeee', res['deploy_kernel'][0]) - self.assertEqual('ffff', res['deploy_ramdisk'][0]) - - # However, if invalid values are passed on the image extra_specs, - # this should still raise an exception. - extra_specs = { - 'baremetal:deploy_kernel_id': '', - 'baremetal:deploy_ramdisk_id': '', - } - flavor['extra_specs'] = extra_specs - self.assertRaises(exception.NovaException, - pxe.get_tftp_image_info, - self.instance, flavor) - - -class PXEPrivateMethodsTestCase(BareMetalPXETestCase): - - def test_collect_mac_addresses(self): - self._create_node() - address_list = [nic['address'] for nic in self.nic_info] - address_list.sort() - macs = self.driver._collect_mac_addresses(self.context, self.node) - self.assertEqual(address_list, macs) - - def test_cache_tftp_images(self): - self.instance['kernel_id'] = 'aaaa' - self.instance['ramdisk_id'] = 'bbbb' - flavor = utils.get_test_flavor() - extra_specs = { - 'baremetal:deploy_kernel_id': 'cccc', - 'baremetal:deploy_ramdisk_id': 'dddd', - } - flavor['extra_specs'] = extra_specs - image_info = pxe.get_tftp_image_info(self.instance, flavor) - - self.mox.StubOutWithMock(os, 'makedirs') - self.mox.StubOutWithMock(os.path, 'exists') - os.makedirs(os.path.join(CONF.baremetal.tftp_root, - self.instance['uuid'])).AndReturn(True) - for uuid, path in [image_info[label] for label in image_info]: - os.path.exists(path).AndReturn(True) - self.mox.ReplayAll() - - self.driver._cache_tftp_images( - self.context, self.instance, image_info) - self.mox.VerifyAll() - - def test_cache_image(self): - self.mox.StubOutWithMock(os, 'makedirs') - self.mox.StubOutWithMock(os, 'unlink') - self.mox.StubOutWithMock(os.path, 'exists') - os.makedirs(pxe.get_image_dir_path(self.instance)).AndReturn(True) - disk_path = os.path.join( - pxe.get_image_dir_path(self.instance), 'disk') - os.unlink(disk_path).AndReturn(None) - os.path.exists(disk_path).AndReturn(True) - os.path.exists(pxe.get_image_file_path(self.instance)).\ - AndReturn(True) - self.mox.ReplayAll() - - image_meta = utils.get_test_image_info( - self.context, self.instance) - self.driver._cache_image( - self.context, self.instance, image_meta) - self.mox.VerifyAll() - - def test_inject_into_image(self): - # NOTE(deva): we could also test this method by stubbing - # nova.virt.disk.api._inject_*_into_fs - self._create_node() - files = [] - self.instance['hostname'] = 'fake hostname' - files.append(('/etc/hostname', 'fake hostname')) - self.instance['key_data'] = 'fake ssh key' - net_info = utils.get_test_network_info(1) - net = pxe.build_network_config(net_info) - admin_password = 'fake password' - - self.mox.StubOutWithMock(os.path, 'exists') - os.path.exists(mox.IgnoreArg()).AndReturn(True) - - self.mox.StubOutWithMock(disk_api, 'inject_data') - disk_api.inject_data( - admin_password=admin_password, - image=pxe.get_image_file_path(self.instance), - key='fake ssh key', - metadata=None, - partition=None, - net=net, - files=files, # this is what we're really testing - ).AndReturn(True) - self.mox.ReplayAll() - - self.driver._inject_into_image( - self.context, self.node, self.instance, - network_info=net_info, - admin_password=admin_password, - injected_files=None) - self.mox.VerifyAll() - - -class PXEPublicMethodsTestCase(BareMetalPXETestCase): - - def test_cache_images(self): - self._create_node() - self.mox.StubOutWithMock(objects.Flavor, 'get_by_id') - self.mox.StubOutWithMock(pxe, "get_tftp_image_info") - self.mox.StubOutWithMock(self.driver, "_cache_tftp_images") - self.mox.StubOutWithMock(self.driver, "_cache_image") - self.mox.StubOutWithMock(self.driver, "_inject_into_image") - - objects.Flavor.get_by_id(self.context, - self.instance['instance_type_id'] - ).AndReturn({}) - pxe.get_tftp_image_info(self.instance, {}).AndReturn([]) - self.driver._cache_tftp_images(self.context, self.instance, []) - self.driver._cache_image(self.context, self.instance, []) - self.driver._inject_into_image(self.context, self.node, self.instance, - self.test_network_info, None, '') - self.mox.ReplayAll() - - self.driver.cache_images( - self.context, self.node, self.instance, - admin_password='', - image_meta=[], - injected_files=None, - network_info=self.test_network_info, - ) - self.mox.VerifyAll() - - def test_destroy_images(self): - self._create_node() - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - self.mox.StubOutWithMock(bm_utils, 'rmtree_without_raise') - - bm_utils.unlink_without_raise(pxe.get_image_file_path(self.instance)) - bm_utils.rmtree_without_raise(pxe.get_image_dir_path(self.instance)) - self.mox.ReplayAll() - - self.driver.destroy_images(self.context, self.node, self.instance) - self.mox.VerifyAll() - - def test_dhcp_options_for_instance(self): - self._create_node() - self.mox.ReplayAll() - expected = [{'opt_name': 'bootfile-name', - 'opt_value': CONF.baremetal.pxe_bootfile_name}, - {'opt_name': 'server-ip-address', 'opt_value': CONF.my_ip}, - {'opt_name': 'tftp-server', 'opt_value': CONF.my_ip}] - res = self.driver.dhcp_options_for_instance(self.instance) - self.assertEqual(expected.sort(), res.sort()) - self.mox.VerifyAll() - - def test_activate_bootloader_passes_details(self): - self._create_node() - macs = [nic['address'] for nic in self.nic_info] - macs.sort() - image_info = { - 'deploy_kernel': [None, 'aaaa'], - 'deploy_ramdisk': [None, 'bbbb'], - 'kernel': [None, 'cccc'], - 'ramdisk': [None, 'dddd'], - } - self.instance['uuid'] = 'fake-uuid' - iqn = "iqn-%s" % self.instance['uuid'] - pxe_config = 'this is a fake pxe config' - pxe_path = pxe.get_pxe_config_file_path(self.instance) - pxe.get_image_file_path(self.instance) - - self.mox.StubOutWithMock(objects.Flavor, 'get_by_id') - self.mox.StubOutWithMock(pxe, 'get_tftp_image_info') - self.mox.StubOutWithMock(pxe, 'get_partition_sizes') - self.mox.StubOutWithMock(bm_utils, 'random_alnum') - self.mox.StubOutWithMock(pxe, 'build_pxe_config') - self.mox.StubOutWithMock(bm_utils, 'write_to_file') - self.mox.StubOutWithMock(bm_utils, 'create_link_without_raise') - - objects.Flavor.get_by_id(self.context, - self.instance['instance_type_id'] - ).AndReturn({}) - pxe.get_tftp_image_info(self.instance, {}).AndReturn(image_info) - pxe.get_partition_sizes(self.instance).AndReturn((0, 0, 0)) - bm_utils.random_alnum(32).AndReturn('alnum') - pxe.build_pxe_config( - self.node['id'], 'alnum', iqn, - 'aaaa', 'bbbb', 'cccc', 'dddd', - self.test_network_info).AndReturn(pxe_config) - bm_utils.write_to_file(pxe_path, pxe_config) - for mac in macs: - bm_utils.create_link_without_raise( - pxe_path, pxe.get_pxe_mac_path(mac)) - - self.mox.ReplayAll() - - self.driver.activate_bootloader(self.context, self.node, self.instance, - network_info=self.test_network_info) - - self.mox.VerifyAll() - - def test_activate_and_deactivate_bootloader(self): - self._create_node() - flavor = objects.Flavor( - context=self.context, - extra_specs={ - 'baremetal:deploy_kernel_id': 'eeee', - 'baremetal:deploy_ramdisk_id': 'ffff', - }) - self.instance['uuid'] = 'fake-uuid' - - self.mox.StubOutWithMock(objects.Flavor, 'get_by_id') - self.mox.StubOutWithMock(bm_utils, 'write_to_file') - self.mox.StubOutWithMock(bm_utils, 'create_link_without_raise') - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - self.mox.StubOutWithMock(bm_utils, 'rmtree_without_raise') - - objects.Flavor.get_by_id( - self.context, self.instance['instance_type_id']).AndReturn( - flavor) - - # create the config file - bm_utils.write_to_file(mox.StrContains('fake-uuid'), - mox.StrContains(CONF.baremetal.tftp_root)) - # unlink and link the 2 interfaces - for i in range(2): - bm_utils.unlink_without_raise(mox.Or( - mox.StrContains('fake-uuid'), - mox.StrContains(CONF.baremetal.tftp_root))) - bm_utils.create_link_without_raise( - mox.StrContains('fake-uuid'), - mox.StrContains(CONF.baremetal.tftp_root)) - # unlink all 2 interfaces, 4 images, and the config file - for i in range(7): - bm_utils.unlink_without_raise(mox.Or( - mox.StrContains('fake-uuid'), - mox.StrContains(CONF.baremetal.tftp_root))) - bm_utils.rmtree_without_raise(mox.StrContains('fake-uuid')) - - self.mox.ReplayAll() - - # activate and deactivate the bootloader - # and check the deployment task_state in the database - row = db.bm_node_get(self.context, 1) - self.assertIsNone(row['deploy_key']) - - self.driver.activate_bootloader(self.context, self.node, self.instance, - network_info=self.test_network_info) - row = db.bm_node_get(self.context, 1) - self.assertIsNotNone(row['deploy_key']) - - self.driver.deactivate_bootloader(self.context, self.node, - self.instance) - row = db.bm_node_get(self.context, 1) - self.assertIsNone(row['deploy_key']) - - self.mox.VerifyAll() - - def test_deactivate_bootloader_for_nonexistent_instance(self): - self._create_node() - self.instance['uuid'] = 'fake-uuid' - pxe_path = pxe.get_pxe_config_file_path(self.instance) - - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - self.mox.StubOutWithMock(bm_utils, 'rmtree_without_raise') - self.mox.StubOutWithMock(pxe, 'get_tftp_image_info') - self.mox.StubOutWithMock(self.driver, '_collect_mac_addresses') - - extra_specs = dict(extra_specs={ - 'baremetal:deploy_ramdisk_id': 'ignore', - 'baremetal:deploy_kernel_id': 'ignore'}) - pxe.get_tftp_image_info(self.instance, extra_specs).\ - AndRaise(exception.NovaException) - bm_utils.unlink_without_raise(pxe_path) - self.driver._collect_mac_addresses(self.context, self.node).\ - AndRaise(db_exc.DBError) - bm_utils.rmtree_without_raise( - os.path.join(CONF.baremetal.tftp_root, 'fake-uuid')) - self.mox.ReplayAll() - - self.driver.deactivate_bootloader( - self.context, self.node, self.instance) - self.mox.VerifyAll() - - def test_activate_node(self): - self._create_node() - self.instance['uuid'] = 'fake-uuid' - self.flags(pxe_deploy_timeout=1, group='baremetal') - - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.DEPLOYING, - 'instance_uuid': 'fake-uuid'}) - - # test timeout - self.assertRaises(exception.InstanceDeployFailure, - self.driver.activate_node, - self.context, self.node, self.instance) - - # test DEPLOYDONE - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.DEPLOYDONE}) - self.driver.activate_node(self.context, self.node, self.instance) - - # test no deploy -- state is just ACTIVE - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.ACTIVE}) - self.driver.activate_node(self.context, self.node, self.instance) - - # test node gone - db.bm_node_destroy(self.context, 1) - self.assertRaises(exception.InstanceDeployFailure, - self.driver.activate_node, - self.context, self.node, self.instance) diff --git a/nova/tests/virt/baremetal/test_tilera.py b/nova/tests/virt/baremetal/test_tilera.py deleted file mode 100644 index 7f20d0f3aa..0000000000 --- a/nova/tests/virt/baremetal/test_tilera.py +++ /dev/null @@ -1,398 +0,0 @@ -# coding=utf-8 - -# Copyright (c) 2011-2013 University of Southern California / ISI -# 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. - -"""Tests for baremetal tilera driver.""" - -import os - -import mox -from oslo.config import cfg -from oslo.db import exception as db_exc - -from nova import exception -from nova.tests.image import fake as fake_image -from nova.tests import utils -from nova.tests.virt.baremetal.db import base as bm_db_base -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import db -from nova.virt.baremetal import tilera -from nova.virt.baremetal import utils as bm_utils -from nova.virt.disk import api as disk_api -from nova.virt import fake as fake_virt - - -CONF = cfg.CONF - -COMMON_FLAGS = dict( - firewall_driver='nova.virt.baremetal.fake.FakeFirewallDriver', - host='test_host', -) - -BAREMETAL_FLAGS = dict( - driver='nova.virt.baremetal.tilera.Tilera', - flavor_extra_specs=['cpu_arch:test', 'test_spec:test_value'], - power_manager='nova.virt.baremetal.fake.FakePowerManager', - vif_driver='nova.virt.baremetal.fake.FakeVifDriver', - volume_driver='nova.virt.baremetal.fake.FakeVolumeDriver', - group='baremetal', -) - - -class BareMetalTileraTestCase(bm_db_base.BMDBTestCase): - - def setUp(self): - super(BareMetalTileraTestCase, self).setUp() - self.flags(**COMMON_FLAGS) - self.flags(**BAREMETAL_FLAGS) - self.driver = tilera.Tilera(fake_virt.FakeVirtAPI()) - - fake_image.stub_out_image_service(self.stubs) - self.addCleanup(fake_image.FakeImageService_reset) - self.context = utils.get_test_admin_context() - self.test_block_device_info = None, - self.instance = utils.get_test_instance() - self.test_network_info = utils.get_test_network_info() - self.node_info = bm_db_utils.new_bm_node( - service_host='test_host', - cpus=4, - memory_mb=2048, - ) - self.nic_info = [ - {'address': '22:22:22:22:22:22', 'datapath_id': '0x1', - 'port_no': 1}, - {'address': '33:33:33:33:33:33', 'datapath_id': '0x2', - 'port_no': 2}, - ] - - def _create_node(self): - self.node = db.bm_node_create(self.context, self.node_info) - for nic in self.nic_info: - db.bm_interface_create( - self.context, - self.node['id'], - nic['address'], - nic['datapath_id'], - nic['port_no'], - ) - self.instance['node'] = self.node['id'] - self.spawn_params = dict( - admin_password='test_pass', - block_device_info=self.test_block_device_info, - context=self.context, - image_meta=utils.get_test_image_info(None, - self.instance), - injected_files=[('/fake/path', 'hello world')], - instance=self.instance, - network_info=self.test_network_info, - ) - - -class TileraClassMethodsTestCase(BareMetalTileraTestCase): - - def test_build_network_config(self): - net = utils.get_test_network_info(1) - config = tilera.build_network_config(net) - self.assertIn('eth0', config) - self.assertNotIn('eth1', config) - - net = utils.get_test_network_info(2) - config = tilera.build_network_config(net) - self.assertIn('eth0', config) - self.assertIn('eth1', config) - - def test_build_network_config_dhcp(self): - self.flags( - net_config_template='$pybasedir/nova/virt/baremetal/' - 'net-dhcp.ubuntu.template', - group='baremetal', - ) - net = utils.get_test_network_info() - net[0]['network']['subnets'][0]['ips'][0]['address'] = '1.2.3.4' - config = tilera.build_network_config(net) - self.assertIn('iface eth0 inet dhcp', config) - self.assertNotIn('address 1.2.3.4', config) - - def test_build_network_config_static(self): - self.flags( - net_config_template='$pybasedir/nova/virt/baremetal/' - 'net-static.ubuntu.template', - group='baremetal', - ) - net = utils.get_test_network_info() - net[0]['network']['subnets'][0]['ips'][0]['address'] = '1.2.3.4' - config = tilera.build_network_config(net) - self.assertIn('iface eth0 inet static', config) - self.assertIn('address 1.2.3.4', config) - - def test_image_dir_path(self): - self.assertEqual( - tilera.get_image_dir_path(self.instance), - os.path.join(CONF.instances_path, 'instance-00000001')) - - def test_image_file_path(self): - self.assertEqual( - tilera.get_image_file_path(self.instance), - os.path.join( - CONF.instances_path, 'instance-00000001', 'disk')) - - def test_tilera_nfs_path(self): - self._create_node() - self.node['id'] = '123' - tilera_nfs_dir = "fs_" + self.node['id'] - self.assertEqual( - tilera.get_tilera_nfs_path(self.node['id']), - os.path.join(CONF.baremetal.tftp_root, - tilera_nfs_dir)) - - def test_get_partition_sizes(self): - # default "kinda.big" instance - sizes = tilera.get_partition_sizes(self.instance) - self.assertEqual(sizes[0], 40960) - self.assertEqual(sizes[1], 1024) - - def test_swap_not_zero(self): - # override swap to 0 - flavor = utils.get_test_flavor(self.context) - flavor['swap'] = 0 - self.instance = utils.get_test_instance(self.context, flavor) - - sizes = tilera.get_partition_sizes(self.instance) - self.assertEqual(sizes[0], 40960) - self.assertEqual(sizes[1], 1) - - def test_get_tftp_image_info(self): - # Tilera case needs only kernel_id. - self.instance['kernel_id'] = 'aaaa' - self.instance['uuid'] = 'fake-uuid' - - # Here, we confirm both that kernel_id was set - # and that the proper paths are getting set for all of them - base = os.path.join(CONF.baremetal.tftp_root, self.instance['uuid']) - res = tilera.get_tftp_image_info(self.instance) - expected = { - 'kernel': ['aaaa', os.path.join(base, 'kernel')], - } - self.assertEqual(res, expected) - - -class TileraPrivateMethodsTestCase(BareMetalTileraTestCase): - - def test_collect_mac_addresses(self): - self._create_node() - address_list = [nic['address'] for nic in self.nic_info] - address_list.sort() - macs = self.driver._collect_mac_addresses(self.context, self.node) - self.assertEqual(macs, address_list) - - def test_cache_tftp_images(self): - self.instance['kernel_id'] = 'aaaa' - image_info = tilera.get_tftp_image_info(self.instance) - - self.mox.StubOutWithMock(os, 'makedirs') - self.mox.StubOutWithMock(os.path, 'exists') - os.makedirs(os.path.join(CONF.baremetal.tftp_root, - self.instance['uuid'])).AndReturn(True) - for uuid, path in [image_info[label] for label in image_info]: - os.path.exists(path).AndReturn(True) - self.mox.ReplayAll() - - self.driver._cache_tftp_images( - self.context, self.instance, image_info) - self.mox.VerifyAll() - - def test_cache_image(self): - self.mox.StubOutWithMock(os, 'makedirs') - self.mox.StubOutWithMock(os, 'unlink') - self.mox.StubOutWithMock(os.path, 'exists') - os.makedirs(tilera.get_image_dir_path(self.instance)).AndReturn(True) - disk_path = os.path.join( - tilera.get_image_dir_path(self.instance), 'disk') - os.path.exists(disk_path).AndReturn(True) - os.unlink(disk_path).AndReturn(None) - os.path.exists(tilera.get_image_file_path(self.instance)).\ - AndReturn(True) - self.mox.ReplayAll() - - image_meta = utils.get_test_image_info( - self.context, self.instance) - self.driver._cache_image( - self.context, self.instance, image_meta) - self.mox.VerifyAll() - - def test_inject_into_image(self): - self._create_node() - files = [] - self.instance['hostname'] = 'fake hostname' - files.append(('/etc/hostname', 'fake hostname')) - self.instance['key_data'] = 'fake ssh key' - net_info = utils.get_test_network_info(1) - net = tilera.build_network_config(net_info) - admin_password = 'fake password' - - self.mox.StubOutWithMock(os.path, 'exists') - os.path.exists(mox.IgnoreArg()).AndReturn(True) - - self.mox.StubOutWithMock(disk_api, 'inject_data') - disk_api.inject_data( - admin_password=admin_password, - image=tilera.get_image_file_path(self.instance), - key='fake ssh key', - metadata=None, - partition=None, - net=net, - files=files, - ).AndReturn(True) - self.mox.ReplayAll() - - self.driver._inject_into_image( - self.context, self.node, self.instance, - network_info=net_info, - admin_password=admin_password, - injected_files=None) - self.mox.VerifyAll() - - -class TileraPublicMethodsTestCase(BareMetalTileraTestCase): - - def test_cache_images(self): - self._create_node() - self.mox.StubOutWithMock(tilera, "get_tftp_image_info") - self.mox.StubOutWithMock(self.driver, "_cache_tftp_images") - self.mox.StubOutWithMock(self.driver, "_cache_image") - self.mox.StubOutWithMock(self.driver, "_inject_into_image") - - tilera.get_tftp_image_info(self.instance).AndReturn([]) - self.driver._cache_tftp_images(self.context, self.instance, []) - self.driver._cache_image(self.context, self.instance, []) - self.driver._inject_into_image(self.context, self.node, self.instance, - self.test_network_info, None, '') - self.mox.ReplayAll() - - self.driver.cache_images( - self.context, self.node, self.instance, - admin_password='', - image_meta=[], - injected_files=None, - network_info=self.test_network_info, - ) - self.mox.VerifyAll() - - def test_destroy_images(self): - self._create_node() - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - self.mox.StubOutWithMock(bm_utils, 'rmtree_without_raise') - - bm_utils.unlink_without_raise(tilera.get_image_file_path( - self.instance)) - bm_utils.rmtree_without_raise(tilera.get_image_dir_path(self.instance)) - self.mox.ReplayAll() - - self.driver.destroy_images(self.context, self.node, self.instance) - self.mox.VerifyAll() - - def test_activate_bootloader_passes_details(self): - self._create_node() - image_info = { - 'kernel': [None, 'cccc'], - } - self.instance['uuid'] = 'fake-uuid' - tilera.get_tilera_nfs_path(self.instance) - tilera.get_image_file_path(self.instance) - - self.mox.StubOutWithMock(tilera, 'get_tftp_image_info') - self.mox.StubOutWithMock(tilera, 'get_partition_sizes') - - tilera.get_tftp_image_info(self.instance).AndReturn(image_info) - tilera.get_partition_sizes(self.instance).AndReturn((0, 0)) - - self.mox.ReplayAll() - - self.driver.activate_bootloader(self.context, self.node, self.instance, - network_info=self.test_network_info) - - self.mox.VerifyAll() - - def test_activate_and_deactivate_bootloader(self): - self._create_node() - self.instance['uuid'] = 'fake-uuid' - tilera.get_tilera_nfs_path(self.instance) - tilera.get_image_file_path(self.instance) - - self.mox.ReplayAll() - - # activate and deactivate the bootloader - # and check the deployment task_state in the database - row = db.bm_node_get(self.context, 1) - self.assertIsNone(row['deploy_key']) - - self.driver.activate_bootloader(self.context, self.node, self.instance, - network_info=self.test_network_info) - row = db.bm_node_get(self.context, 1) - self.assertIsNotNone(row['deploy_key']) - - self.driver.deactivate_bootloader(self.context, self.node, - self.instance) - row = db.bm_node_get(self.context, 1) - self.assertIsNone(row['deploy_key']) - - self.mox.VerifyAll() - - def test_deactivate_bootloader_for_nonexistent_instance(self): - self._create_node() - self.node['id'] = 'fake-node-id' - - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - self.mox.StubOutWithMock(bm_utils, 'rmtree_without_raise') - self.mox.StubOutWithMock(tilera, 'get_tftp_image_info') - self.mox.StubOutWithMock(self.driver, '_collect_mac_addresses') - - tilera.get_tilera_nfs_path(self.node['id']) - - tilera.get_tftp_image_info(self.instance).\ - AndRaise(exception.NovaException) - self.driver._collect_mac_addresses(self.context, self.node).\ - AndRaise(db_exc.DBError) - self.mox.ReplayAll() - - self.driver.deactivate_bootloader( - self.context, self.node, self.instance) - self.mox.VerifyAll() - - def test_activate_node(self): - self._create_node() - self.instance['uuid'] = 'fake-uuid' - - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.DEPLOYING, - 'instance_uuid': 'fake-uuid'}) - - # test DEPLOYDONE - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.DEPLOYDONE}) - self.driver.activate_node(self.context, self.node, self.instance) - - # test no deploy -- state is just ACTIVE - db.bm_node_update(self.context, 1, - {'task_state': baremetal_states.ACTIVE}) - self.driver.activate_node(self.context, self.node, self.instance) - - # test node gone - db.bm_node_destroy(self.context, 1) - self.assertRaises(exception.InstanceDeployFailure, - self.driver.activate_node, - self.context, self.node, self.instance) diff --git a/nova/tests/virt/baremetal/test_tilera_pdu.py b/nova/tests/virt/baremetal/test_tilera_pdu.py deleted file mode 100644 index 62ffd0ec68..0000000000 --- a/nova/tests/virt/baremetal/test_tilera_pdu.py +++ /dev/null @@ -1,141 +0,0 @@ -# coding=utf-8 - -# Copyright (c) 2011-2013 University of Southern California / ISI -# 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. - -"""Test class for baremetal PDU power manager.""" - -from oslo.config import cfg - -from nova import test -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import tilera_pdu -from nova.virt.baremetal import utils as bm_utils - -CONF = cfg.CONF - - -class BareMetalPduTestCase(test.NoDBTestCase): - - def setUp(self): - super(BareMetalPduTestCase, self).setUp() - self.flags(tile_power_wait=0, group='baremetal') - self.node = bm_db_utils.new_bm_node( - id=123, - pm_address='fake-address', - pm_user='fake-user', - pm_password='fake-password') - self.tilera_pdu = tilera_pdu.Pdu(self.node) - self.tile_pdu_on = 1 - self.tile_pdu_off = 2 - self.tile_pdu_status = 9 - - def test_construct(self): - self.assertEqual(self.tilera_pdu.node_id, 123) - self.assertEqual(self.tilera_pdu.address, 'fake-address') - self.assertEqual(self.tilera_pdu.user, 'fake-user') - self.assertEqual(self.tilera_pdu.password, 'fake-password') - - def test_exec_pdutool(self): - self.flags(tile_pdu_mgr='fake-pdu-mgr', group='baremetal') - self.flags(tile_pdu_ip='fake-address', group='baremetal') - self.mox.StubOutWithMock(utils, 'execute') - self.mox.StubOutWithMock(bm_utils, 'unlink_without_raise') - args = [ - 'fake-pdu-mgr', - 'fake-address', - self.tile_pdu_on, - ] - utils.execute(*args).AndReturn('') - self.mox.ReplayAll() - - self.tilera_pdu._exec_pdutool(self.tile_pdu_on) - self.mox.VerifyAll() - - def test_is_power(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_on) - self.mox.ReplayAll() - - self.tilera_pdu._is_power(self.tile_pdu_on) - self.mox.VerifyAll() - - def test_power_already_on(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - - self.tilera_pdu._exec_pdutool(self.tile_pdu_on).AndReturn(None) - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_on) - self.mox.ReplayAll() - - self.tilera_pdu.state = baremetal_states.DELETED - self.tilera_pdu._power_on() - self.mox.VerifyAll() - self.assertEqual(self.tilera_pdu.state, baremetal_states.ACTIVE) - - def test_power_on_ok(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - - self.tilera_pdu._exec_pdutool(self.tile_pdu_on).AndReturn(None) - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_on) - self.mox.ReplayAll() - - self.tilera_pdu.state = baremetal_states.DELETED - self.tilera_pdu._power_on() - self.mox.VerifyAll() - self.assertEqual(self.tilera_pdu.state, baremetal_states.ACTIVE) - - def test_power_on_fail(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - - self.tilera_pdu._exec_pdutool(self.tile_pdu_on).AndReturn(None) - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_off) - self.mox.ReplayAll() - - self.tilera_pdu.state = baremetal_states.DELETED - self.tilera_pdu._power_on() - self.mox.VerifyAll() - self.assertEqual(self.tilera_pdu.state, baremetal_states.ERROR) - - def test_power_on_max_retries(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - - self.tilera_pdu._exec_pdutool(self.tile_pdu_on).AndReturn(None) - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_off) - self.mox.ReplayAll() - - self.tilera_pdu.state = baremetal_states.DELETED - self.tilera_pdu._power_on() - self.mox.VerifyAll() - self.assertEqual(self.tilera_pdu.state, baremetal_states.ERROR) - - def test_power_off_ok(self): - self.mox.StubOutWithMock(self.tilera_pdu, '_exec_pdutool') - - self.tilera_pdu._exec_pdutool(self.tile_pdu_off).AndReturn(None) - self.tilera_pdu._exec_pdutool(self.tile_pdu_status).AndReturn( - self.tile_pdu_off) - self.mox.ReplayAll() - - self.tilera_pdu.state = baremetal_states.ACTIVE - self.tilera_pdu._power_off() - self.mox.VerifyAll() - self.assertEqual(self.tilera_pdu.state, baremetal_states.DELETED) diff --git a/nova/tests/virt/baremetal/test_utils.py b/nova/tests/virt/baremetal/test_utils.py deleted file mode 100644 index 81b96e360b..0000000000 --- a/nova/tests/virt/baremetal/test_utils.py +++ /dev/null @@ -1,77 +0,0 @@ -# coding=utf-8 - -# Copyright 2012,2014 Hewlett-Packard Development Company, L.P. -# 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. - -"""Tests for baremetal utils.""" - -import errno -import os -import tempfile - -from nova import test -from nova.virt.baremetal import utils -from nova.virt import images - - -class BareMetalUtilsTestCase(test.NoDBTestCase): - - def test_random_alnum(self): - s = utils.random_alnum(10) - self.assertEqual(len(s), 10) - s = utils.random_alnum(100) - self.assertEqual(len(s), 100) - - def test_unlink(self): - self.mox.StubOutWithMock(os, "unlink") - os.unlink("/fake/path") - - self.mox.ReplayAll() - utils.unlink_without_raise("/fake/path") - self.mox.VerifyAll() - - def test_unlink_ENOENT(self): - self.mox.StubOutWithMock(os, "unlink") - os.unlink("/fake/path").AndRaise(OSError(errno.ENOENT)) - - self.mox.ReplayAll() - utils.unlink_without_raise("/fake/path") - self.mox.VerifyAll() - - def test_create_link(self): - self.mox.StubOutWithMock(os, "symlink") - os.symlink("/fake/source", "/fake/link") - - self.mox.ReplayAll() - utils.create_link_without_raise("/fake/source", "/fake/link") - self.mox.VerifyAll() - - def test_create_link_EEXIST(self): - self.mox.StubOutWithMock(os, "symlink") - os.symlink("/fake/source", "/fake/link").AndRaise( - OSError(errno.EEXIST)) - - self.mox.ReplayAll() - utils.create_link_without_raise("/fake/source", "/fake/link") - self.mox.VerifyAll() - - def test_cache_image_with_clean(self): - self.mox.StubOutWithMock(images, "fetch_to_raw") - temp_f, temp_file = tempfile.mkstemp() - images.fetch_to_raw(None, None, temp_file, None, None) - self.mox.ReplayAll() - utils.cache_image(None, temp_file, None, None, None, clean=True) - self.mox.VerifyAll() - self.assertFalse(os.path.exists(temp_file)) diff --git a/nova/tests/virt/baremetal/test_virtual_power_driver.py b/nova/tests/virt/baremetal/test_virtual_power_driver.py deleted file mode 100644 index d51239d431..0000000000 --- a/nova/tests/virt/baremetal/test_virtual_power_driver.py +++ /dev/null @@ -1,392 +0,0 @@ -# coding=utf-8 - -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# 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. - -"""Tests for baremetal virtual power driver.""" - -import mox -from oslo.config import cfg - -from nova import exception -from nova.openstack.common import processutils -from nova.tests.image import fake as fake_image -from nova.tests import utils -from nova.tests.virt.baremetal.db import base as bm_db_base -from nova.tests.virt.baremetal.db import utils as bm_db_utils -from nova.virt.baremetal import common as connection -from nova.virt.baremetal import db -from nova.virt.baremetal import virtual_power_driver - -CONF = cfg.CONF - -COMMON_FLAGS = dict( - firewall_driver='nova.virt.baremetal.fake.FakeFirewallDriver', - host='test_host', -) - -BAREMETAL_FLAGS = dict( - driver='nova.virt.baremetal.pxe.PXE', - flavor_extra_specs=['cpu_arch:test', 'test_spec:test_value'], - power_manager= - 'nova.virt.baremetal.virtual_power_driver.VirtualPowerManager', - vif_driver='nova.virt.baremetal.fake.FakeVifDriver', - volume_driver='nova.virt.baremetal.fake.FakeVolumeDriver', - virtual_power_ssh_host=None, - virtual_power_type='vbox', - virtual_power_host_user=None, - virtual_power_host_pass=None, - virtual_power_host_key=None, - group='baremetal', -) - - -class BareMetalVPDTestCase(bm_db_base.BMDBTestCase): - - def setUp(self): - super(BareMetalVPDTestCase, self).setUp() - self.flags(**COMMON_FLAGS) - self.flags(**BAREMETAL_FLAGS) - - fake_image.stub_out_image_service(self.stubs) - self.context = utils.get_test_admin_context() - self.test_block_device_info = None, - self.instance = utils.get_test_instance() - self.test_network_info = utils.get_test_network_info(), - self.node_info = bm_db_utils.new_bm_node( - id=123, - service_host='test_host', - cpus=2, - memory_mb=2048, - ) - self.nic_info = [ - {'address': '11:11:11:11:11:11', 'datapath_id': '0x1', - 'port_no': 1}, - {'address': '22:22:22:22:22:22', 'datapath_id': '0x2', - 'port_no': 2}, - ] - self.addCleanup(fake_image.FakeImageService_reset) - - def _create_node(self): - self.node = db.bm_node_create(self.context, self.node_info) - for nic in self.nic_info: - db.bm_interface_create( - self.context, - self.node['id'], - nic['address'], - nic['datapath_id'], - nic['port_no'], - ) - self.instance['node'] = self.node['id'] - - def _create_pm(self): - self.pm = virtual_power_driver.VirtualPowerManager( - node=self.node, - instance=self.instance) - return self.pm - - -class VPDMissingOptionsTestCase(BareMetalVPDTestCase): - - def test_get_conn_missing_options(self): - self.flags(virtual_power_ssh_host=None, group="baremetal") - self.flags(virtual_power_host_user=None, group="baremetal") - self.flags(virtual_power_host_pass=None, group="baremetal") - self._create_node() - self._create_pm() - self._conn = None - self.assertRaises(exception.NovaException, - self.pm._get_conn) - self._conn = None - self.flags(virtual_power_ssh_host='127.0.0.1', group="baremetal") - self.assertRaises(exception.NovaException, - self.pm._get_conn) - self._conn = None - self.flags(virtual_power_host_user='user', group="baremetal") - self.assertRaises(exception.NovaException, - self.pm._get_conn) - - -class VPDClassMethodsTestCase(BareMetalVPDTestCase): - - def setUp(self): - super(VPDClassMethodsTestCase, self).setUp() - self.flags(virtual_power_ssh_host='127.0.0.1', group="baremetal") - self.flags(virtual_power_host_user='user', group="baremetal") - self.flags(virtual_power_host_pass='password', group="baremetal") - - def test_get_conn_success_pass(self): - self._create_node() - self._create_pm() - self._conn = self.pm._get_conn() - self.mox.StubOutWithMock(connection, 'ssh_connect') - connection.ssh_connect(mox.IsA(self._conn)).AndReturn(True) - self.mox.ReplayAll() - self.pm._set_connection() - self.assertEqual(self.pm.connection_data.host, '127.0.0.1') - self.assertEqual(self.pm.connection_data.username, 'user') - self.assertEqual(self.pm.connection_data.password, 'password') - self.assertIsNone(self.pm.connection_data.keyfile) - self.mox.VerifyAll() - - def test_get_conn_success_key(self): - self.flags(virtual_power_host_pass='', group="baremetal") - self.flags(virtual_power_host_key='/id_rsa_file.txt', - group="baremetal") - self._create_node() - self._create_pm() - self._conn = self.pm._get_conn() - self.mox.StubOutWithMock(connection, 'ssh_connect') - connection.ssh_connect(mox.IsA(self._conn)).AndReturn(True) - self.mox.ReplayAll() - self.pm._set_connection() - self.assertEqual(self.pm.connection_data.host, '127.0.0.1') - self.assertEqual(self.pm.connection_data.username, 'user') - self.assertEqual(self.pm.connection_data.password, '') - self.assertEqual(self.pm.connection_data.keyfile, '/id_rsa_file.txt') - self.mox.VerifyAll() - - def test_get_full_node_list(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_run_command') - cmd = self.pm._vp_cmd.list_cmd - self.pm._run_command(cmd).AndReturn("testNode") - - self.mox.ReplayAll() - name = self.pm._get_full_node_list() - self.assertEqual(name, 'testNode') - self.mox.VerifyAll() - - def test_check_for_node(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_get_full_node_list') - self.pm._get_full_node_list().\ - AndReturn(["testNode"]) - - self.mox.StubOutWithMock(self.pm, '_run_command') - cmd = self.pm._vp_cmd.get_node_macs.replace('{_NodeName_}', 'testNode') - self.pm._run_command(cmd).\ - AndReturn(["111111111111", "ffeeddccbbaa"]) - - self.mox.ReplayAll() - name = self.pm._check_for_node() - self.assertEqual(name, '"testNode"') - self.mox.VerifyAll() - - def test_check_for_node_not_found(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_get_full_node_list') - self.pm._get_full_node_list().AndReturn(["testNode"]) - - self.mox.StubOutWithMock(self.pm, '_run_command') - cmd = self.pm._vp_cmd.get_node_macs.replace('{_NodeName_}', 'testNode') - self.pm._run_command(cmd).AndReturn(["ffeeddccbbaa"]) - - self.mox.ReplayAll() - name = self.pm._check_for_node() - self.assertEqual(name, '') - self.mox.VerifyAll() - - def test_activate_node(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn('"testNode"') - self.pm._run_command(self.pm._vp_cmd.start_cmd).AndReturn("Started") - self.pm.is_power_on().AndReturn(True) - self.mox.ReplayAll() - state = self.pm.activate_node() - self.assertEqual(state, 'active') - self.mox.VerifyAll() - - def test_activate_node_fail(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn('"testNode"') - self.pm._run_command(self.pm._vp_cmd.start_cmd).AndReturn("Started") - self.pm.is_power_on().AndReturn(False) - self.mox.ReplayAll() - state = self.pm.activate_node() - self.assertEqual(state, 'error') - self.mox.VerifyAll() - - def test_deactivate_node(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn('"testNode"') - self.pm.is_power_on().AndReturn(True) - self.pm._run_command(self.pm._vp_cmd.stop_cmd).AndReturn("Stopped") - self.pm.is_power_on().AndReturn(False) - self.mox.ReplayAll() - state = self.pm.deactivate_node() - self.assertEqual(state, 'deleted') - self.mox.VerifyAll() - - def test_deactivate_node_fail(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn('"testNode"') - self.pm.is_power_on().AndReturn(True) - self.pm._run_command(self.pm._vp_cmd.stop_cmd).AndReturn("Stopped") - self.pm.is_power_on().AndReturn(True) - self.mox.ReplayAll() - state = self.pm.deactivate_node() - self.assertEqual(state, 'error') - self.mox.VerifyAll() - - def test_reboot_node(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn(['"testNode"']) - self.pm._run_command(self.pm._vp_cmd.reboot_cmd).AndReturn("Restarted") - self.pm.is_power_on().AndReturn(True) - self.mox.ReplayAll() - state = self.pm.reboot_node() - self.assertEqual(state, 'active') - self.mox.VerifyAll() - - def test_reboot_node_fail(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.mox.StubOutWithMock(self.pm, 'is_power_on') - self.pm._check_for_node().AndReturn(['"testNode"']) - self.pm._run_command(self.pm._vp_cmd.reboot_cmd).AndReturn("Restarted") - self.pm.is_power_on().AndReturn(False) - self.mox.ReplayAll() - state = self.pm.reboot_node() - self.assertEqual(state, 'error') - self.mox.VerifyAll() - - def test_is_power_on(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.pm._check_for_node().AndReturn(['"testNode"']) - self.pm._run_command(self.pm._vp_cmd.list_running_cmd).\ - AndReturn(['"testNode"']) - self.pm._matched_name = 'testNode' - self.mox.ReplayAll() - state = self.pm.is_power_on() - self.assertEqual(state, True) - self.mox.VerifyAll() - - def test_is_power_on_fail(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.pm._check_for_node().AndReturn(None) - self.mox.ReplayAll() - self.assertRaises(exception.NodeNotFound, self.pm.is_power_on) - self.mox.VerifyAll() - - def test_is_power_on_match_subname(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(self.pm, '_run_command') - self.pm._check_for_node().AndReturn(['"testNode"']) - self.pm._run_command(self.pm._vp_cmd.list_running_cmd).\ - AndReturn(['"testNode01"']) - self.pm._matched_name = '"testNode"' - self.mox.ReplayAll() - state = self.pm.is_power_on() - self.assertEqual(state, False) - self.mox.VerifyAll() - - def test_run_command(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_set_connection') - self.mox.StubOutWithMock(processutils, 'ssh_execute') - self.pm._set_connection().AndReturn(True) - processutils.ssh_execute(None, '/usr/bin/VBoxManage test return', - check_exit_code=True).AndReturn(("test\nreturn", "")) - self.pm._matched_name = 'testNode' - self.mox.ReplayAll() - result = self.pm._run_command("test return") - self.assertEqual(result, ['test', 'return']) - self.mox.VerifyAll() - - def test_run_command_raises_exception(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_set_connection') - self.mox.StubOutWithMock(processutils, 'ssh_execute') - - self.pm._set_connection().AndReturn(True) - processutils.ssh_execute(None, '/usr/bin/VBoxManage test return', - check_exit_code=True).\ - AndRaise(processutils.ProcessExecutionError) - self.mox.ReplayAll() - - result = self.pm._run_command("test return") - self.assertEqual(result, []) - self.mox.VerifyAll() - - def test_activate_node_with_exception(self): - self._create_node() - self._create_pm() - - self.mox.StubOutWithMock(self.pm, '_check_for_node') - self.mox.StubOutWithMock(processutils, 'ssh_execute') - - self.pm._check_for_node().AndReturn(['"testNode"']) - self.pm._check_for_node().AndReturn(['"testNode"']) - processutils.ssh_execute('test', '/usr/bin/VBoxManage startvm ', - check_exit_code=True).\ - AndRaise(processutils.ProcessExecutionError) - processutils.ssh_execute('test', '/usr/bin/VBoxManage list runningvms', - check_exit_code=True).\ - AndRaise(processutils.ProcessExecutionError) - - self.mox.ReplayAll() - self.pm._connection = 'test' - state = self.pm.activate_node() - self.assertEqual(state, 'error') - self.mox.VerifyAll() diff --git a/nova/tests/virt/baremetal/test_volume_driver.py b/nova/tests/virt/baremetal/test_volume_driver.py deleted file mode 100644 index 8ea358804b..0000000000 --- a/nova/tests/virt/baremetal/test_volume_driver.py +++ /dev/null @@ -1,294 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -"""Tests for baremetal volume driver.""" - -from oslo.config import cfg - -from nova import exception -from nova import test -from nova.virt.baremetal import volume_driver -from nova.virt import fake -from nova.virt.libvirt import volume as libvirt_volume - -CONF = cfg.CONF - -SHOW_OUTPUT = """Target 1: iqn.2010-10.org.openstack:volume-00000001 - System information: - Driver: iscsi - State: ready - I_T nexus information: - I_T nexus: 8 - Initiator: iqn.1993-08.org.debian:01:7780c6a16b4 - Connection: 0 - IP Address: 172.17.12.10 - LUN information: - LUN: 0 - Type: controller - SCSI ID: IET 00010000 - SCSI SN: beaf10 - Size: 0 MB, Block size: 1 - Online: Yes - Removable media: No - Readonly: No - Backing store type: null - Backing store path: None - Backing store flags: - LUN: 1 - Type: disk - SCSI ID: IET 00010001 - SCSI SN: beaf11 - Size: 1074 MB, Block size: 512 - Online: Yes - Removable media: No - Readonly: No - Backing store type: rdwr - Backing store path: /dev/nova-volumes/volume-00000001 - Backing store flags: - Account information: - ACL information: - ALL -Target 2: iqn.2010-10.org.openstack:volume-00000002 - System information: - Driver: iscsi - State: ready - I_T nexus information: - LUN information: - LUN: 0 - Type: controller - SCSI ID: IET 00020000 - SCSI SN: beaf20 - Size: 0 MB, Block size: 1 - Online: Yes - Removable media: No - Readonly: No - Backing store type: null - Backing store path: None - Backing store flags: - LUN: 1 - Type: disk - SCSI ID: IET 00020001 - SCSI SN: beaf21 - Size: 2147 MB, Block size: 512 - Online: Yes - Removable media: No - Readonly: No - Backing store type: rdwr - Backing store path: /dev/nova-volumes/volume-00000002 - Backing store flags: - Account information: - ACL information: - ALL -Target 1000001: iqn.2010-10.org.openstack.baremetal:1000001-dev.vdc - System information: - Driver: iscsi - State: ready - I_T nexus information: - LUN information: - LUN: 0 - Type: controller - SCSI ID: IET f42410000 - SCSI SN: beaf10000010 - Size: 0 MB, Block size: 1 - Online: Yes - Removable media: No - Readonly: No - Backing store type: null - Backing store path: None - Backing store flags: - LUN: 1 - Type: disk - SCSI ID: IET f42410001 - SCSI SN: beaf10000011 - Size: 1074 MB, Block size: 512 - Online: Yes - Removable media: No - Readonly: No - Backing store type: rdwr - Backing store path: /dev/disk/by-path/ip-172.17.12.10:3260-iscsi-\ -iqn.2010-10.org.openstack:volume-00000001-lun-1 - Backing store flags: - Account information: - ACL information: - ALL -""" - - -def fake_show_tgtadm(): - return SHOW_OUTPUT - - -class BareMetalVolumeTestCase(test.NoDBTestCase): - - def setUp(self): - super(BareMetalVolumeTestCase, self).setUp() - self.stubs.Set(volume_driver, '_show_tgtadm', fake_show_tgtadm) - - def test_list_backingstore_path(self): - l = volume_driver._list_backingstore_path() - self.assertEqual(len(l), 3) - self.assertIn('/dev/nova-volumes/volume-00000001', l) - self.assertIn('/dev/nova-volumes/volume-00000002', l) - self.assertIn('/dev/disk/by-path/ip-172.17.12.10:3260-iscsi-' - 'iqn.2010-10.org.openstack:volume-00000001-lun-1', l) - - def test_get_next_tid(self): - tid = volume_driver._get_next_tid() - self.assertEqual(1000002, tid) - - def test_find_tid_found(self): - tid = volume_driver._find_tid( - 'iqn.2010-10.org.openstack.baremetal:1000001-dev.vdc') - self.assertEqual(1000001, tid) - - def test_find_tid_not_found(self): - tid = volume_driver._find_tid( - 'iqn.2010-10.org.openstack.baremetal:1000002-dev.vdc') - self.assertIsNone(tid) - - def test_get_iqn(self): - self.flags(iscsi_iqn_prefix='iqn.2012-12.a.b', group='baremetal') - iqn = volume_driver._get_iqn('instname', '/dev/vdx') - self.assertEqual('iqn.2012-12.a.b:instname-dev-vdx', iqn) - - -class FakeConf(object): - def __init__(self, source_path): - self.source_path = source_path - - -class BareMetalLibVirtVolumeDriverTestCase(test.TestCase): - - def setUp(self): - super(BareMetalLibVirtVolumeDriverTestCase, self).setUp() - self.flags(volume_drivers=[ - 'fake=nova.virt.libvirt.volume.LibvirtFakeVolumeDriver', - 'fake2=nova.virt.libvirt.volume.LibvirtFakeVolumeDriver', - ], group='libvirt') - self.driver = volume_driver.LibvirtVolumeDriver(fake.FakeVirtAPI()) - self.disk_info = { - 'dev': 'vdc', - 'bus': 'baremetal', - 'type': 'baremetal', - } - self.connection_info = {'driver_volume_type': 'fake'} - self.mount_point = '/dev/vdc' - self.mount_device = 'vdc' - self.source_path = '/dev/sdx' - self.instance = {'uuid': '12345678-1234-1234-1234-123467890123456', - 'name': 'instance-00000001'} - self.fixed_ips = [{'address': '10.2.3.4'}, - {'address': '172.16.17.18'}, - ] - self.iqn = 'iqn.fake:instance-00000001-dev-vdc' - self.tid = 100 - - def test_init_loads_volume_drivers(self): - self.assertIsInstance(self.driver.volume_drivers['fake'], - libvirt_volume.LibvirtFakeVolumeDriver) - self.assertIsInstance(self.driver.volume_drivers['fake2'], - libvirt_volume.LibvirtFakeVolumeDriver) - self.assertEqual(len(self.driver.volume_drivers), 2) - - def test_fake_connect_volume(self): - """Check connect_volume returns without exceptions.""" - self.driver._connect_volume(self.connection_info, - self.disk_info) - - def test_volume_driver_method_ok(self): - fake_driver = self.driver.volume_drivers['fake'] - self.mox.StubOutWithMock(fake_driver, 'connect_volume') - fake_driver.connect_volume(self.connection_info, self.disk_info) - self.mox.ReplayAll() - self.driver._connect_volume(self.connection_info, - self.disk_info) - - def test_volume_driver_method_driver_type_not_found(self): - self.connection_info['driver_volume_type'] = 'qwerty' - self.assertRaises(exception.VolumeDriverNotFound, - self.driver._connect_volume, - self.connection_info, - self.disk_info) - - def test_publish_iscsi(self): - self.mox.StubOutWithMock(volume_driver, '_get_iqn') - self.mox.StubOutWithMock(volume_driver, '_get_next_tid') - self.mox.StubOutWithMock(volume_driver, '_create_iscsi_export_tgtadm') - self.mox.StubOutWithMock(volume_driver, '_allow_iscsi_tgtadm') - volume_driver._get_iqn(self.instance['name'], self.mount_point).\ - AndReturn(self.iqn) - volume_driver._get_next_tid().AndReturn(self.tid) - volume_driver._create_iscsi_export_tgtadm(self.source_path, - self.tid, - self.iqn) - volume_driver._allow_iscsi_tgtadm(self.tid, - self.fixed_ips[0]['address']) - volume_driver._allow_iscsi_tgtadm(self.tid, - self.fixed_ips[1]['address']) - self.mox.ReplayAll() - self.driver._publish_iscsi(self.instance, - self.mount_point, - self.fixed_ips, - self.source_path) - - def test_depublish_iscsi_ok(self): - self.mox.StubOutWithMock(volume_driver, '_get_iqn') - self.mox.StubOutWithMock(volume_driver, '_find_tid') - self.mox.StubOutWithMock(volume_driver, '_delete_iscsi_export_tgtadm') - volume_driver._get_iqn(self.instance['name'], self.mount_point).\ - AndReturn(self.iqn) - volume_driver._find_tid(self.iqn).AndReturn(self.tid) - volume_driver._delete_iscsi_export_tgtadm(self.tid) - self.mox.ReplayAll() - self.driver._depublish_iscsi(self.instance, self.mount_point) - - def test_depublish_iscsi_do_nothing_if_tid_is_not_found(self): - self.mox.StubOutWithMock(volume_driver, '_get_iqn') - self.mox.StubOutWithMock(volume_driver, '_find_tid') - volume_driver._get_iqn(self.instance['name'], self.mount_point).\ - AndReturn(self.iqn) - volume_driver._find_tid(self.iqn).AndReturn(None) - self.mox.ReplayAll() - self.driver._depublish_iscsi(self.instance, self.mount_point) - - def test_attach_volume(self): - self.mox.StubOutWithMock(volume_driver, '_get_fixed_ips') - self.mox.StubOutWithMock(self.driver, '_connect_volume') - self.mox.StubOutWithMock(self.driver, '_publish_iscsi') - volume_driver._get_fixed_ips(self.instance).AndReturn(self.fixed_ips) - self.driver._connect_volume(self.connection_info, self.disk_info).\ - AndReturn(FakeConf(self.source_path)) - self.driver._publish_iscsi(self.instance, self.mount_point, - self.fixed_ips, self.source_path) - self.mox.ReplayAll() - self.driver.attach_volume(self.connection_info, - self.instance, - self.mount_point) - - def test_detach_volume(self): - self.mox.StubOutWithMock(volume_driver, '_get_iqn') - self.mox.StubOutWithMock(volume_driver, '_find_tid') - self.mox.StubOutWithMock(volume_driver, '_delete_iscsi_export_tgtadm') - self.mox.StubOutWithMock(self.driver, '_disconnect_volume') - volume_driver._get_iqn(self.instance['name'], self.mount_point).\ - AndReturn(self.iqn) - volume_driver._find_tid(self.iqn).AndReturn(self.tid) - volume_driver._delete_iscsi_export_tgtadm(self.tid) - self.driver._disconnect_volume(self.connection_info, - self.mount_device) - self.mox.ReplayAll() - self.driver.detach_volume(self.connection_info, - self.instance, - self.mount_point) diff --git a/nova/virt/baremetal/__init__.py b/nova/virt/baremetal/__init__.py deleted file mode 100644 index 9c8318660f..0000000000 --- a/nova/virt/baremetal/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. -from nova.virt.baremetal import driver - -BareMetalDriver = driver.BareMetalDriver diff --git a/nova/virt/baremetal/baremetal_states.py b/nova/virt/baremetal/baremetal_states.py deleted file mode 100644 index 82e41fb3ce..0000000000 --- a/nova/virt/baremetal/baremetal_states.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright 2010 OpenStack Foundation -# 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. - -""" -Possible baremetal node states for instances. - -Compute instance baremetal states represent the state of an instance as it -pertains to a user or administrator. When combined with task states -(task_states.py), a better picture can be formed regarding the instance's -health. - -""" - -ACTIVE = 'active' -BUILDING = 'building' -DEPLOYING = 'deploying' -DEPLOYFAIL = 'deploy failed' -DEPLOYDONE = 'deploy complete' -DELETED = 'deleted' -ERROR = 'error' -PREPARED = 'prepared' diff --git a/nova/virt/baremetal/base.py b/nova/virt/baremetal/base.py deleted file mode 100644 index 9553260287..0000000000 --- a/nova/virt/baremetal/base.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright (c) 2011 University of Southern California / ISI -# 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. - -from nova.virt.baremetal import baremetal_states - - -class NodeDriver(object): - - def __init__(self, virtapi): - self.virtapi = virtapi - - def cache_images(self, context, node, instance, **kwargs): - raise NotImplementedError() - - def destroy_images(self, context, node, instance): - raise NotImplementedError() - - def activate_bootloader(self, context, node, instance, **kwargs): - raise NotImplementedError() - - def deactivate_bootloader(self, context, node, instance): - raise NotImplementedError() - - def activate_node(self, context, node, instance): - """For operations after power on.""" - raise NotImplementedError() - - def deactivate_node(self, context, node, instance): - """For operations before power off.""" - raise NotImplementedError() - - def get_console_output(self, node, instance): - raise NotImplementedError() - - def dhcp_options_for_instance(self, instance): - """Optional override to return the DHCP options to use for instance. - - If no DHCP options are needed, this should not be overridden or None - should be returned. - """ - return None - - -class PowerManager(object): - - def __init__(self, **kwargs): - self.state = baremetal_states.DELETED - pass - - def activate_node(self): - self.state = baremetal_states.ACTIVE - return self.state - - def reboot_node(self): - self.state = baremetal_states.ACTIVE - return self.state - - def deactivate_node(self): - self.state = baremetal_states.DELETED - return self.state - - def is_power_on(self): - """Returns True or False according as the node's power state.""" - return True - - # TODO(NTTdocomo): split out console methods to its own class - def start_console(self): - pass - - def stop_console(self): - pass diff --git a/nova/virt/baremetal/common.py b/nova/virt/baremetal/common.py deleted file mode 100644 index 94165007e6..0000000000 --- a/nova/virt/baremetal/common.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 paramiko - -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - -CONNECTION_TIMEOUT = 60 - - -class ConnectionFailed(exception.NovaException): - msg_fmt = _('Connection failed') - - -class Connection(object): - - def __init__(self, host, username, password, port=22, keyfile=None): - self.host = host - self.username = username - self.password = password - self.port = port - self.keyfile = keyfile - - -def ssh_connect(connection): - """Method to connect to remote system using ssh protocol. - - :param connection: a Connection object. - :returns: paramiko.SSHClient -- an active ssh connection. - :raises: ConnectionFailed - """ - try: - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect(connection.host, - username=connection.username, - password=connection.password, - port=connection.port, - key_filename=connection.keyfile, - timeout=CONNECTION_TIMEOUT) - - LOG.debug("SSH connection with %s established successfully." % - connection.host) - - # send TCP keepalive packets every 20 seconds - ssh.get_transport().set_keepalive(20) - - return ssh - except Exception: - LOG.exception(_('Connection error')) - raise ConnectionFailed() diff --git a/nova/virt/baremetal/db/__init__.py b/nova/virt/baremetal/db/__init__.py deleted file mode 100644 index 038ec445d3..0000000000 --- a/nova/virt/baremetal/db/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -from nova.virt.baremetal.db.api import * # noqa diff --git a/nova/virt/baremetal/db/api.py b/nova/virt/baremetal/db/api.py deleted file mode 100644 index e7592c1ea0..0000000000 --- a/nova/virt/baremetal/db/api.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -"""Defines interface for DB access. - -The underlying driver is loaded as a :class:`LazyPluggable`. - -Functions in this module are imported into the nova.virt.baremetal.db -namespace. Call these functions from nova.virt.baremetal.db namespace, not -the nova.virt.baremetal.db.api namespace. - -All functions in this module return objects that implement a dictionary-like -interface. Currently, many of these objects are sqlalchemy objects that -implement a dictionary interface. However, a future goal is to have all of -these objects be simple dictionaries. - - -**Related Flags** - -:baremetal_db_backend: string to lookup in the list of LazyPluggable backends. - `sqlalchemy` is the only supported backend right now. - -:[BAREMETAL] sql_connection: string specifying the sqlalchemy connection to - use, like: `sqlite:///var/lib/nova/nova.sqlite`. - -""" - -from oslo.config import cfg - -from nova import utils - -# NOTE(deva): we can't move baremetal_db_backend into an OptGroup yet -# because utils.LazyPluggable doesn't support reading from -# option groups. See bug #1093043. -db_opts = [ - cfg.StrOpt('db_backend', - default='sqlalchemy', - help='The backend to use for bare-metal database'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(db_opts, baremetal_group) - -IMPL = utils.LazyPluggable( - 'db_backend', - config_group='baremetal', - sqlalchemy='nova.virt.baremetal.db.sqlalchemy.api') - - -def bm_node_get_all(context, service_host=None): - return IMPL.bm_node_get_all(context, - service_host=service_host) - - -def bm_node_get_associated(context, service_host=None): - return IMPL.bm_node_get_associated(context, - service_host=service_host) - - -def bm_node_get_unassociated(context, service_host=None): - return IMPL.bm_node_get_unassociated(context, - service_host=service_host) - - -def bm_node_find_free(context, service_host=None, - memory_mb=None, cpus=None, local_gb=None): - return IMPL.bm_node_find_free(context, - service_host=service_host, - memory_mb=memory_mb, - cpus=cpus, - local_gb=local_gb) - - -def bm_node_get(context, bm_node_id): - return IMPL.bm_node_get(context, bm_node_id) - - -def bm_node_get_by_instance_uuid(context, instance_uuid): - return IMPL.bm_node_get_by_instance_uuid(context, - instance_uuid) - - -def bm_node_get_by_node_uuid(context, node_uuid): - return IMPL.bm_node_get_by_node_uuid(context, node_uuid) - - -def bm_node_create(context, values): - return IMPL.bm_node_create(context, values) - - -def bm_node_destroy(context, bm_node_id): - return IMPL.bm_node_destroy(context, bm_node_id) - - -def bm_node_update(context, bm_node_id, values): - return IMPL.bm_node_update(context, bm_node_id, values) - - -def bm_node_associate_and_update(context, node_uuid, values): - return IMPL.bm_node_associate_and_update(context, node_uuid, values) - - -def bm_interface_get(context, if_id): - return IMPL.bm_interface_get(context, if_id) - - -def bm_interface_get_all(context): - return IMPL.bm_interface_get_all(context) - - -def bm_interface_destroy(context, if_id): - return IMPL.bm_interface_destroy(context, if_id) - - -def bm_interface_create(context, bm_node_id, address, datapath_id, port_no): - return IMPL.bm_interface_create(context, bm_node_id, address, - datapath_id, port_no) - - -def bm_interface_set_vif_uuid(context, if_id, vif_uuid): - return IMPL.bm_interface_set_vif_uuid(context, if_id, vif_uuid) - - -def bm_interface_get_by_vif_uuid(context, vif_uuid): - return IMPL.bm_interface_get_by_vif_uuid(context, vif_uuid) - - -def bm_interface_get_all_by_bm_node_id(context, bm_node_id): - return IMPL.bm_interface_get_all_by_bm_node_id(context, bm_node_id) diff --git a/nova/virt/baremetal/db/migration.py b/nova/virt/baremetal/db/migration.py deleted file mode 100644 index eaa43ca3e6..0000000000 --- a/nova/virt/baremetal/db/migration.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -"""Database setup and migration commands.""" - -from nova import utils - - -IMPL = utils.LazyPluggable( - 'db_backend', - config_group='baremetal', - sqlalchemy='nova.virt.baremetal.db.sqlalchemy.migration') - - -def db_sync(version=None): - """Migrate the database to `version` or the most recent version.""" - return IMPL.db_sync(version=version) - - -def db_version(): - """Display the current database version.""" - return IMPL.db_version() - - -def db_initial_version(): - """The starting version for the database.""" - return IMPL.db_initial_version() diff --git a/nova/virt/baremetal/db/sqlalchemy/__init__.py b/nova/virt/baremetal/db/sqlalchemy/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/virt/baremetal/db/sqlalchemy/api.py b/nova/virt/baremetal/db/sqlalchemy/api.py deleted file mode 100644 index 9a6607ea7b..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/api.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -"""Implementation of SQLAlchemy backend.""" - -import uuid - -from oslo.db import exception as db_exc -from oslo.utils import timeutils -import six -from sqlalchemy.sql.expression import asc -from sqlalchemy.sql.expression import literal_column -from sqlalchemy.sql import null - -import nova.context -from nova.db.sqlalchemy import api as sqlalchemy_api -from nova import exception -from nova.i18n import _ -from nova.openstack.common import uuidutils -from nova.virt.baremetal.db.sqlalchemy import models -from nova.virt.baremetal.db.sqlalchemy import session as db_session - - -def model_query(context, *args, **kwargs): - """Query helper that accounts for context's `read_deleted` field. - - :param context: context to query under - :param session: if present, the session to use - :param read_deleted: if present, overrides context's read_deleted field. - :param project_only: if present and context is user-type, then restrict - query to match the context's project_id. - """ - session = kwargs.get('session') or db_session.get_session() - read_deleted = kwargs.get('read_deleted') or context.read_deleted - project_only = kwargs.get('project_only') - - query = session.query(*args) - - if read_deleted == 'no': - query = query.filter_by(deleted=False) - elif read_deleted == 'yes': - pass # omit the filter to include deleted and active - elif read_deleted == 'only': - query = query.filter_by(deleted=True) - else: - raise Exception( - _("Unrecognized read_deleted value '%s'") % read_deleted) - - if project_only and nova.context.is_user_context(context): - query = query.filter_by(project_id=context.project_id) - - return query - - -def _save(ref, session=None): - if not session: - session = db_session.get_session() - # We must not call ref.save() with session=None, otherwise NovaBase - # uses nova-db's session, which cannot access bm-db. - ref.save(session=session) - - -def _build_node_order_by(query): - query = query.order_by(asc(models.BareMetalNode.memory_mb)) - query = query.order_by(asc(models.BareMetalNode.cpus)) - query = query.order_by(asc(models.BareMetalNode.local_gb)) - return query - - -@sqlalchemy_api.require_admin_context -def bm_node_get_all(context, service_host=None): - query = model_query(context, models.BareMetalNode, read_deleted="no") - if service_host: - query = query.filter_by(service_host=service_host) - return query.all() - - -@sqlalchemy_api.require_admin_context -def bm_node_get_associated(context, service_host=None): - query = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter(models.BareMetalNode.instance_uuid != null()) - if service_host: - query = query.filter_by(service_host=service_host) - return query.all() - - -@sqlalchemy_api.require_admin_context -def bm_node_get_unassociated(context, service_host=None): - query = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter(models.BareMetalNode.instance_uuid == null()) - if service_host: - query = query.filter_by(service_host=service_host) - return query.all() - - -@sqlalchemy_api.require_admin_context -def bm_node_find_free(context, service_host=None, - cpus=None, memory_mb=None, local_gb=None): - query = model_query(context, models.BareMetalNode, read_deleted="no") - query = query.filter(models.BareMetalNode.instance_uuid == null()) - if service_host: - query = query.filter_by(service_host=service_host) - if cpus is not None: - query = query.filter(models.BareMetalNode.cpus >= cpus) - if memory_mb is not None: - query = query.filter(models.BareMetalNode.memory_mb >= memory_mb) - if local_gb is not None: - query = query.filter(models.BareMetalNode.local_gb >= local_gb) - query = _build_node_order_by(query) - return query.first() - - -@sqlalchemy_api.require_admin_context -def bm_node_get(context, bm_node_id): - # bm_node_id may be passed as a string. Convert to INT to improve DB perf. - bm_node_id = int(bm_node_id) - result = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter_by(id=bm_node_id).\ - first() - - if not result: - raise exception.NodeNotFound(node_id=bm_node_id) - - return result - - -@sqlalchemy_api.require_admin_context -def bm_node_get_by_instance_uuid(context, instance_uuid): - if not uuidutils.is_uuid_like(instance_uuid): - raise exception.InstanceNotFound(instance_id=instance_uuid) - - result = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter_by(instance_uuid=instance_uuid).\ - first() - - if not result: - raise exception.InstanceNotFound(instance_id=instance_uuid) - - return result - - -@sqlalchemy_api.require_admin_context -def bm_node_get_by_node_uuid(context, bm_node_uuid): - result = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter_by(uuid=bm_node_uuid).\ - first() - - if not result: - raise exception.NodeNotFoundByUUID(node_uuid=bm_node_uuid) - - return result - - -@sqlalchemy_api.require_admin_context -def bm_node_create(context, values): - if not values.get('uuid'): - values['uuid'] = str(uuid.uuid4()) - bm_node_ref = models.BareMetalNode() - bm_node_ref.update(values) - _save(bm_node_ref) - return bm_node_ref - - -@sqlalchemy_api.require_admin_context -def bm_node_update(context, bm_node_id, values): - rows = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter_by(id=bm_node_id).\ - update(values) - - if not rows: - raise exception.NodeNotFound(node_id=bm_node_id) - - -@sqlalchemy_api.require_admin_context -def bm_node_associate_and_update(context, node_uuid, values): - """Associate an instance to a node safely - - Associate an instance to a node only if that node is not yet associated. - Allow the caller to set any other fields they require in the same - operation. For example, this is used to set the node's task_state to - BUILDING at the beginning of driver.spawn(). - - """ - if 'instance_uuid' not in values: - raise exception.NovaException(_( - "instance_uuid must be supplied to bm_node_associate_and_update")) - - session = db_session.get_session() - with session.begin(): - query = model_query(context, models.BareMetalNode, - session=session, read_deleted="no").\ - filter_by(uuid=node_uuid) - - count = query.filter_by(instance_uuid=None).\ - update(values, synchronize_session=False) - if count != 1: - raise exception.NovaException(_( - "Failed to associate instance %(i_uuid)s to baremetal node " - "%(n_uuid)s.") % {'i_uuid': values['instance_uuid'], - 'n_uuid': node_uuid}) - ref = query.first() - return ref - - -@sqlalchemy_api.require_admin_context -def bm_node_destroy(context, bm_node_id): - # First, delete all interfaces belonging to the node. - # Delete physically since these have unique columns. - session = db_session.get_session() - with session.begin(): - model_query(context, models.BareMetalInterface, read_deleted="no").\ - filter_by(bm_node_id=bm_node_id).\ - delete() - rows = model_query(context, models.BareMetalNode, read_deleted="no").\ - filter_by(id=bm_node_id).\ - update({'deleted': True, - 'deleted_at': timeutils.utcnow(), - 'updated_at': literal_column('updated_at')}) - - if not rows: - raise exception.NodeNotFound(node_id=bm_node_id) - - -@sqlalchemy_api.require_admin_context -def bm_interface_get(context, if_id): - result = model_query(context, models.BareMetalInterface, - read_deleted="no").\ - filter_by(id=if_id).\ - first() - - if not result: - raise exception.NovaException(_("Baremetal interface %s " - "not found") % if_id) - - return result - - -@sqlalchemy_api.require_admin_context -def bm_interface_get_all(context): - query = model_query(context, models.BareMetalInterface, - read_deleted="no") - return query.all() - - -@sqlalchemy_api.require_admin_context -def bm_interface_destroy(context, if_id): - # Delete physically since it has unique columns - model_query(context, models.BareMetalInterface, read_deleted="no").\ - filter_by(id=if_id).\ - delete() - - -@sqlalchemy_api.require_admin_context -def bm_interface_create(context, bm_node_id, address, datapath_id, port_no): - ref = models.BareMetalInterface() - ref.bm_node_id = bm_node_id - ref.address = address - ref.datapath_id = datapath_id - ref.port_no = port_no - _save(ref) - return ref.id - - -@sqlalchemy_api.require_admin_context -def bm_interface_set_vif_uuid(context, if_id, vif_uuid): - session = db_session.get_session() - with session.begin(): - bm_interface = model_query(context, models.BareMetalInterface, - read_deleted="no", session=session).\ - filter_by(id=if_id).\ - with_lockmode('update').\ - first() - if not bm_interface: - raise exception.NovaException(_("Baremetal interface %s " - "not found") % if_id) - - bm_interface.vif_uuid = vif_uuid - try: - session.add(bm_interface) - session.flush() - except db_exc.DBError as e: - # TODO(deva): clean up when db layer raises DuplicateKeyError - if six.text_type(e).find('IntegrityError') != -1: - raise exception.NovaException(_("Baremetal interface %s " - "already in use") % vif_uuid) - raise - - -@sqlalchemy_api.require_admin_context -def bm_interface_get_by_vif_uuid(context, vif_uuid): - result = model_query(context, models.BareMetalInterface, - read_deleted="no").\ - filter_by(vif_uuid=vif_uuid).\ - first() - - if not result: - raise exception.NovaException(_("Baremetal virtual interface %s " - "not found") % vif_uuid) - - return result - - -@sqlalchemy_api.require_admin_context -def bm_interface_get_all_by_bm_node_id(context, bm_node_id): - result = model_query(context, models.BareMetalInterface, - read_deleted="no").\ - filter_by(bm_node_id=bm_node_id).\ - all() - - if not result: - raise exception.NodeNotFound(node_id=bm_node_id) - - return result diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/__init__.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/migrate.cfg b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/migrate.cfg deleted file mode 100644 index 368e93a526..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/migrate.cfg +++ /dev/null @@ -1,20 +0,0 @@ -[db_settings] -# Used to identify which repository this database is versioned under. -# You can use the name of your project. -repository_id=nova_bm - -# The name of the database table used to track the schema version. -# This name shouldn't already be used by your project. -# If this is changed once a database is under version control, you'll need to -# change the table name in each database too. -version_table=migrate_version - -# When committing a change script, Migrate will attempt to generate the -# sql for all supported databases; normally, if one of them fails - probably -# because you don't have that database installed - it is ignored and the -# commit continues, perhaps ending successfully. -# Databases in this list MUST compile successfully during a commit, or the -# entire commit will fail. List the databases your application will actually -# be using to ensure your updates to that database work properly. -# This must be a list; example: ['postgres','sqlite'] -required_dbs=[] diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/001_init.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/001_init.py deleted file mode 100644 index 351ca20f64..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/001_init.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -from sqlalchemy import Boolean, Column, DateTime -from sqlalchemy import Index, Integer, MetaData, String, Table - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - bm_nodes = Table('bm_nodes', meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('cpus', Integer), - Column('memory_mb', Integer), - Column('local_gb', Integer), - Column('pm_address', String(length=255)), - Column('pm_user', String(length=255)), - Column('pm_password', String(length=255)), - Column('service_host', String(length=255)), - Column('prov_mac_address', String(length=255)), - Column('instance_uuid', String(length=36)), - Column('registration_status', String(length=16)), - Column('task_state', String(length=255)), - Column('prov_vlan_id', Integer), - Column('terminal_port', Integer), - mysql_engine='InnoDB', - ) - - bm_interfaces = Table('bm_interfaces', meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('bm_node_id', Integer), - Column('address', String(length=255), unique=True), - Column('datapath_id', String(length=255)), - Column('port_no', Integer), - Column('vif_uuid', String(length=36), unique=True), - mysql_engine='InnoDB', - ) - - bm_pxe_ips = Table('bm_pxe_ips', meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('address', String(length=255), unique=True), - Column('bm_node_id', Integer), - Column('server_address', String(length=255), unique=True), - mysql_engine='InnoDB', - ) - - bm_deployments = Table('bm_deployments', meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('bm_node_id', Integer), - Column('key', String(length=255)), - Column('image_path', String(length=255)), - Column('pxe_config_path', String(length=255)), - Column('root_mb', Integer), - Column('swap_mb', Integer), - mysql_engine='InnoDB', - ) - - bm_nodes.create() - bm_interfaces.create() - bm_pxe_ips.create() - bm_deployments.create() - - Index('idx_bm_nodes_service_host_deleted', - bm_nodes.c.service_host, bm_nodes.c.deleted)\ - .create(migrate_engine) - Index('idx_bm_nodes_instance_uuid_deleted', - bm_nodes.c.instance_uuid, bm_nodes.c.deleted)\ - .create(migrate_engine) - Index('idx_bm_nodes_hmcld', - bm_nodes.c.service_host, bm_nodes.c.memory_mb, bm_nodes.c.cpus, - bm_nodes.c.local_gb, bm_nodes.c.deleted)\ - .create(migrate_engine) - - Index('idx_bm_interfaces_bm_node_id_deleted', - bm_interfaces.c.bm_node_id, bm_interfaces.c.deleted)\ - .create(migrate_engine) - - Index('idx_bm_pxe_ips_bm_node_id_deleted', - bm_pxe_ips.c.bm_node_id, bm_pxe_ips.c.deleted)\ - .create(migrate_engine) - - -def downgrade(migrate_engine): - raise NotImplementedError('Downgrade from 001_init is unsupported.') diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/002_drop_bm_deployments.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/002_drop_bm_deployments.py deleted file mode 100644 index ae9f477b7b..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/002_drop_bm_deployments.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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. - -from sqlalchemy import Column, Index, MetaData, Table -from sqlalchemy import Integer, String, DateTime, Boolean - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - bm_nodes = Table('bm_nodes', meta, autoload=True) - - image_path = Column('image_path', String(length=255)) - pxe_config_path = Column('pxe_config_path', String(length=255)) - deploy_key = Column('deploy_key', String(length=255)) - root_mb = Column('root_mb', Integer()) - swap_mb = Column('swap_mb', Integer()) - - for c in [image_path, pxe_config_path, deploy_key, root_mb, swap_mb]: - bm_nodes.create_column(c) - - deploy_key_idx = Index('deploy_key_idx', bm_nodes.c.deploy_key) - deploy_key_idx.create(migrate_engine) - - bm_deployments = Table('bm_deployments', meta, autoload=True) - bm_deployments.drop() - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - bm_nodes = Table('bm_nodes', meta, autoload=True) - - for c in ['image_path', 'pxe_config_path', 'deploy_key', 'root_mb', - 'swap_mb']: - bm_nodes.drop_column(c) - - bm_deployments = Table('bm_deployments', meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('bm_node_id', Integer), - Column('key', String(length=255)), - Column('image_path', String(length=255)), - Column('pxe_config_path', String(length=255)), - Column('root_mb', Integer), - Column('swap_mb', Integer), - mysql_engine='InnoDB', - ) - bm_deployments.create() diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/003_add_uuid_to_bm_nodes.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/003_add_uuid_to_bm_nodes.py deleted file mode 100644 index 12c97e1ffc..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/003_add_uuid_to_bm_nodes.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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. - -from sqlalchemy import Column, MetaData, String, Table, Index - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - uuid_col = Column('uuid', String(36)) - t.create_column(uuid_col) - - uuid_ux = Index('uuid_ux', t.c.uuid, unique=True) - uuid_ux.create(migrate_engine) - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - - t.drop_column('uuid') diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py deleted file mode 100644 index fec8054f23..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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. - -from sqlalchemy import Column, MetaData, String, Table - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - name_col = Column('instance_name', String(255)) - t.create_column(name_col) - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - t.drop_column('instance_name') diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/005_drop_unused_columns_from_nodes.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/005_drop_unused_columns_from_nodes.py deleted file mode 100644 index 5247b920da..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/005_drop_unused_columns_from_nodes.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2013 NTT DOCOMO, 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 sqlalchemy import Column, String, Integer, MetaData, Table - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - nodes.drop_column('prov_vlan_id') - nodes.drop_column('registration_status') - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - nodes.create_column(Column('prov_vlan_id', Integer)) - nodes.create_column(Column('registration_status', String(length=16))) diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/006_move_prov_mac_address.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/006_move_prov_mac_address.py deleted file mode 100644 index f3548fca29..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/006_move_prov_mac_address.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2013 NTT DOCOMO, 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 oslo.db import exception as db_exc -from sqlalchemy import MetaData, Table, exists -from sqlalchemy import sql - -from nova.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - ifs = Table('bm_interfaces', meta, autoload=True) - - q = sql.select([nodes.c.id, nodes.c.prov_mac_address], - from_obj=nodes) - - # Iterate all elements before starting insert since IntegrityError - # may disturb the iteration. - node_address = {} - for node_id, address in q.execute(): - node_address[node_id] = address - - i = ifs.insert() - for node_id, address in node_address.iteritems(): - try: - i.execute({'bm_node_id': node_id, 'address': address}) - except db_exc.DBError: - # TODO(ekudryashova): replace by DBReferenceError when db layer - # raise it. - # The address is registered in both bm_nodes and bm_interfaces. - # It is expected. - pass - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - ifs = Table('bm_interfaces', meta, autoload=True) - - subq = exists().where(sql.and_( - ifs.c.bm_node_id == nodes.c.id, - ifs.c.address == nodes.c.prov_mac_address)) - - ifs.delete().where(subq).execute() - - # NOTE(arata): - # In fact, this downgrade may not return the db to the previous state. - # It seems to be not so match a problem, so this is just for memo. - # - # Think these two state before upgrading: - # - # (A) address 'x' is duplicate - # bm_nodes.prov_mac_address='x' - # bm_interfaces.address=['x', 'y'] - # - # (B) no address is duplicate - # bm_nodes.prov_mac_address='x' - # bm_interfaces.address=['y'] - # - # Upgrading them results in the same state: - # - # bm_nodes.prov_mac_address='x' - # bm_interfaces.address=['x', 'y'] - # - # Downgrading this results in B, even if the actual initial status was A - # Of course we can change it to downgrade to B, but then we cannot - # downgrade to A; it is an exclusive choice since we do not have - # information about the initial state. diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/007_drop_prov_mac_address.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/007_drop_prov_mac_address.py deleted file mode 100644 index a1c3568cad..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/007_drop_prov_mac_address.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2013 NTT DOCOMO, 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 sqlalchemy import Column, MetaData, String, Table - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - nodes.drop_column('prov_mac_address') - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - nodes = Table('bm_nodes', meta, autoload=True) - nodes.create_column(Column('prov_mac_address', String(length=255))) - - # NOTE(arata): The values held by prov_mac_address are lost in upgrade. - # So downgrade has no other choice but to set the column to NULL. diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/008_remove_bm_pxe_ips_table.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/008_remove_bm_pxe_ips_table.py deleted file mode 100644 index 66e5e3d6bb..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/008_remove_bm_pxe_ips_table.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 Mirantis Inc. -# 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. - -from sqlalchemy import Boolean -from sqlalchemy import Column -from sqlalchemy import DateTime -from sqlalchemy import Index -from sqlalchemy import Integer -from sqlalchemy import MetaData -from sqlalchemy import String -from sqlalchemy import Table - - -table_name = 'bm_pxe_ips' - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - table = Table(table_name, meta, autoload=True) - table.drop() - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - bm_pxe_ips = Table(table_name, meta, - Column('created_at', DateTime), - Column('updated_at', DateTime), - Column('deleted_at', DateTime), - Column('deleted', Boolean), - Column('id', Integer, primary_key=True, nullable=False), - Column('address', String(length=255), unique=True), - Column('bm_node_id', Integer), - Column('server_address', - String(length=255), unique=True), - mysql_engine='InnoDB', - ) - bm_pxe_ips.create() - - Index( - 'idx_bm_pxe_ips_bm_node_id_deleted', - bm_pxe_ips.c.bm_node_id, - bm_pxe_ips.c.deleted - ).create(migrate_engine) diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/009_add_ephemeral_mb_to_bm_nodes.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/009_add_ephemeral_mb_to_bm_nodes.py deleted file mode 100644 index ca453f7984..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/009_add_ephemeral_mb_to_bm_nodes.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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. - -from sqlalchemy import Column, MetaData, Integer, Table - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - ephemeral_mb_col = Column('ephemeral_mb', Integer) - t.create_column(ephemeral_mb_col) - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table('bm_nodes', meta, autoload=True) - - t.drop_column('ephemeral_mb') diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/010_add_preserve_ephemeral.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/010_add_preserve_ephemeral.py deleted file mode 100644 index 2cd5745327..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/010_add_preserve_ephemeral.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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. - -from sqlalchemy import Column, MetaData, Boolean, Table -from sqlalchemy.sql import expression - - -COLUMN_NAME = 'preserve_ephemeral' -TABLE_NAME = 'bm_nodes' - - -def upgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table(TABLE_NAME, meta, autoload=True) - default = (expression.text('0') if migrate_engine.name == 'sqlite' - else expression.text('false')) - preserve_ephemeral_col = Column(COLUMN_NAME, Boolean, - server_default=default) - t.create_column(preserve_ephemeral_col) - - -def downgrade(migrate_engine): - meta = MetaData() - meta.bind = migrate_engine - - t = Table(TABLE_NAME, meta, autoload=True) - # NOTE(rpodolyaka): SQLite doesn't have native BOOLEAN type, so it's - # emulated by adding a CHECK constraint. We must - # explicitly omit that constraint here so we don't - # receive 'no such column' error when dropping the - # column - if migrate_engine.name == 'sqlite': - t.constraints = set([ - c - for c in t.constraints - if not (hasattr(c, 'sqltext') and COLUMN_NAME in str(c.sqltext)) - ]) - - t.drop_column(COLUMN_NAME) diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/__init__.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/virt/baremetal/db/sqlalchemy/migration.py b/nova/virt/baremetal/db/sqlalchemy/migration.py deleted file mode 100644 index 27beb89f16..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/migration.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -import os - -from migrate import exceptions as versioning_exceptions -from migrate.versioning import api as versioning_api -from migrate.versioning.repository import Repository -import sqlalchemy - -from nova import exception -from nova.i18n import _ -from nova.virt.baremetal.db.sqlalchemy import session - -INIT_VERSION = 0 -_REPOSITORY = None - - -def db_sync(version=None): - if version is not None: - try: - version = int(version) - except ValueError: - raise exception.NovaException(_("version should be an integer")) - - current_version = db_version() - repository = _find_migrate_repo() - if version is None or version > current_version: - return versioning_api.upgrade(session.get_engine(), repository, - version) - else: - return versioning_api.downgrade(session.get_engine(), repository, - version) - - -def db_version(): - repository = _find_migrate_repo() - try: - return versioning_api.db_version(session.get_engine(), repository) - except versioning_exceptions.DatabaseNotControlledError: - meta = sqlalchemy.MetaData() - engine = session.get_engine() - meta.reflect(bind=engine) - tables = meta.tables - if len(tables) == 0: - db_version_control(INIT_VERSION) - return versioning_api.db_version(session.get_engine(), repository) - else: - # Some pre-Essex DB's may not be version controlled. - # Require them to upgrade using Essex first. - raise exception.NovaException( - _("Upgrade DB using Essex release first.")) - - -def db_initial_version(): - return INIT_VERSION - - -def db_version_control(version=None): - repository = _find_migrate_repo() - versioning_api.version_control(session.get_engine(), repository, version) - return version - - -def _find_migrate_repo(): - """Get the path for the migrate repository.""" - global _REPOSITORY - path = os.path.join(os.path.abspath(os.path.dirname(__file__)), - 'migrate_repo') - assert os.path.exists(path) - if _REPOSITORY is None: - _REPOSITORY = Repository(path) - return _REPOSITORY diff --git a/nova/virt/baremetal/db/sqlalchemy/models.py b/nova/virt/baremetal/db/sqlalchemy/models.py deleted file mode 100644 index 5125d7d387..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/models.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -""" -SQLAlchemy models for baremetal data. -""" - -from sqlalchemy import Column, Boolean, Integer, String -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import ForeignKey, Text - -from nova.db.sqlalchemy import models - - -BASE = declarative_base() - - -class BareMetalNode(BASE, models.NovaBase): - """Represents a bare metal node.""" - - __tablename__ = 'bm_nodes' - id = Column(Integer, primary_key=True) - deleted = Column(Boolean, default=False) - uuid = Column(String(36)) - service_host = Column(String(255)) - instance_uuid = Column(String(36)) - instance_name = Column(String(255)) - cpus = Column(Integer) - memory_mb = Column(Integer) - local_gb = Column(Integer) - preserve_ephemeral = Column(Boolean) - pm_address = Column(Text) - pm_user = Column(Text) - pm_password = Column(Text) - task_state = Column(String(255)) - terminal_port = Column(Integer) - image_path = Column(String(255)) - pxe_config_path = Column(String(255)) - deploy_key = Column(String(255)) - # root_mb, swap_mb and ephemeral_mb are cached flavor values for the - # current deployment not attributes of the node. - root_mb = Column(Integer) - swap_mb = Column(Integer) - ephemeral_mb = Column(Integer) - - -class BareMetalInterface(BASE, models.NovaBase): - __tablename__ = 'bm_interfaces' - id = Column(Integer, primary_key=True) - deleted = Column(Boolean, default=False) - bm_node_id = Column(Integer, ForeignKey('bm_nodes.id')) - address = Column(String(255), unique=True) - datapath_id = Column(String(255)) - port_no = Column(Integer) - vif_uuid = Column(String(36), unique=True) diff --git a/nova/virt/baremetal/db/sqlalchemy/session.py b/nova/virt/baremetal/db/sqlalchemy/session.py deleted file mode 100644 index d63aabaace..0000000000 --- a/nova/virt/baremetal/db/sqlalchemy/session.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -"""Session Handling for SQLAlchemy backend.""" - -from oslo.config import cfg -from oslo.db.sqlalchemy import session as db_session - -from nova import paths - -opts = [ - cfg.StrOpt('sql_connection', - default=('sqlite:///' + - paths.state_path_def('baremetal_nova.sqlite')), - help='The SQLAlchemy connection string used to connect to the ' - 'bare-metal database'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(opts, baremetal_group) - - -_FACADE = None - - -def _create_facade_lazily(): - global _FACADE - - if _FACADE is None: - _FACADE = db_session.EngineFacade(CONF.baremetal.sql_connection, - **dict(CONF.database.iteritems())) - - return _FACADE - - -def get_session(autocommit=True, expire_on_commit=False, **kwargs): - """Return a SQLAlchemy session.""" - - facade = _create_facade_lazily() - return facade.get_session(autocommit=autocommit, - expire_on_commit=expire_on_commit, **kwargs) - - -def get_engine(): - """Return a SQLAlchemy engine.""" - - facade = _create_facade_lazily() - return facade.get_engine() diff --git a/nova/virt/baremetal/doc/README.rst b/nova/virt/baremetal/doc/README.rst deleted file mode 100644 index 38a0f4ee4f..0000000000 --- a/nova/virt/baremetal/doc/README.rst +++ /dev/null @@ -1,69 +0,0 @@ -General Bare-metal Provisioning README -====================================== - -:Authors: - [USC/ISI] Mikyung Kang , David Kang - - [NTT DOCOMO] Ken Igarashi - - [VirtualTech Japan Inc.] Arata Notsu -:Date: 2012-08-02 -:Version: 2012.8 -:Wiki: http://wiki.openstack.org/GeneralBareMetalProvisioningFramework - -Code changes ------------- - -:: - - nova/nova/virt/baremetal/* - nova/nova/virt/driver.py - nova/nova/tests/baremetal/* - nova/nova/tests/compute/test_compute.py - nova/nova/compute/manager.py - nova/nova/compute/resource_tracker.py - nova/nova/manager.py - nova/nova/scheduler/driver.py - nova/nova/scheduler/filter_scheduler.py - nova/nova/scheduler/host_manager.py - nova/nova/scheduler/baremetal_host_manager.py - nova/bin/bm_deploy_server - nova/bin/nova-bm-manage - -Additional setting for bare-metal provisioning [nova.conf] ----------------------------------------------------------- - -:: - - # baremetal database connection - baremetal_sql_connection = mysql://$ID:$Password@$IP/nova_bm - - # baremetal compute driver - compute_driver = nova.virt.baremetal.driver.BareMetalDriver - baremetal_driver = {nova.virt.baremetal.tilera.Tilera | nova.virt.baremetal.pxe.PXE} - power_manager = {nova.virt.baremetal.tilera_pdu.Pdu | nova.virt.baremetal.ipmi.Ipmi} - - # flavor_extra_specs this baremetal compute - flavor_extra_specs = cpu_arch:{tilepro64 | x86_64 | arm} - - # TFTP root - baremetal_tftp_root = /tftpboot - - # baremetal scheduler host manager - scheduler_host_manager = nova.scheduler.baremetal_host_manager.BaremetalHostManager - - -Non-PXE (Tilera) Bare-metal Provisioning ----------------------------------------- - -1. tilera-bm-instance-creation.rst - -2. tilera-bm-installation.rst - -PXE Bare-metal Provisioning ---------------------------- - -1. pxe-bm-instance-creation.rst - -2. pxe-bm-installation.rst - diff --git a/nova/virt/baremetal/driver.py b/nova/virt/baremetal/driver.py deleted file mode 100644 index 6be6692300..0000000000 --- a/nova/virt/baremetal/driver.py +++ /dev/null @@ -1,571 +0,0 @@ -# coding=utf-8 -# -# Copyright (c) 2012 NTT DOCOMO, INC -# Copyright (c) 2011 University of Southern California / ISI -# 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. - -""" -A driver for Bare-metal platform. -""" - -from oslo.config import cfg -from oslo.utils import excutils -from oslo.utils import importutils - -from nova.compute import arch -from nova.compute import flavors -from nova.compute import hvtype -from nova.compute import power_state -from nova.compute import task_states -from nova.compute import vm_mode -from nova import context as nova_context -from nova import exception -from nova.i18n import _ -from nova.i18n import _LW -from nova.openstack.common import jsonutils -from nova.openstack.common import lockutils -from nova.openstack.common import log as logging -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import db -from nova.virt import driver -from nova.virt import firewall -from nova.virt.libvirt import imagecache - -LOG = logging.getLogger(__name__) - -opts = [ - cfg.StrOpt('vif_driver', - default='nova.virt.baremetal.vif_driver.BareMetalVIFDriver', - help='Baremetal VIF driver.'), - cfg.StrOpt('volume_driver', - default='nova.virt.baremetal.volume_driver.LibvirtVolumeDriver', - help='Baremetal volume driver.'), - cfg.ListOpt('flavor_extra_specs', - default=[], - help='A list of additional capabilities corresponding to ' - 'flavor_extra_specs for this compute ' - 'host to advertise. Valid entries are name=value, pairs ' - 'For example, "key1:val1, key2:val2"'), - cfg.StrOpt('driver', - default='nova.virt.baremetal.pxe.PXE', - help='Baremetal driver back-end (pxe or tilera)'), - cfg.StrOpt('power_manager', - default='nova.virt.baremetal.ipmi.IPMI', - help='Baremetal power management method'), - cfg.StrOpt('tftp_root', - default='/tftpboot', - help='Baremetal compute node\'s tftp root path'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(opts, baremetal_group) -CONF.import_opt('host', 'nova.netconf') -CONF.import_opt('my_ip', 'nova.netconf') - -DEFAULT_FIREWALL_DRIVER = "%s.%s" % ( - firewall.__name__, - firewall.NoopFirewallDriver.__name__) - - -def _get_baremetal_node_by_instance_uuid(instance_uuid): - ctx = nova_context.get_admin_context() - node = db.bm_node_get_by_instance_uuid(ctx, instance_uuid) - if node['service_host'] != CONF.host: - LOG.error(_("Request for baremetal node %s " - "sent to wrong service host") % instance_uuid) - raise exception.InstanceNotFound(instance_id=instance_uuid) - return node - - -def _update_state(context, node, instance, state): - """Update the node state in baremetal DB - - If instance is not supplied, reset the instance_uuid field for this node. - - """ - values = {'task_state': state} - if not instance: - values['instance_uuid'] = None - values['instance_name'] = None - db.bm_node_update(context, node['id'], values) - - -def get_power_manager(**kwargs): - cls = importutils.import_class(CONF.baremetal.power_manager) - return cls(**kwargs) - - -class BareMetalDriver(driver.ComputeDriver): - """BareMetal hypervisor driver.""" - - capabilities = { - "has_imagecache": True, - "supports_recreate": False, - } - - def __init__(self, virtapi, read_only=False): - super(BareMetalDriver, self).__init__(virtapi) - - self.driver = importutils.import_object( - CONF.baremetal.driver, virtapi) - self.vif_driver = importutils.import_object( - CONF.baremetal.vif_driver) - self.firewall_driver = firewall.load_driver( - default=DEFAULT_FIREWALL_DRIVER) - self.volume_driver = importutils.import_object( - CONF.baremetal.volume_driver, virtapi) - self.image_cache_manager = imagecache.ImageCacheManager() - - extra_specs = {} - extra_specs["baremetal_driver"] = CONF.baremetal.driver - for pair in CONF.baremetal.flavor_extra_specs: - keyval = pair.split(':', 1) - keyval[0] = keyval[0].strip() - keyval[1] = keyval[1].strip() - extra_specs[keyval[0]] = keyval[1] - - self.extra_specs = extra_specs - - if 'cpu_arch' not in extra_specs: - LOG.info( - _('cpu_arch is not found in flavor_extra_specs')) - self.supported_instances = [] - else: - self.supported_instances = [( - arch.canonicalize(extra_specs['cpu_arch']), - hvtype.BAREMETAL, - vm_mode.HVM - ), ] - - @classmethod - def instance(cls): - if not hasattr(cls, '_instance'): - cls._instance = cls() - return cls._instance - - def init_host(self, host): - LOG.warn(_LW('The baremetal driver is deprecated in Juno and will be ' - 'removed before the next release. Please plan to ' - 'transition to Ironic as soon as possible. See ' - 'https://wiki.openstack.org/wiki/Ironic for more ' - 'information')) - - def get_hypervisor_type(self): - return 'baremetal' - - def get_hypervisor_version(self): - # TODO(deva): define the version properly elsewhere - return 1 - - def list_instances(self): - l = [] - context = nova_context.get_admin_context() - for node in db.bm_node_get_associated(context, service_host=CONF.host): - l.append(node['instance_name']) - return l - - def _require_node(self, instance): - """Get a node's uuid out of a manager instance dict. - - The compute manager is meant to know the node uuid, so missing uuid - a significant issue - it may mean we've been passed someone elses data. - """ - node_uuid = instance.get('node') - if not node_uuid: - raise exception.NovaException(_( - "Baremetal node id not supplied to driver for %r") - % instance['uuid']) - return node_uuid - - def _attach_block_devices(self, instance, block_device_info): - block_device_mapping = driver.\ - block_device_info_get_mapping(block_device_info) - for vol in block_device_mapping: - connection_info = vol['connection_info'] - mountpoint = vol['mount_device'] - self.attach_volume(None, - connection_info, instance, mountpoint) - - def _detach_block_devices(self, instance, block_device_info): - block_device_mapping = driver.\ - block_device_info_get_mapping(block_device_info) - for vol in block_device_mapping: - connection_info = vol['connection_info'] - mountpoint = vol['mount_device'] - self.detach_volume( - connection_info, instance, mountpoint) - - def _start_firewall(self, instance, network_info): - self.firewall_driver.setup_basic_filtering( - instance, network_info) - self.firewall_driver.prepare_instance_filter( - instance, network_info) - self.firewall_driver.apply_instance_filter( - instance, network_info) - - def _stop_firewall(self, instance, network_info): - self.firewall_driver.unfilter_instance( - instance, network_info) - - def deallocate_networks_on_reschedule(self, instance): - return True - - def macs_for_instance(self, instance): - context = nova_context.get_admin_context() - node_uuid = self._require_node(instance) - node = db.bm_node_get_by_node_uuid(context, node_uuid) - ifaces = db.bm_interface_get_all_by_bm_node_id(context, node['id']) - return set(iface['address'] for iface in ifaces) - - def _set_default_ephemeral_device(self, instance): - flavor = flavors.extract_flavor(instance) - if flavor['ephemeral_gb']: - instance.default_ephemeral_device = '/dev/sda1' - instance.save() - - def spawn(self, context, instance, image_meta, injected_files, - admin_password, network_info=None, block_device_info=None): - node_uuid = self._require_node(instance) - self._set_default_ephemeral_device(instance) - - # NOTE(deva): this db method will raise an exception if the node is - # already in use. We call it here to ensure no one else - # allocates this node before we begin provisioning it. - node = db.bm_node_associate_and_update(context, node_uuid, - {'instance_uuid': instance['uuid'], - 'instance_name': instance['hostname'], - 'task_state': baremetal_states.BUILDING, - 'preserve_ephemeral': False}) - self._spawn(node, context, instance, image_meta, injected_files, - admin_password, network_info=network_info, - block_device_info=block_device_info) - - def _spawn(self, node, context, instance, image_meta, injected_files, - admin_password, network_info=None, block_device_info=None): - try: - self._plug_vifs(instance, network_info, context=context) - self._attach_block_devices(instance, block_device_info) - self._start_firewall(instance, network_info) - - # Caching images is both CPU and I/O expensive. When running many - # machines from a single nova-compute server, deploys of multiple - # machines can easily thrash the nova-compute server - unlike a - # virt hypervisor which is limited by CPU for VMs, baremetal only - # uses CPU and I/O when deploying. By only downloading one image - # at a time we serialise rather than thrashing, which leads to a - # lower average time-to-complete during overload situations, and - # a (relatively) insignificant delay for compute servers which - # have sufficient IOPS to handle multiple concurrent image - # conversions. - with lockutils.lock('nova-baremetal-cache-images', external=True): - self.driver.cache_images( - context, node, instance, - admin_password=admin_password, - image_meta=image_meta, - injected_files=injected_files, - network_info=network_info, - ) - self.driver.activate_bootloader(context, node, instance, - network_info=network_info) - # NOTE(deva): ensure node is really off before we turn it on - # fixes bug https://code.launchpad.net/bugs/1178919 - self.power_off(instance, node) - self.power_on(context, instance, network_info, block_device_info, - node) - _update_state(context, node, instance, baremetal_states.PREPARED) - - self.driver.activate_node(context, node, instance) - _update_state(context, node, instance, baremetal_states.ACTIVE) - except Exception: - with excutils.save_and_reraise_exception(): - LOG.error(_("Error deploying instance %(instance)s " - "on baremetal node %(node)s.") % - {'instance': instance['uuid'], - 'node': node['uuid']}) - - # Do not set instance=None yet. This prevents another - # spawn() while we are cleaning up. - _update_state(context, node, instance, baremetal_states.ERROR) - - self.driver.deactivate_node(context, node, instance) - self.power_off(instance, node) - self.driver.deactivate_bootloader(context, node, instance) - self.driver.destroy_images(context, node, instance) - - self._detach_block_devices(instance, block_device_info) - self._stop_firewall(instance, network_info) - self._unplug_vifs(instance, network_info) - - _update_state(context, node, None, baremetal_states.DELETED) - else: - # We no longer need the image since we successfully deployed. - self.driver.destroy_images(context, node, instance) - - def rebuild(self, context, instance, image_meta, injected_files, - admin_password, bdms, detach_block_devices, - attach_block_devices, network_info=None, recreate=False, - block_device_info=None, preserve_ephemeral=False): - """Destroy and re-make this instance. - - A 'rebuild' effectively purges all existing data from the system and - remakes the VM with given 'metadata' and 'personalities'. - - :param context: Security context. - :param instance: Instance object. - :param image_meta: Image object returned by nova.image.glance that - defines the image from which to boot this instance. - :param injected_files: User files to inject into instance. - :param admin_password: Administrator password to set in instance. - :param bdms: block-device-mappings to use for rebuild - :param detach_block_devices: function to detach block devices. See - nova.compute.manager.ComputeManager:_rebuild_default_impl for - usage. - :param attach_block_devices: function to attach block devices. See - nova.compute.manager.ComputeManager:_rebuild_default_impl for - usage. - :param network_info: - :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info` - :param block_device_info: Information about block devices to be - attached to the instance. - :param recreate: True if instance should be recreated with same disk. - :param preserve_ephemeral: True if the default ephemeral storage - partition must be preserved on rebuild. - """ - - instance.task_state = task_states.REBUILD_SPAWNING - instance.save(expected_task_state=[task_states.REBUILDING]) - - node_uuid = self._require_node(instance) - node = db.bm_node_get_by_node_uuid(context, node_uuid) - db.bm_node_update( - context, node['id'], - {'task_state': baremetal_states.BUILDING, - 'preserve_ephemeral': preserve_ephemeral} - ) - self._spawn(node, context, instance, image_meta, injected_files, - admin_password, network_info=network_info, - block_device_info=block_device_info) - - def reboot(self, context, instance, network_info, reboot_type, - block_device_info=None, bad_volumes_callback=None): - node = _get_baremetal_node_by_instance_uuid(instance['uuid']) - ctx = nova_context.get_admin_context() - pm = get_power_manager(node=node, instance=instance) - state = pm.reboot_node() - if pm.state != baremetal_states.ACTIVE: - raise exception.InstanceRebootFailure(_( - "Baremetal power manager failed to restart node " - "for instance %r") % instance['uuid']) - _update_state(ctx, node, instance, state) - - def destroy(self, context, instance, network_info, block_device_info=None, - destroy_disks=True, migrate_data=None): - context = nova_context.get_admin_context() - - try: - node = _get_baremetal_node_by_instance_uuid(instance['uuid']) - except exception.InstanceNotFound: - LOG.warning(_("Destroy called on non-existing instance %s") - % instance['uuid']) - return - - try: - self.driver.deactivate_node(context, node, instance) - self.power_off(instance, node) - self.driver.deactivate_bootloader(context, node, instance) - self.driver.destroy_images(context, node, instance) - - self._detach_block_devices(instance, block_device_info) - self._stop_firewall(instance, network_info) - self._unplug_vifs(instance, network_info) - - _update_state(context, node, None, baremetal_states.DELETED) - except Exception as e: - with excutils.save_and_reraise_exception(): - try: - LOG.error(_("Error from baremetal driver " - "during destroy: %s") % e) - _update_state(context, node, instance, - baremetal_states.ERROR) - except Exception: - LOG.error(_("Error while recording destroy failure in " - "baremetal database: %s") % e) - - def cleanup(self, context, instance, network_info, block_device_info=None, - destroy_disks=True, migrate_data=None, destroy_vifs=True): - """Cleanup after instance being destroyed.""" - pass - - def power_off(self, instance, timeout=0, retry_interval=0, node=None): - """Power off the specified instance.""" - # TODO(PhilDay): Add support for timeout (clean shutdown) - if not node: - node = _get_baremetal_node_by_instance_uuid(instance['uuid']) - pm = get_power_manager(node=node, instance=instance) - pm.deactivate_node() - if pm.state != baremetal_states.DELETED: - raise exception.InstancePowerOffFailure(_( - "Baremetal power manager failed to stop node " - "for instance %r") % instance['uuid']) - pm.stop_console() - - def power_on(self, context, instance, network_info, block_device_info=None, - node=None): - """Power on the specified instance.""" - if not node: - node = _get_baremetal_node_by_instance_uuid(instance['uuid']) - pm = get_power_manager(node=node, instance=instance) - pm.activate_node() - if pm.state != baremetal_states.ACTIVE: - raise exception.InstancePowerOnFailure(_( - "Baremetal power manager failed to start node " - "for instance %r") % instance['uuid']) - pm.start_console() - - def get_volume_connector(self, instance): - return self.volume_driver.get_volume_connector(instance) - - def attach_volume(self, context, connection_info, instance, mountpoint, - disk_bus=None, device_type=None, encryption=None): - return self.volume_driver.attach_volume(connection_info, - instance, mountpoint) - - def detach_volume(self, connection_info, instance, mountpoint, - encryption=None): - return self.volume_driver.detach_volume(connection_info, - instance, mountpoint) - - def get_info(self, instance): - inst_uuid = instance.get('uuid') - node = _get_baremetal_node_by_instance_uuid(inst_uuid) - pm = get_power_manager(node=node, instance=instance) - - # NOTE(deva): Power manager may not be able to determine power state - # in which case it may return "None" here. - ps = pm.is_power_on() - if ps: - pstate = power_state.RUNNING - elif ps is False: - pstate = power_state.SHUTDOWN - else: - pstate = power_state.NOSTATE - - return {'state': pstate, - 'max_mem': node['memory_mb'], - 'mem': node['memory_mb'], - 'num_cpu': node['cpus'], - 'cpu_time': 0} - - def refresh_security_group_rules(self, security_group_id): - self.firewall_driver.refresh_security_group_rules(security_group_id) - return True - - def refresh_security_group_members(self, security_group_id): - self.firewall_driver.refresh_security_group_members(security_group_id) - return True - - def refresh_provider_fw_rules(self): - self.firewall_driver.refresh_provider_fw_rules() - - def _node_resource(self, node): - vcpus_used = 0 - memory_mb_used = 0 - local_gb_used = 0 - - vcpus = node['cpus'] - memory_mb = node['memory_mb'] - local_gb = node['local_gb'] - if node['instance_uuid']: - vcpus_used = node['cpus'] - memory_mb_used = node['memory_mb'] - local_gb_used = node['local_gb'] - - dic = {'vcpus': vcpus, - 'memory_mb': memory_mb, - 'local_gb': local_gb, - 'vcpus_used': vcpus_used, - 'memory_mb_used': memory_mb_used, - 'local_gb_used': local_gb_used, - 'hypervisor_type': self.get_hypervisor_type(), - 'hypervisor_version': self.get_hypervisor_version(), - 'hypervisor_hostname': str(node['uuid']), - 'cpu_info': 'baremetal cpu', - 'supported_instances': - jsonutils.dumps(self.supported_instances), - 'stats': jsonutils.dumps(self.extra_specs) - } - return dic - - def refresh_instance_security_rules(self, instance): - self.firewall_driver.refresh_instance_security_rules(instance) - - def get_available_resource(self, nodename): - context = nova_context.get_admin_context() - resource = {} - try: - node = db.bm_node_get_by_node_uuid(context, nodename) - resource = self._node_resource(node) - except exception.NodeNotFoundByUUID: - pass - return resource - - def ensure_filtering_rules_for_instance(self, instance_ref, network_info): - self.firewall_driver.setup_basic_filtering(instance_ref, network_info) - self.firewall_driver.prepare_instance_filter(instance_ref, - network_info) - - def unfilter_instance(self, instance_ref, network_info): - self.firewall_driver.unfilter_instance(instance_ref, - network_info=network_info) - - def plug_vifs(self, instance, network_info): - """Plugin VIFs into networks.""" - self._plug_vifs(instance, network_info) - - def _plug_vifs(self, instance, network_info, context=None): - if not context: - context = nova_context.get_admin_context() - node = _get_baremetal_node_by_instance_uuid(instance['uuid']) - if node: - pifs = db.bm_interface_get_all_by_bm_node_id(context, node['id']) - for pif in pifs: - if pif['vif_uuid']: - db.bm_interface_set_vif_uuid(context, pif['id'], None) - for vif in network_info: - self.vif_driver.plug(instance, vif) - - def _unplug_vifs(self, instance, network_info): - for vif in network_info: - self.vif_driver.unplug(instance, vif) - - def manage_image_cache(self, context, all_instances): - """Manage the local cache of images.""" - self.image_cache_manager.update(context, all_instances) - - def get_console_output(self, context, instance): - node = _get_baremetal_node_by_instance_uuid(instance.uuid) - return self.driver.get_console_output(node, instance) - - def get_available_nodes(self, refresh=False): - context = nova_context.get_admin_context() - return [str(n['uuid']) for n in - db.bm_node_get_all(context, service_host=CONF.host)] - - def dhcp_options_for_instance(self, instance): - return self.driver.dhcp_options_for_instance(instance) diff --git a/nova/virt/baremetal/fake.py b/nova/virt/baremetal/fake.py deleted file mode 100644 index 952549ec5f..0000000000 --- a/nova/virt/baremetal/fake.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright (c) 2011 University of Southern California / ISI -# 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. - -from nova.virt.baremetal import base -from nova.virt import firewall - - -class FakeDriver(base.NodeDriver): - - def cache_images(self, context, node, instance, **kwargs): - pass - - def destroy_images(self, context, node, instance): - pass - - def activate_bootloader(self, context, node, instance, **kwargs): - pass - - def deactivate_bootloader(self, context, node, instance): - pass - - def activate_node(self, context, node, instance): - """For operations after power on.""" - pass - - def deactivate_node(self, context, node, instance): - """For operations before power off.""" - pass - - def get_console_output(self, node, instance): - return 'fake\nconsole\noutput for instance %s' % instance.id - - -class FakePowerManager(base.PowerManager): - - def __init__(self, **kwargs): - super(FakePowerManager, self).__init__(**kwargs) - - -class FakeFirewallDriver(firewall.NoopFirewallDriver): - - def __init__(self): - super(FakeFirewallDriver, self).__init__() - - -class FakeVifDriver(object): - - def __init__(self): - super(FakeVifDriver, self).__init__() - - def plug(self, instance, vif): - pass - - def unplug(self, instance, vif): - pass - - -class FakeVolumeDriver(object): - - def __init__(self, virtapi): - super(FakeVolumeDriver, self).__init__() - self.virtapi = virtapi - self._initiator = "fake_initiator" - - def attach_volume(self, connection_info, instance, mountpoint): - pass - - def detach_volume(self, connection_info, instance, mountpoint): - pass diff --git a/nova/virt/baremetal/iboot_pdu.py b/nova/virt/baremetal/iboot_pdu.py deleted file mode 100644 index 134c926ac2..0000000000 --- a/nova/virt/baremetal/iboot_pdu.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright 2013 Red Hat Inc. -# 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. -# -# iBoot Power Driver - -from oslo.utils import importutils - -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base - -iboot = importutils.try_import('iboot') - - -LOG = logging.getLogger(__name__) - - -class IBootManager(base.PowerManager): - """iBoot Power Driver for Baremetal Nova Compute - - This PowerManager class provides a mechanism for controlling power state - via an iBoot capable device (tested with an iBoot G2). - - Requires installation of python-iboot: - - https://github.com/darkip/python-iboot - - """ - def __init__(self, **kwargs): - node = kwargs.pop('node', {}) - addr_relay = str(node['pm_address']).split(',') - - if len(addr_relay) > 1: - try: - self.relay_id = int(addr_relay[1]) - except ValueError: - msg = _("iboot PDU relay ID must be an integer.") - raise exception.InvalidParameterValue(msg) - else: - self.relay_id = 1 - - addr_port = addr_relay[0].split(':') - self.address = addr_port[0] - if len(addr_port) > 1: - try: - self.port = int(addr_port[1]) - except ValueError: - msg = _("iboot PDU port must be an integer.") - raise exception.InvalidParameterValue(msg) - else: - self.port = 9100 - - self.user = str(node['pm_user']) - self.password = str(node['pm_password']) - instance = kwargs.pop('instance', {}) - self.node_name = instance.get('hostname', "") - self.state = None - self.conn = None - - def _create_connection(self): - if not self.conn: - self.conn = iboot.iBootInterface(self.address, self.user, - self.password, port=self.port, - num_relays=self.relay_id) - return self.conn - - def _switch(self, relay_id, enabled): - return self.conn.switch(relay_id, enabled) - - def _get_relay(self, relay_id): - return self.conn.get_relays()[relay_id - 1] - - def activate_node(self): - LOG.info(_("activate_node name %s"), self.node_name) - self._create_connection() - self._switch(self.relay_id, True) - - if self.is_power_on(): - self.state = baremetal_states.ACTIVE - else: - self.state = baremetal_states.ERROR - - return self.state - - def reboot_node(self): - LOG.info(_("reboot_node: %s"), self.node_name) - self._create_connection() - self._switch(self.relay_id, False) - self._switch(self.relay_id, True) - - if self.is_power_on(): - self.state = baremetal_states.ACTIVE - else: - self.state = baremetal_states.ERROR - - return self.state - - def deactivate_node(self): - LOG.info(_("deactivate_node name %s"), self.node_name) - self._create_connection() - if self.is_power_on(): - self._switch(self.relay_id, False) - - if self.is_power_on(): - self.state = baremetal_states.ERROR - else: - self.state = baremetal_states.DELETED - - return self.state - - def is_power_on(self): - LOG.debug("Checking if %s is running", self.node_name) - self._create_connection() - return self._get_relay(self.relay_id) diff --git a/nova/virt/baremetal/ipmi.py b/nova/virt/baremetal/ipmi.py deleted file mode 100644 index 83dbe4d5bb..0000000000 --- a/nova/virt/baremetal/ipmi.py +++ /dev/null @@ -1,303 +0,0 @@ -# coding=utf-8 - -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -""" -Baremetal IPMI power manager. -""" - -import os -import stat -import tempfile - -from oslo.config import cfg - -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.openstack.common import loopingcall -from nova import paths -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base -from nova.virt.baremetal import utils as bm_utils - -opts = [ - cfg.StrOpt('terminal', - default='shellinaboxd', - help='Path to baremetal terminal program'), - cfg.StrOpt('terminal_cert_dir', - help='Path to baremetal terminal SSL cert(PEM)'), - cfg.StrOpt('terminal_pid_dir', - default=paths.state_path_def('baremetal/console'), - help='Path to directory stores pidfiles of baremetal_terminal'), - cfg.IntOpt('ipmi_power_retry', - default=10, - help='Maximal number of retries for IPMI operations'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(opts, baremetal_group) - -LOG = logging.getLogger(__name__) - - -def _make_password_file(password): - fd, path = tempfile.mkstemp() - os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR) - with os.fdopen(fd, "w") as f: - # NOTE(r-mibu): Since ipmitool hangs with an empty password file, - # we have to write '\0' if password was empty. - # see https://bugs.launchpad.net/nova/+bug/1237802 for more details - f.write(password or b"\0") - return path - - -def _get_console_pid_path(node_id): - name = "%s.pid" % node_id - path = os.path.join(CONF.baremetal.terminal_pid_dir, name) - return path - - -def _get_console_pid(node_id): - pid_path = _get_console_pid_path(node_id) - if os.path.exists(pid_path): - with open(pid_path, 'r') as f: - pid_str = f.read() - try: - return int(pid_str) - except ValueError: - LOG.warn(_("pid file %s does not contain any pid"), pid_path) - return None - - -class IPMI(base.PowerManager): - """IPMI Power Driver for Baremetal Nova Compute - - This PowerManager class provides mechanism for controlling the power state - of physical hardware via IPMI calls. It also provides serial console access - where available. - - """ - - def __init__(self, node, **kwargs): - self.state = None - self.retries = None - self.node_id = node['id'] - self.address = node['pm_address'] - self.user = node['pm_user'] - self.password = node['pm_password'] - self.port = node['terminal_port'] - - if self.node_id is None: - raise exception.InvalidParameterValue(_("Node id not supplied " - "to IPMI")) - if self.address is None: - raise exception.InvalidParameterValue(_("Address not supplied " - "to IPMI")) - if self.user is None: - raise exception.InvalidParameterValue(_("User not supplied " - "to IPMI")) - if self.password is None: - raise exception.InvalidParameterValue(_("Password not supplied " - "to IPMI")) - - def _exec_ipmitool(self, command): - args = ['ipmitool', - '-I', - 'lanplus', - '-H', - self.address, - '-U', - self.user, - '-f'] - pwfile = _make_password_file(self.password) - try: - args.append(pwfile) - args.extend(command.split(" ")) - out, err = utils.execute(*args, attempts=3) - LOG.debug("ipmitool stdout: '%(out)s', stderr: '%(err)s'", - {'out': out, 'err': err}) - return out, err - finally: - bm_utils.unlink_without_raise(pwfile) - - def _power_on(self): - """Turn the power to this node ON.""" - - def _wait_for_power_on(): - """Called at an interval until the node's power is on.""" - - if self.is_power_on(): - self.state = baremetal_states.ACTIVE - raise loopingcall.LoopingCallDone() - if self.retries > CONF.baremetal.ipmi_power_retry: - LOG.error(_("IPMI power on failed after %d tries") % ( - CONF.baremetal.ipmi_power_retry)) - self.state = baremetal_states.ERROR - raise loopingcall.LoopingCallDone() - try: - self.retries += 1 - if not self.power_on_called: - self._exec_ipmitool("power on") - self.power_on_called = True - except Exception: - LOG.exception(_("IPMI power on failed")) - - self.retries = 0 - self.power_on_called = False - timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_on) - timer.start(interval=1.0).wait() - - def _power_off(self): - """Turn the power to this node OFF.""" - - def _wait_for_power_off(): - """Called at an interval until the node's power is off.""" - - if self.is_power_on() is False: - self.state = baremetal_states.DELETED - raise loopingcall.LoopingCallDone() - if self.retries > CONF.baremetal.ipmi_power_retry: - LOG.error(_("IPMI power off failed after %d tries") % ( - CONF.baremetal.ipmi_power_retry)) - self.state = baremetal_states.ERROR - raise loopingcall.LoopingCallDone() - try: - self.retries += 1 - if not self.power_off_called: - self._exec_ipmitool("power off") - self.power_off_called = True - except Exception: - LOG.exception(_("IPMI power off failed")) - - self.retries = 0 - self.power_off_called = False - timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_off) - timer.start(interval=1.0).wait() - - def _set_pxe_for_next_boot(self): - try: - self._exec_ipmitool("chassis bootdev pxe options=persistent") - except Exception: - LOG.exception(_("IPMI set next bootdev failed")) - - def activate_node(self): - """Turns the power to node ON. - - Sets node next-boot to PXE and turns the power on, - waiting up to ipmi_power_retry/2 seconds for confirmation - that the power is on. - - :returns: One of baremetal_states.py, representing the new state. - """ - if self.is_power_on() and self.state == baremetal_states.ACTIVE: - LOG.warning(_("Activate node called, but node %s " - "is already active") % self.address) - self._set_pxe_for_next_boot() - self._power_on() - return self.state - - def reboot_node(self): - """Cycles the power to a node. - - Turns the power off, sets next-boot to PXE, and turns the power on. - Each action waits up to ipmi_power_retry/2 seconds for confirmation - that the power state has changed. - - :returns: One of baremetal_states.py, representing the new state. - """ - self._power_off() - self._set_pxe_for_next_boot() - self._power_on() - return self.state - - def deactivate_node(self): - """Turns the power to node OFF. - - Turns the power off, and waits up to ipmi_power_retry/2 seconds - for confirmation that the power is off. - - :returns: One of baremetal_states.py, representing the new state. - """ - self._power_off() - return self.state - - def is_power_on(self): - """Check if the power is currently on. - - :returns: True if on; False if off; None if unable to determine. - """ - # NOTE(deva): string matching based on - # http://ipmitool.cvs.sourceforge.net/ - # viewvc/ipmitool/ipmitool/lib/ipmi_chassis.c - res = self._exec_ipmitool("power status")[0] - if res == ("Chassis Power is on\n"): - return True - elif res == ("Chassis Power is off\n"): - return False - return None - - def start_console(self): - if not self.port: - return - args = [] - args.append(CONF.baremetal.terminal) - if CONF.baremetal.terminal_cert_dir: - args.append("-c") - args.append(CONF.baremetal.terminal_cert_dir) - else: - args.append("-t") - args.append("-p") - args.append(str(self.port)) - args.append("--background=%s" % _get_console_pid_path(self.node_id)) - args.append("-s") - - try: - pwfile = _make_password_file(self.password) - ipmi_args = "/:%(uid)s:%(gid)s:HOME:ipmitool -H %(address)s" \ - " -I lanplus -U %(user)s -f %(pwfile)s sol activate" \ - % {'uid': os.getuid(), - 'gid': os.getgid(), - 'address': self.address, - 'user': self.user, - 'pwfile': pwfile, - } - - args.append(ipmi_args) - # Run shellinaboxd without pipes. Otherwise utils.execute() waits - # infinitely since shellinaboxd does not close passed fds. - x = ["'" + arg.replace("'", "'\\''") + "'" for arg in args] - x.append('/dev/null') - x.append('2>&1') - utils.execute(' '.join(x), shell=True) - finally: - bm_utils.unlink_without_raise(pwfile) - - def stop_console(self): - console_pid = _get_console_pid(self.node_id) - if console_pid: - # Allow exitcode 99 (RC_UNAUTHORIZED) - utils.execute('kill', '-TERM', str(console_pid), - run_as_root=True, - check_exit_code=[0, 99]) - bm_utils.unlink_without_raise(_get_console_pid_path(self.node_id)) diff --git a/nova/virt/baremetal/net-dhcp.ubuntu.template b/nova/virt/baremetal/net-dhcp.ubuntu.template deleted file mode 100644 index a845a30fb7..0000000000 --- a/nova/virt/baremetal/net-dhcp.ubuntu.template +++ /dev/null @@ -1,17 +0,0 @@ -# Injected by Nova on instance boot -# -# This file describes the network interfaces available on your system -# and how to activate them. For more information, see interfaces(5). - -# The loopback network interface -auto lo -iface lo inet loopback - -{% for ifc in interfaces -%} -auto {{ ifc.name }} -iface {{ ifc.name }} inet dhcp - -{% if use_ipv6 -%} -iface {{ ifc.name }} inet6 dhcp -{%- endif %} -{%- endfor %} diff --git a/nova/virt/baremetal/net-static.ubuntu.template b/nova/virt/baremetal/net-static.ubuntu.template deleted file mode 100644 index cee573dffd..0000000000 --- a/nova/virt/baremetal/net-static.ubuntu.template +++ /dev/null @@ -1,27 +0,0 @@ -# Injected by Nova on instance boot -# -# This file describes the network interfaces available on your system -# and how to activate them. For more information, see interfaces(5). - -# The loopback network interface -auto lo -iface lo inet loopback - -{% for ifc in interfaces -%} -auto {{ ifc.name }} -iface {{ ifc.name }} inet static - address {{ ifc.address }} - netmask {{ ifc.netmask }} - gateway {{ ifc.gateway }} -{%- if ifc.dns %} - dns-nameservers {{ ifc.dns }} -{%- endif %} - -{% if use_ipv6 -%} -iface {{ ifc.name }} inet6 static - address {{ ifc.address_v6 }} - netmask {{ ifc.netmask_v6 }} - gateway {{ ifc.gateway_v6 }} -{%- endif %} - -{%- endfor %} diff --git a/nova/virt/baremetal/pxe.py b/nova/virt/baremetal/pxe.py deleted file mode 100644 index 74fda9283d..0000000000 --- a/nova/virt/baremetal/pxe.py +++ /dev/null @@ -1,503 +0,0 @@ -# Copyright 2012,2014 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -""" -Class for PXE bare-metal nodes. -""" - -import datetime -import os - -import jinja2 -from oslo.config import cfg -from oslo.db import exception as db_exc -from oslo.utils import timeutils - -from nova.compute import flavors -from nova import exception -from nova.i18n import _ -from nova import objects -from nova.openstack.common import fileutils -from nova.openstack.common import log as logging -from nova.openstack.common import loopingcall -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base -from nova.virt.baremetal import db -from nova.virt.baremetal import utils as bm_utils - -pxe_opts = [ - cfg.StrOpt('deploy_kernel', - help='Default kernel image ID used in deployment phase'), - cfg.StrOpt('deploy_ramdisk', - help='Default ramdisk image ID used in deployment phase'), - cfg.StrOpt('net_config_template', - default='$pybasedir/nova/virt/baremetal/' - 'net-dhcp.ubuntu.template', - help='Template file for injected network config'), - cfg.StrOpt('pxe_append_params', - default='nofb nomodeset vga=normal', - help='Additional append parameters for baremetal PXE boot'), - cfg.StrOpt('pxe_config_template', - default='$pybasedir/nova/virt/baremetal/pxe_config.template', - help='Template file for PXE configuration'), - cfg.BoolOpt('use_file_injection', - help='If True, enable file injection for network info, ' - 'files and admin password', - default=False), - cfg.IntOpt('pxe_deploy_timeout', - help='Timeout for PXE deployments. Default: 0 (unlimited)', - default=0), - cfg.BoolOpt('pxe_network_config', - help='If set, pass the network configuration details to the ' - 'initramfs via cmdline.', - default=False), - cfg.StrOpt('pxe_bootfile_name', - help='This gets passed to Neutron as the bootfile dhcp ' - 'parameter.', - default='pxelinux.0'), - ] - -LOG = logging.getLogger(__name__) - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(pxe_opts, baremetal_group) -CONF.import_opt('use_ipv6', 'nova.netconf') - - -def build_pxe_network_config(network_info): - interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6) - template = None - if not CONF.use_ipv6: - template = "ip=%(address)s::%(gateway)s:%(netmask)s::%(name)s:off" - else: - template = ("ip=[%(address_v6)s]::[%(gateway_v6)s]:" - "[%(netmask_v6)s]::%(name)s:off") - - net_config = [template % iface for iface in interfaces] - return ' '.join(net_config) - - -def build_pxe_config(deployment_id, deployment_key, deployment_iscsi_iqn, - deployment_aki_path, deployment_ari_path, - aki_path, ari_path, network_info): - """Build the PXE config file for a node - - This method builds the PXE boot configuration file for a node, - given all the required parameters. - - The resulting file has both a "deploy" and "boot" label, which correspond - to the two phases of booting. This may be extended later. - - """ - LOG.debug("Building PXE config for deployment %s.", deployment_id) - - network_config = None - if network_info and CONF.baremetal.pxe_network_config: - network_config = build_pxe_network_config(network_info) - - pxe_options = { - 'deployment_id': deployment_id, - 'deployment_key': deployment_key, - 'deployment_iscsi_iqn': deployment_iscsi_iqn, - 'deployment_aki_path': deployment_aki_path, - 'deployment_ari_path': deployment_ari_path, - 'aki_path': aki_path, - 'ari_path': ari_path, - 'pxe_append_params': CONF.baremetal.pxe_append_params, - 'pxe_network_config': network_config, - } - tmpl_path, tmpl_file = os.path.split(CONF.baremetal.pxe_config_template) - env = jinja2.Environment(loader=jinja2.FileSystemLoader(tmpl_path)) - template = env.get_template(tmpl_file) - return template.render({'pxe_options': pxe_options, - 'ROOT': '${ROOT}'}) - - -def build_network_config(network_info): - interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6) - tmpl_path, tmpl_file = os.path.split(CONF.baremetal.net_config_template) - env = jinja2.Environment(loader=jinja2.FileSystemLoader(tmpl_path)) - template = env.get_template(tmpl_file) - return template.render({'interfaces': interfaces, - 'use_ipv6': CONF.use_ipv6}) - - -def get_deploy_aki_id(flavor): - return flavor.get('extra_specs', {}).\ - get('baremetal:deploy_kernel_id', CONF.baremetal.deploy_kernel) - - -def get_deploy_ari_id(flavor): - return flavor.get('extra_specs', {}).\ - get('baremetal:deploy_ramdisk_id', CONF.baremetal.deploy_ramdisk) - - -def get_image_dir_path(instance): - """Generate the dir for an instances disk.""" - return os.path.join(CONF.instances_path, instance['name']) - - -def get_image_file_path(instance): - """Generate the full path for an instances disk.""" - return os.path.join(CONF.instances_path, instance['name'], 'disk') - - -def get_pxe_config_file_path(instance): - """Generate the path for an instances PXE config file.""" - return os.path.join(CONF.baremetal.tftp_root, instance['uuid'], 'config') - - -def get_partition_sizes(instance): - flavor = flavors.extract_flavor(instance) - root_mb = flavor['root_gb'] * 1024 - swap_mb = flavor['swap'] - ephemeral_mb = flavor['ephemeral_gb'] * 1024 - - # NOTE(deva): For simpler code paths on the deployment side, - # we always create a swap partition. If the flavor - # does not specify any swap, we default to 1MB - if swap_mb < 1: - swap_mb = 1 - - return (root_mb, swap_mb, ephemeral_mb) - - -def get_pxe_mac_path(mac): - """Convert a MAC address into a PXE config file name.""" - return os.path.join( - CONF.baremetal.tftp_root, - 'pxelinux.cfg', - "01-" + mac.replace(":", "-").lower() - ) - - -def get_tftp_image_info(instance, flavor): - """Generate the paths for tftp files for this instance - - Raises NovaException if - - instance does not contain kernel_id or ramdisk_id - - deploy_kernel_id or deploy_ramdisk_id can not be read from - flavor['extra_specs'] and defaults are not set - - """ - image_info = { - 'kernel': [None, None], - 'ramdisk': [None, None], - 'deploy_kernel': [None, None], - 'deploy_ramdisk': [None, None], - } - try: - image_info['kernel'][0] = str(instance['kernel_id']) - image_info['ramdisk'][0] = str(instance['ramdisk_id']) - image_info['deploy_kernel'][0] = get_deploy_aki_id(flavor) - image_info['deploy_ramdisk'][0] = get_deploy_ari_id(flavor) - except KeyError: - pass - - missing_labels = [] - for label in image_info.keys(): - (uuid, path) = image_info[label] - if not uuid: - missing_labels.append(label) - else: - image_info[label][1] = os.path.join(CONF.baremetal.tftp_root, - instance['uuid'], label) - if missing_labels: - raise exception.NovaException(_( - "Can not activate PXE bootloader. The following boot parameters " - "were not passed to baremetal driver: %s") % missing_labels) - return image_info - - -class PXE(base.NodeDriver): - """PXE bare metal driver.""" - - def __init__(self, virtapi): - super(PXE, self).__init__(virtapi) - - def _collect_mac_addresses(self, context, node): - macs = set() - for nic in db.bm_interface_get_all_by_bm_node_id(context, node['id']): - if nic['address']: - macs.add(nic['address']) - return sorted(macs) - - def _cache_tftp_images(self, context, instance, image_info): - """Fetch the necessary kernels and ramdisks for the instance.""" - fileutils.ensure_tree( - os.path.join(CONF.baremetal.tftp_root, instance['uuid'])) - - LOG.debug("Fetching kernel and ramdisk for instance %s", - instance['name']) - for label in image_info.keys(): - (uuid, path) = image_info[label] - bm_utils.cache_image( - context=context, - target=path, - image_id=uuid, - user_id=instance['user_id'], - project_id=instance['project_id'], - ) - - def _cache_image(self, context, instance, image_meta): - """Fetch the instance's image from Glance - - This method pulls the relevant AMI and associated kernel and ramdisk, - and the deploy kernel and ramdisk from Glance, and writes them - to the appropriate places on local disk. - - Both sets of kernel and ramdisk are needed for PXE booting, so these - are stored under CONF.baremetal.tftp_root. - - At present, the AMI is cached and certain files are injected. - Debian/ubuntu-specific assumptions are made regarding the injected - files. In a future revision, this functionality will be replaced by a - more scalable and os-agnostic approach: the deployment ramdisk will - fetch from Glance directly, and write its own last-mile configuration. - - """ - fileutils.ensure_tree(get_image_dir_path(instance)) - image_path = get_image_file_path(instance) - - LOG.debug("Fetching image %(ami)s for instance %(name)s", - {'ami': image_meta['id'], 'name': instance['name']}) - bm_utils.cache_image(context=context, - target=image_path, - image_id=image_meta['id'], - user_id=instance['user_id'], - project_id=instance['project_id'], - clean=True, - ) - - return [image_meta['id'], image_path] - - def _inject_into_image(self, context, node, instance, network_info, - injected_files=None, admin_password=None): - """Inject last-mile configuration into instances image - - Much of this method is a hack around DHCP and cloud-init - not working together with baremetal provisioning yet. - - """ - # NOTE(deva): We assume that if we're not using a kernel, - # then the target partition is the first partition - partition = None - if not instance['kernel_id']: - partition = "1" - - ssh_key = None - if 'key_data' in instance and instance['key_data']: - ssh_key = str(instance['key_data']) - - if injected_files is None: - injected_files = [] - else: - # NOTE(deva): copy so we don't modify the original - injected_files = list(injected_files) - - net_config = build_network_config(network_info) - - if instance['hostname']: - injected_files.append(('/etc/hostname', instance['hostname'])) - - LOG.debug("Injecting files into image for instance %(name)s", - {'name': instance['name']}) - - bm_utils.inject_into_image( - image=get_image_file_path(instance), - key=ssh_key, - net=net_config, - metadata=utils.instance_meta(instance), - admin_password=admin_password, - files=injected_files, - partition=partition, - ) - - def cache_images(self, context, node, instance, - admin_password, image_meta, injected_files, network_info): - """Prepare all the images for this instance.""" - flavor = objects.Flavor.get_by_id(context, - instance['instance_type_id']) - tftp_image_info = get_tftp_image_info(instance, flavor) - self._cache_tftp_images(context, instance, tftp_image_info) - - self._cache_image(context, instance, image_meta) - if CONF.baremetal.use_file_injection: - self._inject_into_image(context, node, instance, network_info, - injected_files, admin_password) - - def destroy_images(self, context, node, instance): - """Delete instance's image file.""" - bm_utils.unlink_without_raise(get_image_file_path(instance)) - bm_utils.rmtree_without_raise(get_image_dir_path(instance)) - - def dhcp_options_for_instance(self, instance): - return [{'opt_name': 'bootfile-name', - 'opt_value': CONF.baremetal.pxe_bootfile_name}, - {'opt_name': 'server-ip-address', - 'opt_value': CONF.my_ip}, - {'opt_name': 'tftp-server', - 'opt_value': CONF.my_ip} - ] - - def activate_bootloader(self, context, node, instance, network_info): - """Configure PXE boot loader for an instance - - Kernel and ramdisk images are downloaded by cache_tftp_images, - and stored in /tftpboot/{uuid}/ - - This method writes the instances config file, and then creates - symlinks for each MAC address in the instance. - - By default, the complete layout looks like this: - - /tftpboot/ - ./{uuid}/ - kernel - ramdisk - deploy_kernel - deploy_ramdisk - config - ./pxelinux.cfg/ - {mac} -> ../{uuid}/config - """ - flavor = objects.Flavor.get_by_id(context, - instance['instance_type_id']) - image_info = get_tftp_image_info(instance, flavor) - (root_mb, swap_mb, ephemeral_mb) = get_partition_sizes(instance) - pxe_config_file_path = get_pxe_config_file_path(instance) - image_file_path = get_image_file_path(instance) - - deployment_key = bm_utils.random_alnum(32) - deployment_iscsi_iqn = "iqn-%s" % instance['uuid'] - db.bm_node_update(context, node['id'], - {'deploy_key': deployment_key, - 'image_path': image_file_path, - 'pxe_config_path': pxe_config_file_path, - 'root_mb': root_mb, - 'swap_mb': swap_mb, - 'ephemeral_mb': ephemeral_mb}) - pxe_config = build_pxe_config( - node['id'], - deployment_key, - deployment_iscsi_iqn, - image_info['deploy_kernel'][1], - image_info['deploy_ramdisk'][1], - image_info['kernel'][1], - image_info['ramdisk'][1], - network_info, - ) - bm_utils.write_to_file(pxe_config_file_path, pxe_config) - - macs = self._collect_mac_addresses(context, node) - for mac in macs: - mac_path = get_pxe_mac_path(mac) - bm_utils.unlink_without_raise(mac_path) - bm_utils.create_link_without_raise(pxe_config_file_path, mac_path) - - def deactivate_bootloader(self, context, node, instance): - """Delete PXE bootloader images and config.""" - try: - db.bm_node_update(context, node['id'], - {'deploy_key': None, - 'image_path': None, - 'pxe_config_path': None, - 'root_mb': 0, - 'swap_mb': 0}) - except exception.NodeNotFound: - pass - - # NOTE(danms): the flavor extra_specs do not need to be - # present/correct at deactivate time, so pass something empty - # to avoid an extra lookup - flavor = dict(extra_specs={ - 'baremetal:deploy_ramdisk_id': 'ignore', - 'baremetal:deploy_kernel_id': 'ignore'}) - try: - image_info = get_tftp_image_info(instance, flavor) - except exception.NovaException: - pass - else: - for label in image_info.keys(): - (uuid, path) = image_info[label] - bm_utils.unlink_without_raise(path) - - bm_utils.unlink_without_raise(get_pxe_config_file_path(instance)) - try: - macs = self._collect_mac_addresses(context, node) - except db_exc.DBError: - pass - else: - for mac in macs: - bm_utils.unlink_without_raise(get_pxe_mac_path(mac)) - - bm_utils.rmtree_without_raise( - os.path.join(CONF.baremetal.tftp_root, instance['uuid'])) - - def activate_node(self, context, node, instance): - """Wait for PXE deployment to complete.""" - - locals = {'error': '', 'started': False} - - def _wait_for_deploy(): - """Called at an interval until the deployment completes.""" - try: - row = db.bm_node_get(context, node['id']) - if instance['uuid'] != row.get('instance_uuid'): - locals['error'] = _("Node associated with another instance" - " while waiting for deploy of %s") - raise loopingcall.LoopingCallDone() - - status = row.get('task_state') - if (status == baremetal_states.DEPLOYING - and locals['started'] is False): - LOG.info(_("PXE deploy started for instance %s") - % instance['uuid']) - locals['started'] = True - elif status in (baremetal_states.DEPLOYDONE, - baremetal_states.ACTIVE): - LOG.info(_("PXE deploy completed for instance %s") - % instance['uuid']) - raise loopingcall.LoopingCallDone() - elif status == baremetal_states.DEPLOYFAIL: - locals['error'] = _("PXE deploy failed for instance %s") - except exception.NodeNotFound: - locals['error'] = _("Baremetal node deleted while waiting " - "for deployment of instance %s") - - if (CONF.baremetal.pxe_deploy_timeout and - timeutils.utcnow() > expiration): - locals['error'] = _("Timeout reached while waiting for " - "PXE deploy of instance %s") - if locals['error']: - raise loopingcall.LoopingCallDone() - - expiration = timeutils.utcnow() + datetime.timedelta( - seconds=CONF.baremetal.pxe_deploy_timeout) - timer = loopingcall.FixedIntervalLoopingCall(_wait_for_deploy) - timer.start(interval=1).wait() - - if locals['error']: - raise exception.InstanceDeployFailure( - locals['error'] % instance['uuid']) - - def deactivate_node(self, context, node, instance): - pass diff --git a/nova/virt/baremetal/pxe_config.template b/nova/virt/baremetal/pxe_config.template deleted file mode 100644 index 1780de1989..0000000000 --- a/nova/virt/baremetal/pxe_config.template +++ /dev/null @@ -1,11 +0,0 @@ -default deploy - -label deploy -kernel {{ pxe_options.deployment_aki_path }} -append initrd={{ pxe_options.deployment_ari_path }} selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn={{ pxe_options.deployment_iscsi_iqn }} deployment_id={{ pxe_options.deployment_id }} deployment_key={{ pxe_options.deployment_key }} troubleshoot=0 {{ pxe_options.pxe_append_params|default("", true) }} -ipappend 3 - - -label boot -kernel {{ pxe_options.aki_path }} -append initrd={{ pxe_options.ari_path }} root={{ ROOT }} ro {{ pxe_options.pxe_append_params|default("", true) }} {{ pxe_options.pxe_network_config|default("", true) }} diff --git a/nova/virt/baremetal/tilera.py b/nova/virt/baremetal/tilera.py deleted file mode 100644 index 78fa987345..0000000000 --- a/nova/virt/baremetal/tilera.py +++ /dev/null @@ -1,351 +0,0 @@ -# Copyright (c) 2011-2013 University of Southern California / ISI -# 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. - -""" -Class for Tilera bare-metal nodes. -""" - -import base64 -import os - -import jinja2 -from oslo.config import cfg -from oslo.db import exception as db_exc - -from nova.compute import flavors -from nova import exception -from nova.i18n import _ -from nova.openstack.common import fileutils -from nova.openstack.common import log as logging -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base -from nova.virt.baremetal import db -from nova.virt.baremetal import utils as bm_utils - - -LOG = logging.getLogger(__name__) - -CONF = cfg.CONF -CONF.import_opt('use_ipv6', 'nova.netconf') -CONF.import_opt('net_config_template', 'nova.virt.baremetal.pxe', - group='baremetal') - - -def build_network_config(network_info): - interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6) - tmpl_path, tmpl_file = os.path.split(CONF.baremetal.net_config_template) - env = jinja2.Environment(loader=jinja2.FileSystemLoader(tmpl_path)) - template = env.get_template(tmpl_file) - return template.render({'interfaces': interfaces, - 'use_ipv6': CONF.use_ipv6}) - - -def get_image_dir_path(instance): - """Generate the dir for an instances disk.""" - return os.path.join(CONF.instances_path, instance['name']) - - -def get_image_file_path(instance): - """Generate the full path for an instances disk.""" - return os.path.join(CONF.instances_path, instance['name'], 'disk') - - -def get_tilera_nfs_path(node_id): - """Generate the path for an instances Tilera nfs.""" - tilera_nfs_dir = "fs_" + str(node_id) - return os.path.join(CONF.baremetal.tftp_root, tilera_nfs_dir) - - -def get_partition_sizes(instance): - flavor = flavors.extract_flavor(instance) - root_mb = flavor['root_gb'] * 1024 - swap_mb = flavor['swap'] - - if swap_mb < 1: - swap_mb = 1 - - return (root_mb, swap_mb) - - -def get_tftp_image_info(instance): - """Generate the paths for tftp files for this instance. - - Raises NovaException if - - instance does not contain kernel_id - """ - image_info = { - 'kernel': [None, None], - } - try: - image_info['kernel'][0] = str(instance['kernel_id']) - except KeyError: - pass - - missing_labels = [] - for label in image_info.keys(): - (uuid, path) = image_info[label] - if not uuid: - missing_labels.append(label) - else: - image_info[label][1] = os.path.join(CONF.baremetal.tftp_root, - instance['uuid'], label) - if missing_labels: - raise exception.NovaException(_( - "Can not activate Tilera bootloader. " - "The following boot parameters " - "were not passed to baremetal driver: %s") % missing_labels) - return image_info - - -class Tilera(base.NodeDriver): - """Tilera bare metal driver.""" - - def __init__(self, virtapi): - super(Tilera, self).__init__(virtapi) - - def _collect_mac_addresses(self, context, node): - macs = set() - for nic in db.bm_interface_get_all_by_bm_node_id(context, node['id']): - if nic['address']: - macs.add(nic['address']) - return sorted(macs) - - def _cache_tftp_images(self, context, instance, image_info): - """Fetch the necessary kernels and ramdisks for the instance.""" - fileutils.ensure_tree( - os.path.join(CONF.baremetal.tftp_root, instance['uuid'])) - - LOG.debug("Fetching kernel and ramdisk for instance %s", - instance['name']) - for label in image_info.keys(): - (uuid, path) = image_info[label] - bm_utils.cache_image( - context=context, - target=path, - image_id=uuid, - user_id=instance['user_id'], - project_id=instance['project_id'], - ) - - def _cache_image(self, context, instance, image_meta): - """Fetch the instance's image from Glance - - This method pulls the relevant AMI and associated kernel and ramdisk, - and the deploy kernel and ramdisk from Glance, and writes them - to the appropriate places on local disk. - - Both sets of kernel and ramdisk are needed for Tilera booting, so these - are stored under CONF.baremetal.tftp_root. - - At present, the AMI is cached and certain files are injected. - Debian/ubuntu-specific assumptions are made regarding the injected - files. In a future revision, this functionality will be replaced by a - more scalable and os-agnostic approach: the deployment ramdisk will - fetch from Glance directly, and write its own last-mile configuration. - """ - fileutils.ensure_tree(get_image_dir_path(instance)) - image_path = get_image_file_path(instance) - - LOG.debug("Fetching image %(ami)s for instance %(name)s", - {'ami': image_meta['id'], 'name': instance['name']}) - bm_utils.cache_image(context=context, - target=image_path, - image_id=image_meta['id'], - user_id=instance['user_id'], - project_id=instance['project_id'], - clean=True, - ) - - return [image_meta['id'], image_path] - - def _inject_into_image(self, context, node, instance, network_info, - injected_files=None, admin_password=None): - """Inject last-mile configuration into instances image - - Much of this method is a hack around DHCP and cloud-init - not working together with baremetal provisioning yet. - """ - partition = None - if not instance['kernel_id']: - partition = "1" - - ssh_key = None - if 'key_data' in instance and instance['key_data']: - ssh_key = str(instance['key_data']) - - if injected_files is None: - injected_files = [] - else: - injected_files = list(injected_files) - - net_config = build_network_config(network_info) - - if instance['hostname']: - injected_files.append(('/etc/hostname', instance['hostname'])) - - LOG.debug("Injecting files into image for instance %(name)s", - {'name': instance['name']}) - - bm_utils.inject_into_image( - image=get_image_file_path(instance), - key=ssh_key, - net=net_config, - metadata=utils.instance_meta(instance), - admin_password=admin_password, - files=injected_files, - partition=partition, - ) - - def cache_images(self, context, node, instance, - admin_password, image_meta, injected_files, network_info): - """Prepare all the images for this instance.""" - tftp_image_info = get_tftp_image_info(instance) - self._cache_tftp_images(context, instance, tftp_image_info) - - self._cache_image(context, instance, image_meta) - self._inject_into_image(context, node, instance, network_info, - injected_files, admin_password) - - def destroy_images(self, context, node, instance): - """Delete instance's image file.""" - bm_utils.unlink_without_raise(get_image_file_path(instance)) - bm_utils.rmtree_without_raise(get_image_dir_path(instance)) - - def activate_bootloader(self, context, node, instance, network_info): - """Configure Tilera boot loader for an instance - - Kernel and ramdisk images are downloaded by cache_tftp_images, - and stored in /tftpboot/{uuid}/ - - This method writes the instances config file, and then creates - symlinks for each MAC address in the instance. - - By default, the complete layout looks like this:: - - /tftpboot/ - ./{uuid}/ - kernel - ./fs_node_id/ - - """ - get_tftp_image_info(instance) - (root_mb, swap_mb) = get_partition_sizes(instance) - tilera_nfs_path = get_tilera_nfs_path(node['id']) - image_file_path = get_image_file_path(instance) - - deployment_key = bm_utils.random_alnum(32) - db.bm_node_update(context, node['id'], - {'deploy_key': deployment_key, - 'image_path': image_file_path, - 'pxe_config_path': tilera_nfs_path, - 'root_mb': root_mb, - 'swap_mb': swap_mb}) - - if os.path.exists(image_file_path) and \ - os.path.exists(tilera_nfs_path): - utils.execute('mount', '-o', 'loop', image_file_path, - tilera_nfs_path, run_as_root=True) - - def deactivate_bootloader(self, context, node, instance): - """Delete Tilera bootloader images and config.""" - try: - db.bm_node_update(context, node['id'], - {'deploy_key': None, - 'image_path': None, - 'pxe_config_path': None, - 'root_mb': 0, - 'swap_mb': 0}) - except exception.NodeNotFound: - pass - - tilera_nfs_path = get_tilera_nfs_path(node['id']) - - if os.path.ismount(tilera_nfs_path): - utils.execute('rpc.mountd', run_as_root=True) - utils.execute('umount', '-f', tilera_nfs_path, run_as_root=True) - - try: - image_info = get_tftp_image_info(instance) - except exception.NovaException: - pass - else: - for label in image_info.keys(): - (uuid, path) = image_info[label] - bm_utils.unlink_without_raise(path) - - try: - self._collect_mac_addresses(context, node) - except db_exc.DBError: - pass - - if os.path.exists(os.path.join(CONF.baremetal.tftp_root, - instance['uuid'])): - bm_utils.rmtree_without_raise( - os.path.join(CONF.baremetal.tftp_root, instance['uuid'])) - - def _iptables_set(self, node_ip, user_data): - """Sets security setting (iptables:port) if needed. - - iptables -A INPUT -p tcp ! -s $IP --dport $PORT -j DROP - /tftpboot/iptables_rule script sets iptables rule on the given node. - """ - rule_path = CONF.baremetal.tftp_root + "/iptables_rule" - if user_data is not None: - open_ip = base64.b64decode(user_data) - utils.execute(rule_path, node_ip, open_ip) - - def activate_node(self, context, node, instance): - """Wait for Tilera deployment to complete.""" - - locals = {'error': '', 'started': False} - - try: - row = db.bm_node_get(context, node['id']) - if instance['uuid'] != row.get('instance_uuid'): - locals['error'] = _("Node associated with another instance" - " while waiting for deploy of %s") - - status = row.get('task_state') - if (status == baremetal_states.DEPLOYING and - locals['started'] is False): - LOG.info(_('Tilera deploy started for instance %s') - % instance['uuid']) - locals['started'] = True - elif status in (baremetal_states.DEPLOYDONE, - baremetal_states.BUILDING, - baremetal_states.ACTIVE): - LOG.info(_("Tilera deploy completed for instance %s") - % instance['uuid']) - node_ip = node['pm_address'] - user_data = instance['user_data'] - try: - self._iptables_set(node_ip, user_data) - except Exception: - self.deactivate_bootloader(context, node, instance) - raise exception.NovaException(_("Node is " - "unknown error state.")) - elif status == baremetal_states.DEPLOYFAIL: - locals['error'] = _("Tilera deploy failed for instance %s") - except exception.NodeNotFound: - locals['error'] = _("Baremetal node deleted while waiting " - "for deployment of instance %s") - - if locals['error']: - raise exception.InstanceDeployFailure( - locals['error'] % instance['uuid']) - - def deactivate_node(self, context, node, instance): - pass diff --git a/nova/virt/baremetal/tilera_pdu.py b/nova/virt/baremetal/tilera_pdu.py deleted file mode 100644 index 8bbb1a0615..0000000000 --- a/nova/virt/baremetal/tilera_pdu.py +++ /dev/null @@ -1,169 +0,0 @@ -# coding=utf-8 - -# Copyright (c) 2011-2013 University of Southern California / ISI -# 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. - -""" -Baremetal PDU power manager. -""" - -import time - -from oslo.config import cfg - -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.openstack.common import processutils -from nova import utils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base - -opts = [ - cfg.StrOpt('tile_pdu_ip', - default='10.0.100.1', - help='IP address of tilera pdu'), - cfg.StrOpt('tile_pdu_mgr', - default='/tftpboot/pdu_mgr', - help='Management script for tilera pdu'), - cfg.IntOpt('tile_pdu_off', - default=2, - help='Power status of tilera PDU is OFF'), - cfg.IntOpt('tile_pdu_on', - default=1, - help='Power status of tilera PDU is ON'), - cfg.IntOpt('tile_pdu_status', - default=9, - help='Power status of tilera PDU'), - cfg.IntOpt('tile_power_wait', - default=9, - help='Wait time in seconds until check the result ' - 'after tilera power operations'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(opts, baremetal_group) - -LOG = logging.getLogger(__name__) - - -class Pdu(base.PowerManager): - """PDU Power Driver for Baremetal Nova Compute - - This PowerManager class provides mechanism for controlling the power state - of physical hardware via PDU calls. - """ - - def __init__(self, node, **kwargs): - self.state = None - self.retries = None - self.node_id = node['id'] - self.address = node['pm_address'] - self.user = node['pm_user'] - self.password = node['pm_password'] - self.port = node['terminal_port'] - - if self.node_id is None: - raise exception.InvalidParameterValue(_("Node id not supplied " - "to PDU")) - if self.address is None: - raise exception.InvalidParameterValue(_("Address not supplied " - "to PDU")) - if self.user is None: - raise exception.InvalidParameterValue(_("User not supplied " - "to PDU")) - if self.password is None: - raise exception.InvalidParameterValue(_("Password not supplied " - "to PDU")) - - def _exec_pdutool(self, mode): - """Changes power state of the given node. - - According to the mode (1-ON, 2-OFF, 3-REBOOT), power state can be - changed. /tftpboot/pdu_mgr script handles power management of - PDU (Power Distribution Unit). - """ - if mode == CONF.baremetal.tile_pdu_status: - try: - utils.execute('ping', '-c1', self.address, - check_exit_code=True) - return CONF.baremetal.tile_pdu_on - except processutils.ProcessExecutionError: - return CONF.baremetal.tile_pdu_off - else: - try: - utils.execute(CONF.baremetal.tile_pdu_mgr, - CONF.baremetal.tile_pdu_ip, mode) - time.sleep(CONF.baremetal.tile_power_wait) - return mode - except processutils.ProcessExecutionError: - LOG.exception(_("PDU failed")) - - def _is_power(self, state): - out_err = self._exec_pdutool(CONF.baremetal.tile_pdu_status) - return out_err == state - - def _power_on(self): - """Turn the power to this node ON.""" - - try: - self._exec_pdutool(CONF.baremetal.tile_pdu_on) - if self._is_power(CONF.baremetal.tile_pdu_on): - self.state = baremetal_states.ACTIVE - else: - self.state = baremetal_states.ERROR - except Exception: - self.state = baremetal_states.ERROR - LOG.exception(_("PDU power on failed")) - - def _power_off(self): - """Turn the power to this node OFF.""" - - try: - self._exec_pdutool(CONF.baremetal.tile_pdu_off) - if self._is_power(CONF.baremetal.tile_pdu_off): - self.state = baremetal_states.DELETED - else: - self.state = baremetal_states.ERROR - except Exception: - self.state = baremetal_states.ERROR - LOG.exception(_("PDU power off failed")) - - def activate_node(self): - """Turns the power to node ON.""" - if (self._is_power(CONF.baremetal.tile_pdu_on) - and self.state == baremetal_states.ACTIVE): - LOG.warning(_("Activate node called, but node %s " - "is already active") % self.address) - self._power_on() - return self.state - - def reboot_node(self): - """Cycles the power to a node.""" - self._power_off() - self._power_on() - return self.state - - def deactivate_node(self): - """Turns the power to node OFF, regardless of current state.""" - self._power_off() - return self.state - - def is_power_on(self): - return self._is_power(CONF.baremetal.tile_pdu_on) diff --git a/nova/virt/baremetal/utils.py b/nova/virt/baremetal/utils.py deleted file mode 100644 index d45589e582..0000000000 --- a/nova/virt/baremetal/utils.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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. - -import errno -import os -import shutil - -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.virt.disk import api as disk_api -from nova.virt import images - -LOG = logging.getLogger(__name__) - - -def cache_image(context, target, image_id, user_id, project_id, clean=False): - if clean and os.path.exists(target): - os.unlink(target) - if not os.path.exists(target): - images.fetch_to_raw(context, image_id, target, user_id, project_id) - - -def inject_into_image(image, key, net, metadata, admin_password, files, - partition, use_cow=False): - try: - if os.path.exists(image): - disk_api.inject_data(image, key, net, metadata, admin_password, - files, partition, use_cow) - else: - LOG.warning(_('Image %s not found on disk storage. ' - 'Continue without injecting data'), image) - except Exception as e: - LOG.warn(_("Failed to inject data into image %(image)s. " - "Error: %(e)s"), {'image': image, 'e': e}) - - -def unlink_without_raise(path): - try: - os.unlink(path) - except OSError as e: - if e.errno == errno.ENOENT: - return - else: - LOG.warn(_("Failed to unlink %(path)s, error: %(e)s"), - {'path': path, 'e': e}) - - -def rmtree_without_raise(path): - try: - if os.path.isdir(path): - shutil.rmtree(path) - except OSError as e: - LOG.warn(_("Failed to remove dir %(path)s, error: %(e)s"), - {'path': path, 'e': e}) - - -def write_to_file(path, contents): - with open(path, 'w') as f: - f.write(contents) - - -def create_link_without_raise(source, link): - try: - os.symlink(source, link) - except OSError as e: - if e.errno == errno.EEXIST: - return - else: - LOG.warn(_("Failed to create symlink from %(source)s to %(link)s" - ", error: %(e)s"), - {'source': source, 'link': link, 'e': e}) - - -def random_alnum(count): - import random - import string - chars = string.ascii_uppercase + string.digits - return "".join(random.choice(chars) for _ in range(count)) - - -def map_network_interfaces(network_info, use_ipv6=False): - # TODO(deva): fix assumption that device names begin with "eth" - # and fix assumption about ordering - if not isinstance(network_info, list): - network_info = [network_info] - - interfaces = [] - for id, vif in enumerate(network_info): - address_v6 = gateway_v6 = netmask_v6 = None - address_v4 = gateway_v4 = netmask_v4 = dns_v4 = None - - if use_ipv6: - subnets_v6 = [s for s in vif['network']['subnets'] - if s['version'] == 6] - if len(subnets_v6): - address_v6 = subnets_v6[0]['ips'][0]['address'] - netmask_v6 = subnets_v6[0].as_netaddr()._prefixlen - gateway_v6 = subnets_v6[0]['gateway']['address'] - - subnets_v4 = [s for s in vif['network']['subnets'] - if s['version'] == 4] - if len(subnets_v4): - address_v4 = subnets_v4[0]['ips'][0]['address'] - netmask_v4 = subnets_v4[0].as_netaddr().netmask - gateway_v4 = subnets_v4[0]['gateway']['address'] - dns_v4 = ' '.join([x['address'] for x in subnets_v4[0]['dns']]) - - interface = { - 'name': 'eth%d' % id, - 'address': address_v4, - 'gateway': gateway_v4, - 'netmask': netmask_v4, - 'dns': dns_v4, - 'address_v6': address_v6, - 'gateway_v6': gateway_v6, - 'netmask_v6': netmask_v6, - } - interfaces.append(interface) - return interfaces diff --git a/nova/virt/baremetal/vif_driver.py b/nova/virt/baremetal/vif_driver.py deleted file mode 100644 index f71cd39835..0000000000 --- a/nova/virt/baremetal/vif_driver.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -from oslo.config import cfg - -from nova import context -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.virt.baremetal import db as bmdb - -CONF = cfg.CONF - -LOG = logging.getLogger(__name__) - - -class BareMetalVIFDriver(object): - - def _after_plug(self, instance, vif, pif): - pass - - def _after_unplug(self, instance, vif, pif): - pass - - def plug(self, instance, vif): - LOG.debug("plug: instance_uuid=%(uuid)s vif=%(vif)s", - {'uuid': instance['uuid'], 'vif': vif}) - vif_uuid = vif['id'] - ctx = context.get_admin_context() - node = bmdb.bm_node_get_by_instance_uuid(ctx, instance['uuid']) - - # TODO(deva): optimize this database query - # this is just searching for a free physical interface - pifs = bmdb.bm_interface_get_all_by_bm_node_id(ctx, node['id']) - for pif in pifs: - if not pif['vif_uuid']: - bmdb.bm_interface_set_vif_uuid(ctx, pif['id'], vif_uuid) - LOG.debug("pif:%(id)s is plugged (vif_uuid=%(vif_uuid)s)", - {'id': pif['id'], 'vif_uuid': vif_uuid}) - self._after_plug(instance, vif, pif) - return - - # NOTE(deva): should this really be raising an exception - # when there are no physical interfaces left? - raise exception.NovaException(_( - "Baremetal node: %(id)s has no available physical interface" - " for virtual interface %(vif_uuid)s") - % {'id': node['id'], 'vif_uuid': vif_uuid}) - - def unplug(self, instance, vif): - LOG.debug("unplug: instance_uuid=%(uuid)s vif=%(vif)s", - {'uuid': instance['uuid'], 'vif': vif}) - vif_uuid = vif['id'] - ctx = context.get_admin_context() - try: - pif = bmdb.bm_interface_get_by_vif_uuid(ctx, vif_uuid) - bmdb.bm_interface_set_vif_uuid(ctx, pif['id'], None) - LOG.debug("pif:%(id)s is unplugged (vif_uuid=%(vif_uuid)s)", - {'id': pif['id'], 'vif_uuid': vif_uuid}) - self._after_unplug(instance, vif, pif) - except exception.NovaException: - LOG.warn(_("no pif for vif_uuid=%s") % vif_uuid) diff --git a/nova/virt/baremetal/virtual_power_driver.py b/nova/virt/baremetal/virtual_power_driver.py deleted file mode 100644 index 2adc611561..0000000000 --- a/nova/virt/baremetal/virtual_power_driver.py +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# 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. -# -# Virtual power driver - -from oslo.config import cfg -from oslo.utils import importutils - -from nova import context as nova_context -from nova import exception -from nova.i18n import _ -from nova.openstack.common import log as logging -from nova.openstack.common import processutils -from nova.virt.baremetal import baremetal_states -from nova.virt.baremetal import base -from nova.virt.baremetal import common as connection -from nova.virt.baremetal import db - -opts = [ - cfg.StrOpt('virtual_power_ssh_host', - default='', - help='IP or name to virtual power host'), - cfg.IntOpt('virtual_power_ssh_port', - default=22, - help='Port to use for ssh to virtual power host'), - cfg.StrOpt('virtual_power_type', - default='virsh', - help='Base command to use for virtual power(vbox, virsh)'), - cfg.StrOpt('virtual_power_host_user', - default='', - help='User to execute virtual power commands as'), - cfg.StrOpt('virtual_power_host_pass', - default='', - help='Password for virtual power host_user'), - cfg.StrOpt('virtual_power_host_key', - help='The ssh key for virtual power host_user'), - -] - -baremetal_vp = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_vp) -CONF.register_opts(opts, baremetal_vp) - -_conn = None -_vp_cmd = None -_cmds = None - -LOG = logging.getLogger(__name__) - - -def _normalize_mac(mac): - return mac.replace(':', '').lower() - - -class VirtualPowerManager(base.PowerManager): - """Virtual Power Driver for Baremetal Nova Compute - - This PowerManager class provides mechanism for controlling the power state - of VMs based on their name and MAC address. It uses ssh to connect to the - VM's host and issue commands. - - Node will be matched based on mac address - - NOTE: for use in dev/test environments only! - - """ - def __init__(self, **kwargs): - global _conn - global _cmds - - if _cmds is None: - LOG.debug("Setting up %s commands.", - CONF.baremetal.virtual_power_type) - _vpc = 'nova.virt.baremetal.virtual_power_driver_settings.%s' % \ - CONF.baremetal.virtual_power_type - _cmds = importutils.import_class(_vpc) - self._vp_cmd = _cmds() - self.connection_data = _conn - node = kwargs.pop('node', {}) - instance = kwargs.pop('instance', {}) - self._node_name = instance.get('hostname', "") - context = nova_context.get_admin_context() - ifs = db.bm_interface_get_all_by_bm_node_id(context, node['id']) - self._mac_addresses = [_normalize_mac(i['address']) for i in ifs] - self._connection = None - self._matched_name = '' - self.state = None - - def _get_conn(self): - if not CONF.baremetal.virtual_power_ssh_host: - raise exception.NovaException( - _('virtual_power_ssh_host not defined. Can not Start')) - - if not CONF.baremetal.virtual_power_host_user: - raise exception.NovaException( - _('virtual_power_host_user not defined. Can not Start')) - - if not CONF.baremetal.virtual_power_host_pass: - # it is ok to not have a password if you have a keyfile - if CONF.baremetal.virtual_power_host_key is None: - raise exception.NovaException( - _('virtual_power_host_pass/key not set. Can not Start')) - - _conn = connection.Connection( - CONF.baremetal.virtual_power_ssh_host, - CONF.baremetal.virtual_power_host_user, - CONF.baremetal.virtual_power_host_pass, - CONF.baremetal.virtual_power_ssh_port, - CONF.baremetal.virtual_power_host_key) - return _conn - - def _set_connection(self): - if self._connection is None: - if self.connection_data is None: - self.connection_data = self._get_conn() - - self._connection = connection.ssh_connect(self.connection_data) - - def _get_full_node_list(self): - LOG.debug("Getting full node list.") - cmd = self._vp_cmd.list_cmd - full_list = self._run_command(cmd) - return full_list - - def _check_for_node(self): - LOG.debug("Looking up Name for Mac address %s.", - self._mac_addresses) - self._matched_name = '' - full_node_list = self._get_full_node_list() - - for node in full_node_list: - cmd = self._vp_cmd.get_node_macs.replace('{_NodeName_}', node) - mac_address_list = self._run_command(cmd) - - for mac in mac_address_list: - if _normalize_mac(mac) in self._mac_addresses: - self._matched_name = ('"%s"' % node) - break - return self._matched_name - - def activate_node(self): - LOG.info(_("activate_node name %s"), self._node_name) - if self._check_for_node(): - cmd = self._vp_cmd.start_cmd - self._run_command(cmd) - - if self.is_power_on(): - self.state = baremetal_states.ACTIVE - else: - self.state = baremetal_states.ERROR - return self.state - - def reboot_node(self): - LOG.info(_("reset node: %s"), self._node_name) - if self._check_for_node(): - cmd = self._vp_cmd.reboot_cmd - self._run_command(cmd) - if self.is_power_on(): - self.state = baremetal_states.ACTIVE - else: - self.state = baremetal_states.ERROR - return self.state - - def deactivate_node(self): - LOG.info(_("deactivate_node name %s"), self._node_name) - if self._check_for_node(): - if self.is_power_on(): - cmd = self._vp_cmd.stop_cmd - self._run_command(cmd) - - if self.is_power_on(): - self.state = baremetal_states.ERROR - else: - self.state = baremetal_states.DELETED - return self.state - - def is_power_on(self): - LOG.debug("Checking if %s is running", self._node_name) - - if not self._check_for_node(): - err_msg = _('Node "%(name)s" with MAC address %(mac)s not found.') - LOG.error(err_msg, {'name': self._node_name, - 'mac': self._mac_addresses}) - # in our case the _node_name is the node_id - raise exception.NodeNotFound(node_id=self._node_name) - - cmd = self._vp_cmd.list_running_cmd - running_node_list = self._run_command(cmd) - - for node in running_node_list: - if self._matched_name in node: - return True - return False - - def _run_command(self, cmd, check_exit_code=True): - """Run a remote command using an active ssh connection. - - :param command: String with the command to run. - - If {_NodeName_} is in the command it will get replaced by - the _matched_name value. - - base_cmd will also get prepended to the command. - """ - self._set_connection() - - cmd = cmd.replace('{_NodeName_}', self._matched_name) - - cmd = '%s %s' % (self._vp_cmd.base_cmd, cmd) - - try: - stdout, stderr = processutils.ssh_execute( - self._connection, cmd, check_exit_code=check_exit_code) - result = stdout.strip().splitlines() - LOG.debug('Result for run_command: %s', result) - except processutils.ProcessExecutionError: - result = [] - LOG.exception(_("Error running command: %s"), cmd) - return result diff --git a/nova/virt/baremetal/virtual_power_driver_settings.py b/nova/virt/baremetal/virtual_power_driver_settings.py deleted file mode 100644 index 50004ecbd2..0000000000 --- a/nova/virt/baremetal/virtual_power_driver_settings.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. - -# 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. -# -# Virtual power driver commands - - -class vbox(object): - """set commands for basic Virtual Box control.""" - - def __init__(self): - self.base_cmd = '/usr/bin/VBoxManage' - self.start_cmd = 'startvm {_NodeName_}' - self.stop_cmd = 'controlvm {_NodeName_} poweroff' - self.reboot_cmd = 'controlvm {_NodeName_} reset' - self.list_cmd = "list vms|awk -F'\"' '{print $2}'" - self.list_running_cmd = 'list runningvms' - self.get_node_macs = ("showvminfo --machinereadable {_NodeName_} | " - "grep " - '"macaddress" | awk -F ' - "'" - '"' - "' '{print $2}'") - - -class virsh(object): - """set commands for basic Virsh control.""" - - def __init__(self): - self.base_cmd = '/usr/bin/virsh --connect qemu:///system' - self.start_cmd = 'start {_NodeName_}' - self.stop_cmd = 'destroy {_NodeName_}' - self.reboot_cmd = 'reset {_NodeName_}' - self.list_cmd = "list --all | tail -n +2 | awk -F\" \" '{print $2}'" - self.list_running_cmd = \ - "list --all|grep running|awk -v qc='\"' -F\" \" '{print qc$2qc}'" - self.get_node_macs = ("dumpxml {_NodeName_} | grep " - '"mac address" | awk -F' - '"' - "'" - '" ' - "'{print $2}' | tr -d ':'") diff --git a/nova/virt/baremetal/volume_driver.py b/nova/virt/baremetal/volume_driver.py deleted file mode 100644 index c6176d178d..0000000000 --- a/nova/virt/baremetal/volume_driver.py +++ /dev/null @@ -1,292 +0,0 @@ -# coding=utf-8 - -# Copyright (c) 2012 NTT DOCOMO, INC. -# 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. - -import re - -from oslo.config import cfg -from oslo.utils import importutils - -from nova import context as nova_context -from nova import exception -from nova.i18n import _ -from nova import network -from nova.openstack.common import log as logging -from nova.openstack.common import processutils -from nova import utils -from nova.virt.baremetal import db as bmdb -from nova.virt import volumeutils - -opts = [ - cfg.BoolOpt('use_unsafe_iscsi', - default=False, - help='Do not set this out of dev/test environments. ' - 'If a node does not have a fixed PXE IP address, ' - 'volumes are exported with globally opened ACL'), - cfg.StrOpt('iscsi_iqn_prefix', - default='iqn.2010-10.org.openstack.baremetal', - help='The iSCSI IQN prefix used in baremetal volume ' - 'connections.'), - ] - -baremetal_group = cfg.OptGroup(name='baremetal', - title='Baremetal Options') - -CONF = cfg.CONF -CONF.register_group(baremetal_group) -CONF.register_opts(opts, baremetal_group) - -CONF.import_opt('host', 'nova.netconf') -CONF.import_opt('use_ipv6', 'nova.netconf') -CONF.import_opt('volume_drivers', 'nova.virt.libvirt.driver', group='libvirt') - -LOG = logging.getLogger(__name__) - - -def _get_baremetal_node_by_instance_uuid(instance_uuid): - context = nova_context.get_admin_context() - return bmdb.bm_node_get_by_instance_uuid(context, instance_uuid) - - -def _create_iscsi_export_tgtadm(path, tid, iqn): - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'target', - '--op', 'new', - '--tid', tid, - '--targetname', iqn, - run_as_root=True) - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'logicalunit', - '--op', 'new', - '--tid', tid, - '--lun', '1', - '--backing-store', path, - run_as_root=True) - - -def _allow_iscsi_tgtadm(tid, address): - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'target', - '--op', 'bind', - '--tid', tid, - '--initiator-address', address, - run_as_root=True) - - -def _delete_iscsi_export_tgtadm(tid): - try: - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'logicalunit', - '--op', 'delete', - '--tid', tid, - '--lun', '1', - run_as_root=True) - except processutils.ProcessExecutionError: - pass - try: - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'target', - '--op', 'delete', - '--tid', tid, - run_as_root=True) - except processutils.ProcessExecutionError: - pass - # Check if the tid is deleted, that is, check the tid no longer exists. - # If the tid dose not exist, tgtadm returns with exit_code 22. - # utils.execute() can check the exit_code if check_exit_code parameter is - # passed. But, regardless of whether check_exit_code contains 0 or not, - # if the exit_code is 0, the function dose not report errors. So we have to - # catch a ProcessExecutionError and test its exit_code is 22. - try: - utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'target', - '--op', 'show', - '--tid', tid, - run_as_root=True) - except processutils.ProcessExecutionError as e: - if e.exit_code == 22: - # OK, the tid is deleted - return - raise - raise exception.NovaException(_( - 'baremetal driver was unable to delete tid %s') % tid) - - -def _show_tgtadm(): - out, _ = utils.execute('tgtadm', '--lld', 'iscsi', - '--mode', 'target', - '--op', 'show', - run_as_root=True) - return out - - -def _list_backingstore_path(): - out = _show_tgtadm() - l = [] - for line in out.split('\n'): - m = re.search(r'Backing store path: (.*)$', line) - if m: - if '/' in m.group(1): - l.append(m.group(1)) - return l - - -def _get_next_tid(): - out = _show_tgtadm() - last_tid = 0 - for line in out.split('\n'): - m = re.search(r'^Target (\d+):', line) - if m: - tid = int(m.group(1)) - if last_tid < tid: - last_tid = tid - return last_tid + 1 - - -def _find_tid(iqn): - out = _show_tgtadm() - pattern = r'^Target (\d+): *' + re.escape(iqn) - for line in out.split('\n'): - m = re.search(pattern, line) - if m: - return int(m.group(1)) - return None - - -def _get_iqn(instance_name, mountpoint): - mp = mountpoint.replace('/', '-').strip('-') - iqn = '%s:%s-%s' % (CONF.baremetal.iscsi_iqn_prefix, - instance_name, - mp) - return iqn - - -def _get_fixed_ips(instance): - context = nova_context.get_admin_context() - nw_info = network.API().get_instance_nw_info(context, instance) - ips = nw_info.fixed_ips() - return ips - - -class VolumeDriver(object): - - def __init__(self, virtapi): - super(VolumeDriver, self).__init__() - self.virtapi = virtapi - self._initiator = None - - def get_volume_connector(self, instance): - if not self._initiator: - self._initiator = volumeutils.get_iscsi_initiator() - if not self._initiator: - LOG.warn(_('Could not determine iscsi initiator name'), - instance=instance) - return { - 'ip': CONF.my_ip, - 'initiator': self._initiator, - 'host': CONF.host, - } - - def attach_volume(self, connection_info, instance, mountpoint): - raise NotImplementedError() - - def detach_volume(self, connection_info, instance, mountpoint): - raise NotImplementedError() - - -class LibvirtVolumeDriver(VolumeDriver): - """The VolumeDriver delegates to nova.virt.libvirt.volume.""" - - def __init__(self, virtapi): - super(LibvirtVolumeDriver, self).__init__(virtapi) - self.volume_drivers = {} - for driver_str in CONF.libvirt.volume_drivers: - driver_type, _sep, driver = driver_str.partition('=') - driver_class = importutils.import_class(driver) - self.volume_drivers[driver_type] = driver_class(self) - - def attach_volume(self, connection_info, instance, mountpoint): - fixed_ips = _get_fixed_ips(instance) - if not fixed_ips: - if not CONF.baremetal.use_unsafe_iscsi: - raise exception.NovaException(_( - 'No fixed PXE IP is associated to %s') % instance['uuid']) - - mount_device = mountpoint.rpartition("/")[2] - disk_info = { - 'dev': mount_device, - 'bus': 'baremetal', - 'type': 'baremetal', - } - conf = self._connect_volume(connection_info, disk_info) - self._publish_iscsi(instance, mountpoint, fixed_ips, - conf.source_path) - - def _connect_volume(self, connection_info, disk_info): - driver_type = connection_info.get('driver_volume_type') - if driver_type not in self.volume_drivers: - raise exception.VolumeDriverNotFound(driver_type=driver_type) - driver = self.volume_drivers[driver_type] - return driver.connect_volume(connection_info, disk_info) - - def _publish_iscsi(self, instance, mountpoint, fixed_ips, device_path): - iqn = _get_iqn(instance['name'], mountpoint) - tid = _get_next_tid() - _create_iscsi_export_tgtadm(device_path, tid, iqn) - - if fixed_ips: - for ip in fixed_ips: - _allow_iscsi_tgtadm(tid, ip['address']) - else: - # NOTE(NTTdocomo): Since nova-compute does not know the - # instance's initiator ip, it allows any initiators - # to connect to the volume. This means other bare-metal - # instances that are not attached the volume can connect - # to the volume. Do not set CONF.baremetal.use_unsafe_iscsi - # out of dev/test environments. - # TODO(NTTdocomo): support CHAP - _allow_iscsi_tgtadm(tid, 'ALL') - - def detach_volume(self, connection_info, instance, mountpoint): - mount_device = mountpoint.rpartition("/")[2] - try: - self._depublish_iscsi(instance, mountpoint) - finally: - self._disconnect_volume(connection_info, mount_device) - - def _disconnect_volume(self, connection_info, disk_dev): - driver_type = connection_info.get('driver_volume_type') - if driver_type not in self.volume_drivers: - raise exception.VolumeDriverNotFound(driver_type=driver_type) - driver = self.volume_drivers[driver_type] - return driver.connect_volume(connection_info, disk_dev) - - def _depublish_iscsi(self, instance, mountpoint): - iqn = _get_iqn(instance['name'], mountpoint) - tid = _find_tid(iqn) - if tid is not None: - _delete_iscsi_export_tgtadm(tid) - else: - LOG.warn(_('detach volume could not find tid for %s'), iqn, - instance=instance) - - def _get_all_block_devices(self): - """Return all block devices in use on this node.""" - return _list_backingstore_path() - - def _get_hypervisor_version(self): - """A dummy method for LibvirtBaseVolumeDriver.connect_volume.""" - return 1 diff --git a/setup.cfg b/setup.cfg index c3782024b1..ca3f691703 100644 --- a/setup.cfg +++ b/setup.cfg @@ -37,8 +37,6 @@ console_scripts = nova-api-ec2 = nova.cmd.api_ec2:main nova-api-metadata = nova.cmd.api_metadata:main nova-api-os-compute = nova.cmd.api_os_compute:main - nova-baremetal-deploy-helper = nova.cmd.baremetal_deploy_helper:main - nova-baremetal-manage = nova.cmd.baremetal_manage:main nova-cells = nova.cmd.cells:main nova-cert = nova.cmd.cert:main nova-compute = nova.cmd.compute:main