vmware-nsx/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py
Gary Kotton df2b366593 NSX|V: be able to deal with more than 256 edges
Ensure that the admin utility can work when there are more than
256 edges deifned. The NSX api returns details that enable us
to work with pagination.

Change-Id: I1083875193d9d893d725c48d7c1434f064fef5b6
2017-04-19 03:11:10 -07:00

844 lines
34 KiB
Python

# Copyright 2013 VMware, 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 distutils import version
import random
import time
from neutron.plugins.common import constants as plugin_const
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
from sqlalchemy.orm import exc as sa_exc
from vmware_nsx._i18n import _
from vmware_nsx.common import exceptions as nsxv_exc
from vmware_nsx.common import nsxv_constants
from vmware_nsx.common import utils
from vmware_nsx.db import nsxv_db
from vmware_nsx.plugins.nsx_v.vshield.common import constants
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
from vmware_nsx.plugins.nsx_v.vshield.tasks import (
constants as task_constants)
from vmware_nsx.plugins.nsx_v.vshield.tasks import tasks
LOG = logging.getLogger(__name__)
class EdgeApplianceDriver(object):
def __init__(self):
super(EdgeApplianceDriver, self).__init__()
# store the last task per edge that has the latest config
self.updated_task = {
'nat': {},
'route': {},
}
random.seed()
def _assemble_edge(self, name, appliance_size="compact",
deployment_container_id=None, datacenter_moid=None,
enable_aesni=True, dist=False,
enable_fips=False, remote_access=False,
edge_ha=False):
edge = {
'name': name,
'fqdn': None,
'enableAesni': enable_aesni,
'enableFips': enable_fips,
'featureConfigs': {
'features': [
{
'featureType': 'firewall_4.0',
'globalConfig': {
'tcpTimeoutEstablished': 7200
}
}
]
},
'cliSettings': {
'remoteAccess': remote_access
},
'autoConfiguration': {
'enabled': False,
'rulePriority': 'high'
},
'appliances': {
'applianceSize': appliance_size
},
}
if not dist:
edge['type'] = "gatewayServices"
edge['vnics'] = {'vnics': []}
else:
edge['type'] = "distributedRouter"
edge['interfaces'] = {'interfaces': []}
if deployment_container_id:
edge['appliances']['deploymentContainerId'] = (
deployment_container_id)
if datacenter_moid:
edge['datacenterMoid'] = datacenter_moid
if not dist and edge_ha:
self._enable_high_availability(edge)
return edge
def _select_datastores(self, availability_zone):
primary_ds = availability_zone.datastore_id
secondary_ds = availability_zone.ha_datastore_id
if availability_zone.ha_placement_random:
# we want to switch primary and secondary datastores
# half of the times, to balance it
if random.random() > 0.5:
primary_ds = availability_zone.ha_datastore_id
secondary_ds = availability_zone.datastore_id
return primary_ds, secondary_ds
def _assemble_edge_appliances(self, availability_zone):
appliances = []
if availability_zone.ha_datastore_id and availability_zone.edge_ha:
# create appliance with HA
primary_ds, secondary_ds = self._select_datastores(
availability_zone)
appliances.append(self._assemble_edge_appliance(
availability_zone.resource_pool,
primary_ds))
appliances.append(self._assemble_edge_appliance(
availability_zone.resource_pool,
secondary_ds))
elif availability_zone.datastore_id:
# Single datastore
appliances.append(self._assemble_edge_appliance(
availability_zone.resource_pool,
availability_zone.datastore_id))
return appliances
def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
appliance = {}
if resource_pool_id:
appliance['resourcePoolId'] = resource_pool_id
if datastore_id:
appliance['datastoreId'] = datastore_id
return appliance
def _assemble_edge_vnic(self, name, index, portgroup_id, tunnel_index=-1,
primary_address=None, subnet_mask=None,
secondary=None,
type="internal",
enable_proxy_arp=False,
enable_send_redirects=True,
is_connected=True,
mtu=1500,
address_groups=None):
vnic = {
'index': index,
'name': name,
'type': type,
'portgroupId': portgroup_id,
'mtu': mtu,
'enableProxyArp': enable_proxy_arp,
'enableSendRedirects': enable_send_redirects,
'isConnected': is_connected
}
if address_groups is None:
address_groups = []
if not address_groups:
if primary_address and subnet_mask:
address_group = {
'primaryAddress': primary_address,
'subnetMask': subnet_mask
}
if secondary:
address_group['secondaryAddresses'] = {
'ipAddress': secondary,
'type': 'secondary_addresses'
}
vnic['addressGroups'] = {
'addressGroups': [address_group]
}
else:
vnic['subInterfaces'] = {'subInterfaces': address_groups}
else:
if tunnel_index < 0:
vnic['addressGroups'] = {'addressGroups': address_groups}
else:
vnic['subInterfaces'] = {'subInterfaces': address_groups}
return vnic
def _assemble_vdr_interface(self, portgroup_id,
primary_address=None, subnet_mask=None,
secondary=None,
type="internal",
is_connected=True,
mtu=1500,
address_groups=None):
interface = {
'type': type,
'connectedToId': portgroup_id,
'mtu': mtu,
'isConnected': is_connected
}
if address_groups is None:
address_groups = []
if not address_groups:
if primary_address and subnet_mask:
address_group = {
'primaryAddress': primary_address,
'subnetMask': subnet_mask
}
if secondary:
address_group['secondaryAddresses'] = {
'ipAddress': secondary,
'type': 'secondary_addresses'
}
interface['addressGroups'] = {
'addressGroups': [address_group]
}
else:
interface['addressGroups'] = {'addressGroups': address_groups}
interfaces = {'interfaces': [interface]}
return interfaces
def _edge_status_to_level(self, status):
if status == 'GREEN':
status_level = constants.RouterStatus.ROUTER_STATUS_ACTIVE
elif status in ('GREY', 'YELLOW'):
status_level = constants.RouterStatus.ROUTER_STATUS_DOWN
else:
status_level = constants.RouterStatus.ROUTER_STATUS_ERROR
return status_level
def _enable_loadbalancer(self, edge):
if (not edge.get('featureConfigs') or
not edge['featureConfigs'].get('features')):
edge['featureConfigs'] = {'features': []}
edge['featureConfigs']['features'].append(
{'featureType': 'loadbalancer_4.0',
'enabled': True})
def _enable_high_availability(self, edge):
if (not edge.get('featureConfigs') or
not edge['featureConfigs'].get('features')):
edge['featureConfigs'] = {'features': []}
edge['featureConfigs']['features'].append(
{'featureType': 'highavailability_4.0',
'enabled': True})
def get_edge_status(self, edge_id):
try:
response = self.vcns.get_edge_status(edge_id)[1]
status_level = self._edge_status_to_level(
response['edgeStatus'])
except exceptions.VcnsApiException as e:
LOG.error("VCNS: Failed to get edge %(edge_id)s status: "
"Reason: %(reason)s",
{'edge_id': edge_id, 'reason': e.response})
status_level = constants.RouterStatus.ROUTER_STATUS_ERROR
try:
desc = jsonutils.loads(e.response)
if desc.get('errorCode') == (
constants.VCNS_ERROR_CODE_EDGE_NOT_RUNNING):
status_level = constants.RouterStatus.ROUTER_STATUS_DOWN
except ValueError:
LOG.error('Error code not present. %s', e.response)
return status_level
def get_interface(self, edge_id, vnic_index):
# get vnic interface address groups
try:
return self.vcns.query_interface(edge_id, vnic_index)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("NSXv: Failed to query vnic %s", vnic_index)
def update_interface(self, router_id, edge_id, index, network,
tunnel_index=-1, address=None, netmask=None,
secondary=None, is_connected=True,
address_groups=None):
LOG.debug("VCNS: update vnic %(index)d: %(addr)s %(netmask)s", {
'index': index, 'addr': address, 'netmask': netmask})
if index == constants.EXTERNAL_VNIC_INDEX:
name = constants.EXTERNAL_VNIC_NAME
intf_type = 'uplink'
else:
name = constants.INTERNAL_VNIC_NAME + str(index)
if tunnel_index < 0:
intf_type = 'internal'
else:
intf_type = 'trunk'
config = self._assemble_edge_vnic(
name, index, network, tunnel_index,
address, netmask, secondary, type=intf_type,
address_groups=address_groups, is_connected=is_connected)
self.vcns.update_interface(edge_id, config)
def add_vdr_internal_interface(self, edge_id,
network, address=None, netmask=None,
secondary=None, address_groups=None,
type="internal", is_connected=True):
LOG.debug("Add VDR interface on edge: %s", edge_id)
if address_groups is None:
address_groups = []
interface_req = (
self._assemble_vdr_interface(network, address, netmask, secondary,
address_groups=address_groups,
is_connected=is_connected, type=type))
self.vcns.add_vdr_internal_interface(edge_id, interface_req)
header, response = self.vcns.get_edge_interfaces(edge_id)
for interface in response['interfaces']:
if interface['connectedToId'] == network:
vnic_index = int(interface['index'])
return vnic_index
def update_vdr_internal_interface(self, edge_id, index, network,
address_groups=None, is_connected=True):
if not address_groups:
address_groups = []
interface = {
'type': 'internal',
'connectedToId': network,
'mtu': 1500,
'isConnected': is_connected,
'addressGroups': {'addressGroup': address_groups}
}
interface_req = {'interface': interface}
try:
header, response = self.vcns.update_vdr_internal_interface(
edge_id, index, interface_req)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to update vdr interface on edge: "
"%s", edge_id)
def delete_vdr_internal_interface(self, edge_id, interface_index):
LOG.debug("Delete VDR interface on edge: %s", edge_id)
try:
header, response = self.vcns.delete_vdr_internal_interface(
edge_id, interface_index)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to delete vdr interface on edge: "
"%s",
edge_id)
def delete_interface(self, router_id, edge_id, index):
LOG.debug("Deleting vnic %(vnic_index)s: on edge %(edge_id)s",
{'vnic_index': index, 'edge_id': edge_id})
try:
self.vcns.delete_interface(edge_id, index)
except exceptions.ResourceNotFound:
LOG.error('Failed to delete vnic %(vnic_index)s on edge '
'%(edge_id)s: edge was not found',
{'vnic_index': index,
'edge_id': edge_id})
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to delete vnic %(vnic_index)s: "
"on edge %(edge_id)s",
{'vnic_index': index,
'edge_id': edge_id})
LOG.debug("Deletion complete vnic %(vnic_index)s: on edge %(edge_id)s",
{'vnic_index': index, 'edge_id': edge_id})
def deploy_edge(self, context, router_id, name, internal_network,
dist=False, loadbalancer_enable=True,
appliance_size=nsxv_constants.LARGE,
availability_zone=None, deploy_metadata=False):
edge_name = name
edge = self._assemble_edge(
edge_name, datacenter_moid=availability_zone.datacenter_moid,
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist,
edge_ha=availability_zone.edge_ha)
appliances = self._assemble_edge_appliances(availability_zone)
if appliances:
edge['appliances']['appliances'] = appliances
if not dist:
vnic_external = self._assemble_edge_vnic(
constants.EXTERNAL_VNIC_NAME, constants.EXTERNAL_VNIC_INDEX,
availability_zone.external_network, type="uplink")
edge['vnics']['vnics'].append(vnic_external)
else:
edge['mgmtInterface'] = {
'connectedToId': availability_zone.external_network,
'name': "mgmtInterface"}
if internal_network:
vnic_inside = self._assemble_edge_vnic(
constants.INTERNAL_VNIC_NAME, constants.INTERNAL_VNIC_INDEX,
internal_network,
edge_utils.get_vdr_transit_network_plr_address(),
edge_utils.get_vdr_transit_network_netmask(),
type="internal")
edge['vnics']['vnics'].append(vnic_inside)
# If default login credentials for Edge are set, configure accordingly
if (cfg.CONF.nsxv.edge_appliance_user and
cfg.CONF.nsxv.edge_appliance_password):
edge['cliSettings'].update({
'userName': cfg.CONF.nsxv.edge_appliance_user,
'password': cfg.CONF.nsxv.edge_appliance_password})
if not dist and loadbalancer_enable:
self._enable_loadbalancer(edge)
edge_id = None
try:
header = self.vcns.deploy_edge(edge)[0]
edge_id = header.get('location', '/').split('/')[-1]
if edge_id:
nsxv_db.update_nsxv_router_binding(
context.session, router_id, edge_id=edge_id)
if not dist:
# Init Edge vnic binding
nsxv_db.init_edge_vnic_binding(
context.session, edge_id)
else:
if router_id:
nsxv_db.update_nsxv_router_binding(
context.session, router_id,
status=plugin_const.ERROR)
error = _('Failed to deploy edge')
raise nsxv_exc.NsxPluginException(err_msg=error)
self.callbacks.complete_edge_creation(
context, edge_id, name, router_id, dist, True,
availability_zone, deploy_metadata=deploy_metadata)
except exceptions.VcnsApiException:
self.callbacks.complete_edge_creation(
context, edge_id, name, router_id, dist, False)
with excutils.save_and_reraise_exception():
LOG.exception("NSXv: deploy edge failed.")
return edge_id
def update_edge(self, context, router_id, edge_id, name, internal_network,
dist=False, loadbalancer_enable=True,
appliance_size=nsxv_constants.LARGE,
set_errors=False, availability_zone=None):
"""Update edge name."""
edge = self._assemble_edge(
name, datacenter_moid=availability_zone.datacenter_moid,
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist,
edge_ha=availability_zone.edge_ha)
edge['id'] = edge_id
appliances = self._assemble_edge_appliances(availability_zone)
if appliances:
edge['appliances']['appliances'] = appliances
if not dist:
vnic_external = self._assemble_edge_vnic(
constants.EXTERNAL_VNIC_NAME, constants.EXTERNAL_VNIC_INDEX,
availability_zone.external_network, type="uplink")
edge['vnics']['vnics'].append(vnic_external)
else:
edge['mgmtInterface'] = {
'connectedToId': availability_zone.external_network,
'name': "mgmtInterface"}
if internal_network:
internal_vnic = self._assemble_edge_vnic(
constants.INTERNAL_VNIC_NAME, constants.INTERNAL_VNIC_INDEX,
internal_network,
edge_utils.get_vdr_transit_network_plr_address(),
edge_utils.get_vdr_transit_network_netmask(),
type="internal")
edge['vnics']['vnics'].append(internal_vnic)
if not dist and loadbalancer_enable:
self._enable_loadbalancer(edge)
try:
self.vcns.update_edge(edge_id, edge)
self.callbacks.complete_edge_update(
context, edge_id, router_id, True, set_errors)
except exceptions.VcnsApiException as e:
LOG.error("Failed to update edge: %s",
e.response)
self.callbacks.complete_edge_update(
context, edge_id, router_id, False, set_errors)
return False
return True
def rename_edge(self, edge_id, name):
"""rename edge."""
try:
# First get the current edge structure
# [0] is the status, [1] is the body
edge = self.vcns.get_edge(edge_id)[1]
if edge['name'] == name:
LOG.debug('Edge %s is already named %s', edge_id, name)
return
# remove some data that will make the update fail
edge_utils.remove_irrelevant_keys_from_edge_request(edge)
# set the new name in the request
edge['name'] = name
# update the edge
self.vcns.update_edge(edge_id, edge)
except exceptions.VcnsApiException as e:
LOG.error("Failed to rename edge: %s",
e.response)
def resize_edge(self, edge_id, size):
"""update the size of a router edge."""
try:
# First get the current edge structure
# [0] is the status, [1] is the body
edge = self.vcns.get_edge(edge_id)[1]
if edge.get('appliances'):
if edge['appliances']['applianceSize'] == size:
LOG.debug('Edge %s is already with size %s',
edge_id, size)
return
ver = self.vcns.get_version()
if version.LooseVersion(ver) < version.LooseVersion('6.2.3'):
# remove some data that will make the update fail
edge_utils.remove_irrelevant_keys_from_edge_request(edge)
# set the new size in the request
edge['appliances']['applianceSize'] = size
# update the edge
self.vcns.update_edge(edge_id, edge)
except exceptions.VcnsApiException as e:
LOG.error("Failed to resize edge: %s", e.response)
def delete_edge(self, context, router_id, edge_id, dist=False):
try:
nsxv_db.delete_nsxv_router_binding(context.session, router_id)
if not dist:
nsxv_db.clean_edge_vnic_binding(context.session, edge_id)
except sa_exc.NoResultFound:
LOG.warning("Router Binding for %s not found", router_id)
if edge_id:
try:
self.vcns.delete_edge(edge_id)
return True
except exceptions.ResourceNotFound:
return True
except exceptions.VcnsApiException as e:
LOG.exception("VCNS: Failed to delete %(edge_id)s:\n"
"%(response)s",
{'edge_id': edge_id, 'response': e.response})
return False
except Exception:
LOG.exception("VCNS: Failed to delete %s", edge_id)
return False
def _assemble_nat_rule(self, action, original_address,
translated_address,
vnic_index=None,
enabled=True,
protocol='any',
original_port='any',
translated_port='any'):
nat_rule = {}
nat_rule['action'] = action
if vnic_index is not None:
nat_rule['vnic'] = vnic_index
nat_rule['originalAddress'] = original_address
nat_rule['translatedAddress'] = translated_address
nat_rule['enabled'] = enabled
nat_rule['protocol'] = protocol
nat_rule['originalPort'] = original_port
nat_rule['translatedPort'] = translated_port
return nat_rule
def get_nat_config(self, edge_id):
try:
return self.vcns.get_nat_config(edge_id)[1]
except exceptions.VcnsApiException as e:
LOG.exception("VCNS: Failed to get nat config:\n%s",
e.response)
raise e
def update_nat_rules(self, edge_id, snats, dnats, indices=None):
LOG.debug("VCNS: update nat rule\n"
"SNAT:%(snat)s\n"
"DNAT:%(dnat)s\n"
"INDICES: %(index)s\n", {
'snat': snats, 'dnat': dnats, 'index': indices})
nat_rules = []
for dnat in dnats:
vnic_index = None
if 'vnic_index' in dnat:
vnic_index = dnat['vnic_index']
if vnic_index or not indices:
# we are adding a predefined index or
# adding to all interfaces
nat_rules.append(self._assemble_nat_rule(
'dnat', dnat['dst'], dnat['translated'],
vnic_index=vnic_index
))
nat_rules.append(self._assemble_nat_rule(
'snat', dnat['translated'], dnat['dst'],
vnic_index=vnic_index
))
else:
for index in indices:
nat_rules.append(self._assemble_nat_rule(
'dnat', dnat['dst'], dnat['translated'],
vnic_index=index
))
nat_rules.append(self._assemble_nat_rule(
'snat', dnat['translated'], dnat['dst'],
vnic_index=index
))
for snat in snats:
vnic_index = None
if 'vnic_index' in snat:
vnic_index = snat['vnic_index']
if vnic_index or not indices:
# we are adding a predefined index
# or adding to all interfaces
nat_rules.append(self._assemble_nat_rule(
'snat', snat['src'], snat['translated'],
vnic_index=vnic_index
))
else:
for index in indices:
nat_rules.append(self._assemble_nat_rule(
'snat', snat['src'], snat['translated'],
vnic_index=index
))
nat = {
'featureType': 'nat',
'rules': {
'natRulesDtos': nat_rules
}
}
try:
self.vcns.update_nat_config(edge_id, nat)
return True
except exceptions.VcnsApiException as e:
LOG.exception("VCNS: Failed to create snat rule:\n%s",
e.response)
return False
def update_routes(self, edge_id, gateway, routes):
if gateway:
gateway = gateway.split('/')[0]
static_routes = []
for route in routes:
if route.get('vnic_index') is None:
static_routes.append({
"description": "",
"vnic": constants.INTERNAL_VNIC_INDEX,
"network": route['cidr'],
"nextHop": route['nexthop']
})
else:
static_routes.append({
"description": "",
"vnic": route['vnic_index'],
"network": route['cidr'],
"nextHop": route['nexthop']
})
request = {
"staticRoutes": {
"staticRoutes": static_routes
}
}
if gateway:
request["defaultRoute"] = {
"description": "default-gateway",
"gatewayAddress": gateway
}
try:
self.vcns.update_routes(edge_id, request)
return True
except exceptions.VcnsApiException as e:
LOG.exception("VCNS: Failed to update routes:\n%s",
e.response)
return False
def create_lswitch(self, name, tz_config, tags=None,
port_isolation=False, replication_mode="service"):
lsconfig = {
'display_name': utils.check_and_truncate(name),
"tags": tags or [],
"type": "LogicalSwitchConfig",
"_schema": "/ws.v1/schema/LogicalSwitchConfig",
"transport_zones": tz_config
}
if port_isolation is bool:
lsconfig["port_isolation_enabled"] = port_isolation
if replication_mode:
lsconfig["replication_mode"] = replication_mode
response = self.vcns.create_lswitch(lsconfig)[1]
return response
def delete_lswitch(self, lswitch_id):
self.vcns.delete_lswitch(lswitch_id)
def get_loadbalancer_config(self, edge_id):
try:
header, response = self.vcns.get_loadbalancer_config(
edge_id)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to get service config")
return response
def enable_service_loadbalancer(self, edge_id):
config = self.get_loadbalancer_config(
edge_id)
if not config['enabled']:
config['enabled'] = True
try:
self.vcns.enable_service_loadbalancer(edge_id, config)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to enable loadbalancer "
"service config")
def _delete_port_group(self, task):
try:
self.vcns.delete_port_group(
task.userdata['dvs_id'],
task.userdata['port_group_id'])
except Exception as e:
LOG.error('Unable to delete %(pg)s exception %(ex)s',
{'pg': task.userdata['port_group_id'],
'ex': e})
return task_constants.TaskStatus.ERROR
return task_constants.TaskStatus.COMPLETED
def _retry_task(self, task):
delay = 0.5
max_retries = max(cfg.CONF.nsxv.retries, 1)
args = task.userdata.get('args', [])
kwargs = task.userdata.get('kwargs', {})
retry_number = task.userdata['retry_number']
retry_command = task.userdata['retry_command']
try:
retry_command(*args, **kwargs)
except Exception as exc:
LOG.debug("Task %(name)s retry %(retry)s failed %(exc)s",
{'name': task.name,
'exc': exc,
'retry': retry_number})
retry_number += 1
if retry_number > max_retries:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to %s", task.name)
else:
task.userdata['retry_number'] = retry_number
# Sleep twice as long as the previous retry
tts = (2 ** (retry_number - 1)) * delay
time.sleep(min(tts, 60))
return task_constants.TaskStatus.PENDING
LOG.info("Task %(name)s completed.", {'name': task.name})
return task_constants.TaskStatus.COMPLETED
def delete_port_group(self, dvs_id, port_group_id):
task_name = 'delete-port-group-%s-%s' % (port_group_id, dvs_id)
userdata = {'retry_number': 1,
'retry_command': self.vcns.delete_port_group,
'args': [dvs_id, port_group_id]}
task = tasks.Task(task_name, port_group_id,
self._retry_task,
status_callback=self._retry_task,
userdata=userdata)
self.task_manager.add(task)
def delete_virtual_wire(self, vw_id):
task_name = 'delete-virtualwire-%s' % vw_id
userdata = {'retry_number': 1,
'retry_command': self.vcns.delete_virtual_wire,
'args': [vw_id]}
task = tasks.Task(task_name, vw_id,
self._retry_task,
status_callback=self._retry_task,
userdata=userdata)
self.task_manager.add(task)
def create_bridge(self, device_name, bridge):
try:
self.vcns.create_bridge(device_name, bridge)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception("Failed to create bridge in the %s",
device_name)
def delete_bridge(self, device_name):
try:
self.vcns.delete_bridge(device_name)
except exceptions.VcnsApiException:
LOG.exception("Failed to delete bridge in the %s",
device_name)
def update_edge_ha(self, edge_id):
ha_request = {
'featureType': "highavailability_4.0",
'enabled': True}
self.vcns.enable_ha(edge_id, ha_request)
def update_edge_syslog(self, edge_id, syslog_config, router_id):
if 'server_ip' not in syslog_config:
LOG.warning("Server IP missing in syslog config for %s",
router_id)
return
protocol = syslog_config.get('protocol', 'tcp')
if protocol not in ['tcp', 'udp']:
LOG.warning("Invalid protocol in syslog config for %s",
router_id)
return
loglevel = syslog_config.get('log_level')
if loglevel and loglevel not in edge_utils.SUPPORTED_EDGE_LOG_LEVELS:
LOG.warning("Invalid loglevel in syslog config for %s",
router_id)
return
server_ip = syslog_config['server_ip']
request = {'featureType': 'syslog',
'protocol': protocol,
'serverAddresses': {'ipAddress': [server_ip],
'type': 'IpAddressesDto'}}
# edge allows up to 2 syslog servers
if 'server2_ip' in syslog_config:
request['serverAddresses']['ipAddress'].append(
syslog_config['server2_ip'])
self.vcns.update_edge_syslog(edge_id, request)
# update log level for routing in separate API call
if loglevel:
edge_utils.update_edge_loglevel(self.vcns, edge_id,
'routing', loglevel)