Example #1
0
// AddMetadata adds metadata to the announcement of the specified service
func (s *RedisAnnouncementStore) AddMetadata(serviceName, serviceID string, metadata ...Metadata) error {
	key := fmt.Sprintf("%s:%s", serviceName, serviceID)

	metadataStrings := make([]string, 0, len(metadata))
	for _, meta := range metadata {
		txt, err := meta.MarshalText()
		if err != nil {
			return err
		}
		metadataStrings = append(metadataStrings, string(txt))

		switch meta := meta.(type) {
		case AppIDMetadata:
			existing, err := s.byAppID.Get(meta.AppID)
			switch {
			case errors.GetErrType(err) == errors.NotFound:
				if err := s.byAppID.Create(meta.AppID, key); err != nil {
					return err
				}
			case err != nil:
				return err
			case existing == key:
				continue
			default:
				go s.metadata.Remove(existing, string(txt))
				if err := s.byAppID.Update(meta.AppID, key); err != nil {
					return err
				}
			}
		case AppEUIMetadata:
			existing, err := s.byAppEUI.Get(meta.AppEUI.String())
			switch {
			case errors.GetErrType(err) == errors.NotFound:
				if err := s.byAppEUI.Create(meta.AppEUI.String(), key); err != nil {
					return err
				}
			case err != nil:
				return err
			case existing == key:
				continue
			default:
				go s.metadata.Remove(existing, string(txt))
				if err := s.byAppEUI.Update(meta.AppEUI.String(), key); err != nil {
					return err
				}
			}
		}
	}
	err := s.metadata.Add(key, metadataStrings...)
	if err != nil {
		return err
	}
	return nil
}
Example #2
0
func (h *handlerManager) DeleteDevice(ctx context.Context, in *pb.DeviceIdentifier) (*empty.Empty, error) {
	if err := in.Validate(); err != nil {
		return nil, errors.Wrap(err, "Invalid Device Identifier")
	}
	ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId)
	if err != nil {
		return nil, err
	}
	if !claims.AppRight(in.AppId, rights.Devices) {
		return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId))
	}

	if _, err := h.handler.applications.Get(in.AppId); err != nil {
		return nil, errors.Wrap(err, "Application not registered to this Handler")
	}

	dev, err := h.handler.devices.Get(in.AppId, in.DevId)
	if err != nil {
		return nil, err
	}
	_, err = h.deviceManager.DeleteDevice(ctx, &pb_lorawan.DeviceIdentifier{AppEui: &dev.AppEUI, DevEui: &dev.DevEUI})
	if err != nil && errors.GetErrType(errors.FromGRPCError(err)) != errors.NotFound {
		return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not delete device")
	}
	err = h.handler.devices.Delete(in.AppId, in.DevId)
	if err != nil {
		return nil, err
	}
	return &empty.Empty{}, nil
}
Example #3
0
// Set a new Announcement or update an existing one
// The metadata of the announcement is ignored, as metadata should be managed with AddMetadata and RemoveMetadata
func (s *RedisAnnouncementStore) Set(new *Announcement) error {
	key := fmt.Sprintf("%s:%s", new.ServiceName, new.ID)
	now := time.Now()
	new.UpdatedAt = now
	err := s.store.Update(key, *new)
	if errors.GetErrType(err) == errors.NotFound {
		new.CreatedAt = now
		err = s.store.Create(key, *new)
	}
	if err != nil {
		return err
	}
	return nil
}
Example #4
0
func (n *networkServerManager) SetDevice(ctx context.Context, in *pb_lorawan.Device) (*empty.Empty, error) {
	dev, err := n.getDevice(ctx, &pb_lorawan.DeviceIdentifier{AppEui: in.AppEui, DevEui: in.DevEui})
	if err != nil && errors.GetErrType(err) != errors.NotFound {
		return nil, err
	}

	if err := in.Validate(); err != nil {
		return nil, errors.Wrap(err, "Invalid Device")
	}

	claims, err := n.networkServer.Component.ValidateTTNAuthContext(ctx)
	if err != nil {
		return nil, err
	}
	if !claims.AppRight(in.AppId, rights.AppSettings) {
		return nil, errors.NewErrPermissionDenied(fmt.Sprintf("No access to Application %s", dev.AppID))
	}

	if dev == nil {
		dev = new(device.Device)
	} else {
		dev.StartUpdate()
	}

	dev.AppID = in.AppId
	dev.AppEUI = *in.AppEui
	dev.DevID = in.DevId
	dev.DevEUI = *in.DevEui
	dev.FCntUp = in.FCntUp
	dev.FCntDown = in.FCntDown

	dev.Options = device.Options{
		DisableFCntCheck:      in.DisableFCntCheck,
		Uses32BitFCnt:         in.Uses32BitFCnt,
		ActivationConstraints: in.ActivationConstraints,
	}

	if in.NwkSKey != nil && in.DevAddr != nil {
		dev.DevAddr = *in.DevAddr
		dev.NwkSKey = *in.NwkSKey
	}

	err = n.networkServer.devices.Set(dev)
	if err != nil {
		return nil, err
	}

	return &empty.Empty{}, nil
}
Example #5
0
// Delete an Announcement and its metadata
func (s *RedisAnnouncementStore) Delete(serviceName, serviceID string) error {
	metadata, err := s.GetMetadata(serviceName, serviceID)
	if err != nil && errors.GetErrType(err) != errors.NotFound {
		return err
	}
	if len(metadata) > 0 {
		s.RemoveMetadata(serviceName, serviceID, metadata...)
	}
	key := fmt.Sprintf("%s:%s", serviceName, serviceID)
	err = s.store.Delete(key)
	if err != nil {
		return err
	}
	return nil
}
Example #6
0
// GetMetadata returns the metadata of the specified service
func (s *RedisAnnouncementStore) GetMetadata(serviceName, serviceID string) ([]Metadata, error) {
	var out []Metadata
	metadata, err := s.metadata.Get(fmt.Sprintf("%s:%s", serviceName, serviceID))
	if errors.GetErrType(err) == errors.NotFound {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	for _, meta := range metadata {
		if meta := MetadataFromString(meta); meta != nil {
			out = append(out, meta)
		}
	}
	return out, nil
}
Example #7
0
func (h *handlerManager) RegisterApplication(ctx context.Context, in *pb.ApplicationIdentifier) (*empty.Empty, error) {
	if err := in.Validate(); err != nil {
		return nil, errors.Wrap(err, "Invalid Application Identifier")
	}
	ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId)
	if err != nil {
		return nil, err
	}
	if !claims.AppRight(in.AppId, rights.AppSettings) {
		return nil, errors.NewErrPermissionDenied(`No "settings" rights to application`)
	}
	app, err := h.handler.applications.Get(in.AppId)
	if err != nil && errors.GetErrType(err) != errors.NotFound {
		return nil, err
	}
	if app != nil {
		return nil, errors.NewErrAlreadyExists("Application")
	}

	err = h.handler.applications.Set(&application.Application{
		AppID: in.AppId,
	})
	if err != nil {
		return nil, err
	}

	token, _ := api.TokenFromContext(ctx)
	err = h.handler.Discovery.AddAppID(in.AppId, token)
	if err != nil {
		h.handler.Ctx.WithField("AppID", in.AppId).WithError(err).Warn("Could not register Application with Discovery")
	}

	_, err = h.handler.ttnBrokerManager.RegisterApplicationHandler(ctx, &pb_broker.ApplicationHandlerRegistration{
		AppId:     in.AppId,
		HandlerId: h.handler.Identity.Id,
	})
	if err != nil {
		h.handler.Ctx.WithField("AppID", in.AppId).WithError(err).Warn("Could not register Application with Broker")
	}

	return &empty.Empty{}, nil

}
Example #8
0
// ListForAddress lists all devices for a specific DevAddr
func (s *RedisDeviceStore) ListForAddress(devAddr types.DevAddr) ([]*Device, error) {
	deviceKeys, err := s.devAddrIndex.Get(devAddr.String())
	if errors.GetErrType(err) == errors.NotFound {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	devicesI, err := s.store.GetAll(deviceKeys, nil)
	if err != nil {
		return nil, err
	}
	devices := make([]*Device, 0, len(devicesI))
	for _, deviceI := range devicesI {
		if device, ok := deviceI.(Device); ok {
			devices = append(devices, &device)
		}
	}
	return devices, nil
}
Example #9
0
func (d *discovery) Announce(in *pb.Announcement) error {
	service, err := d.services.Get(in.ServiceName, in.Id)
	if err != nil && errors.GetErrType(err) != errors.NotFound {
		return err
	}
	if service == nil {
		service = new(announcement.Announcement)
	}

	service.StartUpdate()

	service.ID = in.Id
	service.ServiceName = in.ServiceName
	service.ServiceVersion = in.ServiceVersion
	service.Description = in.Description
	service.URL = in.Url
	service.Public = in.Public
	service.NetAddress = in.NetAddress
	service.PublicKey = in.PublicKey
	service.Certificate = in.Certificate
	service.APIAddress = in.ApiAddress

	return d.services.Set(service)
}
Example #10
0
func (h *handlerManager) GetDevice(ctx context.Context, in *pb.DeviceIdentifier) (*pb.Device, error) {
	if err := in.Validate(); err != nil {
		return nil, errors.Wrap(err, "Invalid Device Identifier")
	}

	ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId)
	if err != nil {
		return nil, err
	}
	if !claims.AppRight(in.AppId, rights.Devices) {
		return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId))
	}

	if _, err := h.handler.applications.Get(in.AppId); err != nil {
		return nil, errors.Wrap(err, "Application not registered to this Handler")
	}

	dev, err := h.handler.devices.Get(in.AppId, in.DevId)
	if err != nil {
		return nil, err
	}

	pbDev := &pb.Device{
		AppId: dev.AppID,
		DevId: dev.DevID,
		Device: &pb.Device_LorawanDevice{LorawanDevice: &pb_lorawan.Device{
			AppId:                 dev.AppID,
			AppEui:                &dev.AppEUI,
			DevId:                 dev.DevID,
			DevEui:                &dev.DevEUI,
			DevAddr:               &dev.DevAddr,
			NwkSKey:               &dev.NwkSKey,
			AppSKey:               &dev.AppSKey,
			AppKey:                &dev.AppKey,
			DisableFCntCheck:      dev.Options.DisableFCntCheck,
			Uses32BitFCnt:         dev.Options.Uses32BitFCnt,
			ActivationConstraints: dev.Options.ActivationConstraints,
		}},
	}

	nsDev, err := h.deviceManager.GetDevice(ctx, &pb_lorawan.DeviceIdentifier{
		AppEui: &dev.AppEUI,
		DevEui: &dev.DevEUI,
	})
	if errors.GetErrType(errors.FromGRPCError(err)) == errors.NotFound {
		// Re-register the device in the Broker (NetworkServer)
		h.handler.Ctx.WithFields(log.Fields{
			"AppID":  dev.AppID,
			"DevID":  dev.DevID,
			"AppEUI": dev.AppEUI,
			"DevEUI": dev.DevEUI,
		}).Warn("Re-registering missing device to Broker")
		nsDev = dev.GetLoRaWAN()
		_, err = h.deviceManager.SetDevice(ctx, nsDev)
		if err != nil {
			return nil, errors.Wrap(errors.FromGRPCError(err), "Could not re-register missing device to Broker")
		}
	} else if err != nil {
		return pbDev, errors.Wrap(errors.FromGRPCError(err), "Broker did not return device")
	}

	pbDev.GetLorawanDevice().FCntUp = nsDev.FCntUp
	pbDev.GetLorawanDevice().FCntDown = nsDev.FCntDown
	pbDev.GetLorawanDevice().LastSeen = nsDev.LastSeen

	return pbDev, nil
}
Example #11
0
func (h *handlerManager) SetDevice(ctx context.Context, in *pb.Device) (*empty.Empty, error) {
	if err := in.Validate(); err != nil {
		return nil, errors.Wrap(err, "Invalid Device")
	}

	ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId)
	if err != nil {
		return nil, err
	}
	if !claims.AppRight(in.AppId, rights.Devices) {
		return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId))
	}

	if _, err := h.handler.applications.Get(in.AppId); err != nil {
		return nil, errors.Wrap(err, "Application not registered to this Handler")
	}

	dev, err := h.handler.devices.Get(in.AppId, in.DevId)
	if err != nil && errors.GetErrType(err) != errors.NotFound {
		return nil, err
	}

	lorawan := in.GetLorawanDevice()
	if lorawan == nil {
		return nil, errors.NewErrInvalidArgument("Device", "No LoRaWAN Device")
	}

	if dev != nil { // When this is an update
		if dev.AppEUI != *lorawan.AppEui || dev.DevEUI != *lorawan.DevEui {
			// If the AppEUI or DevEUI is changed, we should remove the device from the NetworkServer and re-add it later
			_, err = h.deviceManager.DeleteDevice(ctx, &pb_lorawan.DeviceIdentifier{
				AppEui: &dev.AppEUI,
				DevEui: &dev.DevEUI,
			})
			if err != nil {
				return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not delete device")
			}
		}
		dev.StartUpdate()
	} else { // When this is a create
		existingDevices, err := h.handler.devices.ListForApp(in.AppId)
		if err != nil {
			return nil, err
		}
		for _, existingDevice := range existingDevices {
			if existingDevice.AppEUI == *lorawan.AppEui && existingDevice.DevEUI == *lorawan.DevEui {
				return nil, errors.NewErrAlreadyExists("Device with AppEUI and DevEUI")
			}
		}
		dev = new(device.Device)
	}

	dev.AppID = in.AppId
	dev.AppEUI = *lorawan.AppEui
	dev.DevID = in.DevId
	dev.DevEUI = *lorawan.DevEui

	dev.Options = device.Options{
		DisableFCntCheck:      lorawan.DisableFCntCheck,
		Uses32BitFCnt:         lorawan.Uses32BitFCnt,
		ActivationConstraints: lorawan.ActivationConstraints,
	}
	if dev.Options.ActivationConstraints == "" {
		dev.Options.ActivationConstraints = "local"
	}

	if lorawan.DevAddr != nil {
		dev.DevAddr = *lorawan.DevAddr
	}
	if lorawan.NwkSKey != nil {
		dev.NwkSKey = *lorawan.NwkSKey
	}
	if lorawan.AppSKey != nil {
		dev.AppSKey = *lorawan.AppSKey
	}

	if lorawan.AppKey != nil {
		if dev.AppKey != *lorawan.AppKey { // When the AppKey of an existing device is changed
			dev.UsedAppNonces = []device.AppNonce{}
			dev.UsedDevNonces = []device.DevNonce{}
		}
		dev.AppKey = *lorawan.AppKey
	}

	// Update the device in the Broker (NetworkServer)
	nsUpdated := dev.GetLoRaWAN()
	nsUpdated.FCntUp = lorawan.FCntUp
	nsUpdated.FCntDown = lorawan.FCntDown

	_, err = h.deviceManager.SetDevice(ctx, nsUpdated)
	if err != nil {
		return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not set device")
	}

	err = h.handler.devices.Set(dev)
	if err != nil {
		return nil, err
	}

	return &empty.Empty{}, nil
}
func TestRedisKVStore(t *testing.T) {
	a := New(t)
	c := getRedisClient()
	s := NewRedisKVStore(c, "test-redis-kv-store")
	a.So(s, ShouldNotBeNil)

	// Get non-existing
	{
		_, err := s.Get("test")
		a.So(err, ShouldNotBeNil)
		a.So(errors.GetErrType(err), ShouldEqual, errors.NotFound)
	}

	// Create New
	{
		defer func() {
			c.Del("test-redis-kv-store:test").Result()
		}()
		err := s.Create("test", "value")
		a.So(err, ShouldBeNil)

		exists, err := c.Exists("test-redis-kv-store:test").Result()
		a.So(err, ShouldBeNil)
		a.So(exists, ShouldBeTrue)
	}

	// Create Existing
	{
		err := s.Create("test", "value")
		a.So(err, ShouldNotBeNil)
	}

	// Get
	{
		res, err := s.Get("test")
		a.So(err, ShouldBeNil)
		a.So(res, ShouldEqual, "value")
	}

	for i := 1; i < 10; i++ {
		// Create Extra
		{
			name := fmt.Sprintf("test-%d", i)
			defer func() {
				c.Del("test-redis-kv-store:" + name).Result()
			}()
			s.Create(name, name)
		}
	}

	// GetAll
	{
		res, err := s.GetAll([]string{"test"}, nil)
		a.So(err, ShouldBeNil)
		a.So(res, ShouldHaveLength, 1)
		a.So(res["test"], ShouldEqual, "value")
	}

	// List
	{
		res, err := s.List("", nil)
		a.So(err, ShouldBeNil)
		a.So(res, ShouldHaveLength, 10)
		a.So(res["test"], ShouldEqual, "value")
	}

	// List With Options
	{
		res, _ := s.List("test-*", &ListOptions{Limit: 2})
		a.So(res, ShouldHaveLength, 2)
		a.So(res["test-1"], ShouldEqual, "test-1")
		a.So(res["test-2"], ShouldEqual, "test-2")

		res, _ = s.List("test-*", &ListOptions{Limit: 20})
		a.So(res, ShouldHaveLength, 9)

		res, _ = s.List("test-*", &ListOptions{Offset: 20})
		a.So(res, ShouldHaveLength, 0)

		res, _ = s.List("test-*", &ListOptions{Limit: 2, Offset: 1})
		a.So(res, ShouldHaveLength, 2)
		a.So(res["test-2"], ShouldEqual, "test-2")
		a.So(res["test-3"], ShouldEqual, "test-3")

		res, _ = s.List("test-*", &ListOptions{Limit: 20, Offset: 1})
		a.So(res, ShouldHaveLength, 8)
	}

	// Update Non-Existing
	{
		err := s.Update("not-there", "value")
		a.So(err, ShouldNotBeNil)
	}

	// Update Existing
	{
		err := s.Update("test", "updated")
		a.So(err, ShouldBeNil)

		name, err := c.Get("test-redis-kv-store:test").Result()
		a.So(err, ShouldBeNil)
		a.So(name, ShouldEqual, "updated")
	}

	// Delete Non-Existing
	{
		err := s.Delete("not-there")
		a.So(err, ShouldNotBeNil)
	}

	// Delete Existing
	{
		err := s.Delete("test")
		a.So(err, ShouldBeNil)

		exists, err := c.Exists("test-redis-kv-store:test").Result()
		a.So(err, ShouldBeNil)
		a.So(exists, ShouldBeFalse)
	}

}
func TestRedisMapStore(t *testing.T) {
	a := New(t)
	c := getRedisClient()
	s := NewRedisMapStore(c, "test-redis-map-store")
	a.So(s, ShouldNotBeNil)

	now := time.Now()
	notEmpty := map[string]string{"ab": "cd"}
	testRedisStructVal := testRedisStruct{
		Name:      "My Name",
		UpdatedAt: Time{now},
		NotEmpty:  &notEmpty,
	}

	s.SetBase(testRedisStructVal, "")

	// Get non-existing
	{
		res, err := s.Get("test")
		a.So(err, ShouldNotBeNil)
		a.So(errors.GetErrType(err), ShouldEqual, errors.NotFound)
		a.So(res, ShouldBeNil)
	}

	// Create New
	{
		defer func() {
			c.Del("test-redis-map-store:test").Result()
		}()
		err := s.Create("test", &testRedisStructVal)
		a.So(err, ShouldBeNil)

		exists, err := c.Exists("test-redis-map-store:test").Result()
		a.So(err, ShouldBeNil)
		a.So(exists, ShouldBeTrue)
	}

	// Create Existing
	{
		err := s.Create("test", testRedisStructVal)
		a.So(err, ShouldNotBeNil)
	}

	// Get
	{
		res, err := s.Get("test")
		a.So(err, ShouldBeNil)
		a.So(res, ShouldNotBeNil)
		a.So(res.(testRedisStruct).Name, ShouldEqual, "My Name")
		a.So(res.(testRedisStruct).UpdatedAt.Nanosecond(), ShouldEqual, now.Nanosecond())
	}

	// GetFields
	{
		res, err := s.GetFields("test", "name")
		a.So(err, ShouldBeNil)
		a.So(res, ShouldNotBeNil)
		a.So(res.(testRedisStruct).Name, ShouldEqual, "My Name")
	}

	for i := 1; i < 10; i++ {
		// Create Extra
		{
			name := fmt.Sprintf("test-%d", i)
			defer func() {
				c.Del("test-redis-map-store:" + name).Result()
			}()
			s.Create(name, testRedisStruct{
				Name: name,
			})
		}
	}

	// GetAll
	{
		res, err := s.GetAll([]string{"test"}, nil)
		a.So(err, ShouldBeNil)
		a.So(res, ShouldHaveLength, 1)
		a.So(res[0].(testRedisStruct).Name, ShouldEqual, "My Name")
	}

	// List
	{
		res, err := s.List("", nil)
		a.So(err, ShouldBeNil)
		a.So(res, ShouldHaveLength, 10)
		a.So(res[0].(testRedisStruct).Name, ShouldEqual, "My Name")
	}

	// List With Options
	{
		res, _ := s.List("test-*", &ListOptions{Limit: 2})
		a.So(res, ShouldHaveLength, 2)
		a.So(res[0].(testRedisStruct).Name, ShouldEqual, "test-1")
		a.So(res[1].(testRedisStruct).Name, ShouldEqual, "test-2")

		res, _ = s.List("test-*", &ListOptions{Limit: 20})
		a.So(res, ShouldHaveLength, 9)

		res, _ = s.List("test-*", &ListOptions{Offset: 20})
		a.So(res, ShouldHaveLength, 0)

		res, _ = s.List("test-*", &ListOptions{Limit: 2, Offset: 1})
		a.So(res, ShouldHaveLength, 2)
		a.So(res[0].(testRedisStruct).Name, ShouldEqual, "test-2")
		a.So(res[1].(testRedisStruct).Name, ShouldEqual, "test-3")

		res, _ = s.List("test-*", &ListOptions{Limit: 20, Offset: 1})
		a.So(res, ShouldHaveLength, 8)
	}

	// Update Non-Existing
	{
		err := s.Update("not-there", &testRedisStructVal)
		a.So(err, ShouldNotBeNil)
	}

	// Update Existing
	{
		err := s.Update("test", &testRedisStruct{
			Name: "New Name",
		}, "Name")
		a.So(err, ShouldBeNil)

		name, err := c.HGet("test-redis-map-store:test", "name").Result()
		a.So(err, ShouldBeNil)
		a.So(name, ShouldEqual, "New Name")
	}

	// Delete Non-Existing
	{
		err := s.Delete("not-there")
		a.So(err, ShouldNotBeNil)
	}

	// Delete Existing
	{
		err := s.Delete("test")
		a.So(err, ShouldBeNil)

		exists, err := c.Exists("test-redis-map-store:test").Result()
		a.So(err, ShouldBeNil)
		a.So(exists, ShouldBeFalse)
	}

}