First Commit of Voltha-Go-Controller from Radisys

Change-Id: I8e2e908e7ab09a4fe3d86849da18b6d69dcf4ab0
diff --git a/internal/pkg/application/minor_upgrade.go b/internal/pkg/application/minor_upgrade.go
new file mode 100644
index 0000000..8953470
--- /dev/null
+++ b/internal/pkg/application/minor_upgrade.go
@@ -0,0 +1,247 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+ */
+
+package application
+
+import (
+	"errors"
+	"net"
+	"voltha-go-controller/internal/pkg/types"
+
+	"strings"
+
+	"github.com/google/gopacket/layers"
+	"voltha-go-controller/database"
+	"github.com/opencord/voltha-lib-go/v7/pkg/log"
+)
+
+type paramsUpdationFunc func(hash string, value interface{}) error
+
+//map to store conversion functions
+var updationMap = map[string]paramsUpdationFunc{
+	database.VnetPath:       updateVnets,
+	database.VpvPath:        updateVpvs,
+	database.ServicePath:    updateServices,
+	database.MvlanPath:      updateMvlans,
+	database.IgmpGroupPath:  updateIgmpGroups,
+	database.IgmpDevicePath: updateIgmpDevices,
+	database.IgmpProfPath:   updateIgmpProfiles,
+}
+
+// UpdateDbData to update database data
+func UpdateDbData(dbPath, hash string, value interface{}) error {
+	if migrationFunc, ok := updationMap[dbPath]; ok {
+		err := migrationFunc(hash, value)
+		if err != nil {
+			logger.Error(ctx, "Error in migrating data\n")
+			return errors.New("Error-in-migration")
+		}
+	}
+	return nil
+}
+
+//This function modifyies the old data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateServices(hash string, value interface{}) error {
+	param := value.(*VoltService)
+	param.VnetID = VnetKey(param.SVlan, param.CVlan, param.UniVlan)
+	return nil
+}
+
+//This function modifyies the old data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateVnets(hash string, value interface{}) error {
+	param := value.(*VoltVnet)
+	newKey := VnetKey(param.SVlan, param.CVlan, param.UniVlan)
+	if newKey != hash {
+		//Delete the older key
+		_ = db.DelVnet(hash)
+	} else {
+		//Update SVlan Tag Protocol id param with default valud if not present
+		if param.SVlanTpid == 0 {
+			param.SVlanTpid = layers.EthernetTypeDot1Q
+		}
+	}
+	param.Name = newKey
+	if param.DevicesList == nil || len(param.DevicesList) == 0 {
+		param.DevicesList = append(param.DevicesList, "") //Empty OLT serial number as of now since submgr won't have proper serial num
+	}
+	return nil
+}
+
+//This function modifyies the old data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateVpvs(hash string, value interface{}) error {
+
+	//var param VoltPortVnet
+	param := value.(*VoltPortVnet)
+
+	//Update SVlan Tag Protocol id param with default valud if not present
+	if param.SVlanTpid == 0 {
+		param.SVlanTpid = layers.EthernetTypeDot1Q
+	}
+
+	if strings.Count(hash, "-") > 1 {
+		logger.Info(ctx, "Already upgraded")
+		return nil
+	}
+
+	//Add the vpv under new path
+	param.WriteToDb()
+	//delete the older path
+	fullPath := database.BasePath + database.VpvPath + hash
+	if err := db.Del(fullPath); err != nil {
+		logger.Errorw(ctx, "Vpv Delete from DB failed", log.Fields{"Error": err, "key": fullPath})
+	}
+	return nil
+}
+
+func updateMvlans(hash string, value interface{}) error {
+	param := value.(*MvlanProfile)
+	if param.DevicesList == nil || len(param.DevicesList) == 0 {
+		param.DevicesList = make(map[string]OperInProgress) //Empty OLT serial number as of now since submgr won't have proper serial num
+		if err := param.WriteToDb(); err != nil {
+			logger.Errorw(ctx, "Mvlan profile write to DB failed", log.Fields{"ProfileName": param.Name})
+		}
+
+	}
+	if _, ok := param.Groups[common.StaticGroup]; ok {
+		param.Groups[common.StaticGroup].IsStatic = true
+	}
+	return nil
+}
+
+//This function modifyies the old Igmp Group data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateIgmpGroups(hash string, value interface{}) error {
+
+	ig := value.(*IgmpGroup)
+	logger.Infow(ctx, "Group Data Migration", log.Fields{"ig": ig, "GroupAddr": ig.GroupAddr, "hash": hash})
+	if ig.GroupAddr == nil {
+		ig.GroupAddr = net.ParseIP("0.0.0.0")
+	}
+	if err := ig.WriteToDb(); err != nil {
+		logger.Errorw(ctx, "Igmp group Write to DB failed", log.Fields{"groupName": ig.GroupName})
+	}
+
+	return nil
+}
+
+//This function modifyies the old Igmp  Device data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateIgmpDevices(hash string, value interface{}) error {
+	igd := value.(*IgmpGroupDevice)
+	logger.Infow(ctx, "Group Device Migration", log.Fields{"igd": igd, "GroupAddr": igd.GroupAddr, "hash": hash})
+	if igd.GroupAddr == nil {
+		igd.GroupAddr = net.ParseIP("0.0.0.0")
+	}
+	if err := igd.WriteToDb(); err != nil {
+		logger.Errorw(ctx, "Igmp group device Write to DB failed", log.Fields{"Device": igd.Device,
+					"GroupName": igd.GroupName, "GroupAddr": igd.GroupAddr.String()})
+	}
+
+	return nil
+}
+
+//This function modifyies the old Igmp  Profile data as per current version requirement and also
+//returns the new path on which the modified data has to be written
+func updateIgmpProfiles(hash string, value interface{}) error {
+	igmpProfile := value.(*IgmpProfile)
+	logger.Infow(ctx, "IGMP Profile Migration", log.Fields{"igmpProfile": igmpProfile, "hash": hash})
+	return nil
+}
+
+func (ig *IgmpGroup) migrateIgmpDevices() {
+
+	devices, _ := db.GetPrevIgmpDevices(ig.Mvlan, ig.GroupName)
+	logger.Infow(ctx, "Migratable Devices", log.Fields{"Devices": devices})
+	for _, device := range devices {
+		b, ok := device.Value.([]byte)
+		if !ok {
+			logger.Warn(ctx, "The value type is not []byte")
+			continue
+		}
+		if igd, err := NewIgmpGroupDeviceFromBytes(b); err == nil {
+			key := database.BasePath + database.IgmpDevicePath + igd.Mvlan.String() + "/" + igd.GroupName + "/" + igd.Device
+			logger.Infow(ctx, "Deleting old entry", log.Fields{"Path": key, "igd": igd})
+			if err := db.Del(key); err != nil {
+				logger.Errorw(ctx, "Igmp Group Delete from DB failed", log.Fields{"Error": err, "key": key})
+			}
+			if err := UpdateDbData(database.IgmpDevicePath, key, igd); err != nil {
+				logger.Warnw(ctx, "Group Device Migration failed", log.Fields{"IGD": igd, "Error": err})
+			} else {
+				logger.Infow(ctx, "Group Device Migrated", log.Fields{"IGD": igd})
+			}
+		} else {
+			logger.Warnw(ctx, "Unable to decode device from database", log.Fields{"str": string(b)})
+		}
+	}
+}
+
+func (igd *IgmpGroupDevice) migrateIgmpChannels() {
+
+	channels, _ := db.GetPrevIgmpChannels(igd.GroupName, igd.Device)
+	logger.Infow(ctx, "Migratable Channels", log.Fields{"Channels": channels})
+	for _, channel := range channels {
+
+		b, ok := channel.Value.([]byte)
+		if !ok {
+			logger.Warn(ctx, "The value type is not []byte")
+			continue
+		}
+		if igc, err := NewIgmpGroupChannelFromBytes(b); err == nil {
+			key := database.BasePath + database.IgmpChannelPath + igc.GroupName + "/" + igc.Device + "/" + igc.GroupAddr.String()
+			logger.Infow(ctx, "Deleting old entry", log.Fields{"Path": key, "igc": igc})
+			if err := db.Del(key); err != nil {
+				logger.Errorw(ctx, "Igmp Group Delete from DB failed", log.Fields{"Error": err, "key": key})
+			}
+			if err := igc.WriteToDb(); err != nil {
+				logger.Errorw(ctx, "Igmp group channel Write to DB failed", log.Fields{"mvlan": igc.Mvlan, "GroupAddr": igc.GroupAddr})
+			}
+
+			logger.Infow(ctx, "Group Channel Migrated", log.Fields{"IGD": igc})
+		} else {
+			logger.Warnw(ctx, "Unable to decode channel from database", log.Fields{"str": string(b)})
+		}
+	}
+}
+
+func (igc *IgmpGroupChannel) migrateIgmpPorts() {
+
+	ports, _ := db.GetPrevIgmpRcvrs(igc.GroupAddr, igc.Device)
+	logger.Infow(ctx, "Migratable Ports", log.Fields{"Ports": ports})
+	for _, port := range ports {
+
+		b, ok := port.Value.([]byte)
+		if !ok {
+			logger.Warn(ctx, "The value type is not []byte")
+			continue
+		}
+		if igp, err := NewIgmpGroupPortFromBytes(b); err == nil {
+			key := database.BasePath + database.IgmpPortPath + igc.GroupAddr.String() + "/" + igc.Device + "/" + igp.Port
+			logger.Infow(ctx, "Deleting old entry", log.Fields{"Key": key, "Igp": igp})
+			if err := db.Del(key); err != nil {
+				logger.Errorw(ctx, "Igmp Group port Delete from DB failed", log.Fields{"Error": err, "key": key})
+			}
+			if err := igp.WriteToDb(igc.Mvlan, igc.GroupAddr, igc.Device); err != nil {
+				logger.Errorw(ctx, "Igmp group port Write to DB failed", log.Fields{"mvlan": igc.Mvlan, "GroupAddr": igc.GroupAddr})
+			}
+
+			logger.Infow(ctx, "Group Port Migrated", log.Fields{"IGD": igp})
+		} else {
+			logger.Warnw(ctx, "Unable to decode port from database", log.Fields{"str": string(b)})
+		}
+	}
+}