NSX|V3: Update upgrade scripts for native DHCP/Metadata
1. Upgrade ports with IPv4 address only 2. Delete previous internal metadata networks 3. Add list function for metadata proxy 4. Add more checking and logs 5. Pass required UUID from command-line 6. Refactor codes DocImpact Change-Id: I4e0f05b2dff9394cc6d0d567abf58507efaf6685
This commit is contained in:
parent
38c163b3e1
commit
c8b984ed5b
@ -205,6 +205,17 @@ Security Groups
|
||||
|
||||
nsx -r nsx-security-groups -o migrate-to-dynamic-criteria
|
||||
|
||||
Metadata Proxy
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- List version 1.0.0 metadata networks in Neutron::
|
||||
|
||||
nsxadmin -r metadata-proxy -o list
|
||||
|
||||
- Resync metadata proxies for NSXv3 version 1.1.0 and above::
|
||||
|
||||
nsxadmin -r metadata-proxy -o nsx-update --property metadata_proxy_uuid=<metadata_proxy_uuid>
|
||||
|
||||
DHCP Bindings
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@ -212,6 +223,30 @@ DHCP Bindings
|
||||
|
||||
nsxadmin -r dhcp-binding -o list
|
||||
|
||||
- Resync DHCP bindings for NSXv3 CrossHairs::
|
||||
- Resync DHCP bindings for NSXv3 version 1.1.0 and above::
|
||||
|
||||
nsxadmin -r dhcp-binding -o nsx-update
|
||||
nsxadmin -r dhcp-binding -o nsx-update --property dhcp_profile_uuid=<dhcp_profile_uuid>
|
||||
|
||||
Upgrade Steps (Version 1.0.0 to Version 1.1.0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. Upgrade NSX backend from version 1.0.0 to version 1.1.0
|
||||
|
||||
2. Create a DHCP-Profile and a Metadata-Proxy in NSX backend
|
||||
|
||||
3. Stop Neutron
|
||||
|
||||
4. Install version 1.1.0 Neutron plugin
|
||||
|
||||
5. Run admin tools to migrate version 1.0.0 objects to version 1.1.0 objects
|
||||
|
||||
nsxadmin -r metadata-proxy -o nsx-update --property metadata_proxy_uuid=<UUID of Metadata-Proxy created in Step 2>
|
||||
|
||||
nsxadmin -r dhcp-binding -o nsx-update --property dhcp_profile_uuid=<UUID of DHCP-Profile created in Step 2>
|
||||
|
||||
6. Start Neutron
|
||||
|
||||
7. Make sure /etc/nova/nova.conf has
|
||||
metadata_proxy_shared_secret = <Secret of Metadata-Proxy created in Step 2>
|
||||
|
||||
8. Restart VMs or ifdown/ifup their network interface to get new DHCP options
|
||||
|
@ -157,6 +157,31 @@ Example
|
||||
}
|
||||
|
||||
|
||||
Upgrade Steps (Version 1.0.0 to Version 1.1.0)
|
||||
----------------------------------------------
|
||||
|
||||
1. Upgrade NSX backend from version 1.0.0 to version 1.1.0
|
||||
|
||||
2. Create a DHCP-Profile and a Metadata-Proxy in NSX backend
|
||||
|
||||
3. Stop Neutron
|
||||
|
||||
4. Install version 1.1.0 Neutron plugin
|
||||
|
||||
5. Run admin tools to migrate version 1.0.0 objects to version 1.1.0 objects
|
||||
|
||||
* nsxadmin -r metadata-proxy -o nsx-update --property metadata_proxy_uuid=<UUID of Metadata-Proxy created in Step 2>
|
||||
|
||||
* nsxadmin -r dhcp-binding -o nsx-update --property dhcp_profile_uuid=<UUID of DHCP-Profile created in Step 2>
|
||||
|
||||
6. Start Neutron
|
||||
|
||||
7. Make sure /etc/nova/nova.conf has
|
||||
metadata_proxy_shared_secret = <Secret of Metadata-Proxy created in Step 2>
|
||||
|
||||
8. Restart VMs or ifdown/ifup their network interface to get new DHCP options
|
||||
|
||||
|
||||
Help
|
||||
----
|
||||
::
|
||||
|
@ -13,14 +13,15 @@
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import netaddr
|
||||
|
||||
from neutron.callbacks import registry
|
||||
from neutron_lib import constants as const
|
||||
from oslo_config import cfg
|
||||
|
||||
from vmware_nsx._i18n import _LI
|
||||
from vmware_nsx._i18n import _LE, _LI
|
||||
from vmware_nsx.common import nsx_constants
|
||||
from vmware_nsx.common import utils as comm_utils
|
||||
from vmware_nsx.common import utils as nsx_utils
|
||||
from vmware_nsx.nsxlib.v3 import native_dhcp
|
||||
from vmware_nsx.nsxlib.v3 import resources
|
||||
from vmware_nsx.shell.admin.plugins.common import constants
|
||||
@ -37,9 +38,9 @@ neutron_client = utils.NeutronDbClient()
|
||||
def list_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||
"""List DHCP bindings in Neutron."""
|
||||
|
||||
ports = neutron_client.get_ports()
|
||||
comp_ports = [port for port in ports if port['device_owner'].startswith(
|
||||
const.DEVICE_OWNER_COMPUTE_PREFIX)]
|
||||
comp_ports = [port for port in neutron_client.get_ports()
|
||||
if port['device_owner'].startswith(
|
||||
const.DEVICE_OWNER_COMPUTE_PREFIX)]
|
||||
LOG.info(formatters.output_formatter(constants.DHCP_BINDING, comp_ports,
|
||||
['id', 'mac_address', 'fixed_ips']))
|
||||
|
||||
@ -49,51 +50,81 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||
"""Resync DHCP bindings for NSXv3 CrossHairs."""
|
||||
|
||||
nsx_version = utils.get_connected_nsxlib().get_version()
|
||||
if not comm_utils.is_nsx_version_1_1_0(nsx_version):
|
||||
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||
LOG.info(_LI("This utility is not available for NSX version %s"),
|
||||
nsx_version)
|
||||
return
|
||||
|
||||
dhcp_profile_uuid = None
|
||||
if kwargs.get('property'):
|
||||
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||
dhcp_profile_uuid = properties.get('dhcp_profile_uuid')
|
||||
if not dhcp_profile_uuid:
|
||||
LOG.error(_LE("dhcp_profile_uuid is not defined"))
|
||||
return
|
||||
|
||||
cfg.CONF.set_override('dhcp_agent_notification', False)
|
||||
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||
cfg.CONF.set_override('dhcp_profile_uuid', dhcp_profile_uuid, 'nsx_v3')
|
||||
|
||||
nsx_client = utils.get_nsxv3_client()
|
||||
port_resource = resources.LogicalPort(nsx_client)
|
||||
dhcp_server_resource = resources.LogicalDhcpServer(nsx_client)
|
||||
|
||||
port_bindings = {} # lswitch_id: [(mac, ip, prefix_length), ...]
|
||||
port_bindings = {} # lswitch_id: [(port_id, mac, ip), ...]
|
||||
server_bindings = {} # lswitch_id: dhcp_server_id
|
||||
ports = neutron_client.get_ports()
|
||||
for port in ports:
|
||||
network_id = port['network_id']
|
||||
device_owner = port['device_owner']
|
||||
if device_owner == const.DEVICE_OWNER_DHCP:
|
||||
# For each DHCP-enabled network, create a logical DHCP server
|
||||
# and update the attachment type to DHCP on the corresponding
|
||||
# logical port of the Neutron DHCP port.
|
||||
subnet_id = port['fixed_ips'][0]['subnet_id']
|
||||
subnet = neutron_client.get_subnet(subnet_id)
|
||||
network = neutron_client.get_network(port['network_id'])
|
||||
if len(port['fixed_ips']) > 1:
|
||||
LOG.info(_LI("Network %(network)s has multiple subnets - "
|
||||
"only enable native DHCP on subnet %(subnet)s"),
|
||||
{'network': port['network_id'], 'subnet': subnet_id})
|
||||
server_data = native_dhcp.build_dhcp_server_config(
|
||||
network, subnet, port, 'NSX Neutron plugin upgrade')
|
||||
dhcp_server = dhcp_server_resource.create(**server_data)
|
||||
lswitch_id, lport_id = neutron_client.get_lswitch_and_lport_id(
|
||||
port['id'])
|
||||
port_resource.update(lport_id, dhcp_server['id'],
|
||||
attachment_type=nsx_constants.ATTACHMENT_DHCP)
|
||||
server_bindings[lswitch_id] = dhcp_server['id']
|
||||
elif device_owner.startswith(const.DEVICE_OWNER_COMPUTE_PREFIX):
|
||||
lswitch_id = neutron_client.net_id_to_lswitch_id(network_id)
|
||||
bindings = port_bindings.get(lswitch_id, [])
|
||||
bindings.append((port['mac_address'],
|
||||
port['fixed_ips'][0]['ip_address']))
|
||||
port_bindings[lswitch_id] = bindings
|
||||
if (device_owner != const.DEVICE_OWNER_DHCP and
|
||||
not device_owner.startswith(const.DEVICE_OWNER_COMPUTE_PREFIX)):
|
||||
continue
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
if netaddr.IPNetwork(fixed_ip['ip_address']).version == 6:
|
||||
continue
|
||||
network_id = port['network_id']
|
||||
subnet = neutron_client.get_subnet(fixed_ip['subnet_id'])
|
||||
if device_owner == const.DEVICE_OWNER_DHCP:
|
||||
# For each DHCP-enabled network, create a logical DHCP server
|
||||
# and update the attachment type to DHCP on the corresponding
|
||||
# logical port of the Neutron DHCP port.
|
||||
network = neutron_client.get_network(port['network_id'])
|
||||
server_data = native_dhcp.build_dhcp_server_config(
|
||||
network, subnet, port, 'admin')
|
||||
dhcp_server = dhcp_server_resource.create(**server_data)
|
||||
LOG.info(_LI("Created logical DHCP server %(server)s for "
|
||||
"network %(network)s"),
|
||||
{'server': dhcp_server['id'],
|
||||
'network': port['network_id']})
|
||||
# Add DHCP service binding in neutron DB.
|
||||
neutron_client.add_dhcp_service_binding(
|
||||
network['id'], port['id'], dhcp_server['id'])
|
||||
# Update logical port for DHCP purpose.
|
||||
lswitch_id, lport_id = (
|
||||
neutron_client.get_lswitch_and_lport_id(port['id']))
|
||||
port_resource.update(
|
||||
lport_id, dhcp_server['id'],
|
||||
attachment_type=nsx_constants.ATTACHMENT_DHCP)
|
||||
server_bindings[lswitch_id] = dhcp_server['id']
|
||||
LOG.info(_LI("Updated DHCP logical port %(port)s for "
|
||||
"network %(network)s"),
|
||||
{'port': lport_id, 'network': port['network_id']})
|
||||
elif subnet['enable_dhcp']:
|
||||
# Store (mac, ip) binding of each compute port in a
|
||||
# DHCP-enabled subnet.
|
||||
lswitch_id = neutron_client.net_id_to_lswitch_id(network_id)
|
||||
bindings = port_bindings.get(lswitch_id, [])
|
||||
bindings.append((port['id'], port['mac_address'],
|
||||
fixed_ip['ip_address']))
|
||||
port_bindings[lswitch_id] = bindings
|
||||
break # process only the first IPv4 address
|
||||
|
||||
# Populate mac/IP bindings in each logical DHCP server.
|
||||
for lswitch_id, bindings in port_bindings.items():
|
||||
dhcp_server_id = server_bindings[lswitch_id]
|
||||
for (mac, ip) in bindings:
|
||||
dhcp_server_id = server_bindings.get(lswitch_id)
|
||||
if not dhcp_server_id:
|
||||
continue
|
||||
for (port_id, mac, ip) in bindings:
|
||||
hostname = 'host-%s' % ip.replace('.', '-')
|
||||
options = {'option121': {'static_routes': [
|
||||
{'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route,
|
||||
@ -101,6 +132,9 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||
dhcp_server_resource.create_binding(
|
||||
dhcp_server_id, mac, ip, hostname,
|
||||
cfg.CONF.nsx_v3.dhcp_lease_time, options)
|
||||
LOG.info(_LI("Added DHCP binding (mac: %(mac)s, ip: %(ip)s) "
|
||||
"for neutron port %(port)s"),
|
||||
{'mac': mac, 'ip': ip, 'port': port_id})
|
||||
|
||||
|
||||
registry.subscribe(list_dhcp_bindings,
|
||||
|
@ -15,13 +15,16 @@
|
||||
import logging
|
||||
|
||||
from neutron.callbacks import registry
|
||||
from neutron_lib import constants as const
|
||||
from oslo_config import cfg
|
||||
|
||||
from vmware_nsx._i18n import _LI, _LE
|
||||
from vmware_nsx._i18n import _LE, _LI
|
||||
from vmware_nsx.common import nsx_constants
|
||||
from vmware_nsx.common import utils as nsx_utils
|
||||
from vmware_nsx.dhcp_meta import rpc as nsx_rpc
|
||||
from vmware_nsx.nsxlib.v3 import resources
|
||||
from vmware_nsx.shell.admin.plugins.common import constants
|
||||
from vmware_nsx.shell.admin.plugins.common import formatters
|
||||
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
|
||||
from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils
|
||||
import vmware_nsx.shell.resources as shell
|
||||
@ -30,30 +33,92 @@ LOG = logging.getLogger(__name__)
|
||||
neutron_client = utils.NeutronDbClient()
|
||||
|
||||
|
||||
def _is_metadata_network(network):
|
||||
# If a Neutron network has only one subnet with 169.254.169.252/30 CIDR,
|
||||
# then it is an internal metadata network.
|
||||
if len(network['subnets']) == 1:
|
||||
subnet = neutron_client.get_subnet(network['subnets'][0])
|
||||
if subnet['cidr'] == nsx_rpc.METADATA_SUBNET_CIDR:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@admin_utils.output_header
|
||||
def list_metadata_networks(resource, event, trigger, **kwargs):
|
||||
"""List Metadata networks in Neutron."""
|
||||
|
||||
meta_networks = [network for network in neutron_client.get_networks()
|
||||
if _is_metadata_network(network)]
|
||||
LOG.info(formatters.output_formatter(constants.METADATA_PROXY,
|
||||
meta_networks,
|
||||
['id', 'name', 'subnets']))
|
||||
|
||||
|
||||
@admin_utils.output_header
|
||||
def nsx_update_metadata_proxy(resource, event, trigger, **kwargs):
|
||||
"""Update Metadata proxy for NSXv3 CrossHairs."""
|
||||
|
||||
nsx_version = utils.get_connected_nsxlib().get_version()
|
||||
if not nsx_utils.is_nsx_version_1_1_0(nsx_version):
|
||||
LOG.info(_LI("This utility is not available for NSX version %s"),
|
||||
nsx_version)
|
||||
return
|
||||
|
||||
metadata_proxy_uuid = None
|
||||
if kwargs.get('property'):
|
||||
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||
metadata_proxy_uuid = properties.get('metadata_proxy_uuid')
|
||||
if not metadata_proxy_uuid:
|
||||
LOG.error(_LE("metadata_proxy_uuid is not defined"))
|
||||
return
|
||||
|
||||
cfg.CONF.set_override('dhcp_agent_notification', False)
|
||||
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||
cfg.CONF.set_override('metadata_proxy_uuid', metadata_proxy_uuid, 'nsx_v3')
|
||||
|
||||
plugin = utils.NsxV3PluginWrapper()
|
||||
nsx_client = utils.get_nsxv3_client()
|
||||
port_resource = resources.LogicalPort(nsx_client)
|
||||
|
||||
# For each Neutron network, check if it is an internal metadata network.
|
||||
# If yes, delete the network and associated router interface.
|
||||
# Otherwise, create a logical switch port with MD-Proxy attachment.
|
||||
for network in neutron_client.get_networks():
|
||||
# For each Neutron network, create a logical switch port with
|
||||
# MD-Proxy attachment.
|
||||
lswitch_id = neutron_client.net_id_to_lswitch_id(network['id'])
|
||||
if lswitch_id:
|
||||
if _is_metadata_network(network):
|
||||
# It is a metadata network, find the attached router,
|
||||
# remove the router interface and the network.
|
||||
filters = {'device_owner': const.ROUTER_INTERFACE_OWNERS,
|
||||
'fixed_ips': {
|
||||
'subnet_id': [network['subnets'][0]],
|
||||
'ip_address': [nsx_rpc.METADATA_GATEWAY_IP]}}
|
||||
ports = neutron_client.get_ports(filters=filters)
|
||||
if not ports:
|
||||
continue
|
||||
router_id = ports[0]['device_id']
|
||||
interface = {'subnet_id': network['subnets'][0]}
|
||||
plugin.remove_router_interface(router_id, interface)
|
||||
LOG.info(_LI("Removed metadata interface on router %s"), router_id)
|
||||
plugin.delete_network(network['id'])
|
||||
LOG.info(_LI("Removed metadata network %s"), network['id'])
|
||||
else:
|
||||
lswitch_id = neutron_client.net_id_to_lswitch_id(network['id'])
|
||||
if not lswitch_id:
|
||||
continue
|
||||
tags = nsx_utils.build_v3_tags_payload(
|
||||
network, resource_type='os-neutron-net-id',
|
||||
project_name='NSX Neutron plugin upgrade')
|
||||
project_name='admin')
|
||||
name = nsx_utils.get_name_and_uuid('%s-%s' % (
|
||||
'mdproxy', network['name'] or 'network'), network['id'])
|
||||
port_resource.create(
|
||||
lswitch_id, cfg.CONF.nsx_v3.metadata_proxy_uuid, tags=tags,
|
||||
lswitch_id, metadata_proxy_uuid, tags=tags, name=name,
|
||||
attachment_type=nsx_constants.ATTACHMENT_MDPROXY)
|
||||
LOG.info(_LI("Enabled native metadata proxy for network %s"),
|
||||
network['id'])
|
||||
else:
|
||||
LOG.error(_LE("Unable to find logical switch for network %s"),
|
||||
network['id'])
|
||||
|
||||
|
||||
registry.subscribe(list_metadata_networks,
|
||||
constants.METADATA_PROXY,
|
||||
shell.Operations.LIST.value)
|
||||
registry.subscribe(nsx_update_metadata_proxy,
|
||||
constants.METADATA_PROXY,
|
||||
shell.Operations.NSX_UPDATE.value)
|
||||
|
@ -17,6 +17,7 @@ from neutron import context
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from oslo_config import cfg
|
||||
|
||||
from vmware_nsx.common import nsx_constants
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.nsxlib import v3
|
||||
from vmware_nsx.plugins.nsx_v3 import plugin
|
||||
@ -72,8 +73,17 @@ class NeutronDbClient(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
lswitch_ids = nsx_db.get_nsx_switch_ids(self.context.session, net_id)
|
||||
return lswitch_ids[0] if lswitch_ids else None
|
||||
|
||||
def add_dhcp_service_binding(self, network_id, port_id, server_id):
|
||||
return nsx_db.add_neutron_nsx_service_binding(
|
||||
self.context.session, network_id, port_id,
|
||||
nsx_constants.SERVICE_DHCP, server_id)
|
||||
|
||||
|
||||
class NsxV3PluginWrapper(plugin.NsxV3Plugin):
|
||||
def __init__(self):
|
||||
super(NsxV3PluginWrapper, self).__init__()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def _init_dhcp_metadata(self):
|
||||
pass
|
||||
|
||||
@ -90,3 +100,11 @@ class NsxV3PluginWrapper(plugin.NsxV3Plugin):
|
||||
self._extend_network_dict_provider(context, net)
|
||||
# skip getting the Qos policy ID because get_object calls
|
||||
# plugin init again on admin-util environment
|
||||
|
||||
def delete_network(self, network_id):
|
||||
return super(NsxV3PluginWrapper, self).delete_network(
|
||||
self.context, network_id)
|
||||
|
||||
def remove_router_interface(self, router_id, interface):
|
||||
return super(NsxV3PluginWrapper, self).remove_router_interface(
|
||||
self.context, router_id, interface)
|
||||
|
@ -79,6 +79,9 @@ nsxv3_resources = {
|
||||
constants.DHCP_BINDING: Resource(constants.DHCP_BINDING,
|
||||
[Operations.LIST.value,
|
||||
Operations.NSX_UPDATE.value]),
|
||||
constants.METADATA_PROXY: Resource(constants.METADATA_PROXY,
|
||||
[Operations.LIST.value,
|
||||
Operations.NSX_UPDATE.value]),
|
||||
}
|
||||
|
||||
# Add supported NSX-V resources in this dictionary
|
||||
|
Loading…
Reference in New Issue
Block a user