Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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
Example #6
0
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)
Example #8
0
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)
Example #9
0
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)
Example #10
0
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
Example #11
0
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
Example #12
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
Example #13
0
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])
Example #14
0
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])
Example #15
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
Example #16
0
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)
Example #17
0
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)
Example #18
0
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)
Example #19
0
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)
Example #20
0
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)
Example #21
0
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)
Example #22
0
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)