func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error { ep.joinLeaveStart() defer ep.joinLeaveEnd() if sbox == nil || sbox.ID() == "" || sbox.Key() == "" { return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox) } sb, ok := sbox.(*sandbox) if !ok { return types.BadRequestErrorf("not a valid Sandbox interface") } ep.Lock() sid := ep.sandboxID ep.Unlock() if sid == "" { return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox") } if sid != sbox.ID() { return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID()) } ep.processOptions(options...) ep.Lock() ep.sandboxID = "" n := ep.network ep.Unlock() n.Lock() c := n.ctrlr d := n.driver n.Unlock() if err := c.updateEndpointToStore(ep); err != nil { ep.Lock() ep.sandboxID = sid ep.Unlock() return err } if err := d.Leave(n.id, ep.id); err != nil { return err } if err := sb.clearNetworkResources(ep); err != nil { return err } if sb.needDefaultGW() { ep := sb.getEPwithoutGateway() if ep == nil { return fmt.Errorf("endpoint without GW expected, but not found") } return sb.setupDefaultGW(ep) } return sb.clearDefaultGW() }
func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) { if cOptions == nil { return nil, nil } cc := &connectivityConfiguration{} if opt, ok := cOptions[netlabel.PortMap]; ok { if pb, ok := opt.([]types.PortBinding); ok { cc.PortBindings = pb } else { return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt) } } if opt, ok := cOptions[netlabel.ExposedPorts]; ok { if ports, ok := opt.([]types.TransportPort); ok { cc.ExposedPorts = ports } else { return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt) } } return cc, nil }
// ReleaseAddress releases the address from the specified pool ID func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error { logrus.Debugf("ReleaseAddress(%s, %v)", poolID, address) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) } if err := a.refresh(k.AddressSpace); err != nil { return err } aSpace, err := a.getAddrSpace(k.AddressSpace) if err != nil { return err } aSpace.Lock() p, ok := aSpace.subnets[k] if !ok { aSpace.Unlock() return types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID) } if address == nil { aSpace.Unlock() return types.BadRequestErrorf("invalid address: nil") } if !p.Pool.Contains(address) { aSpace.Unlock() return ipamapi.ErrIPOutOfRange } c := p for c.Range != nil { k = c.ParentKey c = aSpace.subnets[k] } aSpace.Unlock() mask := p.Pool.Mask h, err := types.GetHostPartIP(address, mask) if err != nil { return types.InternalErrorf("failed to release address %s: %v", address.String(), err) } bm, err := a.retrieveBitmask(k, c.Pool) if err != nil { return types.InternalErrorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v", k.String(), address, poolID, err) } return bm.Unset(ipToUint64(h)) }
// PutObjectAtomic adds a new Record based on an object into the datastore func (ds *datastore) PutObjectAtomic(kvObject KVObject) error { var ( previous *store.KVPair pair *store.KVPair err error ) if ds.sequential { ds.Lock() defer ds.Unlock() } if kvObject == nil { return types.BadRequestErrorf("invalid KV Object : nil") } kvObjValue := kvObject.Value() if kvObjValue == nil { return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...)) } if kvObject.Skip() { goto add_cache } if kvObject.Exists() { previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()} } else { previous = nil } _, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil) if err != nil { if err == store.ErrKeyExists { return ErrKeyModified } return err } kvObject.SetIndex(pair.LastIndex) add_cache: if ds.cache != nil { // If persistent store is skipped, sequencing needs to // happen in cache. return ds.cache.add(kvObject, kvObject.Skip()) } return nil }
// NewSandbox creates a new sandbox for the passed container id func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) { var err error if containerID == "" { return nil, types.BadRequestErrorf("invalid container ID") } var existing Sandbox look := SandboxContainerWalker(&existing, containerID) c.WalkSandboxes(look) if existing != nil { return nil, types.BadRequestErrorf("container %s is already present: %v", containerID, existing) } // Create sandbox and process options first. Key generation depends on an option sb := &sandbox{ id: stringid.GenerateRandomID(), containerID: containerID, endpoints: epHeap{}, epPriority: map[string]int{}, config: containerConfig{}, controller: c, } // This sandbox may be using an existing osl sandbox, sharing it with another sandbox var peerSb Sandbox c.WalkSandboxes(SandboxKeyWalker(&peerSb, sb.Key())) if peerSb != nil { sb.osSbox = peerSb.(*sandbox).osSbox } heap.Init(&sb.endpoints) sb.processOptions(options...) if err = sb.setupResolutionFiles(); err != nil { return nil, err } if sb.osSbox == nil && !sb.config.useExternalKey { if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil { return nil, fmt.Errorf("failed to create new osl sandbox: %v", err) } } c.Lock() c.sandboxes[sb.id] = sb c.Unlock() return sb, nil }
func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error { if sbox == nil { return types.BadRequestErrorf("endpoint cannot be joined by nil container") } sb, ok := sbox.(*sandbox) if !ok { return types.BadRequestErrorf("not a valid Sandbox interface") } sb.joinLeaveStart() defer sb.joinLeaveEnd() return ep.sbJoin(sb, options...) }
func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error { if sbox == nil || sbox.ID() == "" || sbox.Key() == "" { return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox) } sb, ok := sbox.(*sandbox) if !ok { return types.BadRequestErrorf("not a valid Sandbox interface") } sb.joinLeaveStart() defer sb.joinLeaveEnd() return ep.sbLeave(sb, false, options...) }
func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { if addressSpace != defaultAS { return "", nil, nil, types.BadRequestErrorf("unknown address space: %s", addressSpace) } if pool != "" { return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address pool requests") } if subPool != "" { return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address subpool requests") } if v6 { return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle IPv6 address pool pool requests") } return defaultPoolID, defaultPool, nil, nil }
// NewDataStore creates a new instance of LibKV data store func NewDataStore(cfg *config.DatastoreCfg) (DataStore, error) { if cfg == nil { return nil, types.BadRequestErrorf("invalid configuration passed to datastore") } // TODO : cfg.Embedded case return newClient(cfg.Client.Provider, cfg.Client.Address) }
// DeleteObjectAtomic performs atomic delete on a record func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error { ds.Lock() defer ds.Unlock() if kvObject == nil { return types.BadRequestErrorf("invalid KV Object : nil") } previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()} if kvObject.Skip() { goto del_cache } if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil { return err } del_cache: // cleanup the cache only if AtomicDelete went through successfully if ds.cache != nil { return ds.cache.del(kvObject) } return nil }
// AtomicDelete deletes a value at "key" if the key has not // been modified in the meantime, throws an error if this is the case func (s *MockStore) AtomicDelete(key string, previous *store.KVPair) (bool, error) { mData := s.db[key] if mData != nil && mData.Index != previous.LastIndex { return false, types.BadRequestErrorf("atomic delete failed due to mismatched Index") } return true, s.Delete(key) }
func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) { var ( err error config *networkConfiguration ) switch opt := data.(type) { case *networkConfiguration: config = opt case map[string]interface{}: config = &networkConfiguration{ EnableICC: true, EnableIPTables: true, EnableIPMasquerade: true, } err = config.fromMap(opt) case options.Generic: var opaqueConfig interface{} if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil { config = opaqueConfig.(*networkConfiguration) } default: err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt) } return config, err }
// DeleteObjectAtomic performs atomic delete on a record func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error { if ds.sequential { ds.Lock() defer ds.Unlock() } if kvObject == nil { return types.BadRequestErrorf("invalid KV Object : nil") } previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()} if kvObject.Skip() { goto del_cache } if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil { if err == store.ErrKeyExists { return ErrKeyModified } return err } del_cache: // cleanup the cache only if AtomicDelete went through successfully if ds.cache != nil { // If persistent store is skipped, sequencing needs to // happen in cache. return ds.cache.del(kvObject, kvObject.Skip()) } return nil }
// PutObject adds a new Record based on an object into the datastore func (ds *datastore) PutObject(kvObject KVObject) error { if ds.sequential { ds.Lock() defer ds.Unlock() } if kvObject == nil { return types.BadRequestErrorf("invalid KV Object : nil") } if kvObject.Skip() { goto add_cache } if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil { return err } add_cache: if ds.cache != nil { // If persistent store is skipped, sequencing needs to // happen in cache. return ds.cache.add(kvObject, kvObject.Skip()) } return nil }
func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 { return types.ForbiddenErrorf("bridge driver doesn't support multiple subnets") } if len(ipamV4Data) == 0 { return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id) } if ipamV4Data[0].Gateway != nil { c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway) } if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok { c.DefaultGatewayIPv4 = gw.IP } if len(ipamV6Data) > 0 { c.AddressIPv6 = ipamV6Data[0].Pool if ipamV6Data[0].Gateway != nil { c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway) } if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok { c.DefaultGatewayIPv6 = gw.IP } } return nil }
// ReleasePool releases the address pool identified by the passed id func (a *Allocator) ReleasePool(poolID string) error { logrus.Debugf("ReleasePool(%s)", poolID) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) } retry: if err := a.refresh(k.AddressSpace); err != nil { return err } aSpace, err := a.getAddrSpace(k.AddressSpace) if err != nil { return err } remove, err := aSpace.updatePoolDBOnRemoval(k) if err != nil { return err } if err = a.writeToStore(aSpace); err != nil { if _, ok := err.(types.RetryError); !ok { return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err) } goto retry } return remove() }
// updateKeys allows to add a new key and/or change the primary key and/or prune an existing key // The primary key is the key used in transmission and will go in first position in the list. func (d *driver) updateKeys(newKey, primary, pruneKey *key) error { logrus.Debugf("Updating Keys. New: %v, Primary: %v, Pruned: %v", newKey, primary, pruneKey) logrus.Debugf("Current: %v", d.keys) var ( newIdx = -1 priIdx = -1 delIdx = -1 lIP = net.ParseIP(d.bindAddress) ) d.Lock() // add new if newKey != nil { d.keys = append(d.keys, newKey) newIdx += len(d.keys) } for i, k := range d.keys { if primary != nil && k.tag == primary.tag { priIdx = i } if pruneKey != nil && k.tag == pruneKey.tag { delIdx = i } } d.Unlock() if (newKey != nil && newIdx == -1) || (primary != nil && priIdx == -1) || (pruneKey != nil && delIdx == -1) { return types.BadRequestErrorf("cannot find proper key indices while processing key update:"+ "(newIdx,priIdx,delIdx):(%d, %d, %d)", newIdx, priIdx, delIdx) } d.secMapWalk(func(rIPs string, spis []*spi) ([]*spi, bool) { rIP := net.ParseIP(rIPs) return updateNodeKey(lIP, rIP, spis, d.keys, newIdx, priIdx, delIdx), false }) d.Lock() // swap primary if priIdx != -1 { swp := d.keys[0] d.keys[0] = d.keys[priIdx] d.keys[priIdx] = swp } // prune if delIdx != -1 { if delIdx == 0 { delIdx = priIdx } d.keys = append(d.keys[:delIdx], d.keys[delIdx+1:]...) } d.Unlock() logrus.Debugf("Updated: %v", d.keys) return nil }
func (sb *sandbox) SetKey(basePath string) error { var err error if basePath == "" { return types.BadRequestErrorf("invalid sandbox key") } sb.Lock() if sb.osSbox != nil { sb.Unlock() return types.ForbiddenErrorf("failed to set sandbox key : already assigned") } sb.Unlock() osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key()) if err != nil { return err } sb.Lock() sb.osSbox = osSbox sb.Unlock() defer func() { if err != nil { sb.Lock() sb.osSbox = nil sb.Unlock() } }() for _, ep := range sb.getConnectedEndpoints() { if err = sb.populateNetworkResources(ep); err != nil { return err } } return nil }
// ReleasePool releases the address pool identified by the passed id func (a *Allocator) ReleasePool(poolID string) error { k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) } cfg, err := a.getPoolsConfig(k.AddressSpace) if err != nil { return err } retry: remove, err := cfg.updatePoolDBOnRemoval(k) if err != nil { return err } if err = cfg.writeToStore(); err != nil { if _, ok := err.(types.RetryError); !ok { return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err) } if erru := cfg.readFromStore(); erru != nil { return fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err) } goto retry } return remove() }
// Create a new network using bridge plugin func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error { if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { return types.BadRequestErrorf("ipv4 pool is empty") } // Sanity checks d.Lock() if _, ok := d.networks[id]; ok { d.Unlock() return types.ForbiddenErrorf("network %s exists", id) } d.Unlock() // Parse and validate the config. It should not conflict with existing networks' config config, err := parseNetworkOptions(id, option) if err != nil { return err } err = config.processIPAM(id, ipV4Data, ipV6Data) if err != nil { return err } if err = d.createNetwork(config); err != nil { return err } return d.storeUpdate(config) }
func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error { kvObjValue := kvObject.Value() if kvObjValue == nil { return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...)) } return ds.store.Put(Key(key...), kvObjValue, nil) }
func (test *testEndpoint) SetIPAddress(address *net.IPNet) error { if address.IP == nil { return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") } test.address = address.String() return nil }
// FromString populate the SubnetKey object reading it from string func (s *SubnetKey) FromString(str string) error { if str == "" || !strings.Contains(str, "/") { return types.BadRequestErrorf("invalid string form for subnetkey: %s", str) } p := strings.Split(str, "/") if len(p) != 3 && len(p) != 5 { return types.BadRequestErrorf("invalid string form for subnetkey: %s", str) } s.AddressSpace = p[0] s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2]) if len(p) == 5 { s.ChildSubnet = fmt.Sprintf("%s/%s", p[3], p[4]) } return nil }
func (sb *sandbox) SetKey(basePath string) error { start := time.Now() defer func() { logrus.Debugf("sandbox set key processing took %s for container %s", time.Now().Sub(start), sb.ContainerID()) }() if basePath == "" { return types.BadRequestErrorf("invalid sandbox key") } sb.Lock() oldosSbox := sb.osSbox sb.Unlock() if oldosSbox != nil { // If we already have an OS sandbox, release the network resources from that // and destroy the OS snab. We are moving into a new home further down. Note that none // of the network resources gets destroyed during the move. sb.releaseOSSbox() } osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key()) if err != nil { return err } sb.Lock() sb.osSbox = osSbox sb.Unlock() defer func() { if err != nil { sb.Lock() sb.osSbox = nil sb.Unlock() } }() // If the resolver was setup before stop it and set it up in the // new osl sandbox. if oldosSbox != nil && sb.resolver != nil { sb.resolver.Stop() if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil { if err := sb.resolver.Start(); err != nil { logrus.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) } } else { logrus.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) } } for _, ep := range sb.getConnectedEndpoints() { if err = sb.populateNetworkResources(ep); err != nil { return err } } return nil }
func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { var ( poolID *string address **net.IPNet prefAdd net.IP progAdd net.IP ) n := ep.getNetwork() switch ipVer { case 4: poolID = &ep.iface.v4PoolID address = &ep.iface.addr prefAdd = ep.prefAddress case 6: poolID = &ep.iface.v6PoolID address = &ep.iface.addrv6 prefAdd = ep.prefAddressV6 default: return types.InternalErrorf("incorrect ip version number passed: %d", ipVer) } ipInfo := n.getIPInfo(ipVer) // ipv6 address is not mandatory if len(ipInfo) == 0 && ipVer == 6 { return nil } // The address to program may be chosen by the user or by the network driver in one specific // case to support backward compatibility with `docker daemon --fixed-cidrv6` use case if prefAdd != nil { progAdd = prefAdd } else if *address != nil { progAdd = (*address).IP } for _, d := range ipInfo { if progAdd != nil && !d.Pool.Contains(progAdd) { continue } addr, _, err := ipam.RequestAddress(d.PoolID, progAdd, ep.ipamOptions) if err == nil { ep.Lock() *address = addr *poolID = d.PoolID ep.Unlock() return nil } if err != ipamapi.ErrNoAvailableIPs || progAdd != nil { return err } } if progAdd != nil { return types.BadRequestErrorf("Invalid address %s: It does not belong to any of this network's subnets", prefAdd) } return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) }
// DeleteObjectAtomic performs atomic delete on a record func (ds *datastore) DeleteObjectAtomic(kvObject KV) error { if kvObject == nil { return types.BadRequestErrorf("invalid KV Object : nil") } previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()} _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous) return err }
// Given the address space, returns the local or global PoolConfig based on the // address space is local or global. AddressSpace locality is being registered with IPAM out of band. func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) { a.Lock() defer a.Unlock() aSpace, ok := a.addrSpaces[as] if !ok { return nil, types.BadRequestErrorf("cannot find address space %s (most likely the backing datastore is not configured)", as) } return aSpace, nil }
func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error { if address.IP == nil { return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") } if address.IP.To4() == nil { return setAddress(&epi.addrv6, address) } return setAddress(&epi.addr, address) }
func (test *testEndpoint) SetIPAddress(address *net.IPNet) error { if address.IP == nil { return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") } if address.IP.To4() == nil { return setAddress(&test.addressIPv6, address) } return setAddress(&test.address, address) }
//ParseKey provides convenient method to unpack the key to complement the Key function func ParseKey(key string) ([]string, error) { chain := strings.Split(strings.Trim(key, "/"), "/") // The key must atleast be equal to the rootChain in order to be considered as valid if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) { return nil, types.BadRequestErrorf("invalid Key : %s", key) } return chain[len(rootChain):], nil }