Skip to content

Commit

Permalink
dev: Add awsiot source
Browse files Browse the repository at this point in the history
  • Loading branch information
happyRip committed Nov 14, 2024
1 parent 90ea664 commit c99cf9f
Show file tree
Hide file tree
Showing 8 changed files with 552 additions and 26 deletions.
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ require (
github.com/TheThingsNetwork/go-utils v0.0.0-20200807125606-b3493662e4bf
github.com/TheThingsNetwork/ttn/core/types v0.0.0-20190516112328-fcd38e2b9dc6
github.com/apex/log v1.9.0
github.com/aws/aws-sdk-go-v2 v1.32.2
github.com/aws/aws-sdk-go-v2/config v1.27.43
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2
github.com/chirpstack/chirpstack/api/go/v4 v4.9.0
github.com/mdempsky/unconvert v0.0.0-20230125054757-2661c2c99a9b
github.com/mgechev/revive v1.4.0
Expand All @@ -32,6 +35,17 @@ require (
github.com/TheThingsNetwork/ttn/utils/errors v0.0.0-20190516081709-034d40b328bd // indirect
github.com/TheThingsNetwork/ttn/utils/random v0.0.0-20190516092602-86414c703ee1 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect
github.com/aws/smithy-go v1.22.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/brocaar/lorawan v0.0.0-20170626123636-a64aca28516d // indirect
Expand Down
54 changes: 28 additions & 26 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -80,44 +80,46 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI=
github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU=
github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc=
github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10 h1:zeN9UtUlA6FTx0vFSayxSX32HDw73Yb6Hh2izDSFxXY=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10/go.mod h1:3HKuexPDcwLWPaqpW2UR/9n8N/u/3CKcGAzSs8p8u8g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg=
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2 h1:AkocH6/PAgUwsi5CfCSj/d0iDCrUP+2pRqO7iXvBvDg=
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2/go.mod h1:wOgnKZTgxWdzeIp4I50HcsI6d+Ir2YVgSf5qK36jTIU=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo=
github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
Expand Down
17 changes: 17 additions & 0 deletions pkg/source/awsiot/awsiot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package awsiot

import (
"go.thethings.network/lorawan-stack-migrate/pkg/source"
"go.thethings.network/lorawan-stack-migrate/pkg/source/awsiot/config"
)

func init() {
cfg := config.New()

source.RegisterSource(source.Registration{
Name: "awsiot",
Description: "Migrate from AWS IoT",
FlagSet: cfg.Flags(),
Create: createNewSource(cfg),
})
}
75 changes: 75 additions & 0 deletions pkg/source/awsiot/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package config

import (
"context"
"net/http"
"os"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/iotwireless"
"github.com/spf13/pflag"
"go.thethings.network/lorawan-stack-migrate/pkg/source"
"go.thethings.network/lorawan-stack/v3/pkg/fetch"
"go.thethings.network/lorawan-stack/v3/pkg/frequencyplans"
)

type Config struct {
source.Config

Client *iotwireless.Client

AppID string
FrequencyPlanID string
NoSession bool

flags *pflag.FlagSet
fpStore *frequencyplans.Store
}

func New() *Config {
c := &Config{
flags: new(pflag.FlagSet),
}

c.flags.StringVar(&c.AppID,
"app-id",
os.Getenv("APP_ID"),
"Application ID for the exported devices")
c.flags.StringVar(&c.FrequencyPlanID,
"frequency-plan-id",
os.Getenv("FREQUENCY_PLAN_ID"),
"Frequency Plan ID for the exported devices")
c.flags.BoolVar(&c.NoSession,
"no-session",
os.Getenv("NO_SESSION") == "true",
"TTS export devices without session")

return c
}

func (c *Config) Initialize(rootCfg source.Config) error {
c.Config = rootCfg

cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
return err
}
c.Client = iotwireless.NewFromConfig(cfg)

fpFetcher, err := fetch.FromHTTP(http.DefaultClient, c.FrequencyPlansURL)
if err != nil {
return err
}
c.fpStore = frequencyplans.NewStore(fpFetcher)

return nil
}

// Flags returns the flags for the configuration.
func (c *Config) Flags() *pflag.FlagSet {
return c.flags
}

func (c *Config) FPStore() *frequencyplans.Store {
return c.fpStore
}
124 changes: 124 additions & 0 deletions pkg/source/awsiot/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package awsiot

import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/iotwireless/types"
"go.thethings.network/lorawan-stack-migrate/pkg/util"
"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
ttntypes "go.thethings.network/lorawan-stack/v3/pkg/types"
)

type Device struct{ *types.LoRaWANDevice }

func (d Device) SetFields(dev *ttnpb.EndDevice, noSession bool) (err error) {
if dev.Ids == nil {
dev.Ids = &ttnpb.EndDeviceIdentifiers{}
}

eui, err := util.UnmarshalTextToBytes(&ttntypes.EUI64{}, aws.ToString(d.DevEui))
if err != nil {
return err
}
dev.Ids.DevEui = eui

if dev.Session == nil {
dev.Session = &ttnpb.Session{}
}
if dev.Session.Keys == nil {
dev.Session.Keys = &ttnpb.SessionKeys{}
}

if noSession {
return nil
}

apb, otaa := d.sessionKeys()
keys := dev.Session.Keys
if err := unmarshalKeys([]struct {
envelope *ttnpb.KeyEnvelope
key *string
}{
{keys.AppSKey, apb.appSKey},
{keys.NwkSEncKey, apb.nwkSKey},
{keys.FNwkSIntKey, apb.fNwkSIntKey},
{keys.SNwkSIntKey, apb.sNwkSIntKey},
{dev.RootKeys.AppKey, otaa.appKey},
{dev.RootKeys.NwkKey, otaa.nwkKey},
}); err != nil {
return err
}

var b []byte
if b, err = util.UnmarshalTextToBytes(&ttntypes.DevAddr{}, aws.ToString(apb.devAddr)); err != nil {
return err
}
dev.Session.DevAddr = b
if b, err = util.UnmarshalTextToBytes(&ttntypes.EUI64{}, aws.ToString(otaa.joinEUI)); err != nil {
return err
}
dev.Ids.JoinEui = b

return nil
}

type apbKeys struct {
appSKey, fNwkSIntKey, nwkSKey, sNwkSIntKey, devAddr *string
}

type otaaKeys struct {
joinEUI, appKey, nwkKey *string
}

func (d Device) sessionKeys() (apb apbKeys, otaa otaaKeys) {
if v := d.AbpV1_0_x; v != nil {
apb = apbKeys{
devAddr: v.DevAddr,
appSKey: v.SessionKeys.AppSKey,
nwkSKey: v.SessionKeys.NwkSKey,
}
}
if v := d.AbpV1_1; v != nil {
apb = apbKeys{
devAddr: v.DevAddr,
appSKey: v.SessionKeys.AppSKey,
fNwkSIntKey: v.SessionKeys.FNwkSIntKey,
nwkSKey: v.SessionKeys.NwkSEncKey,
sNwkSIntKey: v.SessionKeys.SNwkSIntKey,
}
}
if o := d.OtaaV1_0_x; o != nil {
otaa = otaaKeys{
appKey: o.AppKey,
joinEUI: o.AppEui,
}
if eui := o.AppEui; eui != nil {
otaa.joinEUI = eui
}
}
if o := d.OtaaV1_1; o != nil {
otaa = otaaKeys{
appKey: o.AppKey,
joinEUI: o.JoinEui,
nwkKey: o.NwkKey,
}
}
return apb, otaa
}

func unmarshalKeys(data []struct {
envelope *ttnpb.KeyEnvelope
key *string
},
) (err error) {
for _, v := range data {
if v.envelope == nil {
v.envelope = &ttnpb.KeyEnvelope{}
}
b, err := util.UnmarshalTextToBytes(&ttntypes.AES128Key{}, aws.ToString(v.key))
if err != nil {
return err
}
v.envelope.Key = b
}
return nil
}
14 changes: 14 additions & 0 deletions pkg/source/awsiot/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package awsiot

import "go.thethings.network/lorawan-stack/v3/pkg/errors"

var (
errNoValuesInCSV = errors.DefineInvalidArgument("no_values_in_csv", "no values in CSV file")
errNoAppID = errors.DefineInvalidArgument("no_app_id", "no app id")
errNoCSVFileProvided = errors.DefineInvalidArgument("no_csv_file_provided", "no csv file provided")
errNoJoinEUI = errors.DefineInvalidArgument("no_join_eui", "no join eui")
errNoDeviceFound = errors.DefineInvalidArgument("no_device_found", "no device with eui `{eui}` found")
errNoFrequencyPlanID = errors.DefineInvalidArgument("no_frequency_plan_id", "no frequency plan ID")
errInvalidMACVersion = errors.DefineInvalidArgument("invalid_mac_version", "invalid MAC version `{mac_version}`")
errInvalidPHYForMACVersion = errors.DefineInvalidArgument("invalid_phy_for_mac_version", "invalid PHY version `{phy_version}` for MAC version `{mac_version}`")
)
Loading

0 comments on commit c99cf9f

Please sign in to comment.