def __init__(self, network_name, subnet, reserved_ips=None): self.name = network_name self.ovs = True self.subnet = ipaddress.ip_network(subnet) self.address_pool = SortedSet(self.subnet.hosts()) self.containers = dict() self.registrator = None self.listening = False self.dpid = None self.reservations = reserved_ips # reserve 1 IP address for the default gateway self.reservations['_'] = self._get_next_address() for _, ip in self.reservations.items(): self._remove_ip(ip) if not self.check_bridge_exists(): self.create_network(network_name) else: logger.debug('Bridge already exists, using it instead') self.get_ovs_dpid() self._handlers = { ('container', 'die'): self.handler_container_die, ('container', 'start'): self.handler_container_start }
def __init__(self, consul_container): consul_container.reload() consul_ip = consul_container.attrs['NetworkSettings']['Networks'][ 'bridge']['IPAddress'] logger.debug(f'Connecting to Consul at address {consul_ip}') self.consul = consul.Consul(host=consul_ip)
def add_container(self, container, addr=None, reservation=None, register=False): reserved_ip = self.reservations.get(reservation) if reserved_ip: ipaddr = ipaddress.ip_address(reserved_ip) elif addr: ipaddr = self._remove_ip(addr) else: ipaddr = self._get_next_address() mac = _generate_random_MAC() logger.debug(f'Connect container {container.id[:12]} to network') if register: self.registrator.register(container, str(ipaddr)) # connect to ovs bridge command = f'ovs-docker add-port {self.name} eth1 {container.id[:12]} ' command += f'--ipaddress={str(ipaddr)}/{self.subnet.prefixlen} ' command += f'--macaddress="{mac}"' run = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = run.communicate() if run.returncode != 0: logger.error(f'Error while connecting container {container.id[:12]} to network') return OvsException('Failed while connecting container to network') else: self.containers[container.id] = Interface(ipaddr, mac)
def _get_next_address(self): if self.address_pool: next_addr = self.address_pool[0] self.address_pool.pop(0) logger.debug(f'Lending IP address {str(next_addr)}') return str(next_addr) else: logger.debug(f'No available IP address in the address pool') return None
def _remove_ip(self, ip): addr = ipaddress.ip_address(ip) if addr not in self.subnet: raise ValueError try: self.address_pool.remove(addr) logger.debug(f'Address {ip} is now in use') return addr except KeyError: return None
def remove_container(self, cid): logger.debug(f'Disconnect container {cid[:12]} from network') try: docker_api_client.disconnect_container_from_network( cid, self._network.id, force=True ) except docker.errors.APIError: pass ipaddr = self.containers.pop(cid, None) if ipaddr: self._add_ip(ipaddr)
def add_container(self, container, addr=None, reservation=None, register=None): reserved_ip = self.reservations.get(reservation) if reserved_ip: ipaddr = ipaddress.ip_address(reserved_ip) elif addr: ipaddr = self._remove_ip(addr) else: ipaddr = self._get_next_address() logger.debug(f'Connect container {container.id[:12]} to network') # docker network connect docker_api_client.connect_container_to_network( container.id, self._network.id, ipv4_address=str(ipaddr) ) self.containers[container.id] = ipaddr
def remove_container(self, cid): logger.debug(f'Disconnect container {cid[:12]} from network') if self.listening: self.registrator.deregister(cid) command = f'ovs-docker del-port {self.name} eth1 {cid[:12]}' run = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) run.communicate() if run.returncode != 0: logger.error(f'Error while removing container {cid[:12]} from network') raise OvsException('Failed while removing container from network') interface = self.containers.pop(cid, None) if interface.ip: self._add_ip(interface.ip)
def register(self, container, ip): container.reload() config = container.attrs['Config'] env_vars = config['Env'] ports = list(config['ExposedPorts'].keys()) port = int(ports[0].split('/')[0]) service = dict() for var in env_vars: key, val = var.split('=') if key.startswith('SERVICE'): _, attr = key.lower().split('_') service[attr] = val if 'name' in service: logger.debug(f'Registering container {container.id} with {ip}') self.consul.agent.service.register(service['name'], service_id=container.id, port=port, address=ip)
def cleanup(self): """ Stop the cloud manager and all components """ logger.debug("Cleaning up everything") self.network.stop_listening() for container in (self.registry, self.registrator, self.proxy): try: self.network.remove_container(container.id) _stop_container(container) except: continue for service in self.services.values(): service.stop() if self.sfc_orchestrator: self.sfc_orchestrator.stop() try: self.network.remove() except: pass self.running = False logger.debug("Removed running services and docker network")
def deregister(self, cid): logger.debug(f'De-registering container {cid}') self.consul.agent.service.deregister(cid)
def __init__(self, subnet=None, network_name=None, ovs=False, proxy_ip=None, gateway_ip=None, initial_services=None, entrypoint=None): self.running = True # declare variables for network stuff self.proxy_ip = proxy_ip self.gateway_ip = gateway_ip reservations = {'proxy': proxy_ip, 'gateway': gateway_ip} if not proxy_ip: reservations.pop('proxy') if not gateway_ip: reservations.pop('gateway') if ovs: self.network = OpenVSwitchNetwork(network_name, subnet, reservations) else: self.network = BridgeNetwork(network_name, subnet, reservations) self.registry_ip = self.network.reserve_ip('registry') logger.debug(f'registry ip requested: {self.registry_ip}') # create variables for important containers self.registry_name = "service-registry-%s" % network_name self.registrator_name = "service-registrator-%s" % network_name self.proxy_name = "proxy-%s" % network_name self.proxy_entrypoint = entrypoint self.registry = None self.registrator = None self.proxy = None self.services = {} self.used_ports = set() try: self.sfc_orchestrator = SfcOrchestrator(self.network) except SfcException: self.sfc_orchestrator = None try: self.create_registry() self.create_proxy() self.proxy.start() self.network.add_container(self.proxy, reservation='proxy') self.proxy.exec_run('/root/entry/custom-entrypoint.sh') logger.info("Proxy has been started") self.registry.start() self.network.add_container(self.registry, reservation='registry') logger.info("Service registry has been started") if self.network.ovs: self.network.registrator = Registrator(self.registry) else: self.create_registrator() if self.registrator: self.network.add_container(self.registrator) self.registrator.start() logger.info("Service registrator has been started") if initial_services: self.initialize_services(initial_services) except Exception as e: logger.error(''.join( traceback.format_exception(type(e), e, e.__traceback__))) self.cleanup() raise CloudException
def _add_ip(self, ip): addr = ipaddress.ip_address(ip) self.address_pool.add(addr) logger.debug(f'Address {ip} is now available in the address pool') return addr