Пример #1
0
def endpoint_profile_show(hostname, orchestrator_id, workload_id, endpoint_id):
    """
    List the profiles assigned to a particular endpoint.

    :param hostname: The hostname.
    :param orchestrator_id: The orchestrator ID.
    :param workload_id: The workload ID.
    :param endpoint_id: The endpoint ID.

    :return: None
    """
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id,
                                       endpoint_id=endpoint_id)
    except MultipleEndpointsMatch:
        print "Failed to list profiles in endpoint.\n"
        print_paragraph("More than 1 endpoint matches the provided "
                        "criteria.  Please provide additional parameters to "
                        "refine the search.")
        sys.exit(1)
    except KeyError:
        print "Failed to list profiles in endpoint.\n"
        print_paragraph("Endpoint %s is unknown to Calico.\n" % endpoint_id)
        sys.exit(1)

    if endpoint.profile_ids:
        x = PrettyTable(["Name"], sortby="Name")
        for name in endpoint.profile_ids:
            x.add_row([name])
        print str(x) + "\n"
    else:
        print "Endpoint has no profiles associated with it."
Пример #2
0
def endpoint_profile_show(hostname, orchestrator_id, workload_id, endpoint_id):
    """
    List the profiles assigned to a particular endpoint.

    :param hostname: The hostname.
    :param orchestrator_id: The orchestrator ID.
    :param workload_id: The workload ID.
    :param endpoint_id: The endpoint ID.

    :return: None
    """
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id,
                                       endpoint_id=endpoint_id)
    except MultipleEndpointsMatch:
        print "Failed to list profiles in endpoint.\n"
        print_paragraph("More than 1 endpoint matches the provided "
                        "criteria.  Please provide additional parameters to "
                        "refine the search.")
        sys.exit(1)
    except KeyError:
        print "Failed to list profiles in endpoint.\n"
        print_paragraph("Endpoint %s is unknown to Calico.\n" % endpoint_id)
        sys.exit(1)

    if endpoint.profile_ids:
        x = PrettyTable(["Name"], sortby="Name")
        for name in endpoint.profile_ids:
            x.add_row([name])
        print str(x) + "\n"
    else:
        print "Endpoint has no profiles associated with it."
Пример #3
0
def container_ip_remove(container_name, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_name: The name of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)

    info = get_container_info_or_exit(container_name)
    container_id = info["Id"]

    # Check the container is actually running.
    if not info["State"]["Running"]:
        print "%s is not currently running." % container_name
        sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=container_id)
        if address.version == 4:
            nets = endpoint.ipv4_nets
        else:
            nets = endpoint.ipv6_nets

        if not IPNetwork(address) in nets:
            print "IP address is not assigned to container. Aborting."
            sys.exit(1)

    except KeyError:
        print "Container is unknown to Calico."
        sys.exit(1)

    try:
        nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        container_pid = info["State"]["Pid"]
        netns.remove_ip_from_ns_veth(container_pid, address, interface)

    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        sys.exit(1)

    client.unassign_address(pool, ip)

    print "IP %s removed from %s" % (ip, container_name)
Пример #4
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
Пример #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
Пример #6
0
def container_endpoint_id_show(container_name):
    """
    Prints the endpoint-id of the endpoint attached to the specified
    container, or an appropriate Not-found error message.

    :param container_name: Name of the container the target endpoint
    is attached to.
    :return: None
    """
    workload_id = get_container_id(container_name)
    try:
        endpoint = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=workload_id)
        print endpoint.endpoint_id
    except KeyError:
        print "No endpoint was found for %s" % container_name
Пример #7
0
def container_endpoint_id_show(container_name):
    """
    Prints the endpoint-id of the endpoint attached to the specified
    container, or an appropriate Not-found error message.

    :param container_name: Name of the container the target endpoint
    is attached to.
    :return: None
    """
    workload_id = get_container_id(container_name)
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=ORCHESTRATOR_ID,
                                       workload_id=workload_id)
        print endpoint.endpoint_id
    except KeyError:
        print "No endpoint was found for %s" % container_name
Пример #8
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
Пример #9
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
Пример #10
0
def container_ip_remove(container_id, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_id: The namespace path or container_id of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)
    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)
        namespace = netns.Namespace(container_id)
        orchestrator_id = NAMESPACE_ORCHESTRATOR_ID
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        namespace = netns.PidNamespace(info["State"]["Pid"])
        orchestrator_id = DOCKER_ORCHESTRATOR_ID

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print "%s is not currently running." % container_id
            sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id)
        if address.version == 4:
            nets = endpoint.ipv4_nets
        else:
            nets = endpoint.ipv6_nets

        if not IPNetwork(address) in nets:
            print "IP address is not assigned to container. Aborting."
            sys.exit(1)

    except KeyError:
        print "Container is unknown to Calico."
        sys.exit(1)

    try:
        nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        netns.remove_ip_from_ns_veth(namespace, address, interface)

    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        sys.exit(1)

    client.release_ips({address})

    print "IP %s removed from %s" % (ip, container_id)
Пример #11
0
def container_ip_add(container_id, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_id: The namespace path or container_id of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """

    # The netns manipulations must be done as root.
    enforce_root()

    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)
        namespace = netns.Namespace(container_id)
        orchestrator_id = NAMESPACE_ORCHESTRATOR_ID
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        namespace = netns.PidNamespace(info["State"]["Pid"])
        orchestrator_id = DOCKER_ORCHESTRATOR_ID

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print "%s is not currently running." % container_id
            sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id)
    except KeyError:
        print "Failed to add IP address to container.\n"
        print_container_not_in_calico_msg(container_id)
        sys.exit(1)

    # From here, this method starts having side effects. If something
    # fails then at least try to leave the system in a clean state.
    address, pool = get_ip_and_pool(ip)

    try:
        if address.version == 4:
            endpoint.ipv4_nets.add(IPNetwork(address))
        else:
            endpoint.ipv6_nets.add(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        client.release_ips({address})
        print "Error updating datastore. Aborting."
        sys.exit(1)

    if not netns.ns_veth_exists(namespace, interface):
        print "Interface provided does not exist in container. Aborting."
        sys.exit(1)

    try:
        netns.add_ip_to_ns_veth(namespace, address, interface)
    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        if address.version == 4:
            endpoint.ipv4_nets.remove(IPNetwork(address))
        else:
            endpoint.ipv6_nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
        client.release_ips({address})
        sys.exit(1)

    print "IP %s added to %s" % (str(address), container_id)
Пример #12
0
def container_add(container_id, ip, interface):
    """
    Add a container (on this host) to Calico networking with the given IP.

    :param container_id: The namespace path or the docker name/ID of the container.
    :param ip: An IPAddress object with the desired IP to assign.
    :param interface: The name of the interface in the container.
    """
    # The netns manipulations must be done as root.
    enforce_root()

    # TODO: This section is redundant in container_add_ip and elsewhere
    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
        namespace = netns.Namespace(container_id)
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        orchestrator_id = DOCKER_ORCHESTRATOR_ID
        namespace = netns.PidNamespace(info["State"]["Pid"])

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print_paragraph("%s is not currently running." % container_id)
            sys.exit(1)

        # We can't set up Calico if the container shares the host namespace.
        if info["HostConfig"]["NetworkMode"] == "host":
            print_paragraph("Can't add %s to Calico because it is "
                            "running NetworkMode = host." % container_id)
            sys.exit(1)

    # Check if the container already exists
    try:
        _ = client.get_endpoint(hostname=hostname,
                                orchestrator_id=orchestrator_id,
                                workload_id=workload_id)
    except KeyError:
        # Calico doesn't know about this container.  Continue.
        pass
    else:
        # Calico already set up networking for this container.  Since we got
        # called with an IP address, we shouldn't just silently exit, since
        # that would confuse the user: the container would not be reachable on
        # that IP address.
        print_paragraph("%s has already been configured with Calico "
                        "Networking." % container_id)
        sys.exit(1)

    ip, pool = get_ip_and_pool(ip)

    try:
        # The next hop IPs for this host are stored in etcd.
        next_hops = client.get_default_next_hops(hostname)
        next_hops[ip.version]
    except KeyError:
        print_paragraph("This node is not configured for IPv%d.  "
                        "Is calico-node running?" % ip.version)
        unallocated_ips = client.release_ips({ip})
        if unallocated_ips:
            print_paragraph("Error during cleanup. %s was already"
                            "unallocated." % ip)
        sys.exit(1)

    # Get the next hop for the IP address.
    next_hop = next_hops[ip.version]

    network = IPNetwork(IPAddress(ip))
    ep = Endpoint(hostname=hostname,
                  orchestrator_id=DOCKER_ORCHESTRATOR_ID,
                  workload_id=workload_id,
                  endpoint_id=uuid.uuid1().hex,
                  state="active",
                  mac=None)
    if network.version == 4:
        ep.ipv4_nets.add(network)
        ep.ipv4_gateway = next_hop
    else:
        ep.ipv6_nets.add(network)
        ep.ipv6_gateway = next_hop

    # Create the veth, move into the container namespace, add the IP and
    # set up the default routes.
    netns.increment_metrics(namespace)
    netns.create_veth(ep.name, ep.temp_interface_name)
    netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface)
    netns.add_ip_to_ns_veth(namespace, ip, interface)
    netns.add_ns_default_route(namespace, next_hop, interface)

    # Grab the MAC assigned to the veth in the namespace.
    ep.mac = netns.get_ns_veth_mac(namespace, interface)

    # Register the endpoint with Felix.
    client.set_endpoint(ep)

    # Let the caller know what endpoint was created.
    print_paragraph("IP %s added to %s" % (str(ip), container_id))
    return ep
Пример #13
0
def container_ip_remove(container_id, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_id: The namespace path or container_id of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)
    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)
        namespace = netns.Namespace(container_id)
        orchestrator_id = NAMESPACE_ORCHESTRATOR_ID
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        namespace = netns.PidNamespace(info["State"]["Pid"])
        orchestrator_id = DOCKER_ORCHESTRATOR_ID

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print "%s is not currently running." % container_id
            sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id)
        if address.version == 4:
            nets = endpoint.ipv4_nets
        else:
            nets = endpoint.ipv6_nets

        if not IPNetwork(address) in nets:
            print "IP address is not assigned to container. Aborting."
            sys.exit(1)

    except KeyError:
        print "Container is unknown to Calico."
        sys.exit(1)

    try:
        nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        netns.remove_ip_from_ns_veth(namespace, address, interface)

    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        sys.exit(1)

    client.unassign_address(pool, address)

    print "IP %s removed from %s" % (ip, container_id)
Пример #14
0
def container_ip_add(container_id, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_id: The namespace path or container_id of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)

    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)
        namespace = netns.Namespace(container_id)
        orchestrator_id = NAMESPACE_ORCHESTRATOR_ID
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        namespace = netns.PidNamespace(info["State"]["Pid"])
        orchestrator_id = DOCKER_ORCHESTRATOR_ID

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print "%s is not currently running." % container_id
            sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=orchestrator_id,
                                       workload_id=workload_id)
    except KeyError:
        print "Failed to add IP address to container.\n"
        print_container_not_in_calico_msg(container_id)
        sys.exit(1)

    # From here, this method starts having side effects. If something
    # fails then at least try to leave the system in a clean state.
    if not client.assign_address(pool, address):
        print "IP address is already assigned in pool %s " % pool
        sys.exit(1)

    try:
        if address.version == 4:
            endpoint.ipv4_nets.add(IPNetwork(address))
        else:
            endpoint.ipv6_nets.add(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        client.unassign_address(pool, ip)
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        netns.add_ip_to_ns_veth(namespace, address, interface)
    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        if address.version == 4:
            endpoint.ipv4_nets.remove(IPNetwork(address))
        else:
            endpoint.ipv6_nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
        client.unassign_address(pool, ip)
        sys.exit(1)

    print "IP %s added to %s" % (ip, container_id)
Пример #15
0
def container_add(container_id, ip, interface):
    """
    Add a container (on this host) to Calico networking with the given IP.

    :param container_id: The namespace path or the docker name/ID of the container.
    :param ip: An IPAddress object with the desired IP to assign.
    :param interface: The name of the interface in the container.
    """
    # The netns manipulations must be done as root.
    enforce_root()

    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
        namespace = netns.Namespace(container_id)
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        orchestrator_id = DOCKER_ORCHESTRATOR_ID
        namespace = netns.PidNamespace(info["State"]["Pid"])

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print "%s is not currently running." % container_id
            sys.exit(1)

        # We can't set up Calico if the container shares the host namespace.
        if info["HostConfig"]["NetworkMode"] == "host":
            print "Can't add %s to Calico because it is " \
                  "running NetworkMode = host." % container_id
            sys.exit(1)

    # Check if the container already exists
    try:
        _ = client.get_endpoint(hostname=hostname,
                                orchestrator_id=orchestrator_id,
                                workload_id=workload_id)
    except KeyError:
        # Calico doesn't know about this container.  Continue.
        pass
    else:
        # Calico already set up networking for this container.  Since we got
        # called with an IP address, we shouldn't just silently exit, since
        # that would confuse the user: the container would not be reachable on
        # that IP address.
        print "%s has already been configured with Calico Networking." % \
              container_id
        sys.exit(1)

    # Check the IP is in the allocation pool.  If it isn't, BIRD won't export
    # it.
    ip = IPAddress(ip)
    pool = get_pool_or_exit(ip)

    # The next hop IPs for this host are stored in etcd.
    next_hops = client.get_default_next_hops(hostname)
    try:
        next_hops[ip.version]
    except KeyError:
        print "This node is not configured for IPv%d." % ip.version
        sys.exit(1)

    # Assign the IP
    if not client.assign_address(pool, ip):
        print "IP address is already assigned in pool %s " % pool
        sys.exit(1)

    # Get the next hop for the IP address.
    next_hop = next_hops[ip.version]

    network = IPNetwork(IPAddress(ip))
    ep = Endpoint(hostname=hostname,
                  orchestrator_id=DOCKER_ORCHESTRATOR_ID,
                  workload_id=workload_id,
                  endpoint_id=uuid.uuid1().hex,
                  state="active",
                  mac=None)
    if network.version == 4:
        ep.ipv4_nets.add(network)
        ep.ipv4_gateway = next_hop
    else:
        ep.ipv6_nets.add(network)
        ep.ipv6_gateway = next_hop

    # Create the veth, move into the container namespace, add the IP and
    # set up the default routes.
    netns.create_veth(ep.name, ep.temp_interface_name)
    netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface)
    netns.add_ip_to_ns_veth(namespace, ip, interface)
    netns.add_ns_default_route(namespace, next_hop, interface)

    # Grab the MAC assigned to the veth in the namespace.
    ep.mac = netns.get_ns_veth_mac(namespace, interface)

    # Register the endpoint with Felix.
    client.set_endpoint(ep)

    # Let the caller know what endpoint was created.
    return ep
Пример #16
0
def container_ip_add(container_name, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_name: The name of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)

    info = get_container_info_or_exit(container_name)
    container_id = info["Id"]

    # Check the container is actually running.
    if not info["State"]["Running"]:
        print "%s is not currently running." % container_name
        sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=ORCHESTRATOR_ID,
                                       workload_id=container_id)
    except KeyError:
        print "Failed to add IP address to container.\n"
        print_container_not_in_calico_msg(container_name)
        sys.exit(1)

    # From here, this method starts having side effects. If something
    # fails then at least try to leave the system in a clean state.
    if not client.assign_address(pool, address):
        print "IP address is already assigned in pool %s " % pool
        sys.exit(1)

    try:
        if address.version == 4:
            endpoint.ipv4_nets.add(IPNetwork(address))
        else:
            endpoint.ipv6_nets.add(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        client.unassign_address(pool, ip)
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        container_pid = info["State"]["Pid"]
        netns.add_ip_to_ns_veth(container_pid, address, interface)
    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        if address.version == 4:
            endpoint.ipv4_nets.remove(IPNetwork(address))
        else:
            endpoint.ipv6_nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
        client.unassign_address(pool, ip)
        sys.exit(1)

    print "IP %s added to %s" % (ip, container_id)
Пример #17
0
def container_ip_remove(container_name, ip, interface):
    """
    Add an IP address to an existing Calico networked container.

    :param container_name: The name of the container.
    :param ip: The IP to add
    :param interface: The name of the interface in the container.

    :return: None
    """
    address = IPAddress(ip)

    # The netns manipulations must be done as root.
    enforce_root()

    pool = get_pool_or_exit(address)

    info = get_container_info_or_exit(container_name)
    container_id = info["Id"]

    # Check the container is actually running.
    if not info["State"]["Running"]:
        print "%s is not currently running." % container_name
        sys.exit(1)

    # Check that the container is already networked
    try:
        endpoint = client.get_endpoint(hostname=hostname,
                                       orchestrator_id=ORCHESTRATOR_ID,
                                       workload_id=container_id)
        if address.version == 4:
            nets = endpoint.ipv4_nets
        else:
            nets = endpoint.ipv6_nets

        if not IPNetwork(address) in nets:
            print "IP address is not assigned to container. Aborting."
            sys.exit(1)

    except KeyError:
        print "Container is unknown to Calico."
        sys.exit(1)

    try:
        nets.remove(IPNetwork(address))
        client.update_endpoint(endpoint)
    except (KeyError, ValueError):
        print "Error updating datastore. Aborting."
        sys.exit(1)

    try:
        container_pid = info["State"]["Pid"]
        netns.remove_ip_from_ns_veth(container_pid, address, interface)

    except CalledProcessError:
        print "Error updating networking in container. Aborting."
        sys.exit(1)

    client.unassign_address(pool, ip)

    print "IP %s removed from %s" % (ip, container_name)
Пример #18
0
def container_add(container_name, ip, interface):
    """
    Add a container (on this host) to Calico networking with the given IP.

    :param container_name: The name or ID of the container.
    :param ip: An IPAddress object with the desired IP to assign.
    :param interface: The name of the interface in the container.
    """
    # The netns manipulations must be done as root.
    enforce_root()
    info = get_container_info_or_exit(container_name)
    container_id = info["Id"]

    # Check if the container already exists
    try:
        _ = client.get_endpoint(hostname=hostname,
                                orchestrator_id=ORCHESTRATOR_ID,
                                workload_id=container_id)
    except KeyError:
        # Calico doesn't know about this container.  Continue.
        pass
    else:
        # Calico already set up networking for this container.  Since we got
        # called with an IP address, we shouldn't just silently exit, since
        # that would confuse the user: the container would not be reachable on
        # that IP address.
        print "%s has already been configured with Calico Networking." % \
              container_name
        sys.exit(1)

    # Check the container is actually running.
    if not info["State"]["Running"]:
        print "%s is not currently running." % container_name
        sys.exit(1)

    # We can't set up Calico if the container shares the host namespace.
    if info["HostConfig"]["NetworkMode"] == "host":
        print "Can't add %s to Calico because it is " \
              "running NetworkMode = host." % container_name
        sys.exit(1)

    # Check the IP is in the allocation pool.  If it isn't, BIRD won't export
    # it.
    ip = IPAddress(ip)
    pool = get_pool_or_exit(ip)

    # The next hop IPs for this host are stored in etcd.
    next_hops = client.get_default_next_hops(hostname)
    try:
        next_hops[ip.version]
    except KeyError:
        print "This node is not configured for IPv%d." % ip.version
        sys.exit(1)

    # Assign the IP
    if not client.assign_address(pool, ip):
        print "IP address is already assigned in pool %s " % pool
        sys.exit(1)

    # Get the next hop for the IP address.
    next_hop = next_hops[ip.version]

    network = IPNetwork(IPAddress(ip))
    ep = Endpoint(hostname=hostname,
                  orchestrator_id=ORCHESTRATOR_ID,
                  workload_id=container_id,
                  endpoint_id=uuid.uuid1().hex,
                  state="active",
                  mac=None)
    if network.version == 4:
        ep.ipv4_nets.add(network)
        ep.ipv4_gateway = next_hop
    else:
        ep.ipv6_nets.add(network)
        ep.ipv6_gateway = next_hop

    # Create the veth, move into the container namespace, add the IP and
    # set up the default routes.
    pid = info["State"]["Pid"]
    netns.create_veth(ep.name, ep.temp_interface_name)
    netns.move_veth_into_ns(pid, ep.temp_interface_name, interface)
    netns.add_ip_to_ns_veth(pid, ip, interface)
    netns.add_ns_default_route(pid, next_hop, interface)

    # Grab the MAC assigned to the veth in the namespace.
    ep.mac = netns.get_ns_veth_mac(pid, interface)

    # Register the endpoint with Felix.
    client.set_endpoint(ep)

    # Let the caller know what endpoint was created.
    return ep
Пример #19
0
def container_add(container_id, ip, interface):
    """
    Add a container (on this host) to Calico networking with the given IP.

    :param container_id: The namespace path or the docker name/ID of the container.
    :param ip: An IPAddress object with the desired IP to assign.
    :param interface: The name of the interface in the container.
    """
    # The netns manipulations must be done as root.
    enforce_root()

    # TODO: This section is redundant in container_add_ip and elsewhere
    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
        namespace = netns.Namespace(container_id)
    else:
        info = get_container_info_or_exit(container_id)
        workload_id = info["Id"]
        orchestrator_id = DOCKER_ORCHESTRATOR_ID
        namespace = netns.PidNamespace(info["State"]["Pid"])

        # Check the container is actually running.
        if not info["State"]["Running"]:
            print_paragraph("%s is not currently running." % container_id)
            sys.exit(1)

        # We can't set up Calico if the container shares the host namespace.
        if info["HostConfig"]["NetworkMode"] == "host":
            print_paragraph("Can't add %s to Calico because it is "
                            "running NetworkMode = host." % container_id)
            sys.exit(1)

    # Check if the container already exists
    try:
        _ = client.get_endpoint(hostname=hostname,
                                orchestrator_id=orchestrator_id,
                                workload_id=workload_id)
    except KeyError:
        # Calico doesn't know about this container.  Continue.
        pass
    else:
        # Calico already set up networking for this container.  Since we got
        # called with an IP address, we shouldn't just silently exit, since
        # that would confuse the user: the container would not be reachable on
        # that IP address.
        print_paragraph("%s has already been configured with Calico "
                        "Networking." % container_id)
        sys.exit(1)

    ep = Endpoint(hostname=hostname,
                  orchestrator_id=DOCKER_ORCHESTRATOR_ID,
                  workload_id=workload_id,
                  endpoint_id=uuid.uuid1().hex,
                  state="active",
                  mac=None)

    ip, _ = get_ip_and_pool(ip)

    network = IPNetwork(ip)
    if network.version == 4:
        ep.ipv4_nets.add(network)
    else:
        ep.ipv6_nets.add(network)

    # Create the veth, move into the container namespace, add the IP and
    # set up the default routes.
    netns.increment_metrics(namespace)
    netns.create_veth(ep.name, ep.temp_interface_name)
    netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface)
    netns.add_ip_to_ns_veth(namespace, ip, interface)
    netns.add_ns_default_route(namespace, ep.name, interface)

    # Grab the MAC assigned to the veth in the namespace.
    ep.mac = netns.get_ns_veth_mac(namespace, interface)

    # Register the endpoint with Felix.
    client.set_endpoint(ep)

    # Let the caller know what endpoint was created.
    print_paragraph("IP %s added to %s" % (str(ip), container_id))
    return ep