def delete_network_postcommit(self, context):
        """Send network delete request to Arista HW."""
        network = context.current
        segments = context.network_segments
        if not self.rpc.hpb_supported():
            # Hierarchical port binding is not supported by CVX, only
            # send the request if network type is VLAN.
            if segments[0][driver_api.NETWORK_TYPE] != p_const.TYPE_VLAN:
                # If networtk type is not VLAN, do nothing
                return
        network_id = network['id']
        tenant_id = network['tenant_id'] or INTERNAL_TENANT_ID
        with self.eos_sync_lock:

            # Succeed deleting network in case EOS is not accessible.
            # EOS state will be updated by sync thread once EOS gets
            # alive.
            try:
                self.rpc.delete_network(tenant_id, network_id, segments)
                # if necessary, delete tenant as well.
                self.delete_tenant(tenant_id)
            except arista_exc.AristaRpcError as err:
                LOG.error(
                    _LE('delete_network_postcommit: Did not delete '
                        'network %(network_id)s. Reason: %(err)s'), {
                            'network_id': network_id,
                            'err': err
                        })
Esempio n. 2
0
    def get_tenants(self):
        path = 'region/' + self.region + '/tenant'
        tenants = self._send_api_request(path, 'GET')
        d = {}
        for ten in tenants:
            ten['tenantId'] = ten.pop('id')

            nets = self.get_networks(ten['tenantId'])
            netDict = {}
            try:
                for net in nets:
                    net['networkId'] = net.pop('id')
                    net['networkName'] = net.pop('name')
                    netDict[net['networkId']] = net
            except Exception as exc:
                LOG.error(_LE('Failed to get tenant network %(net)s. '
                              'Reason: %(exc)s'), {'net': net, 'exc': exc})

            ten['tenantNetworks'] = netDict

            vms = self.get_vms_for_tenant(ten['tenantId'])
            vmDict = dict((v['id'], v) for v in vms)
            ten['tenantVmInstances'] = vmDict

            routers = self.get_routers_for_tenant(ten['tenantId'])
            routerDict = dict((r['id'], r) for r in routers)
            ten['tenantRouterInstances'] = routerDict

            bms = self.get_baremetals_for_tenant(ten['tenantId'])
            bmDict = dict((b['id'], b) for b in bms)
            ten['tenantBaremetalInstances'] = bmDict

            d[ten['tenantId']] = ten
        return d
Esempio n. 3
0
    def remove_router_interface(self, context, router_id, interface_info):
        """Remove a subnet of a network from an existing router."""

        router_to_del = (
            super(AristaL3ServicePlugin, self).remove_router_interface(
                context,
                router_id,
                interface_info)
            )

        # Get network information of the subnet that is being removed
        core = directory.get_plugin()
        subnet = core.get_subnet(context, router_to_del['subnet_id'])
        network_id = subnet['network_id']

        # For SVI removal from Arista HW, segmentation ID is needed
        ml2_db = NetworkContext(self, context, {'id': network_id})
        seg_id = ml2_db.network_segments[0]['segmentation_id']

        router = self.get_router(context, router_id)
        router_info = copy.deepcopy(router_to_del)
        router_info['seg_id'] = seg_id
        router_info['name'] = router['name']

        try:
            self.driver.remove_router_interface(context, router_info)
            return router_to_del
        except Exception as exc:
            LOG.error(_LE("Error removing interface %(interface)s from "
                          "router %(router_id)s on Arista HW"
                          "Exception =(exc)s"),
                      {'interface': interface_info, 'router_id': router_id,
                       'exc': exc})
Esempio n. 4
0
    def update_network_postcommit(self, context):
        """At the moment we only support network name change

        If network name is changed, a new network create request is
        sent to the Arista Hardware.
        """
        new_network = context.current
        orig_network = context.original
        if ((new_network['name'] != orig_network['name'])
                or (new_network['shared'] != orig_network['shared'])):
            network_id = new_network['id']
            network_name = new_network['name']
            tenant_id = (new_network['tenant_id']
                         or constants.INTERNAL_TENANT_ID)
            shared_net = new_network['shared']
            with self.eos_sync_lock:
                try:
                    network_dict = {
                        'network_id': network_id,
                        'segments': context.network_segments,
                        'network_name': network_name,
                        'shared': shared_net
                    }
                    self.rpc.create_network(tenant_id, network_dict)
                except arista_exc.AristaRpcError as err:
                    LOG.error(
                        _LE('update_network_postcommit: Did not '
                            'update network %(name)s. '
                            'Reason: %(err)s'), {
                                'name': network_name,
                                'err': err
                            })
Esempio n. 5
0
 def create_routers(self, routers):
     for r in routers:
         try:
             self.driver.create_router(self, r)
         except Exception:
             LOG.error(_LE("Error Adding router %(router_id)s "
                           "on Arista HW"), {'router_id': r})
Esempio n. 6
0
    def remove_router_interface(self, context, router_id, interface_info):
        """Remove a subnet of a network from an existing router."""

        new_router = (super(AristaL3ServicePlugin,
                            self).remove_router_interface(
                                context, router_id, interface_info))

        # Get network information of the subnet that is being removed
        subnet = self.get_subnet(context, new_router['subnet_id'])
        network_id = subnet['network_id']

        # For SVI removal from Arista HW, segmentation ID is needed
        ml2_db = NetworkContext(self, context, {'id': network_id})
        seg_id = ml2_db.network_segments[0]['segmentation_id']

        router = super(AristaL3ServicePlugin,
                       self).get_router(context, router_id)
        router_info = copy.deepcopy(new_router)
        router_info['seg_id'] = seg_id
        router_info['name'] = router['name']

        try:
            self.driver.remove_router_interface(context, router_info)
            return new_router
        except Exception as exc:
            LOG.error(
                _LE("Error removing interface %(interface)s from "
                    "router %(router_id)s on Arista HW"
                    "Exception =(exc)s"), {
                        'interface': interface_info,
                        'router_id': router_id,
                        'exc': exc
                    })
    def create_network_postcommit(self, context):
        """Provision the network on the Arista Hardware."""

        network = context.current
        network_id = network['id']
        network_name = network['name']
        tenant_id = network['tenant_id'] or INTERNAL_TENANT_ID
        segments = context.network_segments
        shared_net = network['shared']
        with self.eos_sync_lock:
            if db_lib.is_network_provisioned(tenant_id, network_id):
                try:
                    network_dict = {
                        'network_id': network_id,
                        'segments': segments,
                        'network_name': network_name,
                        'shared': shared_net
                    }
                    self.rpc.create_network(tenant_id, network_dict)
                except arista_exc.AristaRpcError as err:
                    LOG.error(
                        _LE("create_network_postcommit: Did not create "
                            "network %(name)s. Reason: %(err)s"), {
                                'name': network_name,
                                'err': err
                            })
            else:
                LOG.info(
                    _LI('Network %s is not created as it is not found in '
                        'Arista DB'), network_id)
Esempio n. 8
0
    def get_host_physnet(self, context):
        """Returns dictionary which contains physical topology information

        for a given host_id
        """
        host_id = utils.hostname(context.host)
        cmd = ['show network physical-topology neighbors']
        try:
            response = self._run_eos_cmds(cmd)
            # Get response for 'show network physical-topology neighbors'
            # command
            neighbors = response[0]['neighbors']
            for neighbor in neighbors:
                if host_id in neighbor:
                    physnet = neighbors[neighbor]['toPort'][0]['hostname']
                    LOG.debug("get_physical_network: Physical Network for "
                              "%(host)s is %(physnet)s", {'host': host_id,
                                                          'physnet': physnet})
                    return physnet
            LOG.debug("Physical network not found for %(host)s",
                      {'host': host_id})
        except Exception as exc:
            LOG.error(_LE('command %(cmd)s failed with '
                      '%(exc)s'), {'cmd': cmd, 'exc': exc})
        return None
Esempio n. 9
0
 def create_security_group(self, resource, event, trigger, **kwargs):
     sg = kwargs.get('security_group')
     try:
         self.client.create_security_group(sg)
     except Exception as e:
         with excutils.save_and_reraise_exception():
             LOG.error(
                 _LE("Failed to create a security group %(sg_id)s "
                     "in Arista Driver: %(err)s"), {
                         "sg_id": sg["id"],
                         "err": e
                     })
             try:
                 self.client.delete_security_group(sg)
             except Exception:
                 LOG.exception(_LE("Failed to delete security group %s"),
                               sg['id'])
Esempio n. 10
0
 def create_router_interfaces(self, router_interfaces):
     for r in router_interfaces:
         try:
             self.driver.add_router_interface(self, r)
         except Exception:
             LOG.error(_LE("Error Adding interface %(subnet_id)s "
                           "to router %(router_id)s on Arista HW"),
                       {'subnet_id': r['subnet_id'], 'router_id': r['id']})
Esempio n. 11
0
 def delete_security_group_rule(self, resource, event, trigger, **kwargs):
     sgr_id = kwargs.get('security_group_rule_id')
     try:
         self.client.delete_security_group_rule(sgr_id)
     except Exception as e:
         LOG.error(
             _LE("Failed to delete security group %(sgr_id)s "
                 "rule in Arista Driver: %(err)s"), {
                     "sgr_id": sgr_id,
                     "err": e
                 })
Esempio n. 12
0
 def update_security_group(self, resource, event, trigger, **kwargs):
     sg = kwargs.get('security_group')
     try:
         self.client.update_security_group(sg)
     except Exception as e:
         LOG.error(
             _LE("Failed to update security group %(sg_id)s "
                 "in Arista Driver: %(err)s"), {
                     "sg_id": sg["id"],
                     "err": e
                 })
Esempio n. 13
0
    def delete_router(self, context, router_id):
        """Delete an existing router from Arista HW as well as from the DB."""

        router = self.get_router(context, router_id)

        # Delete router on the Arista Hw
        try:
            self.driver.delete_router(context, router_id, router)
        except Exception as e:
            LOG.error(_LE("Error deleting router on Arista HW "
                          "router %(r)s exception=%(e)s"),
                      {'r': router, 'e': e})

        super(AristaL3ServicePlugin, self).delete_router(context, router_id)
Esempio n. 14
0
    def add_router_interface(self, context, router_id, interface_info):
        """Add a subnet of a network to an existing router."""

        new_router = super(AristaL3ServicePlugin,
                           self).add_router_interface(context, router_id,
                                                      interface_info)

        # Get network info for the subnet that is being added to the router.
        # Check if the interface information is by port-id or subnet-id
        add_by_port, add_by_sub = self._validate_interface_info(interface_info)
        if add_by_sub:
            subnet = self.get_subnet(context, interface_info['subnet_id'])
        elif add_by_port:
            port = self.get_port(context, interface_info['port_id'])
            subnet_id = port['fixed_ips'][0]['subnet_id']
            subnet = self.get_subnet(context, subnet_id)
        network_id = subnet['network_id']

        # To create SVI's in Arista HW, the segmentation Id is required
        # for this network.
        ml2_db = NetworkContext(self, context, {'id': network_id})
        seg_id = ml2_db.network_segments[0]['segmentation_id']

        # Package all the info needed for Hw programming
        router = super(AristaL3ServicePlugin,
                       self).get_router(context, router_id)
        router_info = copy.deepcopy(new_router)
        router_info['seg_id'] = seg_id
        router_info['name'] = router['name']
        router_info['cidr'] = subnet['cidr']
        router_info['gip'] = subnet['gateway_ip']
        router_info['ip_version'] = subnet['ip_version']

        try:
            self.driver.add_router_interface(context, router_info)
            return new_router
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Error Adding subnet %(subnet)s to "
                        "router %(router_id)s on Arista HW"), {
                            'subnet': subnet,
                            'router_id': router_id
                        })
                super(AristaL3ServicePlugin,
                      self).remove_router_interface(context, router_id,
                                                    interface_info)
Esempio n. 15
0
    def synchronize(self):
        """Synchronizes Router DB from Neturon DB with EOS.

        Walks through the Neturon Db and ensures that all the routers
        created in Netuton DB match with EOS. After creating appropriate
        routers, it ensures to add interfaces as well.
        Uses idempotent properties of EOS configuration, which means
        same commands can be repeated.
        """
        LOG.info(_LI('Syncing Neutron Router DB <-> EOS'))
        ctx = nctx.get_admin_context()

        routers = super(AristaL3ServicePlugin, self).get_routers(ctx)
        for r in routers:
            tenant_id = r['tenant_id']
            ports = self.ndb.get_all_ports_for_tenant(tenant_id)

            try:
                self.driver.create_router(self, tenant_id, r)

            except Exception:
                continue

            # Figure out which interfaces are added to this router
            for p in ports:
                if p['device_id'] == r['id']:
                    net_id = p['network_id']
                    subnet_id = p['fixed_ips'][0]['subnet_id']
                    subnet = self.ndb.get_subnet_info(subnet_id)
                    ml2_db = NetworkContext(self, ctx, {'id': net_id})
                    seg_id = ml2_db.network_segments[0]['segmentation_id']

                    r['seg_id'] = seg_id
                    r['cidr'] = subnet['cidr']
                    r['gip'] = subnet['gateway_ip']
                    r['ip_version'] = subnet['ip_version']

                    try:
                        self.driver.add_router_interface(self, r)
                    except Exception:
                        LOG.error(
                            _LE("Error Adding interface %(subnet_id)s "
                                "to router %(router_id)s on Arista HW"), {
                                    'subnet_id': subnet_id,
                                    'router_id': r
                                })
Esempio n. 16
0
    def update_router(self, context, router_id, router):
        """Update an existing router in DB, and update it in Arista HW."""

        # Read existing router record from DB
        original_router = self.get_router(context, router_id)
        # Update router DB
        new_router = super(AristaL3ServicePlugin, self).update_router(
            context, router_id, router)

        # Modify router on the Arista Hw
        try:
            self.driver.update_router(context, router_id,
                                      original_router, new_router)
            return new_router
        except Exception:
            LOG.error(_LE("Error updating router on Arista HW router=%s "),
                      new_router)
Esempio n. 17
0
    def add_router_interface(self, context, router_id, interface_info):
        """Add a subnet of a network to an existing router."""

        new_router = super(AristaL3ServicePlugin, self).add_router_interface(
            context, router_id, interface_info)

        core = directory.get_plugin()

        # Get network info for the subnet that is being added to the router.
        # Check if the interface information is by port-id or subnet-id
        add_by_port, add_by_sub = self._validate_interface_info(interface_info)
        if add_by_sub:
            subnet = core.get_subnet(context, interface_info['subnet_id'])
        elif add_by_port:
            port = core.get_port(context, interface_info['port_id'])
            subnet_id = port['fixed_ips'][0]['subnet_id']
            subnet = core.get_subnet(context, subnet_id)
        network_id = subnet['network_id']

        # To create SVI's in Arista HW, the segmentation Id is required
        # for this network.
        ml2_db = NetworkContext(self, context, {'id': network_id})
        seg_id = ml2_db.network_segments[0]['segmentation_id']

        # Package all the info needed for Hw programming
        router = self.get_router(context, router_id)
        router_info = copy.deepcopy(new_router)
        router_info['seg_id'] = seg_id
        router_info['name'] = router['name']
        router_info['cidr'] = subnet['cidr']
        router_info['gip'] = subnet['gateway_ip']
        router_info['ip_version'] = subnet['ip_version']

        try:
            self.driver.add_router_interface(context, router_info)
            return new_router
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Error Adding subnet %(subnet)s to "
                              "router %(router_id)s on Arista HW"),
                          {'subnet': subnet, 'router_id': router_id})
                super(AristaL3ServicePlugin, self).remove_router_interface(
                    context,
                    router_id,
                    interface_info)
Esempio n. 18
0
    def create_router(self, context, router):
        """Create a new router entry in DB, and create it Arista HW."""

        tenant_id = router['router']['tenant_id']

        # Add router to the DB
        new_router = super(AristaL3ServicePlugin,
                           self).create_router(context, router)
        # create router on the Arista Hw
        try:
            self.driver.create_router(context, tenant_id, new_router)
            return new_router
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Error creating router on Arista HW router=%s "),
                          new_router)
                super(AristaL3ServicePlugin,
                      self).delete_router(context, new_router['id'])
Esempio n. 19
0
    def update_router(self, context, router_id, router):
        """Update an existing router in DB, and update it in Arista HW."""

        # Read existing router record from DB
        original_router = super(AristaL3ServicePlugin,
                                self).get_router(context, router_id)
        # Update router DB
        new_router = super(AristaL3ServicePlugin,
                           self).update_router(context, router_id, router)

        # Modify router on the Arista Hw
        try:
            self.driver.update_router(context, router_id, original_router,
                                      new_router)
            return new_router
        except Exception:
            LOG.error(_LE("Error updating router on Arista HW router=%s "),
                      new_router)
Esempio n. 20
0
    def get_physical_network(self, host_id):
        """Returns dirctionary which contains physical topology information

        for a given host_id
        """
        fqdns_used = cfg.CONF.ml2_arista['use_fqdn']
        physnet = None
        switch_id = None
        mac_to_hostname = {}
        cmds = ['show network physical-topology neighbors',
                'show network physical-topology hosts']
        try:
            response = self._run_eos_cmds(cmds)
            # Get response for 'show network physical-topology neighbors'
            # command
            neighbors = response[0]['neighbors']
            for neighbor in neighbors:
                if host_id in neighbor:
                    switchname = neighbors[neighbor]['toPort'][0]['hostname']
                    physnet = switchname if fqdns_used else (
                        switchname.split('.')[0])
                    switch_id = neighbors[neighbor]['toPort'][0].get('hostid')
                    if not switch_id:
                        switch_id = response[1]['hosts'][switchname]['name']
                    break

            # Check if the switch is part of an MLAG pair, and lookup the
            # pair's physnet name if so
            physnet = self.mlag_pairs.get(physnet, physnet)

            for host in response[1]['hosts'].values():
                mac_to_hostname[host['name']] = host['hostname']

            res = {'physnet': physnet,
                   'switch_id': switch_id,
                   'mac_to_hostname': mac_to_hostname}
            LOG.debug("get_physical_network: Physical Network info for "
                      "%(host)s is %(res)s", {'host': host_id,
                                              'res': res})
            return res
        except Exception as exc:
            LOG.error(_LE('command %(cmds)s failed with '
                      '%(exc)s'), {'cmds': cmds, 'exc': exc})
            return {}
Esempio n. 21
0
    def delete_router(self, context, router_id):
        """Delete an existing router from Arista HW as well as from the DB."""

        router = super(AristaL3ServicePlugin,
                       self).get_router(context, router_id)
        tenant_id = router['tenant_id']

        # Delete router on the Arista Hw
        try:
            self.driver.delete_router(context, tenant_id, router_id, router)
        except Exception as e:
            LOG.error(
                _LE("Error deleting router on Arista HW "
                    "router %(r)s exception=%(e)s"), {
                        'r': router,
                        'e': e
                    })

        super(AristaL3ServicePlugin, self).delete_router(context, router_id)
Esempio n. 22
0
    def create_router(self, context, router):
        """Create a new router entry in DB, and create it Arista HW."""

        # Add router to the DB
        new_router = super(AristaL3ServicePlugin, self).create_router(
            context,
            router)
        # create router on the Arista Hw
        try:
            self.driver.create_router(context, new_router)
            return new_router
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Error creating router on Arista HW router=%s "),
                          new_router)
                super(AristaL3ServicePlugin, self).delete_router(
                    context,
                    new_router['id']
                )
Esempio n. 23
0
 def delete_network_postcommit(self, context):
     """Send network delete request to Arista HW."""
     network = context.current
     segments = context.network_segments
     network_id = network['id']
     tenant_id = network['tenant_id'] or constants.INTERNAL_TENANT_ID
     with self.eos_sync_lock:
         # Succeed deleting network in case EOS is not accessible.
         # EOS state will be updated by sync thread once EOS gets
         # alive.
         try:
             self.rpc.delete_network(tenant_id, network_id, segments)
             # if necessary, delete tenant as well.
             self.delete_tenant(tenant_id)
         except arista_exc.AristaRpcError as err:
             LOG.error(
                 _LE('delete_network_postcommit: Did not delete '
                     'network %(network_id)s. Reason: %(err)s'), {
                         'network_id': network_id,
                         'err': err
                     })
Esempio n. 24
0
 def get_baremetal_physnet(self, context):
     """Returns dictionary which contains mac to hostname mapping"""
     port = context.current
     host_id = context.host
     cmd = ['show network physical-topology hosts']
     try:
         response = self._run_eos_cmds(cmd)
         binding_profile = port.get(portbindings.PROFILE, {})
         link_info = binding_profile.get('local_link_information', [])
         for link in link_info:
             switch_id = link.get('switch_id')
             for host in response[0]['hosts'].values():
                 if switch_id == host['name']:
                     physnet = host['hostname']
                     LOG.debug("get_physical_network: Physical Network for "
                               "%(host)s is %(physnet)s",
                               {'host': host_id, 'physnet': physnet})
                     return physnet
         LOG.debug("Physical network not found for %(host)s",
                   {'host': host_id})
     except Exception as exc:
         LOG.error(_LE('command %(cmd)s failed with '
                   '%(exc)s'), {'cmd': cmd, 'exc': exc})
     return None
    def update_port_postcommit(self, context):
        """Update the name of a given port in EOS.

        At the moment we only support port name change
        Any other change to port is not supported at this time.
        """
        port = context.current
        orig_port = context.original

        device_id = port['device_id']
        device_owner = port['device_owner']
        host = context.host
        is_vm_boot = device_id and device_owner

        vnic_type = port['binding:vnic_type']
        binding_profile = port['binding:profile']
        bindings = []
        if binding_profile:
            bindings = binding_profile['local_link_information']

        port_id = port['id']
        port_name = port['name']
        network_id = port['network_id']
        tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID
        # Ensure that we use tenant Id for the network owner
        tenant_id = self._network_owner_tenant(context, network_id, tenant_id)
        sg = port['security_groups']
        orig_sg = orig_port['security_groups']

        pretty_log("update_port_postcommit: new", port)
        pretty_log("update_port_postcommit: orig", orig_port)

        # Check if it is port migration case
        if self._handle_port_migration_postcommit(context):
            # Return from here as port migration is already handled.
            return

        seg_info = self._bound_segments(context)
        if not seg_info:
            LOG.debug("Ignoring the update as the port is not managed by "
                      "Arista switches.")
            return

        with self.eos_sync_lock:
            hostname = self._host_name(host)
            segmentation_id = seg_info[driver_api.SEGMENTATION_ID]
            port_host_filter = None
            if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE):
                # <port, host> uniquely identifies a DVR port. Other
                # ports are identified by just the port id
                port_host_filter = host

            port_provisioned = db_lib.is_port_provisioned(
                port_id, port_host_filter)
            # If network does not exist under this tenant,
            # it may be a shared network. Get shared network owner Id
            net_provisioned = self._network_provisioned(
                tenant_id, network_id, segmentation_id=segmentation_id)
            segments = []
            if net_provisioned:
                if self.rpc.hpb_supported():
                    for binding_level in context.binding_levels:
                        bound_segment = binding_level.get(
                            driver_api.BOUND_SEGMENT)
                        if bound_segment:
                            segments.append(bound_segment)
                    all_segments = self.ndb.get_all_network_segments(
                        network_id, context=context._plugin_context)
                    try:
                        self.rpc.create_network_segments(
                            tenant_id, network_id,
                            context.network.current['name'], all_segments)
                    except arista_exc.AristaRpcError:
                        LOG.error(_LE("Failed to create network segments"))
                        raise ml2_exc.MechanismDriverError()
                else:
                    # For non HPB cases, the port is bound to the static
                    # segment
                    segments = self.ndb.get_network_segments(network_id)

            try:
                orig_host = context.original_host
                port_down = False
                if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE
                    ):
                    # We care about port status only for DVR ports
                    port_down = context.status == n_const.PORT_STATUS_DOWN

                if orig_host and (port_down or host != orig_host):
                    try:
                        LOG.info("Deleting the port %s" % str(orig_port))
                        # The port moved to a different host or the VM
                        # connected to the port was deleted or its in DOWN
                        # state. So delete the old port on the old host.
                        self._delete_port(orig_port, orig_host, tenant_id)
                    except ml2_exc.MechanismDriverError:
                        # If deleting a port fails, then not much can be done
                        # about it. Log a warning and move on.
                        LOG.warning(UNABLE_TO_DELETE_PORT_MSG)
                if (port_provisioned and net_provisioned and hostname
                        and is_vm_boot and not port_down):
                    LOG.info(_LI("Port plugged into network"))
                    # Plug port into the network only if it exists in the db
                    # and is bound to a host and the port is up.
                    self.rpc.plug_port_into_network(device_id,
                                                    hostname,
                                                    port_id,
                                                    network_id,
                                                    tenant_id,
                                                    port_name,
                                                    device_owner,
                                                    sg,
                                                    orig_sg,
                                                    vnic_type,
                                                    segments=segments,
                                                    switch_bindings=bindings)
                else:
                    LOG.info(_LI("Port not plugged into network"))
            except arista_exc.AristaRpcError as err:
                LOG.error(
                    _LE('update_port_postcommit: Did not update '
                        'port %(port_id)s. Reason: %(err)s'), {
                            'port_id': port_id,
                            'err': err
                        })
Esempio n. 26
0
    def bind_port(self, context):
        """Bind port to a network segment.

        Provisioning request to Arista Hardware to plug a host
        into appropriate network is done when the port is created
        this simply tells the ML2 Plugin that we are binding the port
        """
        host_id = context.host
        port = context.current
        physnet_info = {}
        for segment in context.segments_to_bind:
            physnet = segment.get(driver_api.PHYSICAL_NETWORK)
            if not self._is_in_managed_physnets(physnet):
                LOG.debug(
                    "bind_port for port %(port)s: physical_network "
                    "%(physnet)s is not managed by Arista "
                    "mechanism driver", {
                        'port': port.get('id'),
                        'physnet': physnet
                    })
                continue
            # If physnet is not set, we need to look it up using hostname
            # and topology info
            if not physnet:
                if not physnet_info:
                    # We only need to get physnet_info once
                    physnet_info = self.eapi.get_physical_network(host_id)
                if (port.get('binding:vnic_type') ==
                        portbindings.VNIC_BAREMETAL):
                    # Find physnet using link_information in baremetal case
                    physnet = self._get_physnet_from_link_info(
                        port, physnet_info)
                else:
                    physnet = physnet_info.get('physnet')
            # If physnet was not found, we cannot bind this port
            if not physnet:
                LOG.debug(
                    "bind_port for port %(port)s: no physical_network "
                    "found", {'port': port.get('id')})
                continue
            if segment[driver_api.NETWORK_TYPE] == n_const.TYPE_VXLAN:
                # The physical network is connected to arista switches,
                # allocate dynamic segmentation id to bind the port to
                # the network that the port belongs to.
                try:
                    next_segment = context.allocate_dynamic_segment({
                        'id':
                        context.network.current['id'],
                        'network_type':
                        n_const.TYPE_VLAN,
                        'physical_network':
                        physnet
                    })
                except Exception as exc:
                    LOG.error(
                        _LE("bind_port for port %(port)s: Failed to "
                            "allocate dynamic segment for physnet "
                            "%(physnet)s. %(exc)s"), {
                                'port': port.get('id'),
                                'physnet': physnet,
                                'exc': exc
                            })
                    return

                LOG.debug(
                    "bind_port for port %(port)s: "
                    "current_segment=%(current_seg)s, "
                    "next_segment=%(next_seg)s", {
                        'port': port.get('id'),
                        'current_seg': segment,
                        'next_seg': next_segment
                    })
                context.continue_binding(segment['id'], [next_segment])
            elif port.get('binding:vnic_type') == portbindings.VNIC_BAREMETAL:
                # The network_type is vlan, try binding process for baremetal.
                self._bind_port_to_baremetal(context, segment)
Esempio n. 27
0
    def update_port_postcommit(self, context):
        """Update the name of a given port in EOS.

        At the moment we only support port name change
        Any other change to port is not supported at this time.
        """
        port = context.current
        orig_port = context.original

        device_id = port['device_id']
        device_owner = port['device_owner']
        host = context.host
        is_vm_boot = device_id and device_owner

        # When delete a vm, the trunk port context has no device_owner
        # Keep device_owner as in original port
        if not device_owner and orig_port.get('trunk_details'):
            device_owner = orig_port['device_owner']

        if not utils.supported_device_owner(device_owner):
            return

        vnic_type = port['binding:vnic_type']
        binding_profile = port['binding:profile']
        bindings = []
        if binding_profile:
            bindings = binding_profile.get('local_link_information', [])

        port_id = port['id']
        port_name = port['name']
        network_id = port['network_id']
        tenant_id = port['tenant_id'] or constants.INTERNAL_TENANT_ID
        # Ensure that we use tenant Id for the network owner
        tenant_id = self._network_owner_tenant(context, network_id, tenant_id)
        sg = port['security_groups']
        orig_sg = orig_port['security_groups']

        pretty_log("update_port_postcommit: new", port)
        pretty_log("update_port_postcommit: orig", orig_port)

        # Check if it is port migration case
        if self._handle_port_migration_postcommit(context):
            # Return from here as port migration is already handled.
            return

        # Check if it is trunk_port deletion case
        seg_info = []
        if not port.get('trunk_details') or host:
            seg_info = self._bound_segments(context)
            if not seg_info:
                LOG.debug("Ignoring the update as the port is not managed by "
                          "Arista switches.")
                return

        with self.eos_sync_lock:
            hostname = self._host_name(host)
            try:
                orig_host = context.original_host
                port_down = False
                if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE
                        or port.get('trunk_details')):
                    # We care about port status only for DVR ports and
                    # trunk ports
                    port_down = context.status == n_const.PORT_STATUS_DOWN

                if orig_host and (port_down or host != orig_host or device_id
                                  == n_const.DEVICE_ID_RESERVED_DHCP_PORT):
                    LOG.info("Deleting the port %s" % str(orig_port))
                    # The port moved to a different host or the VM
                    # connected to the port was deleted or its in DOWN
                    # state. So delete the old port on the old host.
                    self._delete_port(orig_port, orig_host, tenant_id)
                if (hostname and is_vm_boot and not port_down
                        and device_id != n_const.DEVICE_ID_RESERVED_DHCP_PORT):
                    segments = seg_info
                    all_segments = self.ndb.get_all_network_segments(
                        network_id, context=context._plugin_context)
                    try:
                        self.rpc.create_network_segments(
                            tenant_id, network_id,
                            context.network.current['name'], all_segments)
                    except arista_exc.AristaRpcError:
                        with excutils.save_and_reraise_exception():
                            LOG.error(_LE("Failed to create network segments"))
                    LOG.info(_LI("Port plugged into network"))
                    # Plug port into the network only if it exists in the db
                    # and is bound to a host and the port is up.
                    trunk_details = port.get('trunk_details')
                    self.rpc.plug_port_into_network(
                        device_id,
                        hostname,
                        port_id,
                        network_id,
                        tenant_id,
                        port_name,
                        device_owner,
                        sg,
                        orig_sg,
                        vnic_type,
                        segments=segments,
                        switch_bindings=bindings,
                        trunk_details=trunk_details)
                else:
                    LOG.info(_LI("Port not plugged into network"))
            except arista_exc.AristaRpcError as err:
                LOG.error(
                    _LE('update_port_postcommit: Did not update '
                        'port %(port_id)s. Reason: %(err)s'), {
                            'port_id': port_id,
                            'err': err
                        })
    def bind_port(self, context):
        """Bind port to a network segment.

        Provisioning request to Arista Hardware to plug a host
        into appropriate network is done when the port is created
        this simply tells the ML2 Plugin that we are binding the port
        """
        host_id = context.host
        port = context.current
        physnet_info = self.eapi.get_physical_network(host_id)
        physnet = physnet_info.get('physnet')
        switch_id = physnet_info.get('switch_id')
        if not physnet or not switch_id:
            if port.get('binding:vnic_type') == portbindings.VNIC_BAREMETAL:
                # Find physnet using link_local_information in baremetal case
                physnet = self._get_physnet_from_link_info(port, physnet_info)
            else:
                LOG.debug(
                    "The host %(host)s not connected to arista "
                    "switches. Physical Network info = %(pi)s", {
                        'host': host_id,
                        'pi': physnet_info
                    })
                return

        if not physnet or not self._is_in_managed_physnets(physnet):
            LOG.debug(
                "bind_port for port %(port)s: physical_network "
                "%(physnet)s is not managed by Arista "
                "mechanism driver", {
                    'port': port.get('id'),
                    'physnet': physnet
                })
            return

        LOG.debug(
            "bind_port for port %(port)s: physical_network=%(physnet)s,"
            "switch_id=%(swid)s", {
                'port': port.get('id'),
                'physnet': physnet,
                'swid': switch_id
            })
        for segment in context.segments_to_bind:
            if segment[driver_api.NETWORK_TYPE] == p_const.TYPE_VXLAN:
                # Check if CVX supports HPB
                if not self.rpc.hpb_supported():
                    LOG.debug("bind_port: HPB is not supported")
                    return

                # The physical network is connected to arista switches,
                # allocate dynamic segmentation id to bind the port to
                # the network that the port belongs to.
                try:
                    next_segment = context.allocate_dynamic_segment({
                        'id':
                        context.network.current['id'],
                        'network_type':
                        p_const.TYPE_VLAN,
                        'physical_network':
                        physnet
                    })
                except Exception as exc:
                    LOG.error(
                        _LE("bind_port for port %(port)s: Failed to "
                            "allocate dynamic segment for physnet "
                            "%(physnet)s. %(exc)s"), {
                                'port': port.get('id'),
                                'physnet': physnet,
                                'exc': exc
                            })
                    return

                LOG.debug(
                    "bind_port for port %(port)s: "
                    "current_segment=%(current_seg)s, "
                    "next_segment=%(next_seg)s", {
                        'port': port.get('id'),
                        'current_seg': segment,
                        'next_seg': next_segment
                    })
                context.continue_binding(segment['id'], [next_segment])
            else:
                # The network_type is vlan, try binding process for baremetal.
                self._bind_port_to_baremetal(context, segment, physnet_info)