4444 migrateGateways bool
4545 migrateDeviceProfiles bool
4646 migrateDevices bool
47+ migrateMulticastGroups bool
4748 migrateGatewayMetrics bool
4849 migrateDeviceMetrics bool
4950 disableMigratedDevices bool
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
9098func 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+
665911func getIntegrationKind (k string ) string {
666912 switch k {
667913 case "HTTP" :
0 commit comments