Example #1
0
// 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)
}
Example #2
0
// 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)
}
Example #3
0
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))
}
Example #4
0
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.")
		}
	}
}
Example #5
0
// 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
		}
	}
}
Example #6
0
// 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
}