// SVCAdd is the public method to add services. We assume the ID provided is not in // synced with the KVStore. If that's the case the service won't be used and an error is // returned to the caller. func (d *Daemon) SVCAdd(feL3n4Addr types.L3n4AddrID, beL3n4Addr []types.L3n4Addr, addRevNAT bool) error { if feL3n4Addr.ID == 0 { return fmt.Errorf("invalid service ID 0") } // Check if the service is already registered with this ID. feAddr, err := d.GetL3n4AddrID(uint32(feL3n4Addr.ID)) if err != nil { return fmt.Errorf("unable to get the service with ID %d: %s", feL3n4Addr.ID, err) } if feAddr == nil { feAddr, err = d.PutL3n4Addr(feL3n4Addr.L3n4Addr, uint32(feL3n4Addr.ID)) if err != nil { return fmt.Errorf("unable to put the service %s: %s", feL3n4Addr.L3n4Addr.String(), err) } // This won't be atomic so we need to check if the baseID, feL3n4Addr.ID was given to the service if feAddr.ID != feL3n4Addr.ID { return fmt.Errorf("the service provided %s is already registered with ID %d, please select that ID instead of %d", feL3n4Addr.L3n4Addr.String(), feAddr.ID, feL3n4Addr.ID) } } feAddr256Sum, err := feAddr.L3n4Addr.SHA256Sum() if err != nil { return fmt.Errorf("unable to calculate SHA256Sum of %s: %s", feAddr.String(), err) } feL3n4Addr256Sum, err := feL3n4Addr.L3n4Addr.SHA256Sum() if err != nil { return fmt.Errorf("unable to calculate SHA256Sum of %s: %s", feL3n4Addr.String(), err) } if feAddr256Sum != feL3n4Addr256Sum { return fmt.Errorf("service ID %d is already registered to service %s, please choose a different ID", feL3n4Addr.ID, feAddr.String()) } return d.svcAdd(feL3n4Addr, beL3n4Addr, addRevNAT) }
// DeleteL3n4AddrIDBySHA256 deletes the L3n4AddrID that belong to the serviceL4ID' // sha256Sum. func (d *Daemon) DeleteL3n4AddrIDBySHA256(sha256Sum string) error { if sha256Sum == "" { return nil } svcPath := path.Join(common.ServicesKeyPath, sha256Sum) // Lock that sha256Sum lockKey, err := d.kvClient.LockPath(svcPath) if err != nil { return err } defer lockKey.Unlock() // After lock complete, get label's path rmsg, err := d.kvClient.GetValue(svcPath) if err != nil { return err } if rmsg == nil { return nil } var l3n4AddrID types.L3n4AddrID if err := json.Unmarshal(rmsg, &l3n4AddrID); err != nil { return err } oldL3n4ID := l3n4AddrID.ID l3n4AddrID.ID = 0 // update the value in the kvstore if err := d.updateL3n4AddrIDRef(oldL3n4ID, l3n4AddrID); err != nil { return err } return d.kvClient.SetValue(svcPath, l3n4AddrID) }
func cliUpdateService(ctx *cli.Context) { feL3n4Addr := parseServiceKey(ctx.String("frontend")) backends := []types.L3n4Addr{} fe := types.L3n4AddrID{ ID: types.ServiceID(ctx.Int("id")), L3n4Addr: *feL3n4Addr, } backendList := ctx.StringSlice("backend") if len(backendList) == 0 { fmt.Printf("Reading backend list from stdin...\n") scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { backendList = append(backendList, scanner.Text()) } } for _, backend := range backendList { beAddr, err := net.ResolveTCPAddr("tcp", backend) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } be, err := types.NewL3n4Addr(types.TCP, beAddr.IP, uint16(beAddr.Port)) if err != nil { fmt.Fprintf(os.Stderr, "Unable to create a new L3n4Addr for backend %s: %s\n", backend, err) os.Exit(1) } if !be.IsIPv6() && fe.IsIPv6() { fmt.Fprintf(os.Stderr, "Address mismatch between frontend and backend %s\n", backend) os.Exit(1) } if fe.Port == 0 && beAddr.Port != 0 { fmt.Fprintf(os.Stderr, "L4 backend found (%v) with L3 frontend\n", beAddr) os.Exit(1) } backends = append(backends, *be) } if err := client.SVCAdd(fe, backends, addRev); err != nil { fmt.Fprintf(os.Stderr, "Unable to add the service: %s\n", err) os.Exit(1) } fmt.Printf("Added %d backends\n", len(backends)) }
func (c *ConsulClient) GASNewL3n4AddrID(basePath string, baseID uint32, lAddrID *types.L3n4AddrID) error { setIDtoL3n4Addr := func(lockPair *consulAPI.KVPair) error { defer c.KV().Release(lockPair, nil) lAddrID.ID = types.ServiceID(baseID) keyPath := path.Join(basePath, strconv.FormatUint(uint64(lAddrID.ID), 10)) if err := c.SetValue(keyPath, lAddrID); err != nil { return err } return c.setMaxL3n4AddrID(baseID + 1) } session, _, err := c.Session().CreateNoChecks(nil, nil) if err != nil { return err } beginning := baseID for { log.Debugf("Trying to aquire a new free ID %d", baseID) keyPath := path.Join(basePath, strconv.FormatUint(uint64(baseID), 10)) lockPair := &consulAPI.KVPair{Key: GetLockPath(keyPath), Session: session} acq, _, err := c.KV().Acquire(lockPair, nil) if err != nil { return err } if acq { svcKey, _, err := c.KV().Get(keyPath, nil) if err != nil { c.KV().Release(lockPair, nil) return err } if svcKey == nil { return setIDtoL3n4Addr(lockPair) } var consulL3n4AddrID types.L3n4AddrID if err := json.Unmarshal(svcKey.Value, &consulL3n4AddrID); err != nil { c.KV().Release(lockPair, nil) return err } if consulL3n4AddrID.ID == 0 { log.Infof("Recycling Service ID %d", baseID) return setIDtoL3n4Addr(lockPair) } c.KV().Release(lockPair, nil) } baseID++ if baseID > common.MaxSetOfServiceID { baseID = common.FirstFreeServiceID } if beginning == baseID { return fmt.Errorf("reached maximum set of serviceIDs available.") } } }
// GASNewL3n4AddrID gets the next available ServiceID and sets it in lAddrID. After // assigning the ServiceID to lAddrID it sets the ServiceID + 1 in // common.LastFreeServiceIDKeyPath path. func (e *EtcdClient) GASNewL3n4AddrID(basePath string, baseID uint32, lAddrID *types.L3n4AddrID) error { setIDtoL3n4Addr := func(id uint32) error { lAddrID.ID = types.ServiceID(id) keyPath := path.Join(basePath, strconv.FormatUint(uint64(lAddrID.ID), 10)) if err := e.SetValue(keyPath, lAddrID); err != nil { return err } return e.setMaxL3n4AddrID(id + 1) } acquireFreeID := func(firstID uint32, incID *uint32) error { log.Debugf("Trying to acquire a new free ID %d", *incID) keyPath := path.Join(basePath, strconv.FormatUint(uint64(*incID), 10)) locker, err := e.LockPath(GetLockPath(keyPath)) if err != nil { return err } defer locker.Unlock() value, err := e.GetValue(keyPath) if err != nil { return err } if value == nil { return setIDtoL3n4Addr(*incID) } var consulL3n4AddrID types.L3n4AddrID if err := json.Unmarshal(value, &consulL3n4AddrID); err != nil { return err } if consulL3n4AddrID.ID == 0 { log.Infof("Recycling Service ID %d", *incID) return setIDtoL3n4Addr(*incID) } *incID++ if *incID > common.MaxSetOfServiceID { *incID = common.FirstFreeServiceID } if firstID == *incID { return fmt.Errorf("reached maximum set of serviceIDs available.") } return nil } var err error beginning := baseID for { if err = acquireFreeID(beginning, &baseID); err != nil { return err } else if beginning == baseID { return nil } } }
// PutL3n4Addr stores the given service in the kvstore and returns the L3n4AddrID // created for the given l3n4Addr. If baseID is different than 0, it tries to acquire that // ID to the l3n4Addr. func (d *Daemon) PutL3n4Addr(l3n4Addr types.L3n4Addr, baseID uint32) (*types.L3n4AddrID, error) { log.Debugf("Resolving service %+v", l3n4Addr) // Retrieve unique SHA256Sum for service sha256Sum, err := l3n4Addr.SHA256Sum() if err != nil { return nil, err } svcPath := path.Join(common.ServicesKeyPath, sha256Sum) // Lock that sha256Sum lockKey, err := d.kvClient.LockPath(svcPath) if err != nil { return nil, err } defer lockKey.Unlock() // After lock complete, get svc's path rmsg, err := d.kvClient.GetValue(svcPath) if err != nil { return nil, err } sl4KV := types.L3n4AddrID{} if rmsg != nil { if err := json.Unmarshal(rmsg, &sl4KV); err != nil { return nil, err } } if sl4KV.ID == 0 { sl4KV.L3n4Addr = l3n4Addr if err := d.gasNewL3n4AddrID(&sl4KV, baseID); err != nil { return nil, err } err = d.kvClient.SetValue(svcPath, sl4KV) } return &sl4KV, err }