+# #############################################################
+# WARNINGS: The following deprecations have been made in the
+# Havana release. Support for the options below will be removed
+# in Ixxx.
+#
+# Section: [DEFAULT], Option: 'metadata_dhcp_host_route'
+# Remarks: Use 'enable_isolated_metadata' in dhcp_agent.ini.
+#
+#
+# Section: [CLUSTER:name], Option: 'nvp_controller_connection'
+# Remarks: The configuration will allow the specification of
+# a single cluster, therefore [CLUSTER:name] is no
+# longer used. Use 'nvp_*', options, 'req_timeout',
+# 'retries', etc. as indicated in the DEFAULT section.
+# Support for multiple clusters will be added through
+# an API extension.
+# ##############################################################
+
+[DEFAULT]
+# User name for NVP controller
+# nvp_user = admin
+
+# Password for NVP controller
+# nvp_password = admin
+
+# Total time limit for a cluster request
+# (including retries across different controllers)
+# req_timeout = 30
+
+# Time before aborting a request on an unresponsive controller
+# http_timeout = 10
+
+# Maximum number of times a particular request should be retried
+# retries = 2
+
+# Maximum number of times a redirect response should be followed
+# redirects = 2
+
+# Comma-separated list of NVP controller endpoints (<ip>:<port>). When port
+# is omitted, 443 is assumed. This option MUST be specified, e.g.:
+# nvp_controllers = xx.yy.zz.ww:443, aa.bb.cc.dd, ee.ff.gg.hh.ee:80
+
+# UUID of the pre-existing default NVP Transport zone to be used for creating
+# tunneled isolated "Quantum" networks. This option MUST be specified, e.g.:
+# default_tz_uuid = 1e8e52cf-fa7f-46b0-a14a-f99835a9cb53
+
+# (Optional) UUID of the cluster in NVP. It can be retrieved from NVP management
+# console "admin" section.
+# nvp_cluster_uuid = 615be8e4-82e9-4fd2-b4b3-fd141e51a5a7
+
+# (Optional) UUID for the default l3 gateway service to use with this cluster.
+# To be specified if planning to use logical routers with external gateways.
+# default_l3_gw_service_uuid =
+
+# (Optional) UUID for the default l2 gateway service to use with this cluster.
+# To be specified for providing a predefined gateway tenant for connecting their networks.
+# default_l2_gw_service_uuid =
+
+# Name of the default interface name to be used on network-gateway. This value
+# will be used for any device associated with a network gateway for which an
+# interface name was not specified
+# default_iface_name = breth0
+
+
[DATABASE]
# This line MUST be changed to actually run the plugin.
# Example:
# Replace 127.0.0.1 above with the IP address of the database used by the
# main quantum server. (Leave it as is if the database runs on this host.)
sql_connection = sqlite://
-# Database reconnection retry times - in event connectivity is lost
-# set to -1 implies an infinite retry count
+
+# Number of reconnection attempts to the DB; Set to -1 to try indefinitely
# sql_max_retries = 10
-# Database reconnection interval in seconds - if the initial connection to the
-# database fails
-reconnect_interval = 2
+
+# Period between reconnection attempts to the DB
+# reconnect_interval = 2
+
# Enable the use of eventlet's db_pool for MySQL. The flags sql_min_pool_size,
# sql_max_pool_size and sql_idle_timeout are relevant only if this is enabled.
+
# sql_dbpool_enable = False
+
# Minimum number of SQL connections to keep open in a pool
# sql_min_pool_size = 1
+
# Maximum number of SQL connections to keep open in a pool
# sql_max_pool_size = 5
+
# Timeout in seconds before idle sql connections are reaped
# sql_idle_timeout = 3600
+
[QUOTAS]
# number of network gateways allowed per tenant, -1 means unlimited
# quota_network_gateway = 5
+
[NVP]
# Maximum number of ports for each bridged logical switch
# max_lp_per_bridged_ls = 64
+
# Maximum number of ports for each overlay (stt, gre) logical switch
# max_lp_per_overlay_ls = 256
+
# Number of connects to each controller node.
# concurrent_connections = 3
-# Name of the default cluster where requests should be sent if a nova zone id
-# is not specified. If it is empty or reference a non-existent cluster
-# the first cluster specified in this configuration file will be used
-# default_cluster_name =
-# If set to access_network this enables a dedicated connection to the
-# metadata proxy for metadata server access via Quantum router. If set to
-# dhcp_host_route this enables host route injection via the dhcp agent.
+
+# Acceptable values for 'metadata_mode' are:
+# - 'access_network': this enables a dedicated connection to the metadata
+# proxy for metadata server access via Quantum router.
+# - 'dhcp_host_route': this enables host route injection via the dhcp agent.
# This option is only useful if running on a host that does not support
# namespaces otherwise access_network should be used.
# metadata_mode = access_network
-
-#[CLUSTER:example]
-# This is uuid of the default NVP Transport zone that will be used for
-# creating tunneled isolated "Quantum" networks. It needs to be created in
-# NVP before starting Quantum with the nvp plugin.
-# default_tz_uuid = 1e8e52cf-fa7f-46b0-a14a-f99835a9cb53
-
-# Nova "zone" that maps to this NVP cluster. This should map to the
-# node_availability_zone in your nova.conf for each nova cluster. Each nova
-# cluster should have a unique node_availability_zone set.
-# nova_zone_id = zone1 # (Optional)
-
-# UUID of the cluster in NVP. This can be retrieved from NVP management
-# console "admin" section.
-# nvp_cluster_uuid = 615be8e4-82e9-4fd2-b4b3-fd141e51a5a7 # (Optional)
-
-# UUID of the default layer 3 gateway service to use for this cluster
-# This is optional, but should be filled if planning to use logical routers
-# with external gateways
-# default_l3_gw_service_uuid =
-
-# UUID of the default layer 2 gateway service to use for this cluster
-# This is optional. It should be filled for providing a predefined gateway
-# tenant case use for connecting their networks.
-# default_l2_gw_service_uuid =
-
-# Name of the default interface name to be used on network-gateway.
-# This value will be used for any device associated with a network
-# gateway for which an interface name was not specified
-# default_iface_name = breth0
-
-# This parameter describes a connection to a single NVP controller. Format:
-# <ip>:<port>:<user>:<pw>:<req_timeout>:<http_timeout>:<retries>:<redirects>
-# <ip> is the ip address of the controller
-# <port> is the port of the controller (default NVP port is 443)
-# <user> is the user name for this controller
-# <pw> is the user password.
-# <req_timeout>: The total time limit on all operations for a controller
-# request (including retries, redirects from unresponsive controllers).
-# Default is 30.
-# <http_timeout>: How long to wait before aborting an unresponsive controller
-# (and allow for retries to another controller in the cluster).
-# Default is 10.
-# <retries>: the maximum number of times to retry a particular request
-# Default is 2.
-# <redirects>: the maximum number of times to follow a redirect response from a server.
-# Default is 2.
-# There must be at least one nvp_controller_connection per system or per cluster.
-# nvp_controller_connection=10.0.1.2:443:admin:admin:30:10:2:2
-# nvp_controller_connection=10.0.1.3:443:admin:admin:30:10:2:2
-# nvp_controller_connection=10.0.1.4:443:admin:admin:30:10:2:2
from quantum.extensions import securitygroup as ext_sg
from quantum.openstack.common import importutils
from quantum.openstack.common import rpc
-from quantum.plugins.nicira.common import config
+from quantum.plugins.nicira.common import config # noqa
from quantum.plugins.nicira.common import exceptions as nvp_exc
from quantum.plugins.nicira.common import metadata_access as nvp_meta
from quantum.plugins.nicira.common import securitygroups as nvp_sec
VLAN = 'vlan'
-def parse_config():
- """Parse the supplied plugin configuration.
-
- :param config: a ConfigParser() object encapsulating nvp.ini.
- :returns: A tuple: (clusters, plugin_config). 'clusters' is a list of
- NVPCluster objects, 'plugin_config' is a dictionary with plugin
- parameters (currently only 'max_lp_per_bridged_ls').
- """
- nvp_conf = config.ClusterConfigOptions(cfg.CONF)
- cluster_names = config.register_cluster_groups(nvp_conf)
- nvp_conf.log_opt_values(LOG, logging.DEBUG)
-
- clusters_options = []
- for cluster_name in cluster_names:
- clusters_options.append(
- {'name': cluster_name,
- 'default_tz_uuid':
- nvp_conf[cluster_name].default_tz_uuid,
- 'nvp_cluster_uuid':
- nvp_conf[cluster_name].nvp_cluster_uuid,
- 'nova_zone_id':
- nvp_conf[cluster_name].nova_zone_id,
- 'nvp_controller_connection':
- nvp_conf[cluster_name].nvp_controller_connection,
- 'default_l3_gw_service_uuid':
- nvp_conf[cluster_name].default_l3_gw_service_uuid,
- 'default_l2_gw_service_uuid':
- nvp_conf[cluster_name].default_l2_gw_service_uuid,
- 'default_interface_name':
- nvp_conf[cluster_name].default_interface_name})
- LOG.debug(_("Cluster options:%s"), clusters_options)
-
- # If no api_extensions_path is provided set the following
- if not cfg.CONF.api_extensions_path:
- cfg.CONF.set_override(
- 'api_extensions_path',
- 'quantum/plugins/nicira/extensions')
- if (cfg.CONF.NVP.metadata_mode == "access_network" and
- not cfg.CONF.allow_overlapping_ips):
- LOG.warn(_("Overlapping IPs must be enabled in order to setup "
- "the metadata access network. Metadata access in "
- "routed mode will not work with this configuration"))
- return cfg.CONF.NVP, clusters_options
-
-
-def parse_clusters_opts(clusters_opts, concurrent_connections,
- nvp_gen_timeout, default_cluster_name):
- # Will store the first cluster in case is needed for default
- # cluster assignment
- clusters = {}
- first_cluster = None
- for c_opts in clusters_opts:
- # Password is guaranteed to be the same across all controllers
- # in the same NVP cluster.
- cluster = nvp_cluster.NVPCluster(c_opts['name'])
- try:
- for ctrl_conn in c_opts['nvp_controller_connection']:
- args = ctrl_conn.split(':')
- try:
- args.extend([c_opts['default_tz_uuid'],
- c_opts['nvp_cluster_uuid'],
- c_opts['nova_zone_id'],
- c_opts['default_l3_gw_service_uuid'],
- c_opts['default_l2_gw_service_uuid'],
- c_opts['default_interface_name']])
- cluster.add_controller(*args)
- except Exception:
- LOG.exception(_("Invalid connection parameters for "
- "controller %(ctrl)s in "
- "cluster %(cluster)s"),
- {'ctrl': ctrl_conn,
- 'cluster': c_opts['name']})
- raise nvp_exc.NvpInvalidConnection(
- conn_params=ctrl_conn)
- except TypeError:
- msg = _("No controller connection specified in cluster "
- "configuration. Please ensure at least a value for "
- "'nvp_controller_connection' is specified in the "
- "[CLUSTER:%s] section") % c_opts['name']
- LOG.exception(msg)
- raise nvp_exc.NvpPluginException(err_msg=msg)
-
- api_providers = [(x['ip'], x['port'], True)
- for x in cluster.controllers]
- cluster.api_client = NvpApiClient.NVPApiHelper(
- api_providers, cluster.user, cluster.password,
- request_timeout=cluster.request_timeout,
- http_timeout=cluster.http_timeout,
- retries=cluster.retries,
- redirects=cluster.redirects,
- concurrent_connections=concurrent_connections,
- nvp_gen_timeout=nvp_gen_timeout)
-
- if not clusters:
- first_cluster = cluster
- clusters[c_opts['name']] = cluster
-
- if default_cluster_name and default_cluster_name in clusters:
- default_cluster = clusters[default_cluster_name]
- else:
- default_cluster = first_cluster
- return (clusters, default_cluster)
+def create_nvp_cluster(cluster_opts, concurrent_connections,
+ nvp_gen_timeout):
+ # NOTE(armando-migliaccio): remove this block once we no longer
+ # want to support deprecated options in the nvp config file
+ # ### BEGIN
+ config.register_deprecated(cfg.CONF)
+ # ### END
+ cluster = nvp_cluster.NVPCluster(**cluster_opts)
+ api_providers = [ctrl.split(':') + [True]
+ for ctrl in cluster.nvp_controllers]
+ cluster.api_client = NvpApiClient.NVPApiHelper(
+ api_providers, cluster.nvp_user, cluster.nvp_password,
+ request_timeout=cluster.req_timeout,
+ http_timeout=cluster.http_timeout,
+ retries=cluster.retries,
+ redirects=cluster.redirects,
+ concurrent_connections=concurrent_connections,
+ nvp_gen_timeout=nvp_gen_timeout)
+ return cluster
class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
# Map nova zones to cluster for easy retrieval
novazone_cluster_map = {}
- # Default controller cluster (to be used when nova zone id is unspecified)
- default_cluster = None
provider_network_view = "extension:provider_network:view"
provider_network_set = "extension:provider_network:set"
'default': self._nvp_delete_port}
}
- self.nvp_opts, self.clusters_opts = parse_config()
- if not self.clusters_opts:
- msg = _("No cluster specified in NVP plugin configuration. "
- "Unable to start. Please ensure at least a "
- "[CLUSTER:<cluster_name>] section is specified in "
- "the NVP Plugin configuration file.")
- LOG.error(msg)
- raise nvp_exc.NvpPluginException(err_msg=msg)
-
- self.clusters, self.default_cluster = parse_clusters_opts(
- self.clusters_opts, self.nvp_opts.concurrent_connections,
- self.nvp_opts.nvp_gen_timeout, self.nvp_opts.default_cluster_name)
+ self.nvp_opts = cfg.CONF.NVP
+ self.cluster = create_nvp_cluster(cfg.CONF,
+ self.nvp_opts.concurrent_connections,
+ self.nvp_opts.nvp_gen_timeout)
db.configure_db()
- # Extend the fault map
self._extend_fault_map()
# Set up RPC interface for DHCP agent
self.setup_rpc()
self.network_scheduler = importutils.import_object(
cfg.CONF.network_scheduler_driver)
- # TODO(salvatore-orlando): Handle default gateways in multiple clusters
self._ensure_default_network_gateway()
def _ensure_default_network_gateway(self):
# Add the gw in the db as default, and unset any previous default
- def_l2_gw_uuid = self.default_cluster.default_l2_gw_service_uuid
+ def_l2_gw_uuid = self.cluster.default_l2_gw_service_uuid
try:
ctx = q_context.get_admin_context()
self._unset_default_network_gateways(ctx)
max_ports = self.nvp_opts.max_lp_per_bridged_ls
allow_extra_lswitches = True
try:
- cluster = self._find_target_cluster(port_data)
- return self._handle_lswitch_selection(
- cluster, network, network_binding, max_ports,
- allow_extra_lswitches)
+ return self._handle_lswitch_selection(self.cluster, network,
+ network_binding, max_ports,
+ allow_extra_lswitches)
except NvpApiClient.NvpApiException:
err_desc = _("An exception occured while selecting logical "
"switch for the port")
# No need to actually update the DB state - the default is down
return port_data
try:
- cluster = self._find_target_cluster(port_data)
selected_lswitch = self._nvp_find_lswitch_for_port(context,
port_data)
- lport = self._nvp_create_port_helper(cluster,
+ lport = self._nvp_create_port_helper(self.cluster,
selected_lswitch['uuid'],
port_data,
True)
if (not port_data['device_owner'] in
(l3_db.DEVICE_OWNER_ROUTER_GW,
l3_db.DEVICE_OWNER_ROUTER_INTF)):
- nvplib.plug_interface(cluster, selected_lswitch['uuid'],
+ nvplib.plug_interface(self.cluster, selected_lswitch['uuid'],
lport['uuid'], "VifAttachment",
port_data['id'])
LOG.debug(_("_nvp_create_port completed for port %(name)s "
"external networks. Port %s will be down."),
port_data['network_id'])
return
- nvp_port_id = self._nvp_get_port_id(context, self.default_cluster,
+ nvp_port_id = self._nvp_get_port_id(context, self.cluster,
port_data)
if not nvp_port_id:
LOG.debug(_("Port '%s' was already deleted on NVP platform"), id)
# back will have zero ports after the delete we should garbage collect
# the lswitch.
try:
- nvplib.delete_port(self.default_cluster,
+ nvplib.delete_port(self.cluster,
port_data['network_id'],
nvp_port_id)
LOG.debug(_("_nvp_delete_port completed for port %(port_id)s "
def _nvp_delete_router_port(self, context, port_data):
# Delete logical router port
lrouter_id = port_data['device_id']
- nvp_port_id = self._nvp_get_port_id(context, self.default_cluster,
+ nvp_port_id = self._nvp_get_port_id(context, self.cluster,
port_data)
if not nvp_port_id:
raise q_exc.PortNotFound(port_id=port_data['id'])
try:
- nvplib.delete_peer_router_lport(self.default_cluster,
+ nvplib.delete_peer_router_lport(self.cluster,
lrouter_id,
port_data['network_id'],
nvp_port_id)
try:
selected_lswitch = self._nvp_find_lswitch_for_port(context,
port_data)
- cluster = self._find_target_cluster(port_data)
# Do not apply port security here!
- lport = self._nvp_create_port_helper(cluster,
+ lport = self._nvp_create_port_helper(self.cluster,
selected_lswitch['uuid'],
port_data,
False)
def _find_router_gw_port(self, context, port_data):
router_id = port_data['device_id']
- cluster = self._find_target_cluster(port_data)
if not router_id:
raise q_exc.BadRequest(_("device_id field must be populated in "
"order to create an external gateway "
"port for network %s"),
port_data['network_id'])
- lr_port = nvplib.find_router_gw_port(context, cluster, router_id)
+ lr_port = nvplib.find_router_gw_port(context, self.cluster, router_id)
if not lr_port:
raise nvp_exc.NvpPluginException(
err_msg=(_("The gateway port for the router %s "
# the fabric status of the NVP router will be down.
# admin_status should always be up for the gateway port
# regardless of what the user specifies in quantum
- cluster = self._find_target_cluster(port_data)
router_id = port_data['device_id']
- nvplib.update_router_lport(cluster,
+ nvplib.update_router_lport(self.cluster,
router_id,
lr_port['uuid'],
port_data['tenant_id'],
if ext_network.get(pnet.NETWORK_TYPE) == NetworkTypes.L3_EXT:
# Update attachment
self._update_router_port_attachment(
- cluster, context, router_id, port_data,
+ self.cluster, context, router_id, port_data,
"L3GatewayAttachment",
ext_network[pnet.PHYSICAL_NETWORK],
ext_network[pnet.SEGMENTATION_ID],
# Set the SNAT rule for each subnet (only first IP)
for cidr in self._find_router_subnets_cidrs(context, router_id):
nvplib.create_lrouter_snat_rule(
- cluster, router_id,
+ self.cluster, router_id,
ip_addresses[0].split('/')[0],
ip_addresses[0].split('/')[0],
order=NVP_EXTGW_NAT_RULES_ORDER,
try:
# Delete is actually never a real delete, otherwise the NVP
# logical router will stop working
- cluster = self._find_target_cluster(port_data)
router_id = port_data['device_id']
- nvplib.update_router_lport(cluster,
+ nvplib.update_router_lport(self.cluster,
router_id,
lr_port['uuid'],
port_data['tenant_id'],
# Delete the SNAT rule for each subnet
for cidr in self._find_router_subnets_cidrs(context, router_id):
nvplib.delete_nat_rules_by_match(
- cluster, router_id, "SourceNatRule",
+ self.cluster, router_id, "SourceNatRule",
max_num_expected=1, min_num_expected=1,
source_ip_addresses=cidr)
# Reset attachment
self._update_router_port_attachment(
- cluster, context, router_id, port_data,
+ self.cluster, context, router_id, port_data,
"L3GatewayAttachment",
- self.default_cluster.default_l3_gw_service_uuid,
+ self.cluster.default_l3_gw_service_uuid,
nvp_router_port_id=lr_port['uuid'])
except NvpApiClient.ResourceNotFound:
# No need to actually update the DB state - the default is down
return port_data
try:
- cluster = self._find_target_cluster(port_data)
selected_lswitch = self._nvp_find_lswitch_for_port(context,
port_data)
- lport = self._nvp_create_port_helper(cluster,
+ lport = self._nvp_create_port_helper(self.cluster,
selected_lswitch['uuid'],
port_data,
True)
nicira_db.add_quantum_nvp_port_mapping(
context.session, port_data['id'], lport['uuid'])
nvplib.plug_l2_gw_service(
- cluster,
+ self.cluster,
port_data['network_id'],
lport['uuid'],
port_data['device_id'],
nvp_exc.NvpNoMorePortsException:
webob.exc.HTTPBadRequest})
- def _novazone_to_cluster(self, novazone_id):
- if novazone_id in self.novazone_cluster_map:
- return self.novazone_cluster_map[novazone_id]
- LOG.debug(_("Looking for nova zone: %s"), novazone_id)
- for x in self.clusters:
- LOG.debug(_("Looking for nova zone %(novazone_id)s in "
- "cluster: %(x)s"),
- {'novazone_id': novazone_id, 'x': x})
- if x.zone == str(novazone_id):
- self.novazone_cluster_map[x.zone] = x
- return x
- LOG.error(_("Unable to find cluster config entry for nova zone: %s"),
- novazone_id)
- raise nvp_exc.NvpInvalidNovaZone(nova_zone=novazone_id)
-
- def _find_target_cluster(self, resource):
- """Return cluster where configuration should be applied
-
- If the resource being configured has a paremeter expressing
- the zone id (nova_id), then select corresponding cluster,
- otherwise return default cluster.
-
- """
- if 'nova_id' in resource:
- return self._novazone_to_cluster(resource['nova_id'])
- else:
- return self.default_cluster
-
def _check_view_auth(self, context, resource, action):
return policy.check(context, action, resource)
allow_extra_lswitches):
lswitches = nvplib.get_lswitches(cluster, network.id)
try:
- # TODO(savatore-orlando) Find main_ls too!
+ # TODO(salvatore-orlando) find main_ls too!
return [ls for ls in lswitches
if (ls['_relations']['LogicalSwitchStatus']
['lport_count'] < max_ports)].pop(0)
# Consume from all consumers in a thread
self.conn.consume_in_thread()
- def get_all_networks(self, tenant_id, **kwargs):
- networks = []
- for c in self.clusters:
- networks.extend(nvplib.get_all_networks(c, tenant_id, networks))
- LOG.debug(_("get_all_networks() completed for tenant "
- "%(tenant_id)s: %(networks)s"),
- {'tenant_id': tenant_id, 'networks': networks})
- return networks
-
def create_network(self, context, network):
net_data = network['network']
tenant_id = self._get_tenant_id_for_create(context, net_data)
LOG.warning(_("Network with admin_state_up=False are not yet "
"supported by this plugin. Ignoring setting for "
"network %s"), net_data.get('name', '<unknown>'))
- target_cluster = self._find_target_cluster(net_data)
external = net_data.get(l3.EXTERNAL)
if (not attr.is_attr_set(external) or
attr.is_attr_set(external) and not external):
if nvp_binding_type in ('flat', 'vlan'):
nvp_binding_type = 'bridge'
lswitch = nvplib.create_lswitch(
- target_cluster, tenant_id, net_data.get('name'),
- nvp_binding_type,
- net_data.get(pnet.PHYSICAL_NETWORK),
+ self.cluster, tenant_id, net_data.get('name'),
+ nvp_binding_type, net_data.get(pnet.PHYSICAL_NETWORK),
net_data.get(pnet.SEGMENTATION_ID),
shared=net_data.get(attr.SHARED))
net_data['id'] = lswitch['uuid']
router_iface_ports = self.get_ports(context, filters=port_filter)
for port in router_iface_ports:
nvp_port_id = self._nvp_get_port_id(
- context, self.default_cluster, port)
+ context, self.cluster, port)
if nvp_port_id:
port['nvp_port_id'] = nvp_port_id
else:
for port in router_iface_ports:
try:
if 'nvp_port_id' in port:
- nvplib.delete_peer_router_lport(self.default_cluster,
+ nvplib.delete_peer_router_lport(self.cluster,
port['device_id'],
port['network_id'],
port['nvp_port_id'])
# Do not go to NVP for external networks
if not external:
try:
- # FIXME(salvatore-orlando): Failures here might lead NVP
- # and quantum state to diverge
- pairs = self._get_lswitch_cluster_pairs(id, context.tenant_id)
- for (cluster, switches) in pairs:
- nvplib.delete_networks(cluster, id, switches)
-
+ lswitch_ids = [ls['uuid'] for ls in
+ nvplib.get_lswitches(self.cluster, id)]
+ nvplib.delete_networks(self.cluster, id, lswitch_ids)
LOG.debug(_("delete_network completed for tenant: %s"),
context.tenant_id)
except q_exc.NotFound:
LOG.warning(_("Did not found lswitch %s in NVP"), id)
- def _get_lswitch_cluster_pairs(self, netw_id, tenant_id):
- """Figure out the set of lswitches on each cluster that maps to this
- network id
- """
- pairs = []
- for c in self.clusters.itervalues():
- lswitches = []
- try:
- results = nvplib.get_lswitches(c, netw_id)
- lswitches.extend([ls['uuid'] for ls in results])
- except q_exc.NetworkNotFound:
- continue
- pairs.append((c, lswitches))
- if not pairs:
- raise q_exc.NetworkNotFound(net_id=netw_id)
- LOG.debug(_("Returning pairs for network: %s"), pairs)
- return pairs
-
def get_network(self, context, id, fields=None):
with context.session.begin(subtransactions=True):
# goto to the plugin DB and fetch the network
# verify the fabric status of the corresponding
# logical switch(es) in nvp
try:
- # FIXME(salvatore-orlando): This is not going to work
- # unless we store the nova_id in the database once we'll
- # enable multiple clusters
- cluster = self._find_target_cluster(network)
- lswitches = nvplib.get_lswitches(cluster, id)
+ lswitches = nvplib.get_lswitches(self.cluster, id)
nvp_net_status = constants.NET_STATUS_ACTIVE
quantum_status = network.status
for lswitch in lswitches:
relations='LogicalSwitchStatus',
filters={'tag': 'true', 'tag_scope': 'shared'})
try:
- for c in self.clusters.itervalues():
- res = nvplib.get_all_query_pages(
- lswitch_url_path_1, c)
- nvp_lswitches.update(dict(
- (ls['uuid'], ls) for ls in res))
- # Issue a second query for fetching shared networks.
- # We cannot unfortunately use just a single query because tags
- # cannot be or-ed
- res_shared = nvplib.get_all_query_pages(
- lswitch_url_path_2, c)
- nvp_lswitches.update(dict(
- (ls['uuid'], ls) for ls in res_shared))
+ res = nvplib.get_all_query_pages(lswitch_url_path_1, self.cluster)
+ nvp_lswitches.update(dict((ls['uuid'], ls) for ls in res))
+ # Issue a second query for fetching shared networks.
+ # We cannot unfortunately use just a single query because tags
+ # cannot be or-ed
+ res_shared = nvplib.get_all_query_pages(lswitch_url_path_2,
+ self.cluster)
+ nvp_lswitches.update(dict((ls['uuid'], ls) for ls in res_shared))
except Exception:
err_msg = _("Unable to get logical switches")
LOG.exception(err_msg)
lport_fields_str = ("tags,admin_status_enabled,display_name,"
"fabric_status_up")
try:
- for c in self.clusters.itervalues():
- lport_query_path = (
- "/ws.v1/lswitch/%s/lport?fields=%s&%s%stag_scope=q_port_id"
- "&relations=LogicalPortStatus" %
- (lswitch, lport_fields_str, vm_filter, tenant_filter))
-
- try:
- ports = nvplib.get_all_query_pages(lport_query_path, c)
- except q_exc.NotFound:
- LOG.warn(_("Lswitch %s not found in NVP"), lswitch)
- ports = None
-
- if ports:
- for port in ports:
- for tag in port["tags"]:
- if tag["scope"] == "q_port_id":
- nvp_lports[tag["tag"]] = port
+ lport_query_path = (
+ "/ws.v1/lswitch/%s/lport?fields=%s&%s%stag_scope=q_port_id"
+ "&relations=LogicalPortStatus" %
+ (lswitch, lport_fields_str, vm_filter, tenant_filter))
+ try:
+ ports = nvplib.get_all_query_pages(lport_query_path,
+ self.cluster)
+ except q_exc.NotFound:
+ LOG.warn(_("Lswitch %s not found in NVP"), lswitch)
+ ports = None
+
+ if ports:
+ for port in ports:
+ for tag in port["tags"]:
+ if tag["scope"] == "q_port_id":
+ nvp_lports[tag["tag"]] = port
except Exception:
err_msg = _("Unable to get ports")
LOG.exception(err_msg)
self._extend_port_dict_security_group(context, ret_port)
LOG.debug(_("Update port request: %s"), port)
nvp_port_id = self._nvp_get_port_id(
- context, self.default_cluster, ret_port)
- nvplib.update_port(self.default_cluster,
+ context, self.cluster, ret_port)
+ nvplib.update_port(self.cluster,
ret_port['network_id'],
nvp_port_id, id, tenant_id,
ret_port['name'], ret_port['device_id'],
# the status.
try:
ret_port['status'] = nvplib.get_port_status(
- self.default_cluster, ret_port['network_id'], nvp_port_id)
+ self.cluster, ret_port['network_id'], nvp_port_id)
except Exception:
LOG.warn(_("Unable to retrieve port status for:%s."), nvp_port_id)
return ret_port
if self._network_is_external(context,
quantum_db_port['network_id']):
return quantum_db_port
- nvp_id = self._nvp_get_port_id(context, self.default_cluster,
+ nvp_id = self._nvp_get_port_id(context, self.cluster,
quantum_db_port)
# If there's no nvp IP do not bother going to NVP and put
# the port in error state
if nvp_id:
- #TODO(salvatore-orlando): pass the appropriate cluster here
try:
port = nvplib.get_logical_port_status(
- self.default_cluster, quantum_db_port['network_id'],
+ self.cluster, quantum_db_port['network_id'],
nvp_id)
quantum_db_port["admin_state_up"] = (
port["admin_status_enabled"])
if ext_net.subnets:
ext_subnet = ext_net.subnets[0]
nexthop = ext_subnet.gateway_ip
- cluster = self._find_target_cluster(router)
- lrouter = nvplib.create_lrouter(cluster, tenant_id,
+ lrouter = nvplib.create_lrouter(self.cluster, tenant_id,
router['router']['name'],
nexthop)
# Use NVP identfier for Quantum resource
raise nvp_exc.NvpPluginException(
err_msg=_("Unable to create logical router on NVP Platform"))
# Create the port here - and update it later if we have gw_info
- self._create_and_attach_router_port(cluster,
- context,
- lrouter['uuid'],
- {'fake_ext_gw': True},
- "L3GatewayAttachment",
- cluster.default_l3_gw_service_uuid)
+ self._create_and_attach_router_port(
+ self.cluster, context, lrouter['uuid'], {'fake_ext_gw': True},
+ "L3GatewayAttachment", self.cluster.default_l3_gw_service_uuid)
with context.session.begin(subtransactions=True):
router_db = l3_db.Router(id=lrouter['uuid'],
if ext_net.subnets:
ext_subnet = ext_net.subnets[0]
nexthop = ext_subnet.gateway_ip
- cluster = self._find_target_cluster(router)
- nvplib.update_lrouter(cluster, id,
+ nvplib.update_lrouter(self.cluster, id,
router['router'].get('name'), nexthop)
except NvpApiClient.ResourceNotFound:
raise nvp_exc.NvpPluginException(
# allow an extra field for storing the cluster information
# together with the resource
try:
- nvplib.delete_lrouter(self.default_cluster, id)
+ nvplib.delete_lrouter(self.cluster, id)
except q_exc.NotFound:
LOG.warning(_("Logical router '%s' not found "
"on NVP Platform") % id)
def get_router(self, context, id, fields=None):
router = self._get_router(context, id)
try:
- # FIXME(salvatore-orlando): We need to
- # find the appropriate cluster!
- cluster = self.default_cluster
try:
- lrouter = nvplib.get_lrouter(cluster, id)
+ lrouter = nvplib.get_lrouter(self.cluster, id)
except q_exc.NotFound:
lrouter = {}
router_op_status = constants.NET_STATUS_ERROR
else:
tenant_id = context.tenant_id
try:
- nvp_lrouters = nvplib.get_lrouters(self.default_cluster,
+ nvp_lrouters = nvplib.get_lrouters(self.cluster,
tenant_id,
fields)
except NvpApiClient.NvpApiException:
port_id = router_iface_info['port_id']
subnet_id = router_iface_info['subnet_id']
# Add port to the logical router as well
- # TODO(salvatore-orlando): Identify the appropriate cluster, instead
- # of always defaulting to self.default_cluster
- cluster = self.default_cluster
# The owner of the router port is always the same as the owner of the
# router. Use tenant_id from the port instead of fetching more records
# from the Quantum database
port = self._get_port(context, port_id)
# Find the NVP port corresponding to quantum port_id
results = nvplib.query_lswitch_lports(
- cluster, '*',
+ self.cluster, '*',
filters={'tag': port_id, 'tag_scope': 'q_port_id'})
if results:
ls_port = results[0]
# Create logical router port and patch attachment
self._create_and_attach_router_port(
- cluster, context, router_id, port,
+ self.cluster, context, router_id, port,
"PatchAttachment", ls_port['uuid'],
subnet_ids=[subnet_id])
subnet = self._get_subnet(context, subnet_id)
if gw_port.get('fixed_ips'):
snat_ip = gw_port['fixed_ips'][0]['ip_address']
nvplib.create_lrouter_snat_rule(
- cluster, router_id, snat_ip, snat_ip,
+ self.cluster, router_id, snat_ip, snat_ip,
order=NVP_EXTGW_NAT_RULES_ORDER,
match_criteria={'source_ip_addresses': subnet['cidr']})
nvplib.create_lrouter_nosnat_rule(
- cluster, router_id,
+ self.cluster, router_id,
order=NVP_NOSNAT_RULES_ORDER,
match_criteria={'destination_ip_addresses': subnet['cidr']})
return router_iface_info
def remove_router_interface(self, context, router_id, interface_info):
- # TODO(salvatore-orlando): Usual thing about cluster selection
- cluster = self.default_cluster
# The code below is duplicated from base class, but comes handy
# as we need to retrieve the router port id before removing the port
subnet = None
raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_id,
subnet_id=subnet_id)
results = nvplib.query_lswitch_lports(
- cluster, '*', relations="LogicalPortAttachment",
+ self.cluster, '*', relations="LogicalPortAttachment",
filters={'tag': port_id, 'tag_scope': 'q_port_id'})
lrouter_port_id = None
if results:
# Remove SNAT rule if external gateway is configured
if router.gw_port:
nvplib.delete_nat_rules_by_match(
- cluster, router_id, "SourceNatRule",
+ self.cluster, router_id, "SourceNatRule",
max_num_expected=1, min_num_expected=1,
source_ip_addresses=subnet['cidr'])
# Relax the minimum expected number as the nosnat rules
# do not exist in 2.x deployments
nvplib.delete_nat_rules_by_match(
- cluster, router_id, "NoSourceNatRule",
+ self.cluster, router_id, "NoSourceNatRule",
max_num_expected=1, min_num_expected=0,
destination_ip_addresses=subnet['cidr'])
- nvplib.delete_router_lport(cluster, router_id, lrouter_port_id)
+ nvplib.delete_router_lport(self.cluster,
+ router_id, lrouter_port_id)
except NvpApiClient.ResourceNotFound:
raise nvp_exc.NvpPluginException(
err_msg=(_("Logical router port resource %s not found "
def _retrieve_and_delete_nat_rules(self, floating_ip_address,
internal_ip, router_id,
min_num_rules_expected=0):
- #TODO(salvatore-orlando): Multiple cluster support
- cluster = self.default_cluster
try:
nvplib.delete_nat_rules_by_match(
- cluster, router_id, "DestinationNatRule",
+ self.cluster, router_id, "DestinationNatRule",
max_num_expected=1,
min_num_expected=min_num_rules_expected,
destination_ip_addresses=floating_ip_address)
# Remove SNAT rule associated with the single fixed_ip
# to floating ip
nvplib.delete_nat_rules_by_match(
- cluster, router_id, "SourceNatRule",
+ self.cluster, router_id, "SourceNatRule",
max_num_expected=1,
min_num_expected=min_num_rules_expected,
source_ip_addresses=internal_ip)
# Fetch logical port of router's external gateway
router_id = fip_db.router_id
nvp_gw_port_id = nvplib.find_router_gw_port(
- context, self.default_cluster, router_id)['uuid']
+ context, self.cluster, router_id)['uuid']
ext_quantum_port_db = self._get_port(context.elevated(),
fip_db.floating_port_id)
nvp_floating_ips = self._build_ip_address_list(
context.elevated(), ext_quantum_port_db['fixed_ips'])
- nvplib.update_lrouter_port_ips(self.default_cluster,
+ nvplib.update_lrouter_port_ips(self.cluster,
router_id,
nvp_gw_port_id,
ips_to_add=[],
fip,
floatingip_db['floating_network_id'])
- cluster = self._find_target_cluster(fip)
floating_ip = floatingip_db['floating_ip_address']
# Retrieve and delete existing NAT rules, if any
if not router_id and floatingip_db.get('fixed_port_id'):
router_id)
# Fetch logical port of router's external gateway
nvp_gw_port_id = nvplib.find_router_gw_port(
- context, self.default_cluster, router_id)['uuid']
+ context, self.cluster, router_id)['uuid']
nvp_floating_ips = self._build_ip_address_list(
context.elevated(), external_port['fixed_ips'])
LOG.debug(_("Address list for NVP logical router "
try:
# Create new NAT rules
nvplib.create_lrouter_dnat_rule(
- cluster, router_id, internal_ip,
+ self.cluster, router_id, internal_ip,
order=NVP_FLOATINGIP_NAT_RULES_ORDER,
match_criteria={'destination_ip_addresses':
floating_ip})
# setup snat rule such that src ip of a IP packet when
# using floating is the floating ip itself.
nvplib.create_lrouter_snat_rule(
- cluster, router_id, floating_ip, floating_ip,
+ self.cluster, router_id, floating_ip, floating_ip,
order=NVP_FLOATINGIP_NAT_RULES_ORDER,
match_criteria={'source_ip_addresses': internal_ip})
# Add Floating IP address to router_port
- nvplib.update_lrouter_port_ips(cluster,
+ nvplib.update_lrouter_port_ips(self.cluster,
router_id,
nvp_gw_port_id,
ips_to_add=nvp_floating_ips,
elif floatingip_db['fixed_port_id']:
# This is a disassociation.
# Remove floating IP address from logical router port
- nvplib.update_lrouter_port_ips(cluster,
+ nvplib.update_lrouter_port_ips(self.cluster,
router_id,
nvp_gw_port_id,
ips_to_add=[],
# Need to re-do authZ checks here in order to avoid creation on NVP
gw_data = network_gateway[networkgw.RESOURCE_NAME.replace('-', '_')]
tenant_id = self._get_tenant_id_for_create(context, gw_data)
- cluster = self._find_target_cluster(gw_data)
devices = gw_data['devices']
# Populate default physical network where not specified
for device in devices:
if not device.get('interface_name'):
- device['interface_name'] = cluster.default_interface_name
+ device['interface_name'] = self.cluster.default_interface_name
try:
- nvp_res = nvplib.create_l2_gw_service(cluster, tenant_id,
- gw_data['name'],
- devices)
+ nvp_res = nvplib.create_l2_gw_service(self.cluster, tenant_id,
+ gw_data['name'], devices)
nvp_uuid = nvp_res.get('uuid')
except Exception:
raise nvp_exc.NvpPluginException(
with context.session.begin(subtransactions=True):
try:
super(NvpPluginV2, self).delete_network_gateway(context, id)
- nvplib.delete_l2_gw_service(self.default_cluster, id)
+ nvplib.delete_l2_gw_service(self.cluster, id)
except NvpApiClient.ResourceNotFound:
# Do not cause a 500 to be returned to the user if
# the corresponding NVP resource does not exist
if not default_sg:
self._ensure_default_security_group(context, tenant_id)
- nvp_secgroup = nvplib.create_security_profile(self.default_cluster,
+ nvp_secgroup = nvplib.create_security_profile(self.cluster,
tenant_id, s)
security_group['security_group']['id'] = nvp_secgroup['uuid']
return super(NvpPluginV2, self).create_security_group(
if super(NvpPluginV2, self)._get_port_security_group_bindings(
context, filters):
raise ext_sg.SecurityGroupInUse(id=security_group['id'])
- nvplib.delete_security_profile(self.default_cluster,
+ nvplib.delete_security_profile(self.cluster,
security_group['id'])
return super(NvpPluginV2, self).delete_security_group(
context, security_group_id)
# of them to PUT to NVP.
combined_rules = self._merge_security_group_rules_with_current(
context, s, security_group['id'])
- nvplib.update_security_group_rules(self.default_cluster,
+ nvplib.update_security_group_rules(self.cluster,
security_group['id'],
combined_rules)
return super(
self._remove_security_group_with_id_and_id_field(
current_rules, sgrid)
nvplib.update_security_group_rules(
- self.default_cluster, sgid, current_rules)
+ self.cluster, sgid, current_rules)
return super(NvpPluginV2, self).delete_security_group_rule(context,
sgrid)
if check_policy:
self._enforce_set_auth(context, q, ext_qos.qos_queue_create)
self._validate_qos_queue(context, q)
- q['id'] = nvplib.create_lqueue(self.default_cluster,
+ q['id'] = nvplib.create_lqueue(self.cluster,
self._nvp_lqueue(q))
return super(NvpPluginV2, self).create_qos_queue(context, qos_queue)
raise ext_qos.QueueInUseByPort()
else:
return
- nvplib.delete_lqueue(self.default_cluster, id)
+ nvplib.delete_lqueue(self.cluster, id)
return super(NvpPluginV2, self).delete_qos_queue(context, id)
def get_qos_queue(self, context, id, fields=None):
- nvp_gen_timout: Number of seconds a generation id should be valid for
(default -1 meaning do not time out)
3) NVP cluster
- The Quantum NVP plugin allow for configuring multiple clusters.
- Each cluster configuration section must be declared in the following way
- in the configuration file: [CLUSTER:cluster_name].
- The following parameters can be configured for each cluster:
+ By default the Quantum NVP plugin can talk to multiple controllers in a
+ single cluster. In the future (Havana+) support for multiple clusters
+ will be added.
+ The following parameters can be configured:
- default_tz_uuid: This is uuid of the default NVP Transport zone that
- will be used for creating tunneled isolated "Quantum" networks. It
- needs to be created in NVP before starting Quantum with the nvp plugin.
- - nova_zone_id: Optional parameter identifying the Nova "zone" that maps
- to this NVP cluster.
- - nvp_cluster_uuid: Optional paramter identifying the UUID of the cluster
- in NVP. This can be retrieved from NVP management console "admin" section.
- - nvp_controller_connetion: describes a connection to a single NVP
- controller. A different connection for each controller in the cluster can
- be specified; there must be at least one connection per cluster.
+ will be used for creating tunneled isolated "Quantum" networks. It
+ needs to be created in NVP before starting Quantum with the nvp plugin.
+ - nvp_cluster_uuid: Optional paramter identifying the UUID of the cluster
+ in NVP. This can be retrieved from NVP management console "admin" section.
+ - nvp_controllers: describes the list of controllers
+ More details can be found in etc/quantum/plugins/nicira/nvp.ini
Quantum Configuration
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Nicira, Inc.
from oslo.config import cfg
from quantum.common import config
-from quantum.plugins.nicira import NvpApiClient
+from quantum.plugins.nicira.common import config as nvp_cfg # noqa
from quantum.plugins.nicira import nvplib
from quantum.plugins.nicira import QuantumPlugin
config.setup_logging(cfg.CONF)
-def help():
- print "Usage ./check_nvp_config path/to/nvp.ini"
- exit(1)
-
-
-def display_controller_info(controller):
- print "\tCan login: %s" % controller.get('can_login')
- print "\tuser: %s" % controller.get('user')
- print "\tpassword: %s" % controller.get('password')
- print "\tip: %s" % controller.get('ip')
- print "\tport: %s" % controller.get('port')
- print "\trequested_timeout: %s" % controller.get('requested_timeout')
- print "\tretires: %s" % controller.get('retries')
- print "\tredirects: %s" % controller.get('redirects')
- print "\thttp_timeout: %s" % controller.get('http_timeout')
-
-
-def test_controller(cluster, controller):
- api_providers = [(controller.get('ip'), controller.get('port'), True)]
- api_client = NvpApiClient.NVPApiHelper(
- api_providers, cluster.user, cluster.password,
- controller.get('requested_timeout'),
- controller.get('http_timeout'),
- controller.get('retries'),
- controller.get('redirects'))
-
- controller['can_login'] = (api_client.login() and True or False)
+def help(name):
+ print "Usage: %s path/to/nvp.ini" % name
+ sys.exit(1)
def get_gateway_services(cluster):
ret_gw_services = {"L2GatewayServiceConfig": [],
"L3GatewayServiceConfig": []}
- gw_services = nvplib.get_gateway_services(cluster).get('results')
- if gw_services:
- for gw_service in gw_services:
- ret_gw_services[gw_service['type']].append(gw_service['uuid'])
-
+ gw_services = nvplib.get_gateway_services(cluster).get('results', [])
+ for gw_service in gw_services:
+ ret_gw_services[gw_service['type']].append(gw_service['uuid'])
return ret_gw_services
def main(argv):
- if len(sys.argv) != 2:
- help()
+ if len(argv) != 2:
+ help(argv[0])
args = ['--config-file']
- args.append(sys.argv[1])
+ args.append(argv[1])
config.parse(args)
- errors = False
- nvp_opts, clusters_opts = QuantumPlugin.parse_config()
- print "-----------Database Options--------------------"
- print "sql_connection: %s" % cfg.CONF.DATABASE.sql_connection
- print "reconnect_interval: %d" % cfg.CONF.DATABASE.reconnect_interval
- print "sql_max_retries: %d" % cfg.CONF.DATABASE.sql_max_retries
- print "-----------NVP Options--------------------"
- print ("Number of concurrents allow to each controller %d" %
- nvp_opts.concurrent_connections)
- print "NVP Generation Timeout %d" % nvp_opts.nvp_gen_timeout
- print "NVP Default Cluster Name %s" % nvp_opts.default_cluster_name
-
- print "-----------Cluster Options--------------------"
- if not clusters_opts:
- print "No NVP Clusters detected in nvp.ini!"
- exit(1)
- clusters, default_cluster = QuantumPlugin.parse_clusters_opts(
- clusters_opts, nvp_opts.concurrent_connections,
- nvp_opts.nvp_gen_timeout, nvp_opts.default_cluster_name)
- for cluster in clusters.itervalues():
- num_controllers = cluster.get_num_controllers()
- print "\n%d controllers found in cluster [CLUSTER:%s]" % (
- num_controllers, cluster.name)
- if num_controllers == 0:
- print ("Cluster %s has no nvp_controller_connection defined!" %
- cluster.name)
- exit(1)
-
- for i in range(0, num_controllers):
- controller = cluster.get_controller(i)
- if i == 0:
- gateway_services = get_gateway_services(cluster)
- transport_zones = get_transport_zones(cluster)
- controller.update(nvplib.check_cluster_connectivity(cluster))
- default_tz_zone = controller.get('default_tz_uuid')
- print ("\n\tdefault_tz_uuid: %s" % default_tz_zone)
- if not default_tz_zone:
- print "\t* ERROR: No default trasport zone specified!"
- errors = True
- elif default_tz_zone not in transport_zones:
- print ("\t* ERROR: did not find default transport %s zone "
- "on NVP!" % default_tz_zone)
- errors = True
- print ("\tapi_redirect_interval: %s" %
- controller.get('api_redirect_interval'))
- print "\tcluster uuid: %s" % controller.get('uuid')
- print "\tapi_mode: %s" % controller.get('api_mode')
- l2_gateway = controller.get('default_l2_gw_service_uuid')
- print ("\tdefault_l2_gw_service_uuid: %s" % l2_gateway)
- if (l2_gateway and l2_gateway not in
- gateway_services['L2GatewayServiceConfig']):
- print ("\t* ERROR: Did not find L2 gateway service uuid %s"
- " in NVP!" % l2_gateway)
- errors = True
- l3_gateway = controller.get('default_l3_gw_service_uuid')
- print ("\tdefault_l3_gw_service_uuid: %s" % l3_gateway)
- if (l3_gateway and l3_gateway not in
- gateway_services['L3GatewayServiceConfig']):
- print ("\t* ERROR did not find L3 gateway service uuid %s"
- " in NVP!" % l3_gateway)
- errors = True
- print ("\n-----controller %d------\n" % (i + 1))
- test_controller(cluster, controller)
- display_controller_info(controller)
- print "\n"
- if errors:
- print ("**There were configuration errors found "
- "please review output carefully!!**")
- print "\n"
+ print "------------------------ Database Options ------------------------"
+ print "\tsql_connection: %s" % cfg.CONF.DATABASE.sql_connection
+ print "\treconnect_interval: %d" % cfg.CONF.DATABASE.reconnect_interval
+ print "\tsql_max_retries: %d" % cfg.CONF.DATABASE.sql_max_retries
+ print "------------------------ NVP Options ------------------------"
+ print "\tNVP Generation Timeout %d" % cfg.CONF.NVP.nvp_gen_timeout
+ print ("\tNumber of concurrent connections to each controller %d" %
+ cfg.CONF.NVP.concurrent_connections)
+ print "\tmax_lp_per_bridged_ls: %s" % cfg.CONF.NVP.max_lp_per_bridged_ls
+ print "\tmax_lp_per_overlay_ls: %s" % cfg.CONF.NVP.max_lp_per_overlay_ls
+ print ("\tenable_metadata_access_network: %s" %
+ cfg.CONF.NVP.enable_metadata_access_network)
+ print "------------------------ Cluster Options ------------------------"
+ print "\trequested_timeout: %s" % cfg.CONF.req_timeout
+ print "\tretries: %s" % cfg.CONF.retries
+ print "\tredirects: %s" % cfg.CONF.redirects
+ print "\thttp_timeout: %s" % cfg.CONF.http_timeout
+ cluster = QuantumPlugin.create_nvp_cluster(
+ cfg.CONF,
+ cfg.CONF.NVP.concurrent_connections,
+ cfg.CONF.NVP.nvp_gen_timeout)
+ num_controllers = len(cluster.nvp_controllers)
+ print "Number of controllers found: %s" % num_controllers
+ if num_controllers == 0:
+ print "You must specify at least one controller!"
+ sys.exit(1)
+
+ for controller in cluster.nvp_controllers:
+ print "\tController endpoint: %s" % controller
+ nvplib.check_cluster_connectivity(cluster)
+ gateway_services = get_gateway_services(cluster)
+ for svc_type in ["L2GatewayServiceConfig",
+ "L3GatewayServiceConfig"]:
+ for uuid in gateway_services[svc_type]:
+ print "\t\tGateway(%s) uuid: %s" % (svc_type, uuid)
+ transport_zones = get_transport_zones(cluster)
+ print "\tTransport zones: %s" % transport_zones
+ print "Done."
from quantum import scheduler
-core_opts = [
- cfg.BoolOpt('metadata_dhcp_host_route', default=False),
-]
-
nvp_opts = [
cfg.IntOpt('max_lp_per_bridged_ls', default=64,
help=_("Maximum number of ports of a logical switch on a "
cfg.IntOpt('nvp_gen_timeout', default=-1,
help=_("Number of seconds a generation id should be valid for "
"(default -1 meaning do not time out)")),
- cfg.StrOpt('default_cluster_name',
- help=_("Default cluster name")),
cfg.StrOpt('metadata_mode', default='access_network',
help=_("If set to access_network this enables a dedicated "
"connection to the metadata proxy for metadata server "
"This option is only useful if running on a host that "
"does not support namespaces otherwise access_network "
"should be used.")),
+ cfg.BoolOpt('enable_metadata_access_network', default=True,
+ help=_("Enables dedicated connection to the metadata proxy "
+ "for metadata server access via Quantum router")),
+]
+
+connection_opts = [
+ cfg.StrOpt('nvp_user',
+ default='admin',
+ help=_('User name for NVP controllers in this cluster')),
+ cfg.StrOpt('nvp_password',
+ default='admin',
+ secret=True,
+ help=_('Password for NVP controllers in this cluster')),
+ cfg.IntOpt('req_timeout',
+ default=30,
+ help=_('Total time limit for a cluster request')),
+ cfg.IntOpt('http_timeout',
+ default=10,
+ help=_('Time before aborting a request')),
+ cfg.IntOpt('retries',
+ default=2,
+ help=_('Number of time a request should be retried')),
+ cfg.IntOpt('redirects',
+ default=2,
+ help=_('Number of times a redirect should be followed')),
+ cfg.ListOpt('nvp_controllers',
+ help=_("Lists the NVP controllers in this cluster")),
]
cluster_opts = [
help=_("Optional paramter identifying the UUID of the cluster "
"in NVP. This can be retrieved from NVP management "
"console \"admin\" section.")),
- cfg.StrOpt('nova_zone_id',
- help=_("Optional parameter identifying the Nova \"zone\" that "
- "maps to this NVP cluster.")),
- cfg.MultiStrOpt('nvp_controller_connection',
- help=_("Describes a connection to a single NVP "
- "controller. A different connection for each "
- "controller in the cluster can be specified; "
- "there must be at least one connection per "
- "cluster.")),
cfg.StrOpt('default_l3_gw_service_uuid',
help=_("Unique identifier of the NVP L3 Gateway service "
"which will be used for implementing routers and "
]
# Register the configuration options
-cfg.CONF.register_opts(core_opts)
+cfg.CONF.register_opts(connection_opts)
+cfg.CONF.register_opts(cluster_opts)
cfg.CONF.register_opts(nvp_opts, "NVP")
cfg.CONF.register_opts(scheduler.AGENTS_SCHEDULER_OPTS)
-
-
-class ClusterConfigOptions(cfg.ConfigOpts):
-
- def __init__(self, config_options):
- super(ClusterConfigOptions, self).__init__()
- self._group_mappings = {}
- self._config_opts = config_options._config_opts
- self._cparser = config_options._cparser
- self._oparser = config_options._oparser
- self.register_cli_opts(self._config_opts)
-
- def _do_get(self, name, group=None):
- """Look up an option value.
-
- :param name: the opt name (or 'dest', more precisely)
- :param group: an OptGroup
- :returns: the option value, or a GroupAttr object
- :raises: NoSuchOptError, NoSuchGroupError, ConfigFileValueError,
- TemplateSubstitutionError
- """
- if group is None and name in self._groups:
- return self.GroupAttr(self, self._get_group(name))
-
- info = self._get_opt_info(name, group)
- opt = info['opt']
-
- if 'override' in info:
- return info['override']
-
- values = []
- if self._cparser is not None:
- section = group.name if group is not None else 'DEFAULT'
- # Check if the name of the group maps to something else in
- # the conf file.Otherwise leave the section name unchanged
-
- section = self._group_mappings.get(section, section)
- try:
- value = opt._get_from_config_parser(self._cparser, section)
- except KeyError:
- pass
- except ValueError as ve:
- raise cfg.ConfigFileValueError(str(ve))
- else:
- if not opt.multi:
- # No need to continue since the last value wins
- return value[-1]
- values.extend(value)
-
- name = name if group is None else group.name + '_' + name
- value = self._cli_values.get(name)
- if value is not None:
- if not opt.multi:
- return value
-
- return value + values
-
- if values:
- return values
-
- if 'default' in info:
- return info['default']
-
- return opt.default
-
- def register_opts(self, opts, group_internal_name=None, group=None):
- """Register multiple option schemas at once."""
- if group_internal_name:
- self._group_mappings[group] = group_internal_name
- for opt in opts:
- self.register_opt(opt, group, clear_cache=False)
-
-
-def _retrieve_extra_groups(conf, key=None, delimiter=':'):
- """retrieve configuration groups not listed above."""
- results = []
- for parsed_file in cfg.CONF._cparser.parsed:
- for parsed_item in parsed_file.keys():
- if parsed_item not in cfg.CONF:
- items = key and parsed_item.split(delimiter)
- if not key or key == items[0]:
- results.append(parsed_item)
- return results
-
-
-def register_cluster_groups(conf):
- """retrieve configuration groups for nvp clusters."""
- cluster_names = []
- cluster_tags = _retrieve_extra_groups(conf, "CLUSTER")
- for tag in cluster_tags:
- cluster_name = tag.split(':')[1]
- conf.register_opts(cluster_opts, tag, cluster_name)
- cluster_names.append(cluster_name)
- return cluster_names
+# NOTE(armando-migliaccio): keep the following code until we support
+# NVP configuration files in older format (Grizzly or older).
+# ### BEGIN
+controller_depr = cfg.MultiStrOpt('nvp_controller_connection',
+ help=_("Describes a connection to a single "
+ "controller. A different connection "
+ "for each controller in the cluster "
+ "can be specified; there must be at "
+ "least one connection per cluster."))
+
+host_route_depr = cfg.BoolOpt('metadata_dhcp_host_route', default=None)
+
+
+def register_deprecated(conf):
+ conf.register_opts([host_route_depr])
+ multi_parser = cfg.MultiConfigParser()
+ read_ok = multi_parser.read(conf.config_file)
+ if len(read_ok) != len(conf.config_file):
+ raise cfg.Error("Some config files were not parsed properly")
+
+ for parsed_file in multi_parser.parsed:
+ for section in parsed_file.keys():
+ if section not in conf and section.startswith("CLUSTER:"):
+ conf.register_opts(cluster_opts + [controller_depr], section)
+# ### END
message = _("Invalid NVP connection parameters: %(conn_params)s")
+class NvpInvalidClusterConfiguration(NvpPluginException):
+ message = _("Invalid cluster values: %(invalid_attrs)s. Please ensure "
+ "that these values are specified in the [DEFAULT] "
+ "section of the nvp plugin ini file.")
+
+
class NvpInvalidNovaZone(NvpPluginException):
message = _("Unable to find cluster config entry "
"for nova zone: %(nova_zone)s")
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
-import re
+from oslo.config import cfg
-from quantum.api.v2 import attributes
from quantum.openstack.common import log as logging
+from quantum.plugins.nicira.common import exceptions
LOG = logging.getLogger(__name__)
+DEFAULT_PORT = 443
+# Raise if one of those attributes is not specified
+REQUIRED_ATTRIBUTES = ['default_tz_uuid', 'nvp_user',
+ 'nvp_password', 'nvp_controllers']
+# Emit a INFO log if one of those attributes is not specified
+IMPORTANT_ATTRIBUTES = ['default_l3_gw_service_uuid']
+# Deprecated attributes
+DEPRECATED_ATTRIBUTES = ['metadata_dhcp_host_route',
+ 'nvp_controller_connection']
class NVPCluster(object):
- """Encapsulates controller connection and api_client for a cluster.
+ """Encapsulates controller connections and the Api client for a
+ NVP cluster. Accessed within the NvpPluginV2 class.
- Accessed within the NvpPluginV2 class.
-
- Each element in the self.controllers list is a dictionary that
- contains the following keys:
- ip, port, user, password, default_tz_uuid, uuid, zone
-
- There may be some redundancy here, but that has been done to provide
- future flexibility.
+ Controller-specific parameters, such as timeouts are stored in the
+ elements of the controllers attribute, which are dicts.
"""
- def __init__(self, name):
- self._name = name
- self.controllers = []
+ def __init__(self, **kwargs):
+ self._required_attributes = REQUIRED_ATTRIBUTES[:]
+ self._important_attributes = IMPORTANT_ATTRIBUTES[:]
+ self._deprecated_attributes = {}
+ self._sanity_check(kwargs)
+
+ for opt, val in self._deprecated_attributes.iteritems():
+ LOG.deprecated(_("Attribute '%s' has been deprecated or moved "
+ "to a new section. See new configuration file "
+ "for details."), opt)
+ depr_func = getattr(self, '_process_%s' % opt, None)
+ if depr_func:
+ depr_func(val)
+
+ # If everything went according to plan these two lists should be empty
+ if self._required_attributes:
+ raise exceptions.NvpInvalidClusterConfiguration(
+ invalid_attrs=self._required_attributes)
+ if self._important_attributes:
+ LOG.info(_("The following cluster attributes were "
+ "not specified: %s'"), self._important_attributes)
+ # The API client will be explicitly created by users of this class
self.api_client = None
- def __repr__(self):
- ss = ['{ "NVPCluster": [']
- ss.append('{ "name" : "%s" }' % self.name)
- ss.append(',')
- for c in self.controllers:
- ss.append(str(c))
- ss.append(',')
- ss.append('] }')
- return ''.join(ss)
-
- def add_controller(self, ip, port, user, password, request_timeout,
- http_timeout, retries, redirects, default_tz_uuid,
- uuid=None, zone=None, default_l3_gw_service_uuid=None,
- default_l2_gw_service_uuid=None,
- default_interface_name=None):
- """Add a new set of controller parameters.
-
- :param ip: IP address of controller.
- :param port: port controller is listening on.
- :param user: user name.
- :param password: user password.
- :param request_timeout: timeout for an entire API request.
- :param http_timeout: timeout for a connect to a controller.
- :param retries: maximum number of request retries.
- :param redirects: maximum number of server redirect responses to
- follow.
- :param default_tz_uuid: default transport zone uuid.
- :param uuid: UUID of this cluster (used in MDI configs).
- :param zone: Zone of this cluster (used in MDI configs).
- :param default_l3_gw_service_uuid: Default l3 gateway service
- :param default_l2_gw_service_uuid: Default l2 gateway service
- :param default_interface_name: Default interface name for l2 gateways
- """
-
- keys = ['ip', 'user', 'password', 'default_tz_uuid',
- 'default_l3_gw_service_uuid', 'default_l2_gw_service_uuid',
- 'default_interface_name', 'uuid', 'zone']
- controller_dict = dict([(k, locals()[k]) for k in keys])
- default_tz_uuid = controller_dict.get('default_tz_uuid')
- if not re.match(attributes.UUID_PATTERN, default_tz_uuid):
- LOG.warning(_("default_tz_uuid:%(default_tz_uuid)s is not a "
- "valid UUID in the cluster %(cluster_name)s. "
- "Network operations might not work "
- "properly in this cluster"),
- {'default_tz_uuid': default_tz_uuid,
- 'cluster_name': self.name})
- # default_l3_gw_service_uuid is an optional parameter
- # validate only if specified
- l3_gw_service_uuid = controller_dict.get('default_l3_gw_service_uuid')
- if (l3_gw_service_uuid and
- not re.match(attributes.UUID_PATTERN, l3_gw_service_uuid)):
- LOG.warning(_("default_l3_gw_service_uuid:%(l3_gw_service_uuid)s "
- "is not a valid UUID in the cluster "
- "%(cluster_name)s. Logical router operations "
- "might not work properly in this cluster"),
- {'l3_gw_service_uuid': l3_gw_service_uuid,
- 'cluster_name': self.name})
- # default_l2_gw_node_uuid is an optional parameter
- # validate only if specified
- l2_gw_service_uuid = controller_dict.get('default_l2_gw_node_uuid')
- if l2_gw_service_uuid and not re.match(attributes.UUID_PATTERN,
- l2_gw_service_uuid):
- LOG.warning(_("default_l2_gw_node_uuid:%(l2_gw_service_uuid)s "
- "is not a valid UUID in the cluster "
- "%(cluster_name)s."),
- {'l2_gw_service_uuid': l2_gw_service_uuid,
- 'cluster_name': self.name})
-
- int_keys = [
- 'port', 'request_timeout', 'http_timeout', 'retries', 'redirects']
- for k in int_keys:
- controller_dict[k] = int(locals()[k])
-
- self.controllers.append(controller_dict)
-
- def get_controller(self, idx):
- return self.controllers[idx]
-
- def get_num_controllers(self):
- return len(self.controllers)
-
- @property
- def name(self):
- return self._name
-
- @name.setter
- def name(self, val=None):
- self._name = val
-
- @property
- def host(self):
- return self.controllers[0]['ip']
-
- @property
- def port(self):
- return self.controllers[0]['port']
-
- @property
- def user(self):
- return self.controllers[0]['user']
-
- @property
- def password(self):
- return self.controllers[0]['password']
-
- @property
- def request_timeout(self):
- return self.controllers[0]['request_timeout']
-
- @property
- def http_timeout(self):
- return self.controllers[0]['http_timeout']
-
- @property
- def retries(self):
- return self.controllers[0]['retries']
-
- @property
- def redirects(self):
- return self.controllers[0]['redirects']
-
- @property
- def default_tz_uuid(self):
- return self.controllers[0]['default_tz_uuid']
-
- @property
- def default_l3_gw_service_uuid(self):
- return self.controllers[0]['default_l3_gw_service_uuid']
-
- @property
- def default_l2_gw_service_uuid(self):
- return self.controllers[0]['default_l2_gw_service_uuid']
-
- @property
- def default_interface_name(self):
- return self.controllers[0]['default_interface_name']
-
- @property
- def zone(self):
- return self.controllers[0]['zone']
-
- @property
- def uuid(self):
- return self.controllers[0]['uuid']
+ def _sanity_check(self, options):
+ # Iterating this way ensures the conf parameters also
+ # define the structure of this class
+ for arg in cfg.CONF:
+ if arg not in DEPRECATED_ATTRIBUTES:
+ setattr(self, arg, options.get(arg, cfg.CONF.get(arg)))
+ self._process_attribute(arg)
+ elif options.get(arg) is not None:
+ # Process deprecated attributes only if specified
+ self._deprecated_attributes[arg] = options.get(arg)
+ if arg.startswith("CLUSTER:"):
+ cluster_section = cfg.CONF.get(arg)
+ for option in cluster_section:
+ v = cluster_section.get(option)
+ if option not in DEPRECATED_ATTRIBUTES:
+ # option may be in dict, but with None value
+ setattr(self, option, options.get(option) or v)
+ self._process_attribute(option)
+ else:
+ self._deprecated_attributes[option] = v
+
+ def _process_attribute(self, attribute):
+ # Process the attribute only if it's not empty!
+ if getattr(self, attribute, None):
+ if attribute in self._required_attributes:
+ self._required_attributes.remove(attribute)
+ if attribute in self._important_attributes:
+ self._important_attributes.remove(attribute)
+ handler_func = getattr(self, '_process_%s' % attribute, None)
+ if handler_func:
+ handler_func()
+ else:
+ LOG.info(_("Attribute:%s is empty or null"), attribute)
+
+ def _process_nvp_controllers(self):
+ # If this raises something is not right, so let it bubble up
+ # TODO(salvatore-orlando): Also validate attribute here
+ for i, ctrl in enumerate(self.nvp_controllers or []):
+ if len(ctrl.split(':')) == 1:
+ self.nvp_controllers[i] = '%s:%s' % (ctrl, DEFAULT_PORT)
+
+ def _process_nvp_controller_connection(self, connections):
+
+ def parse_conn_str(ip, port, user, password, req_timeout,
+ http_timeout, retries, redirects):
+ # TODO(salvatore-orlando): Set the attributes only
+ # if correspondent non-deprecated options have been
+ # explicitly specified in the ini file
+ # TODO(salvatore-orlando): Validate data to avoid ugly ValueError
+ self.nvp_user = user
+ self._process_attribute('nvp_user')
+ self.nvp_password = password
+ self._process_attribute('nvp_password')
+ self.req_timeout = int(req_timeout)
+ self._process_attribute('req_timeout')
+ self.http_timeout = int(http_timeout)
+ self._process_attribute('http_timeout')
+ self.retries = int(retries)
+ self._process_attribute('retries')
+ self.redirects = int(redirects)
+ self._process_attribute('redirects')
+ try:
+ nvp_controllers = getattr(self, 'nvp_controllers')
+ nvp_controllers.append('%s:%s' % (ip, port))
+ except AttributeError:
+ self.nvp_controllers = ['%s:%s' % (ip, port)]
+ self._process_attribute('nvp_controllers')
+ for conn in connections:
+ parse_conn_str(*conn.split(':'))
--- /dev/null
+[DEFAULT]
+default_tz_uuid = fake_tz_uuid
+nvp_controllers=fake_1,fake_2
+nvp_user=foo
+nvp_password=bar
--- /dev/null
+[DEFAULT]
+default_tz_uuid = fake_tz_uuid
+nova_zone_id = whatever
+nvp_cluster_uuid = fake_cluster_uuid
+nvp_controllers = fake_1, fake_2
+nvp_user = foo
+nvp_password = bar
+default_l3_gw_service_uuid = whatever
+default_l2_gw_service_uuid = whatever
+default_interface_name = whatever
+req_timeout = 14
+http_timeout = 13
+redirects = 12
+retries = 11
--- /dev/null
+[DEFAULT]
+metadata_dhcp_host_route = False
+
+[CLUSTER:fake]
+default_tz_uuid = fake_tz_uuid
+nova_zone_id = whatever
+nvp_cluster_uuid = fake_cluster_uuid
+nvp_controller_connection=fake_1:443:foo:bar:4:3:2:1
+nvp_controller_connection=fake_2:443:foo:bar:4:3:2:1
+default_l3_gw_service_uuid = whatever
+default_l2_gw_service_uuid = whatever
[DEFAULT]
-
-[CLUSTER:fake]
default_tz_uuid = fake_tz_uuid
-nova_zone_id = whatever
-nvp_cluster_uuid = fake_cluster_uuid
-nvp_controller_connection=fake:443:admin:admin:30:10:2:2
+nvp_controllers=fake_1, fake_2
+nvp_user=foo
+nvp_password=bar
default_l3_gw_service_uuid = whatever
default_l2_gw_service_uuid = whatever
+++ /dev/null
-# Copyright 2013 Nicira Networks, 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.config import cfg
-
-from quantum.plugins.nicira.common import config # noqa
-from quantum.tests import base
-
-
-class ConfigurationTest(base.BaseTestCase):
-
- def test_defaults(self):
- self.assertEqual(64, cfg.CONF.NVP.max_lp_per_bridged_ls)
- self.assertEqual(256, cfg.CONF.NVP.max_lp_per_overlay_ls)
- self.assertEqual(5, cfg.CONF.NVP.concurrent_connections)
with self.port(subnet=sub):
with self.port(subnet=sub):
plugin = manager.QuantumManager.get_plugin()
- ls = nvplib.get_lswitches(plugin.default_cluster,
+ ls = nvplib.get_lswitches(plugin.cluster,
net['network']['id'])
self.assertEqual(len(ls), 2)
return self.fc.fake_request(*args, **kwargs)
instance.return_value.request.side_effect = _fake_request
- self.fake_cluster = nvp_cluster.NVPCluster('fake-cluster')
- self.fake_cluster.add_controller('1.1.1.1', '999', 'foo', 'bar',
- 9, 9, 9, 9, _uuid())
+ self.fake_cluster = nvp_cluster.NVPCluster(
+ name='fake-cluster', nvp_controllers=['1.1.1.1:999'],
+ default_tz_uuid=_uuid(), nvp_user='foo', nvp_password='bar')
self.fake_cluster.api_client = NvpApiClient.NVPApiHelper(
('1.1.1.1', '999', True),
- self.fake_cluster.user, self.fake_cluster.password,
- self.fake_cluster.request_timeout, self.fake_cluster.http_timeout,
+ self.fake_cluster.nvp_user, self.fake_cluster.nvp_password,
+ self.fake_cluster.req_timeout, self.fake_cluster.http_timeout,
self.fake_cluster.retries, self.fake_cluster.redirects)
super(NvplibTestCase, self).setUp()
--- /dev/null
+# Copyright 2013 Nicira Networks, 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.
+#
+
+import fixtures
+import os
+import testtools
+
+from oslo.config import cfg
+
+from quantum.common import config as q_config
+from quantum.manager import QuantumManager
+from quantum.openstack.common import uuidutils
+from quantum.plugins.nicira.common import config # noqa
+from quantum.plugins.nicira.common import exceptions
+from quantum.plugins.nicira import nvp_cluster
+
+BASE_CONF_PATH = os.path.join(os.path.dirname(__file__),
+ '../../etc/quantum.conf.test')
+NVP_INI_PATH = os.path.join(os.path.dirname(__file__),
+ 'etc/nvp.ini.basic.test')
+NVP_INI_FULL_PATH = os.path.join(os.path.dirname(__file__),
+ 'etc/nvp.ini.full.test')
+NVP_INI_DEPR_PATH = os.path.join(os.path.dirname(__file__),
+ 'etc/nvp.ini.grizzly.test')
+NVP_PLUGIN_PATH = ('quantum.plugins.nicira.nicira_nvp_plugin.'
+ 'QuantumPlugin.NvpPluginV2')
+
+
+class NVPClusterTest(testtools.TestCase):
+
+ cluster_opts = {'default_tz_uuid': uuidutils.generate_uuid(),
+ 'default_l2_gw_service_uuid': uuidutils.generate_uuid(),
+ 'default_l2_gw_service_uuid': uuidutils.generate_uuid(),
+ 'nvp_cluster_uuid': uuidutils.generate_uuid(),
+ 'nvp_user': 'foo',
+ 'nvp_password': 'bar',
+ 'req_timeout': 45,
+ 'http_timeout': 25,
+ 'retries': 7,
+ 'redirects': 23,
+ 'default_interface_name': 'baz',
+ 'nvp_controllers': ['1.1.1.1:443']}
+
+ def setUp(self):
+ super(NVPClusterTest, self).setUp()
+ self.addCleanup(cfg.CONF.reset)
+
+ def test_create_cluster(self):
+ cluster = nvp_cluster.NVPCluster(**self.cluster_opts)
+ for (k, v) in self.cluster_opts.iteritems():
+ self.assertEqual(v, getattr(cluster, k))
+
+ def test_create_cluster_default_port(self):
+ opts = self.cluster_opts.copy()
+ opts['nvp_controllers'] = ['1.1.1.1']
+ cluster = nvp_cluster.NVPCluster(**opts)
+ for (k, v) in self.cluster_opts.iteritems():
+ self.assertEqual(v, getattr(cluster, k))
+
+ def test_create_cluster_missing_required_attribute_raises(self):
+ opts = self.cluster_opts.copy()
+ opts.pop('default_tz_uuid')
+ self.assertRaises(exceptions.NvpInvalidClusterConfiguration,
+ nvp_cluster.NVPCluster, **opts)
+
+
+class ConfigurationTest(testtools.TestCase):
+
+ def setUp(self):
+ super(ConfigurationTest, self).setUp()
+ self.addCleanup(cfg.CONF.reset)
+ self.useFixture(fixtures.MonkeyPatch(
+ 'quantum.manager.QuantumManager._instance',
+ None))
+
+ def _assert_required_options(self, cluster):
+ self.assertEqual(cluster.nvp_controllers, ['fake_1:443', 'fake_2:443'])
+ self.assertEqual(cluster.default_tz_uuid, 'fake_tz_uuid')
+ self.assertEqual(cluster.nvp_user, 'foo')
+ self.assertEqual(cluster.nvp_password, 'bar')
+
+ def _assert_extra_options(self, cluster):
+ self.assertEqual(14, cluster.req_timeout)
+ self.assertEqual(13, cluster.http_timeout)
+ self.assertEqual(12, cluster.redirects)
+ self.assertEqual(11, cluster.retries)
+ self.assertEqual('whatever', cluster.default_l2_gw_service_uuid)
+ self.assertEqual('whatever', cluster.default_l3_gw_service_uuid)
+ self.assertEqual('whatever', cluster.default_interface_name)
+
+ def test_load_plugin_with_full_options(self):
+ q_config.parse(['--config-file', BASE_CONF_PATH,
+ '--config-file', NVP_INI_FULL_PATH])
+ cfg.CONF.set_override('core_plugin', NVP_PLUGIN_PATH)
+ plugin = QuantumManager().get_plugin()
+ cluster = plugin.cluster
+ self._assert_required_options(cluster)
+ self._assert_extra_options(cluster)
+
+ def test_load_plugin_with_required_options_only(self):
+ q_config.parse(['--config-file', BASE_CONF_PATH,
+ '--config-file', NVP_INI_PATH])
+ cfg.CONF.set_override('core_plugin', NVP_PLUGIN_PATH)
+ plugin = QuantumManager().get_plugin()
+ self._assert_required_options(plugin.cluster)
+
+ def test_defaults(self):
+ self.assertEqual(64, cfg.CONF.NVP.max_lp_per_bridged_ls)
+ self.assertEqual(256, cfg.CONF.NVP.max_lp_per_overlay_ls)
+ self.assertEqual(5, cfg.CONF.NVP.concurrent_connections)
+
+ self.assertIsNone(cfg.CONF.default_tz_uuid)
+ self.assertIsNone(cfg.CONF.nvp_cluster_uuid)
+ self.assertEqual('admin', cfg.CONF.nvp_user)
+ self.assertEqual('admin', cfg.CONF.nvp_password)
+ self.assertEqual(30, cfg.CONF.req_timeout)
+ self.assertEqual(10, cfg.CONF.http_timeout)
+ self.assertEqual(2, cfg.CONF.retries)
+ self.assertEqual(2, cfg.CONF.redirects)
+ self.assertIsNone(cfg.CONF.nvp_controllers)
+ self.assertIsNone(cfg.CONF.default_l3_gw_service_uuid)
+ self.assertIsNone(cfg.CONF.default_l2_gw_service_uuid)
+ self.assertEqual('breth0', cfg.CONF.default_interface_name)
+
+
+class OldConfigurationTest(testtools.TestCase):
+
+ def setUp(self):
+ super(OldConfigurationTest, self).setUp()
+ self.addCleanup(cfg.CONF.reset)
+ self.useFixture(fixtures.MonkeyPatch(
+ 'quantum.manager.QuantumManager._instance',
+ None))
+
+ def _assert_required_options(self, cluster):
+ self.assertEqual(cluster.nvp_controllers, ['fake_1:443', 'fake_2:443'])
+ self.assertEqual(cluster.default_tz_uuid, 'fake_tz_uuid')
+ self.assertEqual(cluster.nvp_user, 'foo')
+ self.assertEqual(cluster.nvp_password, 'bar')
+
+ def test_load_plugin_with_deprecated_options(self):
+ q_config.parse(['--config-file', BASE_CONF_PATH,
+ '--config-file', NVP_INI_DEPR_PATH])
+ cfg.CONF.set_override('core_plugin', NVP_PLUGIN_PATH)
+ plugin = QuantumManager().get_plugin()
+ cluster = plugin.cluster
+ self._assert_required_options(cluster)
+ # Verify nvp_controller_connection has been fully parsed
+ self.assertEqual(4, cluster.req_timeout)
+ self.assertEqual(3, cluster.http_timeout)
+ self.assertEqual(2, cluster.retries)
+ self.assertEqual(1, cluster.redirects)