CLI for bare-metal database sync.
Part 3 of 6: blueprint general-bare-metal-provisioning-framework. Change-Id: Ia19ce00edb84aa924c2ab2c9c2217f6b49073d69 Co-authored-by: Mikyung Kang <mkkang@isi.edu> Co-authored-by: David Kang <dkang@isi.edu> Co-authored-by: Ken Igarashi <igarashik@nttdocomo.co.jp> Co-authored-by: Arata Notsu <notsu@virtualtech.jp>
This commit is contained in:
		
				
					committed by
					
						
						Arata Notsu
					
				
			
			
				
	
			
			
			
						parent
						
							af3380a813
						
					
				
				
					commit
					666e2f03d5
				
			
							
								
								
									
										234
									
								
								bin/nova-baremetal-manage
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										234
									
								
								bin/nova-baremetal-manage
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# 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 ast
 | 
			
		||||
import errno
 | 
			
		||||
import gettext
 | 
			
		||||
import math
 | 
			
		||||
import netaddr
 | 
			
		||||
import optparse
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
 | 
			
		||||
# it will override what happens to be installed in /usr/(local/)lib/python...
 | 
			
		||||
POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
			
		||||
                                   os.pardir,
 | 
			
		||||
                                   os.pardir))
 | 
			
		||||
if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')):
 | 
			
		||||
    sys.path.insert(0, POSSIBLE_TOPDIR)
 | 
			
		||||
 | 
			
		||||
gettext.install('nova', unicode=1)
 | 
			
		||||
 | 
			
		||||
from nova import config
 | 
			
		||||
from nova import context
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.openstack.common import cfg
 | 
			
		||||
from nova.openstack.common import cliutils
 | 
			
		||||
from nova.openstack.common import importutils
 | 
			
		||||
from nova.openstack.common import log as logging
 | 
			
		||||
from nova.openstack.common import rpc
 | 
			
		||||
from nova.openstack.common import timeutils
 | 
			
		||||
from nova import utils
 | 
			
		||||
from nova import version
 | 
			
		||||
from nova.virt.baremetal import db as bmdb
 | 
			
		||||
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='<version>',
 | 
			
		||||
            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.'))
 | 
			
		||||
        sys.exit(2)
 | 
			
		||||
 | 
			
		||||
    if CONF.category.name == "version":
 | 
			
		||||
        print(_("%(version)s (%(vcs)s)") %
 | 
			
		||||
               {'version': version.version_string(),
 | 
			
		||||
                'vcs': version.version_string_with_vcs()})
 | 
			
		||||
        sys.exit(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]))
 | 
			
		||||
        sys.exit(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, basestring):
 | 
			
		||||
            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__)
 | 
			
		||||
        parser.print_help()
 | 
			
		||||
        print(e)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    try:
 | 
			
		||||
        fn(*fn_args, **fn_kwargs)
 | 
			
		||||
        sys.exit(0)
 | 
			
		||||
    except Exception:
 | 
			
		||||
        print(_("Command failed, please check log for more info"))
 | 
			
		||||
        raise
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										67
									
								
								doc/source/man/nova-baremetal-manage.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								doc/source/man/nova-baremetal-manage.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
=====================
 | 
			
		||||
nova-baremetal-manage
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
Manage bare-metal DB in OpenStack Nova
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
:Author: openstack@lists.launchpad.net
 | 
			
		||||
:Date:   2012-10-17
 | 
			
		||||
:Copyright: OpenStack LLC
 | 
			
		||||
:Version: 2013.1
 | 
			
		||||
:Manual section: 1
 | 
			
		||||
:Manual group: cloud computing
 | 
			
		||||
 | 
			
		||||
SYNOPSIS
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
  nova-baremetal-manage <category> <action> [<args>]
 | 
			
		||||
 | 
			
		||||
DESCRIPTION
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
nova-baremetal-manage manages bare-metal DB schema.
 | 
			
		||||
 | 
			
		||||
OPTIONS
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
The standard pattern for executing a nova-baremetal-manage command is:
 | 
			
		||||
``nova-baremetal-manage <category> <command> [<args>]``
 | 
			
		||||
 | 
			
		||||
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 <http://nova.openstack.org>`__
 | 
			
		||||
 | 
			
		||||
BUGS
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
* Nova is maintained in Launchpad so you can view current bugs at `OpenStack Nova <https://bugs.launchpad.net/nova>`__
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								nova/tests/baremetal/test_nova_baremetal_manage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								nova/tests/baremetal/test_nova_baremetal_manage.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
#    Copyright (c) 2012 NTT DOCOMO, INC.
 | 
			
		||||
#    Copyright 2011 OpenStack LLC
 | 
			
		||||
#    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 imp
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from nova import context
 | 
			
		||||
from nova import test
 | 
			
		||||
from nova.virt.baremetal import db as bmdb
 | 
			
		||||
 | 
			
		||||
from nova.tests.baremetal.db import base as bm_db_base
 | 
			
		||||
 | 
			
		||||
TOPDIR = os.path.normpath(os.path.join(
 | 
			
		||||
                            os.path.dirname(os.path.abspath(__file__)),
 | 
			
		||||
                            os.pardir,
 | 
			
		||||
                            os.pardir,
 | 
			
		||||
                            os.pardir))
 | 
			
		||||
BM_MAN_PATH = os.path.join(TOPDIR, 'bin', 'nova-baremetal-manage')
 | 
			
		||||
 | 
			
		||||
sys.dont_write_bytecode = True
 | 
			
		||||
bm_man = imp.load_source('bm_man', BM_MAN_PATH)
 | 
			
		||||
sys.dont_write_bytecode = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
		Reference in New Issue
	
	Block a user