Merge "Remove scripts for migrating nova baremetal"
This commit is contained in:
commit
6f36e056d4
@ -1,318 +0,0 @@
|
||||
# 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 __future__ import print_function
|
||||
import argparse
|
||||
import ConfigParser
|
||||
import os
|
||||
import sys
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from ironic.common import states as ironic_states
|
||||
from ironic.db.sqlalchemy import models as ironic_models
|
||||
from ironic.migrate_nova import nova_baremetal_states as nova_states
|
||||
from ironic.migrate_nova import nova_models
|
||||
|
||||
|
||||
DESCRIPTION = """
|
||||
This is an administrative utility to be used for migrating a nova-baremetal
|
||||
node inventory to Ironic. It will migrate nova-baremetal node and interface
|
||||
information and associated driver configuration from the Nova database to the
|
||||
Ironic database. It only supports migrating from the IPMI and
|
||||
VirtualPowerManager power drivers.
|
||||
"""
|
||||
|
||||
IRONIC_ENGINE = None
|
||||
NOVA_BM_ENGINE = None
|
||||
|
||||
|
||||
# Relevant nova-baremetal config with their associated defaults as of Juno.
|
||||
NOVA_BM_CONFIG_KEYS = {
|
||||
# nova.virt.baremetal.driver
|
||||
'driver': 'nova.virt.baremetal.pxe.PXE',
|
||||
'power_manager': 'nova.virt.baremetal.ipmi.IPMI',
|
||||
|
||||
# nova.virt.baremetal.virtual_power_driver
|
||||
'virtual_power_ssh_host': '',
|
||||
'virtual_power_ssh_port': 22,
|
||||
'virtual_power_type': 'virsh',
|
||||
'virtual_power_host_user': '',
|
||||
'virtual_power_host_pass': '',
|
||||
'virtual_power_host_key': '',
|
||||
}
|
||||
|
||||
|
||||
def get_nova_nodes():
|
||||
Session = sessionmaker(bind=NOVA_BM_ENGINE)
|
||||
session = Session()
|
||||
query = session.query(nova_models.BareMetalNode)
|
||||
|
||||
try:
|
||||
nodes = query.all()
|
||||
except sa.exc.OperationalError as err:
|
||||
print("Could not get nodes from Nova:\n%s" % err, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
session.close()
|
||||
|
||||
return nodes
|
||||
|
||||
|
||||
def get_nova_ports():
|
||||
Session = sessionmaker(bind=NOVA_BM_ENGINE)
|
||||
session = Session()
|
||||
|
||||
query = session.query(nova_models.BareMetalInterface)
|
||||
|
||||
try:
|
||||
ports = query.all()
|
||||
except sa.exc.OperationalError as err:
|
||||
print("Could not get ports from Nova:\n%s" % err, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
session.close()
|
||||
|
||||
return ports
|
||||
|
||||
|
||||
def convert_nova_nodes(nodes, cpu_arch, nova_conf):
|
||||
ironic_nodes = []
|
||||
|
||||
for n_node in nodes:
|
||||
# Create an empty Ironic Node
|
||||
i_node = ironic_models.Node()
|
||||
|
||||
# Populate basic properties
|
||||
i_node.id = n_node.id
|
||||
i_node.uuid = n_node.uuid
|
||||
i_node.chassis_id = None
|
||||
i_node.last_error = None
|
||||
i_node.instance_uuid = n_node.instance_uuid
|
||||
i_node.reservation = None
|
||||
i_node.maintenance = False
|
||||
i_node.updated_at = n_node.updated_at
|
||||
i_node.created_at = n_node.created_at
|
||||
|
||||
# Populate states
|
||||
if n_node.task_state == nova_states.ACTIVE:
|
||||
i_node.power_state = ironic_states.POWER_ON
|
||||
else:
|
||||
i_node.power_state = ironic_states.POWER_OFF
|
||||
|
||||
i_node.target_power_state = None
|
||||
|
||||
if i_node.instance_uuid:
|
||||
prov_state = ironic_states.ACTIVE
|
||||
else:
|
||||
prov_state = ironic_states.NOSTATE
|
||||
|
||||
i_node.provision_state = prov_state
|
||||
i_node.target_provision_state = None
|
||||
|
||||
# Populate extra properties
|
||||
i_node.extra = {}
|
||||
|
||||
# Populate driver_info
|
||||
i_node.driver_info = {}
|
||||
|
||||
power_manager = nova_conf['power_manager']
|
||||
if power_manager.endswith('IPMI'):
|
||||
i_node.driver = 'pxe_ipmitool'
|
||||
if n_node.pm_address:
|
||||
i_node.driver_info['ipmi_address'] = n_node.pm_address
|
||||
if n_node.pm_user:
|
||||
i_node.driver_info['ipmi_username'] = n_node.pm_user
|
||||
if n_node.pm_password:
|
||||
i_node.driver_info['ipmi_password'] = n_node.pm_password
|
||||
elif power_manager.endswith('VirtualPowerManager'):
|
||||
i_node.driver = 'pxe_ssh'
|
||||
i_node.driver_info = {
|
||||
'ssh_virt_type': nova_conf['virtual_power_type'],
|
||||
'ssh_address': nova_conf['virtual_power_ssh_host'],
|
||||
'ssh_username': nova_conf['virtual_power_host_user'],
|
||||
}
|
||||
|
||||
ssh_port = nova_conf.get('ssh_port')
|
||||
if ssh_port:
|
||||
ssh_port = nova_conf['virtual_power_ssh_port']
|
||||
|
||||
ssh_key = nova_conf.get('virtual_power_host_key')
|
||||
if ssh_key:
|
||||
i_node.driver_info['ssh_key_filename'] = ssh_key
|
||||
|
||||
ssh_pass = nova_conf.get('virtual_power_host_pass')
|
||||
if ssh_pass:
|
||||
i_node.driver_info['ssh_password'] = ssh_pass
|
||||
else:
|
||||
print("This does not support migration from power driver: "
|
||||
"%s\n" % nova_conf['driver'], file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
# Populate instance_info
|
||||
i_node.instance_info = {}
|
||||
|
||||
if n_node.root_mb:
|
||||
i_node.instance_info['root_mb'] = n_node.root_mb
|
||||
if n_node.swap_mb:
|
||||
i_node.instance_info['swap_mb'] = n_node.swap_mb
|
||||
if n_node.ephemeral_mb:
|
||||
i_node.instance_info['ephemeral_mb'] = n_node.ephemeral_mb
|
||||
|
||||
i_node.properties = {'cpu_arch': cpu_arch,
|
||||
'cpus': n_node.cpus,
|
||||
'local_gb': n_node.local_gb,
|
||||
'memory_mb': n_node.memory_mb}
|
||||
|
||||
ironic_nodes.append(i_node)
|
||||
|
||||
return ironic_nodes
|
||||
|
||||
|
||||
def convert_nova_ports(ports):
|
||||
ironic_ports = []
|
||||
|
||||
for n_port in ports:
|
||||
i_port = ironic_models.Port()
|
||||
|
||||
i_port.id = n_port.id
|
||||
i_port.uuid = uuidutils.generate_uuid()
|
||||
i_port.address = n_port.address
|
||||
i_port.node_id = n_port.bm_node_id
|
||||
|
||||
i_port.extra = {}
|
||||
|
||||
if n_port.vif_uuid:
|
||||
i_port.extra['vif_uuid'] = n_port.vif_uuid
|
||||
|
||||
ironic_ports.append(i_port)
|
||||
|
||||
return ironic_ports
|
||||
|
||||
|
||||
def save_ironic_objects(objects):
|
||||
Session = sessionmaker(bind=IRONIC_ENGINE)
|
||||
session = Session()
|
||||
|
||||
try:
|
||||
session.add_all(objects)
|
||||
session.commit()
|
||||
except sa.exc.OperationalError as err:
|
||||
print("Could not send data to Ironic:\n%s" % err, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
session.close()
|
||||
|
||||
|
||||
def parse_nova_config(config_file):
|
||||
"""Parse nova.conf and return known defaults if setting is not present.
|
||||
|
||||
This avoids having to import nova code from this script and risk conflicts
|
||||
with Ironic's tree around oslo_config resources.
|
||||
"""
|
||||
if not os.path.isfile(config_file):
|
||||
print("nova.conf not found at %s. Please specify the location via "
|
||||
"the --nova-config option." % config_file, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
nova_conf = ConfigParser.SafeConfigParser()
|
||||
nova_conf.read(config_file)
|
||||
|
||||
conf = {}
|
||||
for setting, default in NOVA_BM_CONFIG_KEYS.items():
|
||||
try:
|
||||
conf[setting] = nova_conf.get('baremetal', setting)
|
||||
except ConfigParser.NoOptionError:
|
||||
conf[setting] = default
|
||||
return conf
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
"""Early validation of required configuration prior to touching the db."""
|
||||
if config['power_manager'].endswith('VirtualPowerManager'):
|
||||
# confirm nova.conf contains all required ssh info, as per
|
||||
# ironic.drivers.ssh.REQUIRED_PROPERTIES.
|
||||
req = ['virtual_power_host_user', 'virtual_power_type',
|
||||
'virtual_power_ssh_host']
|
||||
missing = []
|
||||
for r in req:
|
||||
if not config.get(r):
|
||||
missing.append(r)
|
||||
if missing:
|
||||
print('nova.conf is missing required settings in the '
|
||||
'[baremetal] section to migrate VirtualPowerManager: %s' %
|
||||
' '.join(missing), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description=DESCRIPTION)
|
||||
parser.add_argument('--nova-bm-db', '-b', type=str,
|
||||
required=True, dest='nova_bm_conn_string',
|
||||
help='Connection string to Nova baremetal database.')
|
||||
parser.add_argument('--ironic-db', '-i', type=str,
|
||||
required=True, dest='ironic_conn_string',
|
||||
help='Connection string to Ironic database.')
|
||||
parser.add_argument('--node-arch', '-a', type=str,
|
||||
required=True, dest='cpu_arch',
|
||||
help='CPU architecture of the nodes.')
|
||||
parser.add_argument('--nova-config', '-c', type=str,
|
||||
required=False, dest='nova_config',
|
||||
default='/etc/nova/nova.conf',
|
||||
help='Path to nova.conf. (default: '
|
||||
'/etc/nova/nova.conf)')
|
||||
return parser.parse_args(sys.argv[1:])
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
global IRONIC_ENGINE
|
||||
global NOVA_BM_ENGINE
|
||||
|
||||
IRONIC_ENGINE = sa.create_engine(args.ironic_conn_string)
|
||||
NOVA_BM_ENGINE = sa.create_engine(args.nova_bm_conn_string)
|
||||
|
||||
# Load and validate nova.conf
|
||||
nova_conf = parse_nova_config(args.nova_config)
|
||||
validate_config(nova_conf)
|
||||
|
||||
# Process nodes
|
||||
print("Getting data for baremetal nodes from Nova...")
|
||||
nova_nodes = get_nova_nodes()
|
||||
print("Got %d nodes from Nova..." % len(nova_nodes))
|
||||
|
||||
print("Converting information for Nova nodes to Ironic...")
|
||||
ironic_nodes = convert_nova_nodes(nova_nodes, args.cpu_arch,
|
||||
nova_conf)
|
||||
|
||||
print("Saving nodes to Ironic...")
|
||||
save_ironic_objects(ironic_nodes)
|
||||
|
||||
# Process ports
|
||||
print("Getting baremetal ports from Nova...")
|
||||
nova_ports = get_nova_ports()
|
||||
print("Got %d ports from Nova." % len(nova_ports))
|
||||
|
||||
print("Converting Nova ports...")
|
||||
ironic_ports = convert_nova_ports(nova_ports)
|
||||
print("Saving ports to Ironic...")
|
||||
save_ironic_objects(ironic_ports)
|
||||
|
||||
# Printing summary
|
||||
print("All done!")
|
||||
print("%d nodes and %d ports have been migrated from "
|
||||
"Nova to Ironic." % (len(nova_nodes), len(nova_ports)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,38 +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.
|
||||
|
||||
# NOTE(adam_g): This code has been copied directly from Nova (J2) to facilitate
|
||||
# Nova baremetal data migration tools. The original may be found in the Nova
|
||||
# tree (nova.virt.baremetal.baremetal_states).
|
||||
|
||||
"""
|
||||
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'
|
@ -1,71 +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.
|
||||
|
||||
# NOTE(adam_g): This code has been copied directly from Nova (J2) to facilitate
|
||||
# Nova baremetal data migration tools. The original may be found in the Nova
|
||||
# tree (nova.virt.baremetal.db.sqlalchemy.models).
|
||||
|
||||
"""
|
||||
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 ironic.db.sqlalchemy import models
|
||||
|
||||
|
||||
BASE = declarative_base()
|
||||
|
||||
|
||||
class BareMetalNode(BASE, models.Base):
|
||||
"""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.Base):
|
||||
__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)
|
@ -27,7 +27,6 @@ console_scripts =
|
||||
ironic-dbsync = ironic.cmd.dbsync:main
|
||||
ironic-conductor = ironic.cmd.conductor:main
|
||||
ironic-rootwrap = oslo_rootwrap.cmd:main
|
||||
ironic-nova-bm-migrate = ironic.migrate_nova.migrate_db:main
|
||||
|
||||
ironic.dhcp =
|
||||
neutron = ironic.dhcp.neutron:NeutronDHCPApi
|
||||
|
Loading…
x
Reference in New Issue
Block a user