diff --git a/vmware_nsx/common/nsx_constants.py b/vmware_nsx/common/nsx_constants.py index 91ad6505e7..f84a8f744f 100644 --- a/vmware_nsx/common/nsx_constants.py +++ b/vmware_nsx/common/nsx_constants.py @@ -39,6 +39,16 @@ ROUTER_TYPE_TIER1 = "TIER1" ROUTER_TYPES = [ROUTER_TYPE_TIER0, ROUTER_TYPE_TIER1] +LROUTERPORT_UPLINK = "LogicalRouterUplinkPort" +LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort" +LROUTERPORT_LINKONTIER0 = "LogicalRouterLinkPortOnTIER0" +LROUTERPORT_LINKONTIER1 = "LogicalRouterLinkPortOnTIER1" + +LROUTER_TYPES = [LROUTERPORT_UPLINK, + LROUTERPORT_DOWNLINK, + LROUTERPORT_LINKONTIER0, + LROUTERPORT_LINKONTIER1] + # L2 agent vif type VIF_TYPE_DVS = 'dvs' diff --git a/vmware_nsx/nsxlib/v3/__init__.py b/vmware_nsx/nsxlib/v3/__init__.py index 67a141e412..850303e3fc 100644 --- a/vmware_nsx/nsxlib/v3/__init__.py +++ b/vmware_nsx/nsxlib/v3/__init__.py @@ -25,18 +25,6 @@ from vmware_nsx.nsxlib.v3 import client LOG = log.getLogger(__name__) -# TODO(berlin): move them to nsx_constants file -# Router logical port types -LROUTERPORT_UPLINK = "LogicalRouterUplinkPort" -LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort" -LROUTERPORT_LINKONTIER0 = "LogicalRouterLinkPortOnTIER0" -LROUTERPORT_LINKONTIER1 = "LogicalRouterLinkPortOnTIER1" - -LROUTER_TYPES = [LROUTERPORT_UPLINK, - LROUTERPORT_DOWNLINK, - LROUTERPORT_LINKONTIER0, - LROUTERPORT_LINKONTIER1] - def get_edge_cluster(edge_cluster_uuid): resource = "edge-clusters/%s" % edge_cluster_uuid @@ -129,122 +117,6 @@ def update_logical_switch(lswitch_id, name=None, admin_state=None): return client.update_resource(resource, lswitch) -def create_logical_router(display_name, tags, - edge_cluster_uuid=None, tier_0=False): - # TODO(salv-orlando): If possible do not manage edge clusters in the main - # plugin logic. - router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else - nsx_constants.ROUTER_TYPE_TIER1) - resource = 'logical-routers' - body = {'display_name': display_name, - 'router_type': router_type, - 'tags': tags} - if edge_cluster_uuid: - body['edge_cluster_id'] = edge_cluster_uuid - return client.create_resource(resource, body) - - -def get_logical_router(lrouter_id): - resource = 'logical-routers/%s' % lrouter_id - return client.get_resource(resource) - - -def update_logical_router(lrouter_id, **kwargs): - resource = 'logical-routers/%s' % lrouter_id - return update_resource_with_retry(resource, kwargs) - - -def delete_logical_router(lrouter_id): - # TODO(berlin): need to verify whether cascade prefix is valid to delete - # router link port and its relative nat rules - resource = 'logical-routers/%s/' % lrouter_id - - # TODO(salv-orlando): Must handle connection exceptions - return client.delete_resource(resource) - - -def get_logical_router_port_by_ls_id(logical_switch_id): - resource = 'logical-router-ports?logical_switch_id=%s' % logical_switch_id - router_ports = client.get_resource(resource) - if int(router_ports['result_count']) >= 2: - raise nsx_exc.NsxPluginException( - err_msg=_("Can't support more than one logical router ports " - "on same logical switch %s ") % logical_switch_id) - elif int(router_ports['result_count']) == 1: - return router_ports['results'][0] - else: - err_msg = (_("Logical router link port not found on logical " - "switch %s") % logical_switch_id) - raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(), - operation=err_msg) - - -def create_logical_router_port(logical_router_id, - display_name, - resource_type, - logical_port_id, - address_groups, - edge_cluster_member_index=None): - resource = 'logical-router-ports' - body = {'display_name': display_name, - 'resource_type': resource_type, - 'logical_router_id': logical_router_id} - if address_groups: - body['subnets'] = address_groups - if resource_type in [LROUTERPORT_UPLINK, - LROUTERPORT_DOWNLINK]: - body['linked_logical_switch_port_id'] = { - 'target_id': logical_port_id} - elif resource_type == LROUTERPORT_LINKONTIER1: - body['linked_logical_router_port_id'] = { - 'target_id': logical_port_id} - elif logical_port_id: - body['linked_logical_router_port_id'] = logical_port_id - if edge_cluster_member_index: - body['edge_cluster_member_index'] = edge_cluster_member_index - - return client.create_resource(resource, body) - - -def update_logical_router_port_by_ls_id(logical_router_id, ls_id, - **payload): - port = get_logical_router_port_by_ls_id(ls_id) - return update_logical_router_port(port['id'], **payload) - - -def update_logical_router_port(logical_port_id, **kwargs): - resource = 'logical-router-ports/%s?detach=true' % logical_port_id - return update_resource_with_retry(resource, kwargs) - - -def delete_logical_router_port_by_ls_id(ls_id): - port = get_logical_router_port_by_ls_id(ls_id) - delete_logical_router_port(port['id']) - - -def delete_logical_router_port(logical_port_id): - resource = 'logical-router-ports/%s?detach=true' % logical_port_id - client.delete_resource(resource) - - -def get_logical_router_ports_by_router_id(logical_router_id): - resource = 'logical-router-ports' - logical_router_ports = client.get_resource( - resource, logical_router_id=logical_router_id) - return logical_router_ports['results'] - - -def get_tier1_logical_router_link_port(logical_router_id): - logical_router_ports = get_logical_router_ports_by_router_id( - logical_router_id) - for port in logical_router_ports: - if port['resource_type'] == LROUTERPORT_LINKONTIER1: - return port - raise nsx_exc.ResourceNotFound( - manager=client._get_manager_ip(), - operation="get router link port") - - def add_nat_rule(logical_router_id, action, translated_network, source_net=None, dest_net=None, enabled=True, rule_priority=None): diff --git a/vmware_nsx/nsxlib/v3/resources.py b/vmware_nsx/nsxlib/v3/resources.py index 5bc3777f7b..b2f747da11 100644 --- a/vmware_nsx/nsxlib/v3/resources.py +++ b/vmware_nsx/nsxlib/v3/resources.py @@ -21,6 +21,7 @@ from oslo_config import cfg from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.common import nsx_constants from vmware_nsx.common import utils +from vmware_nsx.nsxlib.v3 import client SwitchingProfileTypeId = collections.namedtuple( @@ -238,3 +239,126 @@ class LogicalPort(AbstractRESTResource): # re-fetch, patch the response and send it again with the # new revision_id return self._client.update(lport_id, body=lport) + + +class LogicalRouter(AbstractRESTResource): + + @property + def uri_segment(self): + return 'logical-routers' + + def create(self, display_name, tags, edge_cluster_uuid=None, tier_0=False): + # TODO(salv-orlando): If possible do not manage edge clusters + # in the main plugin logic. + router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else + nsx_constants.ROUTER_TYPE_TIER1) + body = {'display_name': display_name, + 'router_type': router_type, + 'tags': tags} + if edge_cluster_uuid: + body['edge_cluster_id'] = edge_cluster_uuid + return self._client.create(body=body) + + def delete(self, lrouter_id): + return self._client.url_delete(lrouter_id) + + @utils.retry_upon_exception_nsxv3( + nsx_exc.StaleRevision, + max_attempts=cfg.CONF.nsx_v3.retries) + def update(self, lrouter_id, *args, **kwargs): + lrouter = self.get(lrouter_id) + for k in kwargs: + lrouter[k] = kwargs[k] + # If revision_id of the payload that we send is older than what NSX has + # then we will get a 412: Precondition Failed. In that case we need to + # re-fetch, patch the response and send it again with the + # new revision_id + return self._client.update(lrouter_id, body=lrouter) + + +class LogicalRouterPort(AbstractRESTResource): + + @property + def uri_segment(self): + return 'logical-router-ports' + + def create(self, logical_router_id, + display_name, + resource_type, + logical_port_id, + address_groups, + edge_cluster_member_index=None): + body = {'display_name': display_name, + 'resource_type': resource_type, + 'logical_router_id': logical_router_id} + if address_groups: + body['subnets'] = address_groups + if resource_type in [nsx_constants.LROUTERPORT_UPLINK, + nsx_constants.LROUTERPORT_DOWNLINK]: + body['linked_logical_switch_port_id'] = { + 'target_id': logical_port_id} + elif resource_type == nsx_constants.LROUTERPORT_LINKONTIER1: + body['linked_logical_router_port_id'] = { + 'target_id': logical_port_id} + elif logical_port_id: + body['linked_logical_router_port_id'] = logical_port_id + if edge_cluster_member_index: + body['edge_cluster_member_index'] = edge_cluster_member_index + + return self._client.create(body) + + @utils.retry_upon_exception_nsxv3( + nsx_exc.StaleRevision, + max_attempts=cfg.CONF.nsx_v3.retries) + def update(self, logical_port_id, **kwargs): + resource = '%s?detach=true' % logical_port_id + logical_router_port = self.get(logical_port_id) + for k in kwargs: + logical_router_port[k] = kwargs[k] + # If revision_id of the payload that we send is older than what NSX has + # then we will get a 412: Precondition Failed. In that case we need to + # re-fetch, patch the response and send it again with the + # new revision_id + return self._client.update(resource, body=logical_router_port) + + def delete(self, logical_port_id): + return self._client.url_delete(logical_port_id) + + def get_by_lswitch_id(self, logical_switch_id): + resource = ('logical-router-ports?logical_switch_id=%s' % + logical_switch_id) + router_ports = self._client.url_get(resource) + if int(router_ports['result_count']) >= 2: + raise nsx_exc.NsxPluginException( + err_msg=_("Can't support more than one logical router ports " + "on same logical switch %s ") % logical_switch_id) + elif int(router_ports['result_count']) == 1: + return router_ports['results'][0] + else: + err_msg = (_("Logical router link port not found on logical " + "switch %s") % logical_switch_id) + raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(), + operation=err_msg) + + def update_by_lswitch_id(self, logical_router_id, ls_id, **payload): + port = self.get_by_lswitch_id(ls_id) + return self.update(port['id'], **payload) + + def delete_by_lswitch_id(self, ls_id): + port = self.get_by_lswitch_id(ls_id) + self.delete(port['id']) + + def get_by_router_id(self, logical_router_id): + resource = ('logical-router-ports/?logical_router_id=%s' % + logical_router_id) + logical_router_ports = self._client.url_get(resource) + return logical_router_ports['results'] + + def get_tier1_link_port(self, logical_router_id): + logical_router_ports = self.get_by_router_id(logical_router_id) + for port in logical_router_ports: + if port['resource_type'] == nsx_constants.LROUTERPORT_LINKONTIER1: + return port + raise nsx_exc.ResourceNotFound( + manager=client._get_manager_ip(), + operation="get router link port") diff --git a/vmware_nsx/nsxlib/v3/router.py b/vmware_nsx/nsxlib/v3/router.py index dbeef63c6d..c6a9a0fdae 100644 --- a/vmware_nsx/nsxlib/v3/router.py +++ b/vmware_nsx/nsxlib/v3/router.py @@ -24,6 +24,7 @@ from neutron.i18n import _LW from oslo_log import log from vmware_nsx.common import exceptions as nsx_exc +from vmware_nsx.common import nsx_constants from vmware_nsx.nsxlib import v3 as nsxlib LOG = log.getLogger(__name__) @@ -40,144 +41,140 @@ FIP_NAT_PRI = 900 GW_NAT_PRI = 1000 -def validate_tier0(tier0_groups_dict, tier0_uuid): - if tier0_uuid in tier0_groups_dict: - return - err_msg = None - try: - lrouter = nsxlib.get_logical_router(tier0_uuid) - except nsx_exc.ResourceNotFound: - err_msg = _("Failed to validate tier0 router %s since it is " - "not found at the backend") % tier0_uuid - else: - edge_cluster_uuid = lrouter.get('edge_cluster_id') - if not edge_cluster_uuid: - err_msg = _("Failed to get edge cluster uuid from tier0 " - "router %s at the backend") % lrouter +class RouterLib(object): + + def __init__(self, router_client, router_port_client): + self._router_client = router_client + self._router_port_client = router_port_client + + def validate_tier0(self, tier0_groups_dict, tier0_uuid): + if tier0_uuid in tier0_groups_dict: + return + err_msg = None + try: + resource = 'logical-routers/%s' % tier0_uuid + lrouter = self._router_client.get(resource) + except nsx_exc.ResourceNotFound: + err_msg = _("Failed to validate tier0 router %s since it is " + "not found at the backend") % tier0_uuid else: - edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid) - member_index_list = [member['member_index'] - for member in edge_cluster['members']] - if len(member_index_list) < MIN_EDGE_NODE_NUM: - err_msg = _("%(act_num)s edge members found in " - "edge_cluster %(cluster_id)s, however we " - "require at least %(exp_num)s edge nodes " - "in edge cluster for HA use.") % { - 'act_num': len(member_index_list), - 'exp_num': MIN_EDGE_NODE_NUM, - 'cluster_id': edge_cluster_uuid} - if err_msg: - raise n_exc.InvalidInput(error_message=err_msg) - else: - tier0_groups_dict[tier0_uuid] = { - 'edge_cluster_uuid': edge_cluster_uuid, - 'member_index_list': member_index_list} + edge_cluster_uuid = lrouter.get('edge_cluster_id') + if not edge_cluster_uuid: + err_msg = _("Failed to get edge cluster uuid from tier0 " + "router %s at the backend") % lrouter + else: + edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid) + member_index_list = [member['member_index'] + for member in edge_cluster['members']] + if len(member_index_list) < MIN_EDGE_NODE_NUM: + err_msg = _("%(act_num)s edge members found in " + "edge_cluster %(cluster_id)s, however we " + "require at least %(exp_num)s edge nodes " + "in edge cluster for HA use.") % { + 'act_num': len(member_index_list), + 'exp_num': MIN_EDGE_NODE_NUM, + 'cluster_id': edge_cluster_uuid} + if err_msg: + raise n_exc.InvalidInput(error_message=err_msg) + else: + tier0_groups_dict[tier0_uuid] = { + 'edge_cluster_uuid': edge_cluster_uuid, + 'member_index_list': member_index_list} + def add_router_link_port(self, tier1_uuid, tier0_uuid, edge_members): + # Create Tier0 logical router link port + tier0_link_port = self._router_port_client.create( + tier0_uuid, display_name=TIER0_ROUTER_LINK_PORT_NAME, + resource_type=nsx_constants.LROUTERPORT_LINKONTIER0, + logical_port_id=None, + address_groups=None) + linked_logical_port_id = tier0_link_port['id'] + edge_cluster_member_index = random.sample( + edge_members, MIN_EDGE_NODE_NUM) + # Create Tier1 logical router link port + self._router_port_client.create( + tier1_uuid, display_name=TIER1_ROUTER_LINK_PORT_NAME, + resource_type=nsx_constants.LROUTERPORT_LINKONTIER1, + logical_port_id=linked_logical_port_id, + address_groups=None, + edge_cluster_member_index=edge_cluster_member_index) -def add_router_link_port(tier1_uuid, tier0_uuid, edge_members): - # Create Tier0 logical router link port - tier0_link_port = nsxlib.create_logical_router_port( - tier0_uuid, display_name=TIER0_ROUTER_LINK_PORT_NAME, - resource_type=nsxlib.LROUTERPORT_LINKONTIER0, - logical_port_id=None, - address_groups=None) - linked_logical_port_id = tier0_link_port['id'] + def remove_router_link_port(self, tier1_uuid, tier0_uuid): + try: + tier1_link_port = ( + self._router_port_client.get_tier1_link_port(tier1_uuid)) + except nsx_exc.ResourceNotFound: + LOG.warning(_LW("Logical router link port for tier1 router: %s " + "not found at the backend"), tier1_uuid) + return + tier1_link_port_id = tier1_link_port['id'] + tier0_link_port_id = ( + tier1_link_port['linked_logical_router_port_id'].get('target_id')) + self._router_port_client.delete(tier1_link_port_id) + self._router_port_client.delete(tier0_link_port_id) - edge_cluster_member_index = random.sample( - edge_members, MIN_EDGE_NODE_NUM) - # Create Tier1 logical router link port - nsxlib.create_logical_router_port( - tier1_uuid, display_name=TIER1_ROUTER_LINK_PORT_NAME, - resource_type=nsxlib.LROUTERPORT_LINKONTIER1, - logical_port_id=linked_logical_port_id, - address_groups=None, - edge_cluster_member_index=edge_cluster_member_index) + def update_advertisement(self, logical_router_id, advertise_route_nat, + advertise_route_connected): + return nsxlib.update_logical_router_advertisement( + logical_router_id, + advertise_nat_routes=advertise_route_nat, + advertise_nsx_connected_routes=advertise_route_connected) + def delete_gw_snat_rule(self, logical_router_id, gw_ip): + return nsxlib.delete_nat_rule_by_values(logical_router_id, + translated_network=gw_ip) -def remove_router_link_port(tier1_uuid, tier0_uuid): - try: - tier1_link_port = nsxlib.get_tier1_logical_router_link_port( - tier1_uuid) - except nsx_exc.ResourceNotFound: - LOG.warning(_LW("Logical router link port for tier1 router: %s " - "not found at the backend"), tier1_uuid) - return - tier1_link_port_id = tier1_link_port['id'] - tier0_link_port_id = ( - tier1_link_port['linked_logical_router_port_id'].get('target_id')) - nsxlib.delete_logical_router_port(tier1_link_port_id) - nsxlib.delete_logical_router_port(tier0_link_port_id) + def add_gw_snat_rule(self, logical_router_id, gw_ip): + return nsxlib.add_nat_rule(logical_router_id, action="SNAT", + translated_network=gw_ip, + rule_priority=GW_NAT_PRI) + def update_router_edge_cluster(self, nsx_router_id, edge_cluster_uuid): + return self._router_client.update(nsx_router_id, + edge_cluster_id=edge_cluster_uuid) -def update_advertisement(logical_router_id, advertise_route_nat, - advertise_route_connected): - return nsxlib.update_logical_router_advertisement( - logical_router_id, - advertise_nat_routes=advertise_route_nat, - advertise_nsx_connected_routes=advertise_route_connected) - - -def delete_gw_snat_rule(logical_router_id, gw_ip): - return nsxlib.delete_nat_rule_by_values(logical_router_id, - translated_network=gw_ip) - - -def add_gw_snat_rule(logical_router_id, gw_ip): - return nsxlib.add_nat_rule(logical_router_id, action="SNAT", - translated_network=gw_ip, - rule_priority=GW_NAT_PRI) - - -def update_router_edge_cluster(nsx_router_id, edge_cluster_uuid): - return nsxlib.update_logical_router(nsx_router_id, - edge_cluster_id=edge_cluster_uuid) - - -def create_logical_router_intf_port_by_ls_id(logical_router_id, - ls_id, - logical_switch_port_id, - address_groups): - try: - port = nsxlib.get_logical_router_port_by_ls_id(ls_id) - except nsx_exc.ResourceNotFound: - return nsxlib.create_logical_router_port(logical_router_id, - ROUTER_INTF_PORT_NAME, - nsxlib.LROUTERPORT_DOWNLINK, + def create_logical_router_intf_port_by_ls_id(self, logical_router_id, + ls_id, logical_switch_port_id, - address_groups) - else: - return nsxlib.update_logical_router_port( - port['id'], subnets=address_groups) + address_groups): + try: + port = self._router_port_client.get_by_lswitch_id(ls_id) + except nsx_exc.ResourceNotFound: + return self._router_port_client.create( + logical_router_id, + ROUTER_INTF_PORT_NAME, + nsx_constants.LROUTERPORT_DOWNLINK, + logical_switch_port_id, + address_groups) + else: + return self._router_port_client.update( + port['id'], subnets=address_groups) + def add_fip_nat_rules(self, logical_router_id, ext_ip, int_ip): + nsxlib.add_nat_rule(logical_router_id, action="SNAT", + translated_network=ext_ip, + source_net=int_ip, + rule_priority=FIP_NAT_PRI) + nsxlib.add_nat_rule(logical_router_id, action="DNAT", + translated_network=int_ip, + dest_net=ext_ip, + rule_priority=FIP_NAT_PRI) -def add_fip_nat_rules(logical_router_id, ext_ip, int_ip): - nsxlib.add_nat_rule(logical_router_id, action="SNAT", - translated_network=ext_ip, - source_net=int_ip, - rule_priority=FIP_NAT_PRI) - nsxlib.add_nat_rule(logical_router_id, action="DNAT", - translated_network=int_ip, - dest_net=ext_ip, - rule_priority=FIP_NAT_PRI) + def delete_fip_nat_rules(self, logical_router_id, ext_ip, int_ip): + nsxlib.delete_nat_rule_by_values(logical_router_id, + action="SNAT", + translated_network=ext_ip, + match_source_network=int_ip) + nsxlib.delete_nat_rule_by_values(logical_router_id, + action="DNAT", + translated_network=int_ip, + match_destination_network=ext_ip) + def add_static_routes(self, nsx_router_id, route): + return nsxlib.add_static_route(nsx_router_id, route['destination'], + route['nexthop']) -def delete_fip_nat_rules(logical_router_id, ext_ip, int_ip): - nsxlib.delete_nat_rule_by_values(logical_router_id, - action="SNAT", - translated_network=ext_ip, - match_source_network=int_ip) - nsxlib.delete_nat_rule_by_values(logical_router_id, - action="DNAT", - translated_network=int_ip, - match_destination_network=ext_ip) - - -def add_static_routes(nsx_router_id, route): - return nsxlib.add_static_route(nsx_router_id, route['destination'], - route['nexthop']) - - -def delete_static_routes(nsx_router_id, route): - return nsxlib.delete_static_route_by_values( - nsx_router_id, dest_cidr=route['destination'], - nexthop=route['nexthop']) + def delete_static_routes(self, nsx_router_id, route): + return nsxlib.delete_static_route_by_values( + nsx_router_id, dest_cidr=route['destination'], + nexthop=route['nexthop']) diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 06436a6db5..159e8e2602 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -66,7 +66,7 @@ from vmware_nsx.nsxlib import v3 as nsxlib from vmware_nsx.nsxlib.v3 import client as nsx_client from vmware_nsx.nsxlib.v3 import dfw_api as firewall from vmware_nsx.nsxlib.v3 import resources as nsx_resources -from vmware_nsx.nsxlib.v3 import router as routerlib +from vmware_nsx.nsxlib.v3 import router from vmware_nsx.nsxlib.v3 import security @@ -117,6 +117,11 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, self._port_client = nsx_resources.LogicalPort(self._nsx_client) self.nsgroup_container, self.default_section = ( security.init_nsgroup_container_and_default_section_rules()) + self._router_client = nsx_resources.LogicalRouter(self._nsx_client) + self._router_port_client = nsx_resources.LogicalRouterPort( + self._nsx_client) + self._routerlib = router.RouterLib(self._router_client, + self._router_port_client) LOG.debug("Initializing NSX v3 port spoofguard switching profile") self._switching_profiles = nsx_resources.SwitchingProfile( @@ -243,7 +248,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, return net_type, physical_net, vlan_id def _get_edge_cluster_and_members(self, tier0_uuid): - routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid) + self._routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid) tier0_info = self.tier0_groups_dict[tier0_uuid] return (tier0_info['edge_cluster_uuid'], tier0_info['member_index_list']) @@ -255,7 +260,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, else: tier0_uuid = net_data[pnet.PHYSICAL_NETWORK] is_provider_net = True - routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid) + self._routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid) return (is_provider_net, utils.NetworkTypes.L3_EXT, tier0_uuid, 0) def _create_network_at_the_backend(self, context, net_data): @@ -858,25 +863,26 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, # TODO(berlin): revocate bgp announce on org tier0 router pass if remove_snat_rules: - routerlib.delete_gw_snat_rule(nsx_router_id, orgaddr) + self._routerlib.delete_gw_snat_rule(nsx_router_id, orgaddr) if remove_router_link_port: - routerlib.remove_router_link_port(nsx_router_id, org_tier0_uuid) + self._routerlib.remove_router_link_port( + nsx_router_id, org_tier0_uuid) if add_router_link_port: # First update edge cluster info for router edge_cluster_uuid, members = self._get_edge_cluster_and_members( new_tier0_uuid) - routerlib.update_router_edge_cluster( + self._routerlib.update_router_edge_cluster( nsx_router_id, edge_cluster_uuid) - routerlib.add_router_link_port(nsx_router_id, new_tier0_uuid, + self._routerlib.add_router_link_port(nsx_router_id, new_tier0_uuid, members) if add_snat_rules: - routerlib.add_gw_snat_rule(nsx_router_id, newaddr) + self._routerlib.add_gw_snat_rule(nsx_router_id, newaddr) if bgp_announce: # TODO(berlin): bgp announce on new tier0 router pass if remove_snat_rules or add_snat_rules: - routerlib.update_advertisement(nsx_router_id, + self._routerlib.update_advertisement(nsx_router_id, advertise_route_nat_flag, advertise_route_connected_flag) @@ -884,7 +890,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, # TODO(berlin): admin_state_up support gw_info = self._extract_external_gw(context, router, is_extract=True) tags = utils.build_v3_tags_payload(router['router']) - result = nsxlib.create_logical_router( + result = self._router_client.create( display_name=router['router'].get('name'), tags=tags) @@ -922,7 +928,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, # It is safe to do now as db-level checks for resource deletion were # passed (and indeed the resource was removed from the Neutron DB try: - nsxlib.delete_logical_router(nsx_router_id) + self._router_client.delete(nsx_router_id) except nsx_exc.ResourceNotFound: # If the logical router was not found on the backend do not worry # about it. The conditions has already been logged, so there is no @@ -981,9 +987,9 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) for route in routes_removed: - routerlib.delete_static_routes(nsx_router_id, route) + self._routerlib.delete_static_routes(nsx_router_id, route) for route in routes_added: - routerlib.add_static_routes(nsx_router_id, route) + self._routerlib.add_static_routes(nsx_router_id, route) return super(NsxV3Plugin, self).update_router( context, router_id, router) except nsx_exc.ResourceNotFound: @@ -1000,9 +1006,10 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, router_db['status'] = const.NET_STATUS_ERROR if nsx_router_id: for route in routes_added: - routerlib.delete_static_routes(nsx_router_id, route) + self._routerlib.delete_static_routes( + nsx_router_id, route) for route in routes_removed: - routerlib.add_static_routes(nsx_router_id, route) + self._routerlib.add_static_routes(nsx_router_id, route) router_db['status'] = curr_status def _get_router_interface_ports_by_network( @@ -1061,7 +1068,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, router_id) _ports, address_groups = self._get_ports_and_address_groups( context, router_id, network_id) - routerlib.create_logical_router_intf_port_by_ls_id( + self._routerlib.create_logical_router_intf_port_by_ls_id( logical_router_id=nsx_router_id, ls_id=nsx_net_id, logical_switch_port_id=nsx_port_id, @@ -1131,12 +1138,12 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, new_using_port_id = ports[0]['id'] _net_id, new_nsx_port_id = nsx_db.get_nsx_switch_and_port_id( context.session, new_using_port_id) - nsxlib.update_logical_router_port_by_ls_id( + self._router_port_client.update_by_lswitch_id( nsx_router_id, nsx_net_id, linked_logical_switch_port_id=new_nsx_port_id, subnets=address_groups) else: - nsxlib.delete_logical_router_port_by_ls_id(nsx_net_id) + self._router_port_client.delete_by_lswitch_id(nsx_net_id) except nsx_exc.ResourceNotFound: LOG.error(_LE("router port on router %(router_id)s for net " "%(net_id)s not found at the backend"), @@ -1154,7 +1161,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, try: nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) - routerlib.add_fip_nat_rules( + self._routerlib.add_fip_nat_rules( nsx_router_id, new_fip['floating_ip_address'], new_fip['fixed_ip_address']) except nsx_exc.ManagerError: @@ -1169,7 +1176,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, try: nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) - routerlib.delete_fip_nat_rules( + self._routerlib.delete_fip_nat_rules( nsx_router_id, fip['floating_ip_address'], fip['fixed_ip_address']) except nsx_exc.ResourceNotFound: @@ -1194,7 +1201,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, try: old_nsx_router_id = nsx_db.get_nsx_router_id( context.session, old_fip['router_id']) - routerlib.delete_fip_nat_rules( + self._routerlib.delete_fip_nat_rules( old_nsx_router_id, old_fip['floating_ip_address'], old_fip['fixed_ip_address']) except nsx_exc.ResourceNotFound: @@ -1213,7 +1220,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, if router_id: nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) - routerlib.add_fip_nat_rules( + self._routerlib.add_fip_nat_rules( nsx_router_id, new_fip['floating_ip_address'], new_fip['fixed_ip_address']) except nsx_exc.ManagerError: @@ -1234,7 +1241,7 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, try: nsx_router_id = nsx_db.get_nsx_router_id(context.session, fip_db.router_id) - routerlib.delete_fip_nat_rules( + self._routerlib.delete_fip_nat_rules( nsx_router_id, fip_db.floating_ip_address, fip_db.fixed_ip_address) except nsx_exc.ResourceNotFound: diff --git a/vmware_nsx/tests/unit/nsx_v3/test_constants.py b/vmware_nsx/tests/unit/nsx_v3/test_constants.py index 086218c568..910147d01c 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_constants.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_constants.py @@ -97,3 +97,20 @@ FAKE_QOS_PROFILE = { "_create_user": "admin", "_revision": 0 } + +FAKE_ROUTER_UUID = uuidutils.generate_uuid() +FAKE_ROUTER = { + "resource_type": "LogicalRouter", + "revision": 0, + "id": FAKE_ROUTER_UUID, + "display_name": FAKE_NAME +} + +FAKE_ROUTER_PORT_UUID = uuidutils.generate_uuid() +FAKE_ROUTER_PORT = { + "resource_type": "LogicalRouterLinkPort", + "revision": 0, + "id": FAKE_ROUTER_PORT_UUID, + "display_name": FAKE_NAME, + "logical_router_id": FAKE_ROUTER_UUID +} diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index e11ac00faa..16c03aa56f 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -67,7 +67,7 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase, self._patchers.append(mocked) mock_client_module(nsx_plugin.security.firewall) - mock_client_module(nsx_plugin.routerlib.nsxlib) + mock_client_module(nsx_plugin.router.nsxlib) mock_client_module(nsx_plugin) super(NsxV3PluginTestCaseMixin, self).setUp(plugin=plugin, diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py index c8a71e7add..aeceb3a5e0 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py @@ -241,3 +241,110 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): None, client.JSONRESTClient._DEFAULT_HEADERS, nsxlib_testcase.NSX_CERT) + + +class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): + + def test_create_logical_router(self): + """ + Test creating a router returns the correct response and 201 status + """ + fake_router = test_constants_v3.FAKE_ROUTER.copy() + + api = resources.LogicalRouter(client.NSX3Client()) + with self.mocked_resource(api) as mocked: + mocked.get('post').return_value = mocks.MockRequestsResponse( + 201, jsonutils.dumps(fake_router)) + + tier0_router = True + result = api.create(fake_router['display_name'], None, None, + tier0_router) + + data = { + 'display_name': fake_router['display_name'], + 'router_type': 'TIER0' if tier0_router else 'TIER1', + 'tags': None + } + + self.assertEqual(fake_router, result) + test_client.assert_session_call( + mocked.get('post'), + 'https://1.2.3.4/api/v1/logical-routers', + False, + jsonutils.dumps(data), + client.JSONRESTClient._DEFAULT_HEADERS, + nsxlib_testcase.NSX_CERT) + + def test_delete_logical_router(self): + """ + Test deleting router + """ + api = resources.LogicalRouter(client.NSX3Client()) + with self.mocked_resource(api) as mocked: + mocked.get('delete').return_value = mocks.MockRequestsResponse( + 200, None) + + uuid = test_constants_v3.FAKE_ROUTER['id'] + result = api.delete(uuid) + self.assertIsNone(result.content) + test_client.assert_session_call( + mocked.get('delete'), + 'https://1.2.3.4/api/v1/logical-routers/%s' % uuid, + False, + None, + client.JSONRESTClient._DEFAULT_HEADERS, + nsxlib_testcase.NSX_CERT) + + +class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): + + def test_create_logical_router_port(self): + """ + Test creating a router returns the correct response and 201 status + """ + fake_router_port = test_constants_v3.FAKE_ROUTER_PORT.copy() + + api = resources.LogicalRouterPort(client.NSX3Client()) + with self.mocked_resource(api) as mocked: + mocked.get('post').return_value = mocks.MockRequestsResponse( + 201, jsonutils.dumps(fake_router_port)) + + result = api.create(fake_router_port['logical_router_id'], + fake_router_port['display_name'], + fake_router_port['resource_type'], + None, None, None) + + data = { + 'display_name': fake_router_port['display_name'], + 'logical_router_id': fake_router_port['logical_router_id'], + 'resource_type': fake_router_port['resource_type'] + } + + self.assertEqual(fake_router_port, result) + test_client.assert_session_call( + mocked.get('post'), + 'https://1.2.3.4/api/v1/logical-router-ports', + False, + jsonutils.dumps(data), + client.JSONRESTClient._DEFAULT_HEADERS, + nsxlib_testcase.NSX_CERT) + + def test_delete_logical_router_port(self): + """ + Test deleting router port + """ + api = resources.LogicalRouterPort(client.NSX3Client()) + with self.mocked_resource(api) as mocked: + mocked.get('delete').return_value = mocks.MockRequestsResponse( + 200, None) + + uuid = test_constants_v3.FAKE_ROUTER_PORT['id'] + result = api.delete(uuid) + self.assertIsNone(result.content) + test_client.assert_session_call( + mocked.get('delete'), + 'https://1.2.3.4/api/v1/logical-router-ports/%s' % uuid, + False, + None, + client.JSONRESTClient._DEFAULT_HEADERS, + nsxlib_testcase.NSX_CERT)