Skip to content

Commit 98e4ecc

Browse files
committed
Implement multicast-group migration.
Fixes #15.
1 parent 0c423fd commit 98e4ecc

File tree

2 files changed

+247
-1
lines changed

2 files changed

+247
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ database will be removed!
4545

4646
## Notes
4747

48-
* This utility is compatible with the ChirpStack v4.4.0 or later database schema.
48+
* This utility is compatible with the ChirpStack v4.6.0 database schema.
4949
* This utility does not support [environment variables](https://www.chirpstack.io/docs/chirpstack/configuration.html#environment-variables) in configuration files, like ChirpStack does.
5050

5151
## Building from source

main.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ var (
4444
migrateGateways bool
4545
migrateDeviceProfiles bool
4646
migrateDevices bool
47+
migrateMulticastGroups bool
4748
migrateGatewayMetrics bool
4849
migrateDeviceMetrics bool
4950
disableMigratedDevices bool
@@ -60,6 +61,7 @@ var (
6061
nsPrefix string
6162
asPrefix string
6263
csPrefix string
64+
nsBand string
6365
devEUIsList [][]byte
6466
deviceProfileIDList []uuid.UUID
6567
)
@@ -85,6 +87,12 @@ type Config struct {
8587
TLSEnabled bool `mapstructure:"tls_enabled"`
8688
KeyPrefix string `mapstructure:"key_prefix"`
8789
} `mapstructure:"redis"`
90+
91+
NetworkServer struct {
92+
Band struct {
93+
Name string `mapstructure:"name"`
94+
} `mapstructure:"band"`
95+
} `mapstructure:"network_server"`
8896
}
8997

9098
func init() {
@@ -102,6 +110,7 @@ func init() {
102110
rootCmd.PersistentFlags().BoolVarP(&migrateGateways, "migrate-gateways", "", true, "Migrate gateways")
103111
rootCmd.PersistentFlags().BoolVarP(&migrateDeviceProfiles, "migrate-device-profiles", "", true, "Migrate device profiles")
104112
rootCmd.PersistentFlags().BoolVarP(&migrateDevices, "migrate-devices", "", true, "Migrate devices")
113+
rootCmd.PersistentFlags().BoolVarP(&migrateMulticastGroups, "migrate-multicast-groups", "", true, "Migrate multicast-groups")
105114
rootCmd.PersistentFlags().BoolVarP(&migrateGatewayMetrics, "migrate-gateway-metrics", "", true, "Migrate gateway metrics")
106115
rootCmd.PersistentFlags().BoolVarP(&migrateDeviceMetrics, "migrate-device-metrics", "", true, "Migrate device metrics")
107116
}
@@ -216,6 +225,9 @@ func run(cmd *cobra.Command, args []string) error {
216225
nsRedis = getRedisClient(nsConfig)
217226
nsDB = getPostgresClient(nsConfig)
218227
nsPrefix = nsConfig.Redis.KeyPrefix
228+
nsBand = nsConfig.NetworkServer.Band.Name
229+
230+
log.Printf("Migrating region: %s", nsBand)
219231

220232
if migrateGateways {
221233
migrateGatewaysFn()
@@ -228,6 +240,10 @@ func run(cmd *cobra.Command, args []string) error {
228240
if migrateDevices {
229241
migrateDevicesFn()
230242
}
243+
244+
if migrateMulticastGroups {
245+
migrateMulticastGroupsFn()
246+
}
231247
}
232248

233249
log.Println("Done :)")
@@ -662,6 +678,236 @@ func migrateApplicationIntegrationsFn() {
662678
}
663679
}
664680

681+
func migrateMulticastGroupsFn() {
682+
log.Println("Migrating multicast-groups")
683+
684+
type NSMulticastGroup struct {
685+
ID uuid.UUID `db:"id"`
686+
CreatedAt time.Time `db:"created_at"`
687+
UpdatedAt time.Time `db:"updated_at"`
688+
MCAddr lorawan.DevAddr `db:"mc_addr"`
689+
MCNwkSKey lorawan.AES128Key `db:"mc_nwk_s_key"`
690+
FCnt uint32 `db:"f_cnt"`
691+
GroupType string `db:"group_type"`
692+
DR uint8 `db:"dr"`
693+
Frequency uint32 `db:"frequency"`
694+
PingSlotPeriod uint32 `db:"ping_slot_period"`
695+
RoutingProfileID uuid.UUID `db:"routing_profile_id"`
696+
ServiceProfileID uuid.UUID `db:"service_profile_id"`
697+
}
698+
699+
type ASMulticastGroup struct {
700+
ID uuid.UUID `db:"id"`
701+
CreatedAt time.Time `db:"created_at"`
702+
UpdatedAt time.Time `db:"updated_at"`
703+
Name string `db:"name"`
704+
MCAppSKey lorawan.AES128Key `db:"mc_app_s_key"`
705+
ApplicationID int64 `db:"application_id"`
706+
}
707+
708+
nsMulticastGroups := []NSMulticastGroup{}
709+
asMulticastGroups := []ASMulticastGroup{}
710+
err := nsDB.Select(&nsMulticastGroups, "select * from multicast_group")
711+
if err != nil {
712+
log.Fatal("Select multicast groups error", err)
713+
}
714+
715+
var mcIDs []uuid.UUID
716+
for i := range nsMulticastGroups {
717+
mcIDs = append(mcIDs, nsMulticastGroups[i].ID)
718+
}
719+
720+
err = asDB.Select(&asMulticastGroups, "select * from multicast_group where id = any($1)", pq.Array(mcIDs))
721+
if err != nil {
722+
log.Fatal("Select multicast groups error", err)
723+
}
724+
725+
tx, err := csDB.Beginx()
726+
if err != nil {
727+
log.Fatal("Begin transaction error", err)
728+
}
729+
730+
stmt, err := tx.Prepare(pq.CopyIn("multicast_group",
731+
"id",
732+
"application_id",
733+
"created_at",
734+
"updated_at",
735+
"name",
736+
"region",
737+
"mc_addr",
738+
"mc_nwk_s_key",
739+
"mc_app_s_key",
740+
"f_cnt",
741+
"group_type",
742+
"dr",
743+
"frequency",
744+
"class_b_ping_slot_period",
745+
"class_c_scheduling_type",
746+
))
747+
if err != nil {
748+
log.Fatal("Prepare multicast-group statement error", err)
749+
}
750+
751+
for _, nsMCGroup := range nsMulticastGroups {
752+
found := false
753+
754+
for _, asMCGroup := range asMulticastGroups {
755+
if nsMCGroup.ID != asMCGroup.ID {
756+
continue
757+
}
758+
759+
found = true
760+
761+
_, err = stmt.Exec(
762+
nsMCGroup.ID,
763+
intToUUID(asMCGroup.ApplicationID),
764+
asMCGroup.CreatedAt,
765+
asMCGroup.UpdatedAt,
766+
asMCGroup.Name,
767+
nsBand,
768+
nsMCGroup.MCAddr,
769+
nsMCGroup.MCNwkSKey,
770+
asMCGroup.MCAppSKey,
771+
nsMCGroup.FCnt,
772+
nsMCGroup.GroupType,
773+
nsMCGroup.DR,
774+
nsMCGroup.Frequency,
775+
nsMCGroup.PingSlotPeriod,
776+
"DELAY",
777+
)
778+
if err != nil {
779+
log.Fatal("Execute multicast-group statement error", err)
780+
}
781+
}
782+
783+
if !found {
784+
log.Printf("Multicast-group not found in AS database, id: %s", nsMCGroup.ID)
785+
}
786+
}
787+
788+
_, err = stmt.Exec()
789+
if err != nil {
790+
log.Fatal("Exec multicast-group statement error", err)
791+
}
792+
793+
migrateMulticastGroupDevicesFn(tx)
794+
migrateMulticastGroupQueueFn(tx)
795+
796+
err = tx.Commit()
797+
if err != nil {
798+
log.Fatal("Commit transaction error")
799+
}
800+
}
801+
802+
func migrateMulticastGroupDevicesFn(tx *sqlx.Tx) {
803+
log.Println("Migrating multicast-group devices")
804+
805+
type MulticastDevice struct {
806+
DevEUI lorawan.EUI64 `db:"dev_eui"`
807+
MulticastGroupID uuid.UUID `db:"multicast_group_id"`
808+
CreatedAt time.Time `db:"created_at"`
809+
}
810+
811+
multicastDevices := []MulticastDevice{}
812+
if len(devEUIsList) == 0 {
813+
err := nsDB.Select(&multicastDevices, "select * from device_multicast_group")
814+
if err != nil {
815+
log.Fatal("Select multicast-group devices error", err)
816+
}
817+
} else {
818+
err := nsDB.Select(&multicastDevices, "select * from device_multicast_group where dev_eui = any($1)", pq.ByteaArray(devEUIsList))
819+
if err != nil {
820+
log.Fatal("Select multicast-group devices error", err)
821+
}
822+
}
823+
824+
stmt, err := tx.Prepare(pq.CopyIn("multicast_group_device",
825+
"multicast_group_id",
826+
"dev_eui",
827+
"created_at",
828+
))
829+
if err != nil {
830+
log.Fatal("Begin transaction error", err)
831+
}
832+
833+
for _, mcDevice := range multicastDevices {
834+
_, err = stmt.Exec(
835+
mcDevice.MulticastGroupID,
836+
mcDevice.DevEUI,
837+
mcDevice.CreatedAt,
838+
)
839+
if err != nil {
840+
log.Fatal("Execute multicast-group device statement error", err)
841+
}
842+
}
843+
844+
_, err = stmt.Exec()
845+
if err != nil {
846+
log.Fatal("Execute multicast-group device statement error", err)
847+
}
848+
}
849+
850+
func migrateMulticastGroupQueueFn(tx *sqlx.Tx) {
851+
log.Println("Migrating multicast-group queue")
852+
853+
type MulticastGroupQueueItem struct {
854+
ID int64 `db:"id"`
855+
CreatedAt time.Time `db:"created_at"`
856+
ScheduleAt time.Time `db:"schedule_at"`
857+
EmitAtTimeSinceGPSEpoch *int64 `db:"emit_at_time_since_gps_epoch"`
858+
MulticastGroupID uuid.UUID `db:"multicast_group_id"`
859+
GatewayID lorawan.EUI64 `db:"gateway_id"`
860+
FCnt uint32 `db:"f_cnt"`
861+
FPort uint32 `db:"f_port"`
862+
FRMPayload []byte `db:"frm_payload"`
863+
UpdatedAt time.Time `db:"updated_at"`
864+
RetryAfter *time.Time `db:"retry_after"`
865+
}
866+
867+
mcQueueItems := []MulticastGroupQueueItem{}
868+
err := nsDB.Select(&mcQueueItems, "select * from multicast_queue")
869+
if err != nil {
870+
log.Panic("Select multicast-group queue error", err)
871+
}
872+
873+
stmt, err := tx.Prepare(pq.CopyIn("multicast_group_queue_item",
874+
"id",
875+
"created_at",
876+
"scheduler_run_after",
877+
"multicast_group_id",
878+
"gateway_id",
879+
"f_cnt",
880+
"f_port",
881+
"data",
882+
"emit_at_time_since_gps_epoch",
883+
))
884+
if err != nil {
885+
log.Fatal("Prepare multicast-group queue statement error", err)
886+
}
887+
888+
for _, mcQueueItem := range mcQueueItems {
889+
_, err = stmt.Exec(
890+
intToUUID(mcQueueItem.ID),
891+
mcQueueItem.CreatedAt,
892+
mcQueueItem.ScheduleAt,
893+
mcQueueItem.MulticastGroupID,
894+
mcQueueItem.GatewayID,
895+
mcQueueItem.FCnt,
896+
mcQueueItem.FPort,
897+
mcQueueItem.FRMPayload,
898+
mcQueueItem.EmitAtTimeSinceGPSEpoch,
899+
)
900+
if err != nil {
901+
log.Fatal("Execute multicast-group queue statement error", err)
902+
}
903+
}
904+
905+
_, err = stmt.Exec()
906+
if err != nil {
907+
log.Fatal("Execute multicast-group queue statement error", err)
908+
}
909+
}
910+
665911
func getIntegrationKind(k string) string {
666912
switch k {
667913
case "HTTP":

0 commit comments

Comments
 (0)