Example #1
0
 def create_port_dict(self,
                      network_id,
                      subnet_id,
                      mac_address,
                      ip_version=4,
                      ip_address=None):
     ip_address = (self._IP_ADDRS[ip_version]['addr']
                   if not ip_address else ip_address)
     port_dict = dhcp.DictModel({
         "id":
         uuidutils.generate_uuid(),
         "name":
         "foo",
         "mac_address":
         mac_address,
         "network_id":
         network_id,
         "admin_state_up":
         True,
         "device_id":
         uuidutils.generate_uuid(),
         "device_owner":
         "foo",
         "fixed_ips": [{
             "subnet_id": subnet_id,
             "ip_address": ip_address
         }],
     })
     return port_dict
Example #2
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     if self.cache.is_port_message_stale(payload['port']):
         LOG.debug("Discarding stale port update: %s", updated_port)
         return
     network = self.cache.get_network_by_id(updated_port.network_id)
     if network:
         LOG.info(_LI("Trigger reload_allocations for port %s"),
                  updated_port)
         driver_action = 'reload_allocations'
         if self._is_port_on_this_agent(updated_port):
             orig = self.cache.get_port_by_id(updated_port['id'])
             # assume IP change if not in cache
             orig = orig or {'fixed_ips': []}
             old_ips = {i['ip_address'] for i in orig['fixed_ips'] or []}
             new_ips = {i['ip_address'] for i in updated_port['fixed_ips']}
             old_subs = {i['subnet_id'] for i in orig['fixed_ips'] or []}
             new_subs = {i['subnet_id'] for i in updated_port['fixed_ips']}
             if new_subs != old_subs:
                 # subnets being serviced by port have changed, this could
                 # indicate a subnet_delete is in progress. schedule a
                 # resync rather than an immediate restart so we don't
                 # attempt to re-allocate IPs at the same time the server
                 # is deleting them.
                 self.schedule_resync("Agent port was modified",
                                      updated_port.network_id)
                 return
             elif old_ips != new_ips:
                 LOG.debug("Agent IPs on network %s changed from %s to %s",
                           network.id, old_ips, new_ips)
                 driver_action = 'restart'
         self.cache.put_port(updated_port)
         self.call_driver(driver_action, network)
         self.dhcp_ready_ports.add(updated_port.id)
Example #3
0
    def get_subnet(self, subnet_id):
        """Get data for the specified subnet."""
        LOG.debug("Get subnet %s", subnet_id)

        if subnet_id not in self.subnets_by_id:
            return None

        data = self.subnets_by_id[subnet_id]
        LOG.debug("Subnet data: %s", data)

        # Convert to form expected by NetModel.
        ip_version = 6 if ':' in data['cidr'] else 4
        subnet = {
            'enable_dhcp': True,
            'ip_version': ip_version,
            'cidr': data['cidr'],
            'dns_nameservers': data.get('dns_servers') or [],
            'id': subnet_id,
            'gateway_ip': data['gateway_ip'],
            'host_routes': data.get('host_routes', []),
            'network_id': data.get('network_id', NETWORK_ID)
        }
        if ip_version == 6:
            subnet['ipv6_address_mode'] = DHCPV6_STATEFUL
            subnet['ipv6_ra_mode'] = DHCPV6_STATEFUL

        return dhcp.DictModel(subnet)
Example #4
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     network = self.cache.get_network_by_id(updated_port.network_id)
     if network:
         self.cache.put_port(updated_port)
         self.call_driver('reload_allocations', network)
Example #5
0
 def create_dhcp_port(self, port):
     """Make a remote process call to create the dhcp port."""
     cctxt = self.client.prepare(version='1.1')
     port = cctxt.call(self.context, 'create_dhcp_port',
                       port=port, host=self.host)
     if port:
         return dhcp.DictModel(port)
 def create_dhcp_port(self, port):
     """Make a remote process call to create the dhcp port."""
     port = self.call(
         self.context,
         self.make_msg('create_dhcp_port', port=port, host=self.host))
     if port:
         return dhcp.DictModel(port)
    def _get_subnet(self, subnet_id):
        # Read data for subnet SUBNET_ID from etcd and translate it to the dict
        # form expected for insertion into a Neutron NetModel.
        LOG.debug("Read subnet %s from etcd", subnet_id)
        self.dirty_subnets.discard(subnet_id)

        subnet_key = datamodel_v1.key_for_subnet(subnet_id)
        response = self.client.read(subnet_key, consistent=True)
        data = etcdutils.safe_decode_json(response.value, 'subnet')
        LOG.debug("Subnet data: %s", data)

        if not (isinstance(data, dict) and 'cidr' in data
                and 'gateway_ip' in data):
            # Subnet data was invalid.
            LOG.warning("Invalid subnet data: %s => %s", response.value, data)
            raise ValidationFailed("Invalid subnet data")

        # Convert to form expected by NetModel.
        ip_version = 6 if ':' in data['cidr'] else 4
        subnet = {
            'enable_dhcp': True,
            'ip_version': ip_version,
            'cidr': data['cidr'],
            'dns_nameservers': data.get('dns_servers') or [],
            'id': subnet_id,
            'gateway_ip': data['gateway_ip'],
            'host_routes': data.get('host_routes', []),
            'network_id': data.get('network_id', NETWORK_ID)
        }
        if ip_version == 6:
            subnet['ipv6_address_mode'] = DHCPV6_STATEFUL
            subnet['ipv6_ra_mode'] = DHCPV6_STATEFUL

        return dhcp.DictModel(subnet)
Example #8
0
 def create_subnet_dict(self,
                        net_id,
                        dhcp_enabled=True,
                        ip_version=4,
                        prefix_override=None):
     cidr = self._IP_ADDRS[ip_version]['cidr']
     if prefix_override is not None:
         cidr = '/'.join((cidr.split('/')[0], str(prefix_override)))
     sn_dict = dhcp.DictModel({
         "id":
         uuidutils.generate_uuid(),
         "network_id":
         net_id,
         "ip_version":
         ip_version,
         "cidr":
         cidr,
         "gateway_ip": (self._IP_ADDRS[ip_version]['gateway']),
         "enable_dhcp":
         dhcp_enabled,
         "dns_nameservers": [],
         "host_routes": [],
         "ipv6_ra_mode":
         None,
         "ipv6_address_mode":
         None
     })
     if ip_version == 6:
         sn_dict['ipv6_address_mode'] = lib_const.DHCPV6_STATEFUL
     return sn_dict
Example #9
0
 def _get_network(self, network_id):
     network_dict = self.client.show_network(network_id)['network']
     network = dhcp.DictModel(network_dict)
     network.external = network_dict.get('router:external')
     obj_subnet = [self._get_subnet(s_id) for s_id in network.subnets]
     network.subnets = obj_subnet
     return network
 def test_build_cmdline(self, commonutils, device_mgr_cls):
     v4subnet = mock.Mock()
     v4subnet.id = 'v4subnet-1'
     v4subnet.enable_dhcp = True
     v4subnet.ip_version = 4
     v4subnet.cidr = '10.28.0.0/24'
     v6subnet = mock.Mock()
     v6subnet.id = 'v6subnet-1'
     v6subnet.enable_dhcp = True
     v6subnet.ip_version = 6
     v6subnet.cidr = '2001:db8:1::/80'
     v6subnet.ipv6_ra_mode = DHCPV6_STATEFUL
     v6subnet.ipv6_address_mode = DHCPV6_STATEFUL
     network = mock.Mock()
     network.id = 'calico'
     network.subnets = [v4subnet, v6subnet]
     network.mtu = 0
     network.ports = [
         dhcp.DictModel({'device_id': 'tap1'}),
         dhcp.DictModel({'device_id': 'tap2'}),
         dhcp.DictModel({'device_id': 'tap3'}),
     ]
     network.non_local_subnets = []
     network.get.side_effect = lambda key, dflt=None: dflt
     device_mgr_cls.return_value.driver.bridged = False
     dhcp_driver = DnsmasqRouted(cfg.CONF,
                                 network,
                                 None,
                                 plugin=FakePlugin())
     with mock.patch.object(dhcp_driver, '_get_value_from_conf_file') as gv:
         gv.return_value = 'ns-dhcp'
         cmdline = dhcp_driver._build_cmdline_callback('/run/pid_file')
     self.assertEqual([
         'dnsmasq', '--no-hosts', '--no-resolv', '--except-interface=lo',
         '--pid-file=/run/pid_file', '--dhcp-hostsfile=/run/calico/host',
         '--addn-hosts=/run/calico/addn_hosts',
         '--dhcp-optsfile=/run/calico/opts',
         '--dhcp-leasefile=/run/calico/leases', '--dhcp-match=set:ipxe,175',
         '--bind-dynamic', '--interface=ns-dhcp',
         '--dhcp-range=set:subnet-v4subnet-1,10.28.0.0' +
         ',static,255.255.255.0,86400s', '--dhcp-lease-max=16777216',
         '--conf-file=', '--dhcp-range=set:subnet-v6subnet-1,2001:db8:1::' +
         ',static,off-link,80,86400s', '--enable-ra', '--interface=tap1',
         '--interface=tap2', '--interface=tap3',
         '--bridge-interface=ns-dhcp,tap1,tap2,tap3'
     ], cmdline)
Example #11
0
 def get_dhcp_port(self, network_id, device_id):
     """Make a remote process call to get the dhcp port."""
     return dhcp.DictModel(self.call(self.context,
                                     self.make_msg('get_dhcp_port',
                                                   network_id=network_id,
                                                   device_id=device_id,
                                                   host=self.host),
                           topic=self.topic))
Example #12
0
 def _get_network(self, network_id):
     network_dict = self.client.show_network(network_id)['network']
     network = dhcp.DictModel(network_dict)
     # pylint: disable=assigning-non-slot
     network.external = network_dict.get('router:external')
     obj_subnet = [self._get_subnet(s_id) for s_id in network.subnets]
     network.subnets = obj_subnet
     return network
Example #13
0
 def exec_command(self, port_id, command=None):
     port = dhcp.DictModel(self.client.show_port(port_id)['port'])
     ip = ip_lib.IPWrapper()
     namespace = self._get_namespace(port)
     if not command:
         return "sudo ip netns exec %s" % self._get_namespace(port)
     namespace = ip.ensure_namespace(namespace)
     return namespace.netns.execute(shlex.split(command))
Example #14
0
 def get_dhcp_port(self, network_id, device_id):
     """Make a remote process call to get the dhcp port."""
     cctxt = self.client.prepare()
     port = cctxt.call(self.context, 'get_dhcp_port',
                       network_id=network_id, device_id=device_id,
                       host=self.host)
     if port:
         return dhcp.DictModel(port)
Example #15
0
 def update_dhcp_port(self, port_id, port):
     """Make a remote process call to update the dhcp port."""
     return dhcp.DictModel(self.call(self.context,
                                     self.make_msg('update_dhcp_port',
                                                   port_id=port_id,
                                                   port=port,
                                                   host=self.host),
                                     topic=self.topic))
Example #16
0
 def ensure_probe(self, network_id):
     ports = self.client.list_ports(network_id=network_id,
                                    device_id=socket.gethostname(),
                                    device_owner=DEVICE_OWNER_NETWORK_PROBE)
     info = ports.get('ports', [])
     if info:
         return dhcp.DictModel(info[0])
     else:
         return self.create_probe(network_id)
Example #17
0
 def port_create_end(self, context, payload):
     """Handle the port.create.end notification event."""
     created_port = dhcp.DictModel(payload['port'])
     update = queue.ResourceUpdate(created_port.network_id,
                                   payload.get('priority',
                                               DEFAULT_PRIORITY),
                                   action='_port_create',
                                   resource=created_port)
     self._queue.add(update)
Example #18
0
 def list_probes(self):
     ports = self.client.list_ports(device_owner=[
         DEVICE_OWNER_NETWORK_PROBE, DEVICE_OWNER_COMPUTE_PROBE
     ])
     info = ports['ports']
     for port in info:
         port['device_name'] = self.driver.get_device_name(
             dhcp.DictModel(port))
     return info
Example #19
0
 def port_create_end(self, context, payload):
     """Handle the port.create.end notification event."""
     created_port = dhcp.DictModel(payload['port'])
     if not dhcp.port_requires_dhcp_configuration(created_port):
         return
     update = DHCPResourceUpdate(created_port.network_id,
                                 payload.get('priority', DEFAULT_PRIORITY),
                                 action='_port_create',
                                 resource=created_port, obj_type='port')
     self._queue.add(update)
Example #20
0
 def exec_command(self, port_id, command=None):
     port = dhcp.DictModel(self.client.show_port(port_id)['port'])
     ip = ip_lib.IPWrapper()
     namespace = self._get_namespace(port)
     if not command:
         return "sudo ip netns exec %s" % self._get_namespace(port)
     namespace = ip.ensure_namespace(namespace)
     # NOTE(ralonsoh): this is going to be called from inside the
     # "neutron-debug" shell command; privsep is not configured.
     return namespace.netns.execute(shlex.split(command))
Example #21
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     with _net_lock(updated_port.network_id):
         if self.cache.is_port_message_stale(payload['port']):
             LOG.debug("Discarding stale port update: %s", updated_port)
             return
         network = self.cache.get_network_by_id(updated_port.network_id)
         if not network:
             return
         self.reload_allocations(updated_port, network)
Example #22
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     if self.cache.is_port_message_stale(updated_port):
         LOG.debug("Discarding stale port update: %s", updated_port)
         return
     update = queue.ResourceUpdate(updated_port.network_id,
                                   payload.get('priority',
                                               DEFAULT_PRIORITY),
                                   action='_port_update',
                                   resource=updated_port)
     self._queue.add(update)
Example #23
0
 def delete_probe(self, port_id):
     port = dhcp.DictModel(self.client.show_port(port_id)['port'])
     namespace = self._get_namespace(port)
     if ip_lib.network_namespace_exists(namespace):
         self.driver.unplug(self.driver.get_device_name(port),
                            namespace=namespace)
         try:
             ip_lib.delete_network_namespace(namespace)
         except Exception:
             LOG.warning('Failed to delete namespace %s', namespace)
     else:
         self.driver.unplug(self.driver.get_device_name(port))
     self.client.delete_port(port.id)
Example #24
0
 def create_port_dict(self, network_id, subnet_id, mac_address,
                      ip_version=lib_const.IP_VERSION_4, ip_address=None):
     ip_address = (self._IP_ADDRS[ip_version]['addr']
         if not ip_address else ip_address)
     port_dict = dhcp.DictModel(id=uuidutils.generate_uuid(),
                                name="foo",
                                mac_address=mac_address,
                                network_id=network_id,
                                admin_state_up=True,
                                device_id=uuidutils.generate_uuid(),
                                device_owner="foo",
                                fixed_ips=[{"subnet_id": subnet_id,
                                            "ip_address": ip_address}])
     return port_dict
Example #25
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     network = self.cache.get_network_by_id(updated_port.network_id)
     if network:
         driver_action = 'reload_allocations'
         if self._is_port_on_this_agent(updated_port):
             orig = self.cache.get_port_by_id(updated_port['id'])
             # assume IP change if not in cache
             old_ips = {i['ip_address'] for i in orig['fixed_ips'] or []}
             new_ips = {i['ip_address'] for i in updated_port['fixed_ips']}
             if old_ips != new_ips:
                 driver_action = 'restart'
         self.cache.put_port(updated_port)
         self.call_driver(driver_action, network)
Example #26
0
 def create_subnet_dict(self, net_id, dhcp_enabled=True, ip_version=4):
     sn_dict = dhcp.DictModel({
         "id": uuidutils.generate_uuid(),
         "network_id": net_id,
         "ip_version": ip_version,
         "cidr": self._IP_ADDRS[ip_version]['cidr'],
         "gateway_ip": (self.
             _IP_ADDRS[ip_version]['gateway']),
         "enable_dhcp": dhcp_enabled,
         "dns_nameservers": [],
         "host_routes": [],
         "ipv6_ra_mode": None,
         "ipv6_address_mode": None})
     if ip_version == 6:
         sn_dict['ipv6_address_mode'] = constants.DHCPV6_STATEFUL
     return sn_dict
Example #27
0
 def _create_port(self, network, device_owner):
     host = self.conf.host
     body = {'port': {'admin_state_up': True,
                      'network_id': network.id,
                      'device_id': '%s' % socket.gethostname(),
                      'device_owner': '%s:probe' % device_owner,
                      'tenant_id': network.tenant_id,
                      portbindings.HOST_ID: host,
                      'fixed_ips': [dict(subnet_id=s.id)
                                    for s in network.subnets]}}
     port_dict = self.client.create_port(body)['port']
     port = dhcp.DictModel(port_dict)
     port.network = network
     for fixed_ip in port.fixed_ips:
         fixed_ip.subnet = self._get_subnet(fixed_ip.subnet_id)
     return port
Example #28
0
 def port_update_end(self, context, payload):
     """Handle the port.update.end notification event."""
     updated_port = dhcp.DictModel(payload['port'])
     with _net_lock(updated_port.network_id):
         if self.cache.is_port_message_stale(payload['port']):
             LOG.debug("Discarding stale port update: %s", updated_port)
             return
         network = self.cache.get_network_by_id(updated_port.network_id)
         if not network:
             return
         LOG.info("Trigger reload_allocations for port %s",
                  updated_port)
         driver_action = 'reload_allocations'
         orig = self.cache.get_port_by_id(updated_port['id'])
         orig = orig or {'fixed_ips': []}
         if self._is_port_on_this_agent(updated_port):
             old_ips = {i['ip_address'] for i in orig['fixed_ips'] or []}
             new_ips = {i['ip_address'] for i in updated_port['fixed_ips']}
             old_subs = {i['subnet_id'] for i in orig['fixed_ips'] or []}
             new_subs = {i['subnet_id'] for i in updated_port['fixed_ips']}
             if new_subs != old_subs:
                 # subnets being serviced by port have changed, this could
                 # indicate a subnet_delete is in progress. schedule a
                 # resync rather than an immediate restart so we don't
                 # attempt to re-allocate IPs at the same time the server
                 # is deleting them.
                 self.schedule_resync("Agent port was modified",
                                      updated_port.network_id)
                 return
             elif old_ips != new_ips:
                 LOG.debug("Agent IPs on network %s changed from %s to %s",
                           network.id, old_ips, new_ips)
                 driver_action = 'restart'
             elif not old_ips and not new_ips:
                 driver_action = 'disable'
         self.cache.put_port(updated_port)
         # NOTE(alegacy): the port may no longer have any IP addresses so if
         # that's the case we need to use the old ones in order to determine
         # which VLAN we are operating against.
         orig_vlan_ids = self._get_port_vlan_ids(orig, network)
         updated_vlan_ids = self._get_port_vlan_ids(updated_port, network)
         for vlan_id in set(orig_vlan_ids) | set(updated_vlan_ids):
             driver_kwargs = {} if not vlan_id else {'vlan_id': vlan_id}
             self.call_driver(driver_action, network, **driver_kwargs)
             self.dhcp_ready_ports.add(updated_port.id)
Example #29
0
 def delete_probe(self, port_id):
     port = dhcp.DictModel(self.client.show_port(port_id)['port'])
     network = self._get_network(port.network_id)
     bridge = None
     if network.external:
         bridge = self.conf.external_network_bridge
     namespace = self._get_namespace(port)
     if ip_lib.network_namespace_exists(namespace):
         self.driver.unplug(self.driver.get_device_name(port),
                            bridge=bridge,
                            namespace=namespace)
         try:
             ip_lib.delete_network_namespace(namespace)
         except Exception:
             LOG.warning('Failed to delete namespace %s', namespace)
     else:
         self.driver.unplug(self.driver.get_device_name(port),
                            bridge=bridge)
     self.client.delete_port(port.id)
Example #30
0
 def port_create_end(self, context, payload):
     """Handle the port.create.end notification event."""
     created_port = dhcp.DictModel(payload['port'])
     with _net_lock(created_port.network_id):
         network = self.cache.get_network_by_id(created_port.network_id)
         if not network:
             return
         new_ips = {i['ip_address'] for i in created_port['fixed_ips']}
         for port_cached in network.ports:
             # if there are other ports cached with the same ip address in
             # the same network this indicate that the cache is out of sync
             cached_ips = {i['ip_address']
                           for i in port_cached['fixed_ips']}
             if new_ips.intersection(cached_ips):
                 self.schedule_resync("Duplicate IP addresses found, "
                                      "DHCP cache is out of sync",
                                      created_port.network_id)
                 return
         self.reload_allocations(created_port, network)