--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/neutron/files/evs/migrate/evs-neutron-migration.py Thu Mar 19 14:41:20 2015 -0700
@@ -0,0 +1,392 @@
+#!/usr/bin/python2.6
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. 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.
+
+#
+# This script migrates the network, subnet and port information from EVS DB to
+# neutron-server DB. It also re-creates routers and floatingips tables with
+# Neutron's l3 schema. This script needs to be run for the proper upgrade of
+# Neutron from Havana to Juno release.
+#
+
+import ConfigParser
+import rad.connect as radcon
+import rad.bindings.com.oracle.solaris.rad.evscntl as evsc
+
+from neutron import context as ctx
+from neutron.db import common_db_mixin
+from neutron.db import api as db
+from neutron.db import model_base
+from neutron.plugins.evs.migrate import havana_api
+
+import sqlalchemy as sa
+from sqlalchemy import MetaData
+from sqlalchemy.schema import DropConstraint
+from sqlalchemy import sql
+
+from oslo.config import cfg
+from oslo.db import options as db_options
+from oslo.db import exception as excp
+
+
+def create_db_network(nw, engine):
+ ''' Method for creating networks table in the neutron-server DB
+ Input params:
+ @nw - Dictionary with values from EVS DB
+ '''
+ # Importing locally because this module ends up importing neutron.wsgi
+ # which causes RAD to hang
+ from neutron.db import db_base_plugin_v2
+ model_base.BASEV2.metadata.bind = engine
+ model_base.BASEV2.metadata.create_all(engine)
+ ctxt = ctx.get_admin_context()
+ inst = db_base_plugin_v2.NeutronDbPluginV2()
+ dup = False
+ try:
+ db_base_plugin_v2.NeutronDbPluginV2.create_network(inst, ctxt, nw)
+ print "\nnetwork=%s added" % nw['network']['name']
+ except excp.DBDuplicateEntry:
+ print "\nnetwork '%s' already exists" % nw['network']['name']
+ dup = True
+ return dup
+
+
+def create_db_subnet(sub):
+ ''' Method for creating subnets table in the neutron-server DB
+ Input params:
+ @sub - Dictionary with values from EVS DB
+ '''
+ # Importing locally because this module ends up importing neutron.wsgi
+ # which causes RAD to hang
+ from neutron.db import db_base_plugin_v2
+ ctxt = ctx.get_admin_context()
+ inst = db_base_plugin_v2.NeutronDbPluginV2()
+ try:
+ db_base_plugin_v2.NeutronDbPluginV2.create_subnet(inst, ctxt, sub)
+ print "\nsubnet=%s added" % sub['subnet']['id']
+ except excp.DBDuplicateEntry:
+ print "\nsubnet '%s' already exists" % sub['subnet']['id']
+
+
+def create_db_port(port):
+ ''' Method for creating ports table in the neutron-server DB
+ Input params:
+ @port - Dictionary with values from EVS DB
+ '''
+ # Importing locally because this module ends up importing neutron.wsgi
+ # which causes RAD to hang
+ from neutron.db import db_base_plugin_v2
+ ctxt = ctx.get_admin_context()
+ inst = db_base_plugin_v2.NeutronDbPluginV2()
+ try:
+ db_base_plugin_v2.NeutronDbPluginV2.create_port(inst, ctxt, port)
+ print "\nport=%s added" % port['port']['id']
+ except excp.DBDuplicateEntry:
+ print "\nport '%s' already exists" % port['port']['id']
+
+
+def main():
+ print "Start Migration."
+
+ # Connect to EVS controller
+ config = ConfigParser.RawConfigParser()
+ config.readfp(open("/etc/neutron/plugins/evs/evs_plugin.ini"))
+ if config.has_option("EVS", 'evs_controller'):
+ config_suh = config.get("EVS", 'evs_controller')
+ else:
+ config_suh = 'ssh://evsuser@localhost'
+ suh = config_suh.split('://')
+ if len(suh) != 2 or suh[0] != 'ssh' or not suh[1].strip():
+ raise SystemExit(_("Specified evs_controller is invalid"))
+ uh = suh[1].split('@')
+ if len(uh) != 2 or not uh[0].strip() or not uh[1].strip():
+ raise SystemExit(_("'user' and 'hostname' need to be specified "
+ "for evs_controller"))
+ try:
+ rc = radcon.connect_ssh(uh[1], user=uh[0])
+ except:
+ raise SystemExit(_("Cannot connect to EVS Controller"))
+ try:
+ evs_contr = rc.get_object(evsc.EVSController())
+ except:
+ raise SystemExit(_("Could not retrieve EVS info from EVS Controller"))
+ evsinfo = evs_contr.getEVSInfo()
+ if not evsinfo:
+ raise SystemExit(_("No data to migrate"))
+
+ config.readfp(open("/etc/neutron/neutron.conf"))
+ if config.has_option("database", 'connection'):
+ SQL_CONNECTION = config.get("database", 'connection')
+ else:
+ SQL_CONNECTION = 'sqlite:////var/lib/neutron/neutron.sqlite'
+
+ conf = cfg.CONF
+ db_options.set_defaults(cfg.CONF,
+ connection=SQL_CONNECTION,
+ sqlite_db='', max_pool_size=10,
+ max_overflow=20, pool_timeout=10)
+
+ neutron_engine = sa.create_engine(SQL_CONNECTION)
+
+ for e in evsinfo:
+ # Populate networks table
+ n = {
+ 'tenant_id': e.tenantname,
+ 'id': e.uuid,
+ 'name': e.name,
+ 'status': 'ACTIVE',
+ 'admin_state_up': True,
+ 'shared': False
+ }
+ nw = {'network': n}
+ dup = create_db_network(nw, neutron_engine)
+ if dup:
+ continue # No need to iterate over subnets and ports
+
+ # Populate subnets table
+ for i in e.ipnets:
+ cidr = None
+ gateway_ip = None
+ enable_dhcp = None
+ dns = []
+ host = []
+ start = []
+ for p in i.props:
+ if p.name == 'subnet':
+ cidr = p.value
+ elif p.name == 'defrouter':
+ gateway_ip = p.value
+ elif p.name == 'OpenStack:enable_dhcp':
+ enable_dhcp = p.value == 'True'
+ elif p.name == 'OpenStack:dns_nameservers':
+ dns = p.value.split(',')
+ elif p.name == 'OpenStack:host_routes':
+ hh = p.value.split(',')
+ for h in range(0, len(hh), 2):
+ d = {hh[h]: hh[h+1]}
+ host.append(d)
+ elif p.name == 'pool':
+ ss = p.value.split(',')
+ for s in ss:
+ if '-' in s:
+ d = {'start': s.split('-')[0],
+ 'end': s.split('-')[1]}
+ start.append(d)
+ else:
+ d = {'start': s, 'end': s}
+ start.append(d)
+ ip_version = 4 if i.ipvers == evsc.IPVersion.IPV4 else 6
+
+ if i.name.startswith(i.uuid[:8]):
+ # Skip autogenerated names
+ name = None
+ else:
+ name = i.name
+ s = {
+ 'tenant_id': i.tenantname,
+ 'id': i.uuid,
+ 'name': name,
+ 'network_id': e.uuid,
+ 'ip_version': ip_version,
+ 'cidr': cidr,
+ 'gateway_ip': gateway_ip,
+ 'enable_dhcp': enable_dhcp,
+ 'shared': False,
+ 'allocation_pools': start,
+ 'dns_nameservers': dns,
+ 'host_routes': host
+ }
+
+ sub = {'subnet': s}
+ create_db_subnet(sub)
+
+ # Populate ports table
+ for j in e.vports:
+ device_owner = ''
+ device_id = ''
+ mac_address = None
+ ipaddr = None
+ for v in j.props:
+ if v.name == 'OpenStack:device_owner':
+ device_owner = v.value
+ elif v.name == 'OpenStack:device_id':
+ device_id = v.value
+ elif v.name == 'macaddr':
+ mac_address = v.value
+ elif v.name == 'ipaddr':
+ ipaddr = v.value.split('/')[0]
+ if j.name.startswith(j.uuid[:8]):
+ # Skip autogenerated names
+ name = None
+ else:
+ name = j.name
+
+ p = {
+ 'tenant_id': j.tenantname,
+ 'id': j.uuid,
+ 'name': name,
+ 'network_id': e.uuid,
+ 'mac_address': mac_address,
+ 'admin_state_up': True,
+ 'status': 'ACTIVE',
+ 'device_id': device_id,
+ 'device_owner': device_owner,
+ 'fixed_ips': [{'subnet_id': e.ipnets[0].uuid,
+ 'ip_address': ipaddr}]
+ }
+ port = {'port': p}
+ create_db_port(port)
+
+ # Change the schema of the floatingips and routers tables by doing
+ # the following:
+ # Fetch the floatingip, router entry using EVS API,
+ # Temporarily store the information,
+ # Delete floatingip, router entry,
+ # Remove floatingip, router as a constraint from existing tables,
+ # Drop the routers, floatingips table,
+ # Add router, floatingip entry using Neutron API
+
+ # Importing locally because this module ends up importing neutron.wsgi
+ # which causes RAD to hang
+ from neutron.db import l3_db
+ havana_api.configure_db()
+ session = havana_api.get_session()
+
+ # Fetch the floatingip entry using EVS API
+ query = session.query(havana_api.FloatingIP)
+ floatingips = query.all()
+ fl = []
+ if floatingips:
+ for f in floatingips:
+ fi = {
+ 'id': f['id'],
+ 'floating_ip_address': f['floating_ip_address'],
+ 'floating_network_id': f['floating_network_id'],
+ 'floating_port_id': f['floating_port_id'],
+ 'fixed_port_id': f['fixed_port_id'],
+ 'fixed_ip_address': f['fixed_ip_address'],
+ 'tenant_id': f['tenant_id'],
+ 'router_id': f['router_id'],
+ }
+ fl.append(fi)
+
+ # Delete floatingip entry
+ ctxt = ctx.get_admin_context()
+ ctxt = havana_api.get_evs_context(ctxt)
+ with ctxt.session.begin(subtransactions=True):
+ cm_db_inst = common_db_mixin.CommonDbMixin()
+ query = common_db_mixin.CommonDbMixin._model_query(cm_db_inst,
+ ctxt,
+ havana_api.
+ FloatingIP)
+ for fip in query:
+ ctxt.session.delete(fip)
+
+ # Fetch the router entry using EVS API
+ query = session.query(havana_api.Router)
+ routers = []
+ try:
+ routers = query.all()
+ except sa.exc.OperationalError:
+ pass
+ if routers:
+ for r in routers:
+ router_id = r['id']
+ rt = {
+ 'tenant_id': r['tenant_id'],
+ 'id': r['id'],
+ 'name': r['name'],
+ 'admin_state_up': r['admin_state_up'],
+ 'status': 'ACTIVE'
+ }
+
+ # Delete router entry
+ ctxt = ctx.get_admin_context()
+ ctxt = havana_api.get_evs_context(ctxt)
+ with ctxt.session.begin(subtransactions=True):
+ cm_db_inst = common_db_mixin.CommonDbMixin()
+ query = common_db_mixin.CommonDbMixin._model_query(cm_db_inst,
+ ctxt,
+ havana_api.
+ Router)
+ router = query.filter(havana_api.Router.id == router_id).one()
+ ctxt.session.delete(router)
+
+ engine = sa.create_engine(SQL_CONNECTION)
+ meta = MetaData()
+ conn = engine.connect()
+ trans = conn.begin()
+ meta.reflect(engine)
+
+ # Remove router as a constraint from existing tables,
+ # Drop the routers table to remove old schema
+ for t in meta.tables.values():
+ for fk in t.foreign_keys:
+ if fk.column.table.name == "routers":
+ engine.execute(DropConstraint(fk.constraint))
+ for t in meta.tables.values():
+ if t.name == "routers":
+ t.drop(bind=conn)
+
+ # Remove floatingip as a constraint from existing tables,
+ # Drop the floatingip table to remove old schema
+ for t in meta.tables.values():
+ for fk in t.foreign_keys:
+ if fk.column.table.name == "floatingips":
+ engine.execute(DropConstraint(fk.constraint))
+ for t in meta.tables.values():
+ if t.name == "floatingips":
+ t.drop(bind=conn)
+ conn.close()
+
+ # Add the routers and floatingips using the schema in l3_db.py
+
+ setattr(l3_db.Router, 'enable_snat', sa.Column(sa.Boolean,
+ default=True, server_default=sql.true(), nullable=False))
+ neutron_engine = sa.create_engine(SQL_CONNECTION)
+ model_base.BASEV2.metadata.bind = neutron_engine
+ model_base.BASEV2.metadata.create_all(neutron_engine)
+ if routers:
+ ctxt = ctx.get_admin_context()
+ with ctxt.session.begin(subtransactions=True):
+ router_db = l3_db.Router(id=router_id,
+ tenant_id=r['tenant_id'],
+ name=rt['name'],
+ admin_state_up=rt['admin_state_up'],
+ status="ACTIVE")
+ ctxt.session.add(router_db)
+ print "\nrouter=%s updated" % rt['name']
+
+ if floatingips:
+ ctxt = ctx.get_admin_context()
+ with ctxt.session.begin(subtransactions=True):
+ for i in fl:
+ fl_db = l3_db.FloatingIP(
+ id=i['id'],
+ floating_ip_address=i['floating_ip_address'],
+ floating_network_id=i['floating_network_id'],
+ floating_port_id=i['floating_port_id'],
+ fixed_port_id=i['fixed_port_id'],
+ fixed_ip_address=i['fixed_ip_address'],
+ router_id=i['router_id'],
+ tenant_id=i['tenant_id'])
+ ctxt.session.add(fl_db)
+ print "\nfloatingip=%s updated" % i['floating_ip_address']
+
+ print "\nEnd Migration."
+
+
+if __name__ == '__main__':
+ main()