func (i IpamDriver) RequestPool(request *ipam.RequestPoolRequest) (*ipam.RequestPoolResponse, error) { logutils.JSONMessage("RequestPool", request) // Calico IPAM does not allow you to request a SubPool. if request.SubPool != "" { err := errors.New( "Calico IPAM does not support sub pool configuration " + "on 'docker create network'. Calico IP Pools " + "should be configured first and IP assignment is " + "from those pre-configured pools.", ) log.Errorln(err) return nil, err } if request.V6 { err := errors.New("IPv6 isn't supported") log.Errorln(err) return nil, err } // Default the poolID to the fixed value. poolID := i.poolIDV4 pool := "0.0.0.0/0" // If a pool (subnet on the CLI) is specified, it must match one of the // preconfigured Calico pools. if request.Pool != "" { poolsClient := i.client.IPPools() _, ipNet, err := caliconet.ParseCIDR(request.Pool) if err != nil { err := errors.New("Invalid CIDR") log.Errorln(err) return nil, err } pools, err := poolsClient.List(api.IPPoolMetadata{CIDR: *ipNet}) if err != nil || len(pools.Items) < 1 { err := errors.New("The requested subnet must match the CIDR of a " + "configured Calico IP Pool.", ) log.Errorln(err) return nil, err } pool = request.Pool poolID = request.Pool } // We use static pool ID and CIDR. We don't need to signal the // The meta data includes a dummy gateway address. This prevents libnetwork // from requesting a gateway address from the pool since for a Calico // network our gateway is set to a special IP. resp := &ipam.RequestPoolResponse{ PoolID: poolID, Pool: pool, Data: map[string]string{"com.docker.network.gateway": "0.0.0.0/0"}, } logutils.JSONMessage("RequestPool response", resp) return resp, nil }
// getResourceFromArguments returns a resource instance from the command line arguments. func getResourceFromArguments(args map[string]interface{}) (unversioned.Resource, error) { kind := args["<KIND>"].(string) name := argutils.ArgStringOrBlank(args, "<NAME>") node := argutils.ArgStringOrBlank(args, "--node") workload := argutils.ArgStringOrBlank(args, "--workload") orchestrator := argutils.ArgStringOrBlank(args, "--orchestrator") resScope := argutils.ArgStringOrBlank(args, "--scope") switch strings.ToLower(kind) { case "node", "nodes": p := api.NewNode() p.Metadata.Name = name return *p, nil case "hostendpoint", "hostendpoints": h := api.NewHostEndpoint() h.Metadata.Name = name h.Metadata.Node = node return *h, nil case "workloadendpoint", "workloadendpoints": h := api.NewWorkloadEndpoint() h.Metadata.Name = name h.Metadata.Orchestrator = orchestrator h.Metadata.Workload = workload h.Metadata.Node = node return *h, nil case "profile", "profiles": p := api.NewProfile() p.Metadata.Name = name return *p, nil case "policy", "policies": p := api.NewPolicy() p.Metadata.Name = name return *p, nil case "ippool", "ippools": p := api.NewIPPool() if name != "" { _, cidr, err := net.ParseCIDR(name) if err != nil { return nil, err } p.Metadata.CIDR = *cidr } return *p, nil case "bgppeer", "bgppeers": p := api.NewBGPPeer() if name != "" { err := p.Metadata.PeerIP.UnmarshalText([]byte(name)) if err != nil { return nil, err } } p.Metadata.Node = node switch resScope { case "node": p.Metadata.Scope = scope.Node case "global": p.Metadata.Scope = scope.Global case "": p.Metadata.Scope = scope.Undefined default: return nil, fmt.Errorf("Unrecognized scope '%s', must be one of: global, node", resScope) } return *p, nil default: return nil, fmt.Errorf("Resource type '%s' is not supported", kind) } }
func (i IpamDriver) RequestAddress(request *ipam.RequestAddressRequest) (*ipam.RequestAddressResponse, error) { logutils.JSONMessage("RequestAddress", request) hostname, err := osutils.GetHostname() if err != nil { log.Errorln(err) return nil, err } var IPs []caliconet.IP if request.Address == "" { // No address requested, so auto assign from our pools. log.Println("Auto assigning IP from Calico pools") // If the poolID isn't the fixed one then find the pool to assign from. // poolV4 defaults to nil to assign from across all pools. var poolV4 []caliconet.IPNet if request.PoolID != PoolIDV4 { poolsClient := i.client.IPPools() _, ipNet, err := caliconet.ParseCIDR(request.PoolID) if err != nil { err = errors.Wrapf(err, "Invalid CIDR - %v", request.PoolID) log.Errorln(err) return nil, err } pool, err := poolsClient.Get(api.IPPoolMetadata{CIDR: *ipNet}) if err != nil { err := errors.New("The network references a Calico pool which " + "has been deleted. Please re-instate the " + "Calico pool before using the network.") log.Errorln(err) return nil, err } poolV4 = []caliconet.IPNet{caliconet.IPNet{IPNet: pool.Metadata.CIDR.IPNet}} log.Debugln("Using specific pool ", poolV4) } // Auto assign an IP address. // IPv4 pool will be nil if the docker network doesn't have a subnet associated with. // Otherwise, it will be set to the Calico pool to assign from. IPsV4, IPsV6, err := i.client.IPAM().AutoAssign( datastoreClient.AutoAssignArgs{ Num4: 1, Num6: 0, Hostname: hostname, IPv4Pools: poolV4, }, ) if err != nil { err = errors.Wrapf(err, "IP assignment error") log.Errorln(err) return nil, err } IPs = append(IPsV4, IPsV6...) } else { // Docker allows the users to specify any address. // We'll return an error if the address isn't in a Calico pool, but we don't care which pool it's in // (i.e. it doesn't need to match the subnet from the docker network). log.Debugln("Reserving a specific address in Calico pools") ip := net.ParseIP(request.Address) ipArgs := datastoreClient.AssignIPArgs{ IP: caliconet.IP{IP: ip}, Hostname: hostname, } err := i.client.IPAM().AssignIP(ipArgs) if err != nil { err = errors.Wrapf(err, "IP assignment error, data: %+v", ipArgs) log.Errorln(err) return nil, err } IPs = []caliconet.IP{{IP: ip}} } // We should only have one IP address assigned at this point. if len(IPs) != 1 { err := errors.New(fmt.Sprintf("Unexpected number of assigned IP addresses. "+ "A single address should be assigned. Got %v", IPs)) log.Errorln(err) return nil, err } // Return the IP as a CIDR. resp := &ipam.RequestAddressResponse{ Address: fmt.Sprintf("%v/%v", IPs[0], "32"), } logutils.JSONMessage("RequestAddress response", resp) return resp, nil }