def node_start(node_image, runtime, log_dir, ip, ip6, as_num, detach, kubernetes_version, rkt, libnetwork_image): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :param kubernetes_version: The version of the calico-kubernetes plugin to install, or None if the plugin should not be installed. :param rkt: True to install the rkt plugin, False otherwise. :param libnetwork_image: The name of the Calico libnetwork driver image to use. None, if not using libnetwork. :return: None. """ # Normally, Felix will load the modules it needs, but when running inside a # container it might not be able to so ensure the required modules are # loaded each time the node starts. # This is just a best error attempt, as the modules might be builtins. # We'll warn during the check_system() if the modules are unavailable. try: call(["modprobe", "-a"] + REQUIRED_MODULES) except OSError: pass # Print warnings for any known system issues before continuing using_docker = True if runtime == 'docker' else False (_, _, etcd_ok) = \ check_system(quit_if_error=False, libnetwork=libnetwork_image, check_docker=using_docker) if not etcd_ok: sys.exit(1) # We will always want to setup IP forwarding _setup_ip_forwarding() # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=["^docker.*", "^cbr.*"]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Install Kubernetes plugin if kubernetes_version: # Build a URL based on the provided Kubernetes_version. url = KUBERNETES_BINARY_URL % kubernetes_version try: # Attempt to install to the default Kubernetes directory install_plugin(KUBERNETES_PLUGIN_DIR, url) except OSError: # Use the backup directory install_plugin(KUBERNETES_PLUGIN_DIR_BACKUP, url) # Install rkt plugin if rkt: try: # Attempt to install to the default rkt directory install_plugin(RKT_PLUGIN_DIR, RKT_BINARY_URL) except OSError: # Use the backup directory install_plugin(RKT_PLUGIN_DIR_BACKUP, RKT_BINARY_URL) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) # Always try to convert the address(hostname) to an IP. This is a noop if # the address is already an IP address. Note that the format of the authority # string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) etcd_authority_address, etcd_authority_port = etcd_authority.split(':') etcd_authority = '%s:%s' % (socket.gethostbyname(etcd_authority_address), etcd_authority_port) if runtime == 'docker': _start_node_container(ip, ip6, etcd_authority, log_dir, node_image, detach) if libnetwork_image: _start_libnetwork_container(etcd_authority, libnetwork_image)
def node_start(node_image, log_dir, ip, ip6, as_num, detach, kubernetes): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :return: None. """ # Print warnings for any known system issues before continuing check_system(fix=False, quit_if_error=False) # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=["docker0"]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Install kubernetes plugin if kubernetes: try: # Attempt to install to the default kubernetes directory install_kubernetes(KUBERNETES_PLUGIN_DIR) except OSError: # Use the backup directory install_kubernetes(KUBERNETES_PLUGIN_DIR_BACKUP) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) try: docker_client.remove_container("calico-node", force=True) except docker.errors.APIError as err: if err.response.status_code != 404: raise # Always try to convert the address(hostname) to an IP. This is a noop if # the address is already an IP address. Note that the format of the authority # string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) etcd_authority_address, etcd_authority_port = etcd_authority.split(':') etcd_authority = '%s:%s' % (socket.gethostbyname(etcd_authority_address), etcd_authority_port) environment = [ "HOSTNAME=%s" % hostname, "IP=%s" % ip, "IP6=%s" % (ip6 or ""), "ETCD_AUTHORITY=%s" % etcd_authority, # etcd host:port "FELIX_ETCDADDR=%s" % etcd_authority, # etcd host:port "POLICY_ONLY_CALICO=%s" % os.getenv(POLICY_ONLY_ENV, ""), ] binds = { "/proc": { "bind": "/proc_host", "ro": False }, log_dir: { "bind": "/var/log/calico", "ro": False }, "/run/docker/plugins": { "bind": "/usr/share/docker/plugins", "ro": False } } host_config = docker.utils.create_host_config( privileged=True, restart_policy={"Name": "Always"}, network_mode="host", binds=binds) _find_or_pull_node_image(node_image) container = docker_client.create_container( node_image, name="calico-node", detach=True, environment=environment, host_config=host_config, volumes=["/proc_host", "/var/log/calico", "/usr/share/docker/plugins"]) cid = container["Id"] docker_client.start(container) print "Calico node is running with id: %s" % cid if not detach: _attach_and_stream(container)
def node_start(node_image, runtime, log_dir, ip, ip6, as_num, detach, libnetwork_image): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :param libnetwork_image: The name of the Calico libnetwork driver image to use. None, if not using libnetwork. :return: None. """ # Normally, Felix will load the modules it needs, but when running inside a # container it might not be able to do so. Ensure the required modules are # loaded each time the node starts. # We only make a best effort attempt because the command may fail if the # modules are built in. # We'll warn during the check_system() if the modules are unavailable. if not running_in_container(): try: call(["modprobe", "-a"] + REQUIRED_MODULES) except OSError: pass # We will always want to setup IP forwarding _setup_ip_forwarding() # Print warnings for any known system issues before continuing if runtime == 'docker' and not running_in_container(): using_docker = True else: using_docker = False (_, _, etcd_ok) = \ check_system(quit_if_error=False, libnetwork=libnetwork_image, check_docker=using_docker, check_modules=not running_in_container()) if not etcd_ok: sys.exit(1) # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=["^docker.*", "^cbr.*", "virbr.*", "lxcbr.*", "veth.*", "cali.*", "tunl.*"]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that IPs are not already in use by another host. error_if_bgp_ip_conflict(ip, ip6) # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) # If IPIP is enabled, the host requires an IP address for its tunnel # device, which is in an IPIP pool. Without this, a host can't originate # traffic to a pool address because the response traffic would not be # routed via the tunnel (likely being dropped by RPF checks in the fabric). ipv4_pools = client.get_ip_pools(4) ipip_pools = [p for p in ipv4_pools if p.ipip] if ipip_pools: # IPIP is enabled, make sure the host has an address for its tunnel. _ensure_host_tunnel_addr(ipv4_pools, ipip_pools) else: # No IPIP pools, clean up any old address. _remove_host_tunnel_addr() # The format of the authority string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) # Get etcd SSL environment variables if they exist etcd_scheme = os.getenv(ETCD_SCHEME_ENV, ETCD_SCHEME_DEFAULT) etcd_key_file = os.getenv(ETCD_KEY_FILE_ENV, None) etcd_cert_file = os.getenv(ETCD_CERT_FILE_ENV, None) etcd_ca_cert_file = os.getenv(ETCD_CA_CERT_FILE_ENV, None) etcd_volumes = [] etcd_binds = {} etcd_envs = ["ETCD_AUTHORITY=%s" % etcd_authority, "ETCD_SCHEME=%s" % etcd_scheme] felix_envs = ["FELIX_ETCDADDR=%s" % etcd_authority, "FELIX_ETCDSCHEME=%s" % etcd_scheme] if etcd_ca_cert_file and etcd_key_file and etcd_cert_file: etcd_volumes.append(ETCD_CA_CERT_NODE_FILE) etcd_binds[etcd_ca_cert_file] = {"bind": ETCD_CA_CERT_NODE_FILE, "ro": True} etcd_envs.append("ETCD_CA_CERT_FILE=%s" % ETCD_CA_CERT_NODE_FILE) felix_envs.append("FELIX_ETCDCAFILE=%s" % ETCD_CA_CERT_NODE_FILE) etcd_volumes.append(ETCD_KEY_NODE_FILE) etcd_binds[etcd_key_file] = {"bind": ETCD_KEY_NODE_FILE, "ro": True} etcd_envs.append("ETCD_KEY_FILE=%s" % ETCD_KEY_NODE_FILE) felix_envs.append("FELIX_ETCDKEYFILE=%s" % ETCD_KEY_NODE_FILE) etcd_volumes.append(ETCD_CERT_NODE_FILE) etcd_binds[etcd_cert_file] = {"bind": ETCD_CERT_NODE_FILE, "ro": True} etcd_envs.append("ETCD_CERT_FILE=%s" % ETCD_CERT_NODE_FILE) felix_envs.append("FELIX_ETCDCERTFILE=%s" % ETCD_CERT_NODE_FILE) if runtime == 'docker': _start_node_container_docker(ip, ip6, log_dir, node_image, detach, etcd_envs, felix_envs, etcd_volumes, etcd_binds) if libnetwork_image: _start_libnetwork_container(libnetwork_image, etcd_envs, etcd_volumes, etcd_binds) if runtime == 'rkt': _start_node_container_rkt(ip, ip6, node_image, etcd_envs, felix_envs, etcd_volumes, etcd_binds)
def node_start(node_image, runtime, log_dir, ip, ip6, as_num, detach, libnetwork_image): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :param libnetwork_image: The name of the Calico libnetwork driver image to use. None, if not using libnetwork. :return: None. """ # Normally, Felix will load the modules it needs, but when running inside a # container it might not be able to do so. Ensure the required modules are # loaded each time the node starts. # We only make a best effort attempt because the command may fail if the # modules are built in. # We'll warn during the check_system() if the modules are unavailable. if not running_in_container(): try: call(["modprobe", "-a"] + REQUIRED_MODULES) except OSError: pass # We will always want to setup IP forwarding _setup_ip_forwarding() # Print warnings for any known system issues before continuing if runtime == 'docker' and not running_in_container(): using_docker = True else: using_docker = False (_, _, etcd_ok) = \ check_system(quit_if_error=False, libnetwork=libnetwork_image, check_docker=using_docker, check_modules=not running_in_container()) if not etcd_ok: sys.exit(1) # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=[ "^docker.*", "^cbr.*", "virbr.*", "lxcbr.*", "veth.*", "cali.*", "tunl.*" ]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that IPs are not already in use by another host. error_if_bgp_ip_conflict(ip, ip6) # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) # If IPIP is enabled, the host requires an IP address for its tunnel # device, which is in an IPIP pool. Without this, a host can't originate # traffic to a pool address because the response traffic would not be # routed via the tunnel (likely being dropped by RPF checks in the fabric). ipv4_pools = client.get_ip_pools(4) ipip_pools = [p for p in ipv4_pools if p.ipip] if ipip_pools: # IPIP is enabled, make sure the host has an address for its tunnel. _ensure_host_tunnel_addr(ipv4_pools, ipip_pools) else: # No IPIP pools, clean up any old address. _remove_host_tunnel_addr() # The format of the authority string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) # Get etcd SSL environment variables if they exist etcd_scheme = os.getenv(ETCD_SCHEME_ENV, ETCD_SCHEME_DEFAULT) etcd_key_file = os.getenv(ETCD_KEY_FILE_ENV, None) etcd_cert_file = os.getenv(ETCD_CERT_FILE_ENV, None) etcd_ca_cert_file = os.getenv(ETCD_CA_CERT_FILE_ENV, None) etcd_volumes = [] etcd_binds = {} etcd_envs = [ "ETCD_AUTHORITY=%s" % etcd_authority, "ETCD_SCHEME=%s" % etcd_scheme ] felix_envs = [ "FELIX_ETCDADDR=%s" % etcd_authority, "FELIX_ETCDSCHEME=%s" % etcd_scheme ] if etcd_ca_cert_file and etcd_key_file and etcd_cert_file: etcd_volumes.append(ETCD_CA_CERT_NODE_FILE) etcd_binds[etcd_ca_cert_file] = { "bind": ETCD_CA_CERT_NODE_FILE, "ro": True } etcd_envs.append("ETCD_CA_CERT_FILE=%s" % ETCD_CA_CERT_NODE_FILE) felix_envs.append("FELIX_ETCDCAFILE=%s" % ETCD_CA_CERT_NODE_FILE) etcd_volumes.append(ETCD_KEY_NODE_FILE) etcd_binds[etcd_key_file] = {"bind": ETCD_KEY_NODE_FILE, "ro": True} etcd_envs.append("ETCD_KEY_FILE=%s" % ETCD_KEY_NODE_FILE) felix_envs.append("FELIX_ETCDKEYFILE=%s" % ETCD_KEY_NODE_FILE) etcd_volumes.append(ETCD_CERT_NODE_FILE) etcd_binds[etcd_cert_file] = {"bind": ETCD_CERT_NODE_FILE, "ro": True} etcd_envs.append("ETCD_CERT_FILE=%s" % ETCD_CERT_NODE_FILE) felix_envs.append("FELIX_ETCDCERTFILE=%s" % ETCD_CERT_NODE_FILE) if runtime == 'docker': _start_node_container_docker(ip, ip6, log_dir, node_image, detach, etcd_envs, felix_envs, etcd_volumes, etcd_binds) if libnetwork_image: _start_libnetwork_container(libnetwork_image, etcd_envs, etcd_volumes, etcd_binds) if runtime == 'rkt': _start_node_container_rkt(ip, ip6, node_image, etcd_envs, felix_envs, etcd_volumes, etcd_binds)
def node_start(node_image, log_dir, ip, ip6, as_num, detach, kubernetes, libnetwork): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :param kubernetes: True to install the kubernetes plugin, False otherwise. :param libnetwork: True to use the calico/node-libnetwork image as the node image, False otherwise. :return: None. """ # Print warnings for any known system issues before continuing check_system(fix=False, quit_if_error=False) # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=["^docker.*", "^cbr.*"]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Install kubernetes plugin if kubernetes: try: # Attempt to install to the default kubernetes directory install_kubernetes(KUBERNETES_PLUGIN_DIR) except OSError: # Use the backup directory install_kubernetes(KUBERNETES_PLUGIN_DIR_BACKUP) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) try: docker_client.remove_container("calico-node", force=True) except docker.errors.APIError as err: if err.response.status_code != 404: raise # Always try to convert the address(hostname) to an IP. This is a noop if # the address is already an IP address. Note that the format of the authority # string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) etcd_authority_address, etcd_authority_port = etcd_authority.split(':') etcd_authority = '%s:%s' % (socket.gethostbyname(etcd_authority_address), etcd_authority_port) environment = [ "HOSTNAME=%s" % hostname, "IP=%s" % ip, "IP6=%s" % (ip6 or ""), "ETCD_AUTHORITY=%s" % etcd_authority, # etcd host:port "FELIX_ETCDADDR=%s" % etcd_authority, # etcd host:port "POLICY_ONLY_CALICO=%s" % os.getenv(POLICY_ONLY_ENV, ""), ] binds = { "/proc": { "bind": "/proc_host", "ro": False }, log_dir: { "bind": "/var/log/calico", "ro": False }, "/run/docker/plugins": { "bind": "/usr/share/docker/plugins", "ro": False } } host_config = docker.utils.create_host_config( privileged=True, restart_policy={"Name": "Always"}, network_mode="host", binds=binds) if not node_image: # Use the calico/node-libnetwork image if the libnetwork flag was # passed in. Otherwise, use the default calico/node image. node_image = LIBNETWORK_IMAGE if libnetwork else CALICO_DEFAULT_IMAGE _find_or_pull_node_image(node_image) container = docker_client.create_container( node_image, name="calico-node", detach=True, environment=environment, host_config=host_config, volumes=["/proc_host", "/var/log/calico", "/usr/share/docker/plugins"]) cid = container["Id"] docker_client.start(container) print "Calico node is running with id: %s" % cid if not detach: _attach_and_stream(container)
def node_start(node_image, log_dir, ip, ip6, as_num, detach, kubernetes, rkt, libnetwork_image): """ Create the calico-node container and establish Calico networking on this host. :param ip: The IPv4 address of the host. :param node_image: The calico-node image to use. :param ip6: The IPv6 address of the host (or None if not configured) :param as_num: The BGP AS Number to use for this node. If not specified the global default value will be used. :param detach: True to run in Docker's "detached" mode, False to run attached. :param kubernetes: True to install the kubernetes plugin, False otherwise. :param rkt: True to install the rkt plugin, False otherwise. :param libnetwork_image: The name of the Calico libnetwork driver image to use. None, if not using libnetwork. :return: None. """ # Print warnings for any known system issues before continuing check_system(fix=False, quit_if_error=False) # Ensure log directory exists if not os.path.exists(log_dir): os.makedirs(log_dir) # Get IP address of host, if none was specified if not ip: ips = get_host_ips(exclude=["^docker.*", "^cbr.*"]) try: ip = ips.pop() except IndexError: print "Couldn't autodetect a management IP address. Please provide" \ " an IP by rerunning the command with the --ip=<IP_ADDRESS> flag." sys.exit(1) else: print "No IP provided. Using detected IP: %s" % ip # Verify that the chosen IP exists on the current host warn_if_unknown_ip(ip, ip6) # Warn if this hostname conflicts with an existing host warn_if_hostname_conflict(ip) # Install kubernetes plugin if kubernetes: try: # Attempt to install to the default kubernetes directory install_plugin(KUBERNETES_PLUGIN_DIR, KUBERNETES_BINARY_URL) except OSError: # Use the backup directory install_plugin(KUBERNETES_PLUGIN_DIR_BACKUP, KUBERNETES_BINARY_URL) # Install rkt plugin if rkt: try: # Attempt to install to the default rkt directory install_plugin(RKT_PLUGIN_DIR, RKT_BINARY_URL) except OSError: # Use the backup directory install_plugin(RKT_PLUGIN_DIR_BACKUP, RKT_BINARY_URL) # Set up etcd ipv4_pools = client.get_ip_pools(4) ipv6_pools = client.get_ip_pools(6) # Create default pools if required if not ipv4_pools: client.add_ip_pool(4, DEFAULT_IPV4_POOL) if not ipv6_pools: client.add_ip_pool(6, DEFAULT_IPV6_POOL) client.ensure_global_config() client.create_host(hostname, ip, ip6, as_num) # Always try to convert the address(hostname) to an IP. This is a noop if # the address is already an IP address. Note that the format of the authority # string has already been validated. etcd_authority = os.getenv(ETCD_AUTHORITY_ENV, ETCD_AUTHORITY_DEFAULT) etcd_authority_address, etcd_authority_port = etcd_authority.split(':') etcd_authority = '%s:%s' % (socket.gethostbyname(etcd_authority_address), etcd_authority_port) _start_node_container(ip, ip6, etcd_authority, log_dir, node_image, detach) if libnetwork_image: _start_libnetwork_container(etcd_authority, libnetwork_image)