Skip to content

Commit

Permalink
dcs: Set last known location on claim
Browse files Browse the repository at this point in the history
  • Loading branch information
johanstokking committed Aug 26, 2024
1 parent 9aa559b commit 513fa47
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 35 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ require (
go.packetbroker.org/api/mapping/v2 v2.3.2
go.packetbroker.org/api/routing v1.9.2
go.packetbroker.org/api/v3 v3.17.1
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e
go.thethings.network/lorawan-stack-legacy/v2 v2.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ go.packetbroker.org/api/routing v1.9.2 h1:J4+4vYZxa60UWC70Y9yy7sktU7DXaAp9Q13Bfq
go.packetbroker.org/api/routing v1.9.2/go.mod h1:kd2K7gieDI35YfPA8/zDmLX3qiKPuXia/MA77BEAeUA=
go.packetbroker.org/api/v3 v3.17.1 h1:LcyFPUGqVubGWMvQ16tZlQIKd+noGx7urzEYhSLiEQA=
go.packetbroker.org/api/v3 v3.17.1/go.mod h1:6bVbdWAYLnvZ5kgXxA7GBQvZTN7vxI0DoF1Di1NoAT4=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd h1:FvD516hdD/iWqoS20SFdcoiUgwRJP3egNXNiN+Ux2d0=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5 h1:w4NvcBAq7JCwlfthvGw1PRWuI6pCf5TlIjKgFHKml8M=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df h1:IMSctPllwEtJLyM/1AWgBiN1NPwBKqEVkCiK0I/MNY4=
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df/go.mod h1:89OU623VYKW9i3W4CZgIGFmtgb/jsN8JV2PAuCsj+7w=
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e h1:TWGQ3lh7gI2W5hnb6qPdpoAa0d7s/XPwvgf2VVCMJaY=
Expand Down
4 changes: 3 additions & 1 deletion pkg/deviceclaimingserver/gateways/gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ func ParseGatewayEUIRanges(conf map[string][]string) (map[string][]dcstypes.EUI6
// Claimer provides methods for claiming Gateways.
type Claimer interface {
// Claim claims a gateway.
Claim(ctx context.Context, eui types.EUI64, ownerToken string, clusterAddress string) error
Claim(
ctx context.Context, eui types.EUI64, ownerToken string, clusterAddress string,
) (*dcstypes.GatewayMetadata, error)
// Unclaim unclaims a gateway.
Unclaim(ctx context.Context, eui types.EUI64) error
// IsManagedGateway returns true if the gateway is a managed gateway.
Expand Down
47 changes: 37 additions & 10 deletions pkg/deviceclaimingserver/gateways/ttgc/ttgc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import (

northboundv1 "go.thethings.industries/pkg/api/gen/tti/gateway/controller/northbound/v1"
"go.thethings.network/lorawan-stack/v3/pkg/config/tlsconfig"
dcstypes "go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/types"
"go.thethings.network/lorawan-stack/v3/pkg/errors"
"go.thethings.network/lorawan-stack/v3/pkg/log"
"go.thethings.network/lorawan-stack/v3/pkg/ttgc"
"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
"go.thethings.network/lorawan-stack/v3/pkg/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -61,7 +64,9 @@ func New(ctx context.Context, c ttgc.Component, config ttgc.Config) (*Upstream,
// 2. Upsert a LoRa Packet Forwarder profile with the root CA presented by the given Gateway Server
// 3. Upsert a Geolocation profile
// 4. Update the gateway with the profiles
func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clusterAddress string) error {
func (u *Upstream) Claim(
ctx context.Context, eui types.EUI64, ownerToken, clusterAddress string,
) (*dcstypes.GatewayMetadata, error) {
logger := log.FromContext(ctx)

// Claim the gateway.
Expand All @@ -72,7 +77,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
OwnerToken: ownerToken,
})
if err != nil {
return err
return nil, err
}

// Get the root CA from the Gateway Server and upsert the LoRa Packet Forwarder profile.
Expand All @@ -83,7 +88,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
clusterAddress = net.JoinHostPort(host, "8889")
rootCA, err := u.getRootCA(ctx, clusterAddress)
if err != nil {
return err
return nil, err
}
var (
loraPFProfileID []byte
Expand All @@ -107,7 +112,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
if err != nil {
if status.Code(err) != codes.NotFound {
logger.WithError(err).Warn("Failed to get LoRa Packet Forwarder profile")
return err
return nil, err
}
res, err := loraPFProfileClient.Create(ctx, &northboundv1.LoraPacketForwarderProfileServiceCreateRequest{
Domain: u.client.Domain(ctx),
Expand All @@ -116,7 +121,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
})
if err != nil {
logger.WithError(err).Warn("Failed to create LoRa Packet Forwarder profile")
return err
return nil, err
}
loraPFProfileID = res.ProfileId
} else {
Expand All @@ -131,7 +136,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
})
if err != nil {
logger.WithError(err).Warn("Failed to update LoRa Packet Forwarder profile")
return err
return nil, err
}
}
loraPFProfileID = loraPFGetRes.ProfileId
Expand All @@ -158,7 +163,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
if err != nil {
if status.Code(err) != codes.NotFound {
logger.WithError(err).Warn("Failed to get geolocation profile")
return err
return nil, err
}
res, err := geolocationProfileClient.Create(ctx, &northboundv1.GeolocationProfileServiceCreateRequest{
Domain: u.client.Domain(ctx),
Expand All @@ -167,7 +172,7 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
})
if err != nil {
logger.WithError(err).Warn("Failed to create geolocation profile")
return err
return nil, err
}
geolocationProfileID = res.ProfileId
} else {
Expand All @@ -187,10 +192,29 @@ func (u *Upstream) Claim(ctx context.Context, eui types.EUI64, ownerToken, clust
})
if err != nil {
logger.WithError(err).Warn("Failed to update gateway with profiles")
return err
return nil, err
}

return nil
gatewayMetadata := &dcstypes.GatewayMetadata{}
locationRes, err := gtwClient.GetLastLocation(ctx, &northboundv1.GatewayServiceGetLastLocationRequest{
GatewayId: eui.MarshalNumber(),
Domain: u.client.Domain(ctx),
})
if err != nil && !errors.IsNotFound(err) {
logger.WithError(err).Warn("Failed to get gateway location")
} else if err == nil {
gatewayMetadata.Antennas = []*ttnpb.GatewayAntenna{
{
Location: &ttnpb.Location{
Latitude: locationRes.Location.Latitude,
Longitude: locationRes.Location.Longitude,
Accuracy: int32(locationRes.Location.Accuracy),
},
},
}
}

return gatewayMetadata, nil
}

// Unclaim implements gateways.GatewayClaimer.
Expand All @@ -201,6 +225,9 @@ func (u *Upstream) Unclaim(ctx context.Context, eui types.EUI64) error {
Domain: u.client.Domain(ctx),
})
if err != nil {
if errors.IsNotFound(err) { // The gateway does not exist or is already unclaimed.
return nil
}
return err
}
return nil
Expand Down
4 changes: 3 additions & 1 deletion pkg/deviceclaimingserver/grpc_gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ func (gcls *gatewayClaimingServer) Claim(
}

// Claim the gateway on the upstream.
if err := claimer.Claim(ctx, gatewayEUI, string(authCode), req.TargetGatewayServerAddress); err != nil {
res, err := claimer.Claim(ctx, gatewayEUI, string(authCode), req.TargetGatewayServerAddress)
if err != nil {
observability.RegisterFailClaim(ctx, ids.GetEntityIdentifiers(), err)
return nil, errClaim.WithCause(err)
}
Expand All @@ -143,6 +144,7 @@ func (gcls *gatewayClaimingServer) Claim(
EnforceDutyCycle: true,
RequireAuthenticatedConnection: true,
FrequencyPlanIds: req.TargetFrequencyPlanIds,
Antennas: res.Antennas,
}

_, err = gcls.registry.Create(ctx, &ttnpb.CreateGatewayRequest{
Expand Down
28 changes: 14 additions & 14 deletions pkg/deviceclaimingserver/grpc_gateways_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
},
})

mockGatewayclaimer := &MockGatewayClaimer{
mockGatewayClaimer := &MockGatewayClaimer{
IsManagedGatewayFunc: func(_ context.Context, e types.EUI64) (bool, error) {
return e.Equal(supportedEUI), nil
},
Expand All @@ -88,7 +88,7 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
Length: 48,
}),
},
mockGatewayclaimer,
mockGatewayClaimer,
),
)
if err != nil {
Expand Down Expand Up @@ -180,7 +180,7 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
Name string
Req *ttnpb.ClaimGatewayRequest
CallOpt grpc.CallOption
ClaimFunc func(context.Context, types.EUI64, string, string) error
ClaimFunc func(context.Context, types.EUI64, string, string) (*dcstypes.GatewayMetadata, error)
CreateFunc func(context.Context, *ttnpb.CreateGatewayRequest) (*ttnpb.Gateway, error)
UnclaimFunc func(context.Context, types.EUI64) error
ErrorAssertion func(error) bool
Expand Down Expand Up @@ -271,8 +271,8 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
TargetGatewayServerAddress: "things.example.com",
},
CallOpt: authorizedCallOpt,
ClaimFunc: func(_ context.Context, _ types.EUI64, _, _ string) error {
return errClaim.New()
ClaimFunc: func(_ context.Context, _ types.EUI64, _, _ string) (*dcstypes.GatewayMetadata, error) {
return nil, errClaim.New()
},
ErrorAssertion: errors.IsAborted,
},
Expand All @@ -290,8 +290,8 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
TargetGatewayServerAddress: "things.example.com",
},
CallOpt: authorizedCallOpt,
ClaimFunc: func(context.Context, types.EUI64, string, string) error {
return nil
ClaimFunc: func(context.Context, types.EUI64, string, string) (*dcstypes.GatewayMetadata, error) {
return &dcstypes.GatewayMetadata{}, nil
},
CreateFunc: func(context.Context, *ttnpb.CreateGatewayRequest) (*ttnpb.Gateway, error) {
return nil, errCreate.New()
Expand All @@ -318,8 +318,8 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
TargetGatewayServerAddress: "things.example.com",
},
CallOpt: authorizedCallOpt,
ClaimFunc: func(context.Context, types.EUI64, string, string) error {
return nil
ClaimFunc: func(context.Context, types.EUI64, string, string) (*dcstypes.GatewayMetadata, error) {
return &dcstypes.GatewayMetadata{}, nil
},
CreateFunc: func(context.Context, *ttnpb.CreateGatewayRequest) (*ttnpb.Gateway, error) {
return nil, errCreate.New()
Expand All @@ -342,8 +342,8 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
TargetGatewayId: "test-gateway",
TargetGatewayServerAddress: "things.example.com",
},
ClaimFunc: func(context.Context, types.EUI64, string, string) error {
return nil
ClaimFunc: func(context.Context, types.EUI64, string, string) (*dcstypes.GatewayMetadata, error) {
return &dcstypes.GatewayMetadata{}, nil
},
CreateFunc: func(_ context.Context, in *ttnpb.CreateGatewayRequest) (*ttnpb.Gateway, error) {
return in.Gateway, nil
Expand All @@ -354,10 +354,10 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
tc := tc
t.Run(tc.Name, func(t *testing.T) {
if tc.ClaimFunc != nil {
mockGatewayclaimer.ClaimFunc = tc.ClaimFunc
mockGatewayClaimer.ClaimFunc = tc.ClaimFunc
}
if tc.UnclaimFunc != nil {
mockGatewayclaimer.UnclaimFunc = tc.UnclaimFunc
mockGatewayClaimer.UnclaimFunc = tc.UnclaimFunc
}
if tc.CreateFunc != nil {
mockGatewayRegistry.createFunc = tc.CreateFunc
Expand Down Expand Up @@ -480,7 +480,7 @@ func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
tc := tc
t.Run(tc.Name, func(t *testing.T) {
if tc.UnclaimFunc != nil {
mockGatewayclaimer.UnclaimFunc = tc.UnclaimFunc
mockGatewayClaimer.UnclaimFunc = tc.UnclaimFunc
}
if tc.GetFunc != nil {
mockGatewayRegistry.getFunc = tc.GetFunc
Expand Down
10 changes: 9 additions & 1 deletion pkg/deviceclaimingserver/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
// Package types provides types for the Device Claiming Server.
package types

import "go.thethings.network/lorawan-stack/v3/pkg/types"
import (
"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
"go.thethings.network/lorawan-stack/v3/pkg/types"
)

// EUI64Range is a range of EUI64s.
type EUI64Range interface {
Expand Down Expand Up @@ -56,3 +59,8 @@ func RangeFromEUI64Range(start, end types.EUI64) EUI64Range {
end: end.MarshalNumber(),
}
}

// GatewayMetadata contains metadata of a gateway, typically returned on claiming.
type GatewayMetadata struct {
Antennas []*ttnpb.GatewayAntenna
}
5 changes: 3 additions & 2 deletions pkg/deviceclaimingserver/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package deviceclaimingserver_test
import (
"context"

dcstypes "go.thethings.network/lorawan-stack/v3/pkg/deviceclaimingserver/types"
"go.thethings.network/lorawan-stack/v3/pkg/errors"
"go.thethings.network/lorawan-stack/v3/pkg/rpcmetadata"
"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
Expand Down Expand Up @@ -80,7 +81,7 @@ func (m MockEndDeviceClaimer) BatchUnclaim(
type MockGatewayClaimer struct {
EUIs []types.EUI64

ClaimFunc func(context.Context, types.EUI64, string, string) error
ClaimFunc func(context.Context, types.EUI64, string, string) (*dcstypes.GatewayMetadata, error)
UnclaimFunc func(context.Context, types.EUI64) error
IsManagedGatewayFunc func(context.Context, types.EUI64) (bool, error)
}
Expand All @@ -91,7 +92,7 @@ func (claimer MockGatewayClaimer) Claim(
eui types.EUI64,
ownerToken string,
clusterAddress string,
) error {
) (*dcstypes.GatewayMetadata, error) {
return claimer.ClaimFunc(ctx, eui, ownerToken, clusterAddress)
}

Expand Down
2 changes: 1 addition & 1 deletion tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ require (
go.packetbroker.org/api/mapping/v2 v2.3.2 // indirect
go.packetbroker.org/api/routing v1.9.2 // indirect
go.packetbroker.org/api/v3 v3.17.1 // indirect
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd // indirect
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5 // indirect
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df // indirect
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e // indirect
go.thethings.network/lorawan-stack-legacy/v2 v2.1.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions tools/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,8 @@ go.packetbroker.org/api/routing v1.9.2 h1:J4+4vYZxa60UWC70Y9yy7sktU7DXaAp9Q13Bfq
go.packetbroker.org/api/routing v1.9.2/go.mod h1:kd2K7gieDI35YfPA8/zDmLX3qiKPuXia/MA77BEAeUA=
go.packetbroker.org/api/v3 v3.17.1 h1:LcyFPUGqVubGWMvQ16tZlQIKd+noGx7urzEYhSLiEQA=
go.packetbroker.org/api/v3 v3.17.1/go.mod h1:6bVbdWAYLnvZ5kgXxA7GBQvZTN7vxI0DoF1Di1NoAT4=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd h1:FvD516hdD/iWqoS20SFdcoiUgwRJP3egNXNiN+Ux2d0=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240729145607-ea516688afbd/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5 h1:w4NvcBAq7JCwlfthvGw1PRWuI6pCf5TlIjKgFHKml8M=
go.thethings.industries/pkg/api/gen/tti/gateway v0.0.0-20240823134410-68cd7baab6c5/go.mod h1:2+WsMwIunNLh22oauBzGL56JazE3UY34W1fstqEbacw=
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df h1:IMSctPllwEtJLyM/1AWgBiN1NPwBKqEVkCiK0I/MNY4=
go.thethings.industries/pkg/ca v0.0.0-20240809123127-21a24c0e47df/go.mod h1:89OU623VYKW9i3W4CZgIGFmtgb/jsN8JV2PAuCsj+7w=
go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e h1:TWGQ3lh7gI2W5hnb6qPdpoAa0d7s/XPwvgf2VVCMJaY=
Expand Down

0 comments on commit 513fa47

Please sign in to comment.