...

Source file src/edge-infra.dev/pkg/edge/api/graph/mapper/mapper_terminal.go

Documentation: edge-infra.dev/pkg/edge/api/graph/mapper

     1  package mapper
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  
     8  	goVersion "github.com/hashicorp/go-version"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  
    11  	"edge-infra.dev/pkg/edge/api/graph/model"
    12  
    13  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    14  )
    15  
    16  type metadata struct {
    17  	Name   string            `json:"name"`
    18  	Labels map[string]string `json:"labels"`
    19  }
    20  type resource struct {
    21  	Metadata metadata
    22  }
    23  
    24  func GenerateTerminalVersionMap(res []string) (map[string]map[string]string, error) {
    25  	// returns node versions mapped to hostnames
    26  	versionMap := make(map[string]map[string]string) // clusteruuid: hostname : version
    27  	for i := range res {
    28  		var resRow []string // [resource, edgeid]
    29  		err := json.Unmarshal([]byte(res[i]), &resRow)
    30  		if err != nil {
    31  			return nil, err
    32  		}
    33  
    34  		if len(resRow) < 2 {
    35  			return nil, errors.New("error getting terminal version")
    36  		}
    37  
    38  		var node resource
    39  		err = json.Unmarshal([]byte(resRow[0]), &node)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  
    44  		edgeID := resRow[1]
    45  		hostname := node.Metadata.Name
    46  
    47  		if node.Metadata.Labels != nil {
    48  			version := node.Metadata.Labels["feature.node.kubernetes.io/ien-version"]
    49  			if versionMap[edgeID] == nil {
    50  				versionMap[edgeID] = make(map[string]string)
    51  			}
    52  			versionMap[edgeID][hostname] = version
    53  		}
    54  	}
    55  
    56  	return versionMap, nil
    57  }
    58  
    59  func TerminalToIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode {
    60  	return terminalToIENode(terminal, clusterNetworkServices, customLabels, edgeVersion)
    61  }
    62  
    63  func TerminalToCICIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode {
    64  	ien := terminalToIENode(terminal, clusterNetworkServices, customLabels, edgeVersion)
    65  
    66  	// Set unique name in cluster infra cluster
    67  	ien.ObjectMeta.Name = terminal.TerminalID
    68  
    69  	// Fields only required in CIC
    70  	// clusterEdgeID is known via cluster in store
    71  	ien.Spec.ClusterEdgeID = terminal.ClusterEdgeID
    72  	// hostname is known via IENode name in store
    73  	ien.Spec.Hostname = terminal.Hostname
    74  
    75  	return ien
    76  }
    77  
    78  func terminalToIENode(terminal *model.Terminal, clusterNetworkServices []*model.ClusterNetworkServiceInfo, customLabels map[string]string, edgeVersion string) v1ien.IENode {
    79  	// create the network
    80  	nodeNetwork := []v1ien.Network{}
    81  	for _, terminalInterface := range terminal.Interfaces {
    82  		network := TerminalInterfaceToNetwork(terminalInterface)
    83  		nodeNetwork = append(nodeNetwork, network)
    84  	}
    85  
    86  	terminalLane := ""
    87  	if terminal.Lane != nil {
    88  		terminalLane = *terminal.Lane
    89  	}
    90  
    91  	var terminalPrimaryInterface v1ien.PrimaryInterface
    92  
    93  	if terminal.PrimaryInterface == nil && len(terminal.Interfaces) != 0 {
    94  		terminalPrimaryInterface = v1ien.PrimaryInterface{
    95  			InterfaceID:  terminal.Interfaces[0].TerminalInterfaceID,
    96  			MacAddresses: []string{terminal.Interfaces[0].MacAddress},
    97  		}
    98  	}
    99  
   100  	if terminal.PrimaryInterface != nil && len(*terminal.PrimaryInterface) != 0 {
   101  		terminalPrimaryInterface.InterfaceID = *terminal.PrimaryInterface
   102  		for _, itf := range terminal.Interfaces {
   103  			if itf.TerminalInterfaceID == *terminal.PrimaryInterface {
   104  				terminalPrimaryInterface.MacAddresses = append(terminalPrimaryInterface.MacAddresses, itf.MacAddress)
   105  			}
   106  		}
   107  	}
   108  
   109  	// Filter cluster network services into dns and ntp servers
   110  	dnsServers, ntpServers, kubeVip := FilterNetworkServices(clusterNetworkServices)
   111  
   112  	node := v1ien.IENode{
   113  		TypeMeta: metav1.TypeMeta{
   114  			Kind:       v1ien.IENodeGVK.Kind,
   115  			APIVersion: v1ien.IENodeGVK.GroupVersion().String(),
   116  		},
   117  		ObjectMeta: metav1.ObjectMeta{
   118  			Name: terminal.Hostname,
   119  			Labels: map[string]string{
   120  				"node.ncr.com/terminal-id": terminal.TerminalID,
   121  			},
   122  		},
   123  		Spec: v1ien.IENodeSpec{
   124  			Role:             v1ien.Role(terminal.Role),
   125  			Lane:             terminalLane,
   126  			Network:          nodeNetwork,
   127  			PrimaryInterface: &terminalPrimaryInterface,
   128  			NetworkServices: v1ien.NetworkServices{
   129  				NTPServers: ntpServers,
   130  				DNSServers: dnsServers,
   131  				KubeVip:    kubeVip,
   132  			},
   133  			SwapEnabled:  &terminal.SwapEnabled,
   134  			CustomLabels: customLabels,
   135  		},
   136  	}
   137  
   138  	// BWC: remove fields for for stores on previous versions
   139  	currentVersion, _ := goVersion.NewVersion(edgeVersion)
   140  
   141  	// remove primaryInterface field for stores on version < v0.17.0
   142  	minimumVersion, _ := goVersion.NewVersion("v0.17.0")
   143  	if currentVersion != nil && currentVersion.LessThan(minimumVersion) {
   144  		node.Spec.PrimaryInterface = nil
   145  	}
   146  
   147  	// remove swapEnabled field for stores on version < 0.18.0
   148  	minimumVersion, _ = goVersion.NewVersion("v0.18.0")
   149  	if currentVersion != nil && currentVersion.LessThan(minimumVersion) {
   150  		node.Spec.SwapEnabled = nil
   151  	}
   152  
   153  	if terminal.Class != nil {
   154  		node.Spec.Class = v1ien.Class(*terminal.Class)
   155  	}
   156  
   157  	return node
   158  }
   159  
   160  func TerminalInterfaceToNetwork(iface *model.TerminalInterface) v1ien.Network {
   161  	network := v1ien.Network{
   162  		DHCP4:      iface.Dhcp4,
   163  		DHCP6:      iface.Dhcp6,
   164  		MacAddress: iface.MacAddress,
   165  	}
   166  	if iface.Gateway4 != nil {
   167  		network.Gateway4 = *iface.Gateway4
   168  	}
   169  	if iface.Gateway6 != nil {
   170  		network.Gateway6 = *iface.Gateway6
   171  	}
   172  
   173  	addresses := []string{}
   174  	for _, address := range iface.Addresses {
   175  		if address.IP != nil {
   176  			nodeAddress := fmt.Sprintf("%s/%d", *address.IP, address.PrefixLen)
   177  			addresses = append(addresses, nodeAddress)
   178  		}
   179  	}
   180  	if len(addresses) > 0 {
   181  		network.Addresses = addresses
   182  	}
   183  	return network
   184  }
   185  
   186  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 {
   187  	terminals := []*model.Terminal{}
   188  
   189  	for _, address := range addressMap {
   190  		currIface := ifaceMap[address.TerminalInterfaceID]
   191  		currIface.Addresses = append(currIface.Addresses, address)
   192  	}
   193  	for _, iface := range ifaceMap {
   194  		currTerminal := terminalMap[iface.TerminalID]
   195  		currTerminal.Interfaces = append(currTerminal.Interfaces, iface)
   196  	}
   197  	for _, terminal := range terminalMap {
   198  		terminal.Version = versionMap[terminal.ClusterEdgeID][terminal.Hostname]
   199  		terminals = append(terminals, terminal)
   200  	}
   201  
   202  	return terminals
   203  }
   204  
   205  // Filters cluster network services and returns dns and ntp servers
   206  func FilterNetworkServices(clusterNetworkServices []*model.ClusterNetworkServiceInfo) ([]string, []string, string) {
   207  	dnsServers := []string{}
   208  	ntpServers := []string{}
   209  	vipAddress := ""
   210  
   211  	for _, service := range clusterNetworkServices {
   212  		switch service.ServiceType {
   213  		case "dns":
   214  			dnsServers = append(dnsServers, service.IP)
   215  		case "ntp":
   216  			ntpServers = append(ntpServers, service.IP)
   217  		case "kube-vip":
   218  			vipAddress = service.IP
   219  		}
   220  	}
   221  
   222  	return dnsServers, ntpServers, vipAddress
   223  }
   224  

View as plain text