def get_pool_by_cidr_or_exit(cidr): pools = client.get_ip_pools(cidr.version) for pool in pools: if pool.cidr == cidr: return pool print "%s is not found" % cidr sys.exit(1)
def ip_pool_range_add(start_ip, end_ip, version, ipip, masquerade): """ Add the range of ip addresses as CIDRs to the IP address allocation pool. :param start_ip: The first ip address the ip range. :param end_ip: The last ip address in the ip range. :param version: 4 or 6 :param ipip: Use IP in IP for this pool. :return: None """ if version == 6 and ipip: print "IP in IP not supported for IPv6 pools" sys.exit(1) ip_range = IPRange(start_ip, end_ip) pools = client.get_ip_pools(version) for pool in pools: pool_net = IPNetwork(pool.cidr) # Reject the new ip range if any of the following are true: # - The new ip range contains all ips of any existing pool # - An existing pool overlaps ips with the start of the new ip range # - An existing pool overlaps ips with the end of the new ip range if (pool_net in ip_range or start_ip in pool_net or end_ip in pool_net): print "Cannot add range - range conflicts with pool %s" % pool.cidr sys.exit(1) cidrs = netaddr.iprange_to_cidrs(start_ip, end_ip) for ip_net in cidrs: new_pool = IPPool(ip_net.cidr, ipip=ipip, masquerade=masquerade) client.add_ip_pool(version, new_pool)
def container_remove(container_id): """ Remove a container (on this host) from Calico networking. The container may be left in a state without any working networking. If there is a network adaptor in the host namespace used by the container then it is removed. :param container_id: The namespace path or the ID of the container. """ # The netns manipulations must be done as root. enforce_root() # Resolve the name to ID. if container_id.startswith("/") and os.path.exists(container_id): # The ID is a path. Don't do any docker lookups workload_id = escape_etcd(container_id) orchestrator_id = NAMESPACE_ORCHESTRATOR_ID else: workload_id = get_workload_id(container_id) orchestrator_id = DOCKER_ORCHESTRATOR_ID # Find the endpoint ID. We need this to find any ACL rules try: endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=orchestrator_id, workload_id=workload_id) except KeyError: print "Container %s doesn't contain any endpoints" % container_id sys.exit(1) # Remove any IP address assignments that this endpoint has for net in endpoint.ipv4_nets | endpoint.ipv6_nets: assert (net.size == 1) ip = net.ip pools = client.get_ip_pools(ip.version) for pool in pools: if ip in pool: # Ignore failure to unassign address, since we're not # enforcing assignments strictly in datastore.py. client.unassign_address(pool, ip) try: # Remove the interface if it exists netns.remove_veth(endpoint.name) except CalledProcessError: print "Could not remove Calico interface %s" % endpoint.name sys.exit(1) # Remove the container from the datastore. client.remove_workload(hostname, orchestrator_id, workload_id) print "Removed Calico interface from %s" % container_id
def container_remove(container_id): """ Remove a container (on this host) from Calico networking. The container may be left in a state without any working networking. If there is a network adaptor in the host namespace used by the container then it is removed. :param container_id: The namespace path or the ID of the container. """ # The netns manipulations must be done as root. enforce_root() # Resolve the name to ID. if container_id.startswith("/") and os.path.exists(container_id): # The ID is a path. Don't do any docker lookups workload_id = escape_etcd(container_id) orchestrator_id = NAMESPACE_ORCHESTRATOR_ID else: workload_id = get_workload_id(container_id) orchestrator_id = DOCKER_ORCHESTRATOR_ID # Find the endpoint ID. We need this to find any ACL rules try: endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=orchestrator_id, workload_id=workload_id) except KeyError: print "Container %s doesn't contain any endpoints" % container_id sys.exit(1) # Remove any IP address assignments that this endpoint has for net in endpoint.ipv4_nets | endpoint.ipv6_nets: assert(net.size == 1) ip = net.ip pools = client.get_ip_pools(ip.version) for pool in pools: if ip in pool: # Ignore failure to unassign address, since we're not # enforcing assignments strictly in datastore.py. client.unassign_address(pool, ip) try: # Remove the interface if it exists netns.remove_veth(endpoint.name) except CalledProcessError: print "Could not remove Calico interface %s" % endpoint.name sys.exit(1) # Remove the container from the datastore. client.remove_workload(hostname, orchestrator_id, workload_id) print "Removed Calico interface from %s" % container_id
def ip_pool_add(cidrs, version, ipip, masquerade): """ Add the given CIDRS to the IP address allocation pool. :param cidrs: The pools to set in CIDR format, e.g. 192.168.0.0/16 :param version: 4 or 6 :param ipip: Use IP in IP for the pool(s). :param masquerade: Enable masquerade (outgoing NAT) for the pool(s). :return: None """ if version == 6 and ipip: print "IP in IP not supported for IPv6 pools" sys.exit(1) current_pools = client.get_ip_pools(version) new_pools = [] # Ensure new pools are valid and do not overlap with each other or existing # pools. for cidr in cidrs: try: pool = IPPool(cidr, ipip=ipip, masquerade=masquerade) except InvalidBlockSizeError: print "An IPv%s pool must have a prefix length of %s or lower." \ "\nGiven: %s.\nNo pools added." % \ (version, BLOCK_PREFIXLEN[version], cidr) sys.exit(1) # Check if new pool overlaps with any existing pool overlapping_pool = _get_overlapping_pool(pool, current_pools) if overlapping_pool: print "Cannot add IP pool %s - pool overlaps with an " \ "existing pool %s" % (cidr, overlapping_pool.cidr) sys.exit(1) # Check if this new pool overlaps with any other new pool overlapping_pool = _get_overlapping_pool(pool, new_pools) if overlapping_pool: print "Cannot add IP pool %s - pool overlaps with another " \ "new pool %s" % (cidr, overlapping_pool.cidr) sys.exit(1) # Append pool to pending list of new pools to add to Calico new_pools.append(pool) # Make client call to add each pool to Calico for new_pool in new_pools: client.add_ip_pool(version, new_pool)
def ip_pool_range_add(start_ip, end_ip, version, ipip, masquerade): """ Add the range of ip addresses as CIDRs to the IP address allocation pool. :param start_ip: The first ip address the ip range. :param end_ip: The last ip address in the ip range. :param version: 4 or 6 :param ipip: Use IP in IP for the pool(s). :param masquerade: Enable masquerade (outgoing NAT) for the pool(s). :return: None """ if version == 6 and ipip: print "IP in IP not supported for IPv6 pools" sys.exit(1) ip_range = IPRange(start_ip, end_ip) pools = client.get_ip_pools(version) for pool in pools: pool_net = IPNetwork(pool.cidr) # Reject the new ip range if any of the following are true: # - The new ip range contains all ips of any existing pool # - An existing pool overlaps ips with the start of the new ip range # - An existing pool overlaps ips with the end of the new ip range if (pool_net in ip_range or start_ip in pool_net or end_ip in pool_net): print "Cannot add range - range conflicts with pool %s" % pool.cidr sys.exit(1) cidrs = netaddr.iprange_to_cidrs(start_ip, end_ip) new_pools = [] for ip_net in cidrs: try: new_pools.append(IPPool(ip_net.cidr, ipip=ipip, masquerade=masquerade)) except CidrTooSmallError: pool_strings = [str(net) for net in cidrs] print "IPv%s ranges are split into pools, with the smallest pool " \ "size allowed having a prefix length of /%s. One or more " \ "of the generated pools is too small (prefix length is too " \ "high).\nRange given: %s - %s\nPools: %s\nNo pools added." % \ (version, BLOCK_PREFIXLEN[version], start_ip, end_ip, pool_strings) sys.exit(1) for new_pool in new_pools: client.add_ip_pool(version, new_pool)
def get_pool_or_exit(ip): """ Get the first allocation pool that an IP is in. :param ip: The IPAddress to find the pool for. :return: The pool or sys.exit """ pools = client.get_ip_pools(ip.version) pool = None for candidate_pool in pools: if ip in candidate_pool: pool = candidate_pool break if pool is None: print "%s is not in any configured pools" % ip sys.exit(1) return pool
def container_remove(container_name): """ Remove a container (on this host) from Calico networking. The container may be left in a state without any working networking. If there is a network adaptor in the host namespace used by the container then it is removed. :param container_name: The name or ID of the container. """ # The netns manipulations must be done as root. enforce_root() # Resolve the name to ID. workload_id = get_container_id(container_name) # Find the endpoint ID. We need this to find any ACL rules try: endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=workload_id) except KeyError: print "Container %s doesn't contain any endpoints" % container_name sys.exit(1) # Remove any IP address assignments that this endpoint has for net in endpoint.ipv4_nets | endpoint.ipv6_nets: assert(net.size == 1) ip = net.ip pools = client.get_ip_pools(ip.version) for pool in pools: if ip in pool: # Ignore failure to unassign address, since we're not # enforcing assignments strictly in datastore.py. client.unassign_address(pool, ip) # Remove the endpoint netns.remove_veth(endpoint.name) # Remove the container from the datastore. client.remove_workload(hostname, ORCHESTRATOR_ID, workload_id) print "Removed Calico interface from %s" % container_name
def ip_pool_show(version): """ Print a list of IP allocation pools. :return: None """ assert version in (4, 6) headings = ["IPv%s CIDR" % version, "Options"] pools = client.get_ip_pools(version) x = PrettyTable(headings) for pool in pools: enabled_options = [] if version == 4: if pool.ipip: enabled_options.append("ipip") if pool.masquerade: enabled_options.append("nat-outgoing") # convert option array to string row = [str(pool.cidr), ','.join(enabled_options)] x.add_row(row) print x.get_string(sortby=headings[0])
def container_remove(container_name): """ Remove a container (on this host) from Calico networking. The container may be left in a state without any working networking. If there is a network adaptor in the host namespace used by the container then it is removed. :param container_name: The name or ID of the container. """ # The netns manipulations must be done as root. enforce_root() # Resolve the name to ID. workload_id = get_container_id(container_name) # Find the endpoint ID. We need this to find any ACL rules try: endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=workload_id) except KeyError: print "Container %s doesn't contain any endpoints" % container_name sys.exit(1) # Remove any IP address assignments that this endpoint has for net in endpoint.ipv4_nets | endpoint.ipv6_nets: assert net.size == 1 ip = net.ip pools = client.get_ip_pools(ip.version) for pool in pools: if ip in pool: # Ignore failure to unassign address, since we're not # enforcing assignments strictly in datastore.py. client.unassign_address(pool, ip) # Remove the endpoint netns.remove_veth(endpoint.name) # Remove the container from the datastore. client.remove_workload(hostname, ORCHESTRATOR_ID, workload_id) print "Removed Calico interface from %s" % container_name
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): """ 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, 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, 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, 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)