Example #1
0
func (e *etcd) SaveTcpRouteMapping(tcpMapping models.TcpRouteMapping) error {
	key := generateTcpRouteMappingKey(tcpMapping)

	retries := 0
	for retries <= maxRetries {
		response, err := e.keysAPI.Get(context.Background(), key, readOpts())

		// Update
		if response != nil && err == nil {
			var existingTcpRouteMapping models.TcpRouteMapping

			err = json.Unmarshal([]byte(response.Node.Value), &existingTcpRouteMapping)
			if err != nil {
				return err
			}

			tcpMapping.ModificationTag = existingTcpRouteMapping.ModificationTag
			tcpMapping.ModificationTag.Increment()

			tcpRouteJSON, _ := json.Marshal(tcpMapping)
			_, err = e.keysAPI.Set(ctx(), key, string(tcpRouteJSON), updateOptsWithTTL(int(tcpMapping.TTL), response.Node.ModifiedIndex))
		} else if cerr, ok := err.(client.Error); ok && cerr.Code == client.ErrorCodeKeyNotFound { //create
			// Delete came in between a read and update
			if retries > 0 {
				return ErrorConflict
			}

			var tag models.ModificationTag
			tag, err = models.NewModificationTag()
			if err != nil {
				return err
			}

			tcpMapping.ModificationTag = tag
			tcpRouteMappingJSON, _ := json.Marshal(tcpMapping)
			_, err = e.keysAPI.Set(ctx(), key, string(tcpRouteMappingJSON), createOpts(int(tcpMapping.TTL)))
		}

		// return when create or update is successful
		if err == nil {
			return nil
		}

		// only retry on a compare and swap error
		if cerr, ok := err.(client.Error); ok && cerr.Code == client.ErrorCodeTestFailed {
			retries++
		} else {
			return err
		}
	}

	// number of retries exceeded
	return ErrorConflict
}
Example #2
0
func (e *etcd) DeleteTcpRouteMapping(tcpMapping models.TcpRouteMapping) error {
	key := generateTcpRouteMappingKey(tcpMapping)
	deleteOpt := &client.DeleteOptions{}
	_, err := e.keysAPI.Delete(context.Background(), key, deleteOpt)

	if err != nil {
		cerr, ok := err.(client.Error)
		if ok && cerr.Code == client.ErrorCodeKeyNotFound {
			err = DBError{Type: KeyNotFound, Message: "The specified route (" + tcpMapping.String() + ") could not be found."}
		}
	}

	return err
}
Example #3
0
func validateTcpRouteMapping(tcpRouteMapping models.TcpRouteMapping, checkTTL bool, maxTTL uint16) *routing_api.Error {
	if tcpRouteMapping.TcpRoute.RouterGroupGuid == "" {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp mapping requires a non empty router group guid. RouteMapping=["+tcpRouteMapping.String()+"]")
		return &err
	}

	if tcpRouteMapping.TcpRoute.ExternalPort <= 0 {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp mapping requires a positive external port. RouteMapping=["+tcpRouteMapping.String()+"]")
		return &err
	}

	if tcpRouteMapping.HostIP == "" {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp mapping requires a non empty backend ip. RouteMapping=["+tcpRouteMapping.String()+"]")
		return &err
	}

	if tcpRouteMapping.HostPort <= 0 {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp mapping requires a positive backend port. RouteMapping=["+tcpRouteMapping.String()+"]")
		return &err
	}

	if checkTTL && tcpRouteMapping.TTL > maxTTL {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp mapping requires TTL to be less than or equal to "+strconv.Itoa(int(maxTTL))+". RouteMapping=["+tcpRouteMapping.String()+"]")
		return &err
	}

	if checkTTL && tcpRouteMapping.TTL <= 0 {
		err := routing_api.NewError(routing_api.TcpRouteMappingInvalidError,
			"Each tcp route mapping requires a ttl greater than 0")
		return &err
	}

	return nil
}
Example #4
0
				Expect(err.Error()).To(Equal("Each route request requires a port greater than 0"))
			})

			It("returns an error if any request does not have an IP", func() {
				routes[1].IP = ""

				err := validator.ValidateDelete(routes)
				Expect(err.Type).To(Equal(routing_api.RouteInvalidError))
				Expect(err.Error()).To(Equal("Each route request requires an IP"))
			})
		})
	})

	Describe("ValidateCreateTcpRouteMapping", func() {
		var (
			tcpMapping   models.TcpRouteMapping
			routerGroups models.RouterGroups
		)

		BeforeEach(func() {
			routerGroups = models.RouterGroups{
				{
					Guid:            DefaultRouterGroupGuid,
					Name:            "default-tcp",
					Type:            "tcp",
					ReservablePorts: "1024-65535",
				},
			}
			tcpMapping = models.NewTcpRouteMapping(DefaultRouterGroupGuid, 52000, "1.2.3.4", 60000, 60)
		})

		Context("when valid tcp mapping is passed", func() {
Example #5
0
					BeforeEach(func() {
						fakeKeysAPI.DeleteReturns(nil, errors.New("some network error"))
					})

					It("returns network error", func() {
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("some network error"))
						Expect(fakeKeysAPI.DeleteCallCount()).To(Equal(1))
					})
				})
			})
		})

		Describe("Tcp Mappings", func() {
			var (
				tcpMapping models.TcpRouteMapping
			)

			BeforeEach(func() {
				tcpMapping = models.NewTcpRouteMapping("router-group-guid-001", 52000, "1.2.3.4", 60000, 50)
			})

			Describe("SaveTcpRouteMapping", func() {
				Context("when there's no existing entry", func() {
					BeforeEach(func() {
						keyNotFoundError := client.Error{Code: client.ErrorCodeKeyNotFound}
						fakeKeysAPI.GetReturns(nil, keyNotFoundError)
					})

					It("Creates a mapping if none exist", func() {
						err := fakeEtcd.SaveTcpRouteMapping(tcpMapping)