package mapper import ( "encoding/json" "errors" "fmt" goVersion "github.com/hashicorp/go-version" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "edge-infra.dev/pkg/edge/api/graph/model" v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1" ) type metadata struct { Name string `json:"name"` Labels map[string]string `json:"labels"` } type resource struct { Metadata metadata } func GenerateTerminalVersionMap(res []string) (map[string]map[string]string, error) { // returns node versions mapped to hostnames versionMap := make(map[string]map[string]string) // clusteruuid: hostname : version for i := range res { var resRow []string // [resource, edgeid] err := json.Unmarshal([]byte(res[i]), &resRow) if err != nil { return nil, err } if len(resRow) < 2 { return nil, errors.New("error getting terminal version") } var node resource err = json.Unmarshal([]byte(resRow[0]), &node) if err != nil { return nil, err } edgeID := resRow[1] hostname := node.Metadata.Name if node.Metadata.Labels != nil { version := node.Metadata.Labels["feature.node.kubernetes.io/ien-version"] if versionMap[edgeID] == nil { versionMap[edgeID] = make(map[string]string) } versionMap[edgeID][hostname] = version } } return versionMap, nil } func TerminalToIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode { return terminalToIENode(terminal, clusterNetworkServices, customLabels, edgeVersion) } func TerminalToCICIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode { ien := terminalToIENode(terminal, clusterNetworkServices, customLabels, edgeVersion) // Set unique name in cluster infra cluster ien.ObjectMeta.Name = terminal.TerminalID // Fields only required in CIC // clusterEdgeID is known via cluster in store ien.Spec.ClusterEdgeID = terminal.ClusterEdgeID // hostname is known via IENode name in store ien.Spec.Hostname = terminal.Hostname return ien } func terminalToIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode { // create the network nodeNetwork := []v1ien.Network{} for _, terminalInterface := range terminal.Interfaces { network := TerminalInterfaceToNetwork(terminalInterface) nodeNetwork = append(nodeNetwork, network) } terminalLane := "" if terminal.Lane != nil { terminalLane = *terminal.Lane } var terminalPrimaryInterface v1ien.PrimaryInterface if terminal.PrimaryInterface == nil && len(terminal.Interfaces) != 0 { terminalPrimaryInterface = v1ien.PrimaryInterface{ InterfaceID: terminal.Interfaces[0].TerminalInterfaceID, MacAddresses: []string{terminal.Interfaces[0].MacAddress}, } } if terminal.PrimaryInterface != nil && len(*terminal.PrimaryInterface) != 0 { terminalPrimaryInterface.InterfaceID = *terminal.PrimaryInterface for _, itf := range terminal.Interfaces { if itf.TerminalInterfaceID == *terminal.PrimaryInterface { terminalPrimaryInterface.MacAddresses = append(terminalPrimaryInterface.MacAddresses, itf.MacAddress) } } } // Filter cluster network services into dns and ntp servers dnsServers, ntpServers, kubeVip := FilterNetworkServices(clusterNetworkServices) node := v1ien.IENode{ TypeMeta: metav1.TypeMeta{ Kind: v1ien.IENodeGVK.Kind, APIVersion: v1ien.IENodeGVK.GroupVersion().String(), }, ObjectMeta: metav1.ObjectMeta{ Name: terminal.Hostname, Labels: map[string]string{ "node.ncr.com/terminal-id": terminal.TerminalID, }, }, Spec: v1ien.IENodeSpec{ Role: v1ien.Role(terminal.Role), Lane: terminalLane, Network: nodeNetwork, PrimaryInterface: &terminalPrimaryInterface, NetworkServices: v1ien.NetworkServices{ NTPServers: ntpServers, DNSServers: dnsServers, KubeVip: kubeVip, }, SwapEnabled: &terminal.SwapEnabled, CustomLabels: customLabels, }, } // BWC: remove fields for for stores on previous versions currentVersion, _ := goVersion.NewVersion(edgeVersion) // remove primaryInterface field for stores on version < v0.17.0 minimumVersion, _ := goVersion.NewVersion("v0.17.0") if currentVersion != nil && currentVersion.LessThan(minimumVersion) { node.Spec.PrimaryInterface = nil } // remove swapEnabled field for stores on version < 0.18.0 minimumVersion, _ = goVersion.NewVersion("v0.18.0") if currentVersion != nil && currentVersion.LessThan(minimumVersion) { node.Spec.SwapEnabled = nil } if terminal.Class != nil { node.Spec.Class = v1ien.Class(*terminal.Class) } return node } func TerminalInterfaceToNetwork(iface *model.TerminalInterface) v1ien.Network { network := v1ien.Network{ DHCP4: iface.Dhcp4, DHCP6: iface.Dhcp6, MacAddress: iface.MacAddress, } if iface.Gateway4 != nil { network.Gateway4 = *iface.Gateway4 } if iface.Gateway6 != nil { network.Gateway6 = *iface.Gateway6 } addresses := []string{} for _, address := range iface.Addresses { if address.IP != nil { nodeAddress := fmt.Sprintf("%s/%d", *address.IP, address.PrefixLen) addresses = append(addresses, nodeAddress) } } if len(addresses) > 0 { network.Addresses = addresses } return network } func UnpackBannerTerminals(terminalMap map[string]*model.Terminal, ifaceMap map[string]*model.TerminalInterface, addressMap map[string]*model.TerminalAddress, versionMap map[string]map[string]string) []*model.Terminal { terminals := []*model.Terminal{} for _, address := range addressMap { currIface := ifaceMap[address.TerminalInterfaceID] currIface.Addresses = append(currIface.Addresses, address) } for _, iface := range ifaceMap { currTerminal := terminalMap[iface.TerminalID] currTerminal.Interfaces = append(currTerminal.Interfaces, iface) } for _, terminal := range terminalMap { terminal.Version = versionMap[terminal.ClusterEdgeID][terminal.Hostname] terminals = append(terminals, terminal) } return terminals } // Filters cluster network services and returns dns and ntp servers func FilterNetworkServices(clusterNetworkServices []*model.ClusterNetworkServiceInfo) ([]string, []string, string) { dnsServers := []string{} ntpServers := []string{} vipAddress := "" for _, service := range clusterNetworkServices { switch service.ServiceType { case "dns": dnsServers = append(dnsServers, service.IP) case "ntp": ntpServers = append(ntpServers, service.IP) case "kube-vip": vipAddress = service.IP } } return dnsServers, ntpServers, vipAddress }