Beispiel #1
0
 def __init__(self, parent):
     HttpHandler.__init__(self, parent.scheduler, False, parent.vhostbind)
     self._parent = parent
     self._logger = parent._logger
     self._macbase = uint64.create(
         create_binary(mac_addr_bytes(self._parent.mactemplate), 8))
     cidrrange = parent.cidrrange
     try:
         subnet, mask = parse_ip4_network(cidrrange)
         if not (0 <= mask <= 24):
             raise ValueError
     except Exception:
         self._logger.warning(
             'Invalid CIDR range: %r. Using default 10.0.0.0/8', cidrrange)
         subnet = ip4_addr('10.0.0.0')
         mask = 8
     self.cidrrange_subnet = subnet
     self.cidrrange_mask = mask
     self.cidrrange_end = (1 << (24 - mask))
     self.pooltimeout = parent.pooltimeout
     self.iptimeout = parent.iptimeout
     self._reqid = 0
Beispiel #2
0
    def createendpoint(self, env, params):
        lognet_id = 'docker-' + params['NetworkID'] + '-lognet'
        subnet_id = 'docker-' + params['NetworkID'] + '-subnet'
        logport_id = 'docker-' + params['EndpointID']
        logport_params = {}
        if 'Options' in params:
            logport_params.update(params['Options'])
        logport_params['id'] = logport_id
        logport_params['logicalnetwork'] = lognet_id
        logport_params['subnet'] = subnet_id
        mac_address = None
        if 'Interface' in params:
            interface = params['Interface']
            if 'Address' in interface and interface['Address']:
                ip, f, prefix = interface['Address'].partition('/')
                logport_params['ip_address'] = ip
            else:
                ip = None
            if 'MacAddress' in interface and interface['MacAddress']:
                logport_params['mac_address'] = interface['MacAddress']
                mac_address = interface['MacAddress']
        if mac_address is None:
            # Generate a MAC address
            if ip:
                # Generate MAC address based on IP address
                mac_num = self._macbase
                mac_num ^= ((hash(subnet_id) & 0xffffffff) << 8)
                mac_num ^= ip4_addr(ip)
            else:
                # Generate MAC address based on Port ID and random number
                mac_num = self._macbase
                mac_num ^= ((hash(logport_id) & 0xffffffff) << 8)
                mac_num ^= randint(0, 0xffffffff)
            mac_address = mac_addr_bytes.formatter(create_binary(mac_num, 6))
            logport_params['mac_address'] = mac_address
        try:
            for m in callAPI(self, 'viperflow', 'createlogicalport',
                             logport_params):
                yield m
        except Exception as exc:
            # There is an issue that docker daemon may not delete an endpoint correctly
            # If autoremoveports is enabled, we remove the logical port automatically
            # Note that created veth and Openvswitch ports are not cleared because they
            # may not on this server, so you must clean them yourself with vlcp_docker.cleanup
            if self._parent.autoremoveports:
                for m in callAPI(self, 'viperflow', 'listlogicalports', {
                        'logicalnetwork': lognet_id,
                        'ip_address': ip
                }):
                    yield m
                if self.retvalue:
                    if self.retvalue[0]['id'].startswith('docker-'):
                        dup_pid = self.retvalue[0]['id']
                        self._logger.warning(
                            'Duplicated ports detected: %s (%s). Will remove it.',
                            dup_pid, self.retvalue[0]['ip_address'])
                        for m in callAPI(self, 'viperflow',
                                         'deletelogicalport', {'id': dup_pid}):
                            yield m
                        # Retry create logical port
                        for m in callAPI(self, 'viperflow',
                                         'createlogicalport', logport_params):
                            yield m
                    else:
                        self._logger.warning(
                            'Duplicated with a non-docker port')
                        raise exc
                else:
                    raise exc
            else:
                raise exc
        ip_address = self.retvalue[0]['ip_address']
        subnet_cidr = self.retvalue[0]['subnet']['cidr']
        mtu = self.retvalue[0]['network'].get('mtu', self._parent.mtu)
        _, _, prefix = subnet_cidr.partition('/')
        if 'docker_ipam_poolid' in self.retvalue[0]['subnet']:
            docker_ipam_poolid = self.retvalue[0]['subnet'][
                'docker_ipam_poolid']

            def _remove_ip_reservation():
                try:
                    # The reservation is completed, remove the temporary reservation
                    def _ipam_updater(keys, values, timestamp):
                        pool = values[0]
                        self._remove_staled_ips(pool, timestamp)
                        if ip_address in pool.reserved_ips:
                            del pool.reserved_ips[ip_address]
                        return ((keys[0], ), (pool, ))

                    for m in callAPI(
                            self, 'objectdb', 'transact',
                        {
                            'keys':
                            (IPAMReserve.default_key(docker_ipam_poolid), ),
                            'updater': _ipam_updater,
                            'withtime': True
                        }):
                        yield m
                except Exception:
                    self._logger.warning(
                        'Unexpected exception while removing reservation of IP address %r, will ignore and continue',
                        ip_address,
                        exc_info=True)

            self.subroutine(_remove_ip_reservation())
        port_created = False
        try:
            for m in self._parent.taskpool.runTask(
                    self,
                    lambda: _create_veth(self._parent.ipcommand, self._parent.
                                         vethprefix, mac_address, mtu)):
                yield m
            port_created = True
            device_name, _ = self.retvalue
            info = DockerInfo.create_instance(logport_id)
            info.docker_port = device_name

            @updater
            def _updater(dockerinfo):
                dockerinfo = set_new(dockerinfo, info)
                return (dockerinfo, )

            for m in callAPI(self, 'objectdb', 'transact', {
                    'keys': (info.getkey(), ),
                    'updater': _updater
            }):
                yield m
            for m in self._parent.taskpool.runTask(
                    self,
                    lambda: _plug_ovs(self._parent.ovscommand, self._parent.
                                      ovsbridge, device_name, logport_id)):
                yield m
            result = {'Interface': {'MacAddress': mac_address}}
            if 'Address' not in interface:
                result['Interface']['Address'] = ip_address + '/' + prefix
            env.outputjson(result)
        except Exception as exc:
            try:
                if port_created:
                    for m in self._parent.taskpool.runTask(
                            self, lambda: _delete_veth(self._parent.ipcommand,
                                                       device_name)):
                        yield m
            except Exception:
                pass
            try:
                for m in callAPI(self, 'viperflow', 'deletelogicalport',
                                 {'id': logport_id}):
                    yield m
            except Exception:
                pass
            raise exc
Beispiel #3
0
    def createendpoint(self, env, params):
        lognet_id = 'docker-' + params['NetworkID'] + '-lognet'
        subnet_id = 'docker-' + params['NetworkID'] + '-subnet'
        logport_id = 'docker-' + params['EndpointID']
        logport_params = {}
        if 'Options' in params:
            logport_params.update(params['Options'])
        logport_params['id'] = logport_id
        logport_params['logicalnetwork'] = lognet_id
        logport_params['subnet'] = subnet_id
        mac_address = None
        if 'Interface' in params:
            interface = params['Interface']
            if 'Address' in interface and interface['Address']:
                ip, f, prefix = interface['Address'].rpartition('/')
                logport_params['ip_address'] = ip
            else:
                ip = None
            if 'MacAddress' in interface and interface['MacAddress']:
                logport_params['mac_address'] = interface['MacAddress']
                mac_address = interface['MacAddress']
        if mac_address is None:
            # Generate a MAC address
            if ip:
                # Generate MAC address based on IP address
                mac_num = self._macbase
                mac_num ^= ((hash(subnet_id) & 0xffffffff) << 8)
                mac_num ^= ip4_addr(ip)
            else:
                # Generate MAC address based on Port ID and random number
                mac_num = self._macbase
                mac_num ^= ((hash(logport_id) & 0xffffffff) << 8)
                mac_num ^= randint(0, 0xffffffff)
            mac_address = mac_addr_bytes.formatter(create_binary(mac_num, 6))
            logport_params['mac_address'] = mac_address
        for m in callAPI(self, 'viperflow', 'createlogicalport',
                         logport_params):
            yield m
        ip_address = self.retvalue[0]['ip_address']
        subnet_cidr = self.retvalue[0]['subnet']['cidr']
        mtu = self.retvalue[0]['network'].get('mtu', self._parent.mtu)
        _, _, prefix = subnet_cidr.partition('/')
        port_created = False
        try:
            for m in self._parent.taskpool.runTask(
                    self,
                    lambda: _create_veth(self._parent.ipcommand, self._parent.
                                         vethprefix, mac_address, mtu)):
                yield m
            port_created = True
            device_name, _ = self.retvalue
            info = DockerInfo.create_instance(logport_id)
            info.docker_port = device_name

            @updater
            def _updater(dockerinfo):
                dockerinfo = set_new(dockerinfo, info)
                return (dockerinfo, )

            for m in callAPI(self, 'objectdb', 'transact', {
                    'keys': (info.getkey(), ),
                    'updater': _updater
            }):
                yield m
            for m in self._parent.taskpool.runTask(
                    self,
                    lambda: _plug_ovs(self._parent.ovscommand, self._parent.
                                      ovsbridge, device_name, logport_id)):
                yield m
            result = {'Interface': {'MacAddress': mac_address}}
            if 'Address' not in interface:
                result['Interface']['Address'] = ip_address + '/' + prefix
            env.outputjson(result)
        except Exception as exc:
            try:
                if port_created:
                    for m in self._parent.taskpool.runTask(
                            self, lambda: _delete_veth(self._parent.ipcommand,
                                                       device_name)):
                        yield m
            except Exception:
                pass
            try:
                for m in callAPI(self, 'viperflow', 'deletelogicalport',
                                 {'id': logport_id}):
                    yield m
            except Exception:
                pass
            raise exc
Beispiel #4
0
 def __init__(self, parent):
     HttpHandler.__init__(self, parent.scheduler, False, parent.vhostbind)
     self._parent = parent
     self._logger = parent._logger
     self._macbase = uint64.create(
         create_binary(mac_addr_bytes(self._parent.mactemplate), 8))