...

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

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

     1  package mapper
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	corev1 "k8s.io/api/core/v1"
     8  	kr "k8s.io/apimachinery/pkg/api/resource"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	"k8s.io/apimachinery/pkg/runtime/schema"
    11  	virtv1 "kubevirt.io/api/core/v1"
    12  	virtbeta "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
    13  
    14  	"edge-infra.dev/pkg/edge/api/graph/model"
    15  	nodemeta "edge-infra.dev/pkg/sds/ien/node"
    16  )
    17  
    18  var (
    19  	storageTypeVM        = "local-path"
    20  	interfaceModelVM     = "e1000"
    21  	nodeAffinityKeyVM    = nodemeta.ClassLabel
    22  	nodeAffinityValuesVM = []string{model.TerminalClassTypeTouchpoint.String()}
    23  )
    24  
    25  func VirtualMachineToKubeVirtualMachine(virtualMachine *model.VirtualMachine) (virtv1.VirtualMachine, error) {
    26  	return virtualMachineToKubeVirtualMachine(virtualMachine)
    27  }
    28  
    29  func virtualMachineToKubeVirtualMachine(virtualMachine *model.VirtualMachine) (virtv1.VirtualMachine, error) {
    30  	virtualMachineSpec, err := getVirtualMachineSpec(virtualMachine)
    31  	if err != nil {
    32  		return virtv1.VirtualMachine{}, err
    33  	}
    34  	kubeVM := virtv1.VirtualMachine{
    35  		ObjectMeta: metav1.ObjectMeta{
    36  			Name:      virtualMachine.Hostname,
    37  			Namespace: virtualMachine.Namespace,
    38  			Annotations: map[string]string{
    39  				"linkerd.io/inject": "disabled",
    40  			},
    41  		},
    42  		Spec:   virtualMachineSpec,
    43  		Status: virtv1.VirtualMachineStatus{},
    44  	}
    45  
    46  	kubeVM.SetGroupVersionKind(schema.GroupVersionKind{
    47  		Group:   virtv1.GroupVersion.Group,
    48  		Kind:    reflect.TypeOf(virtv1.VirtualMachine{}).Name(),
    49  		Version: virtv1.GroupVersion.Version,
    50  	})
    51  
    52  	return kubeVM, nil
    53  }
    54  
    55  func getKubeVMInstanceSpec(virtualMachine *model.VirtualMachine) (virtv1.VirtualMachineInstanceSpec, error) {
    56  	memoryQuantity, err := kr.ParseQuantity(virtualMachine.Memory)
    57  	if err != nil {
    58  		return virtv1.VirtualMachineInstanceSpec{}, err
    59  	}
    60  
    61  	return virtv1.VirtualMachineInstanceSpec{
    62  		Domain: virtv1.DomainSpec{
    63  			CPU: &virtv1.CPU{
    64  				Cores: uint32(virtualMachine.Cpus), /* #nosec G115 */
    65  			},
    66  			Memory: &virtv1.Memory{
    67  				Guest: &memoryQuantity,
    68  			},
    69  			Devices: virtv1.Devices{
    70  				ClientPassthrough: &virtv1.ClientPassthroughDevices{},
    71  				Disks:             virtualMachineDisksToKubeDisks(virtualMachine.Disks, virtualMachine.Hostname),
    72  				Interfaces: []virtv1.Interface{
    73  					{
    74  						Model: interfaceModelVM,
    75  						Name:  "default",
    76  						InterfaceBindingMethod: virtv1.InterfaceBindingMethod{
    77  							Masquerade: &virtv1.InterfaceMasquerade{},
    78  						},
    79  					},
    80  				},
    81  			},
    82  			Machine: &virtv1.Machine{
    83  				Type: string(virtualMachine.MachineType),
    84  			},
    85  		},
    86  		Networks: []virtv1.Network{
    87  			{
    88  				Name: "default",
    89  				NetworkSource: virtv1.NetworkSource{
    90  					Pod: &virtv1.PodNetwork{},
    91  				},
    92  			},
    93  		},
    94  		Volumes:  virtualMachineDisksToKubeVolumes(virtualMachine.Disks, virtualMachine.Hostname),
    95  		Affinity: getVirtualMachineAffinity(),
    96  	}, nil
    97  }
    98  
    99  func virtualMachineDisksToKubeDisks(disks []*model.VirtualMachineDisk, hostname string) []virtv1.Disk {
   100  	kubeDisks := []virtv1.Disk{}
   101  	for _, disk := range disks {
   102  		bootOrder := uint(disk.BootOrder) /* #nosec G115 */
   103  		kubeDisk := virtv1.Disk{
   104  			BootOrder:  &bootOrder,
   105  			Name:       getKubeDiskName(hostname, disk.DiskID),
   106  			DiskDevice: getKubeDiskDevice(disk),
   107  		}
   108  		kubeDisks = append(kubeDisks, kubeDisk)
   109  	}
   110  	return kubeDisks
   111  }
   112  
   113  func virtualMachineDisksToKubeVolumes(disks []*model.VirtualMachineDisk, hostname string) []virtv1.Volume {
   114  	kubeVolumes := []virtv1.Volume{}
   115  	for _, disk := range disks {
   116  		volumeName := getKubeDiskName(hostname, disk.DiskID)
   117  		kubeVolume := virtv1.Volume{
   118  			Name: volumeName,
   119  			VolumeSource: virtv1.VolumeSource{
   120  				DataVolume: &virtv1.DataVolumeSource{
   121  					Name: volumeName,
   122  				},
   123  			},
   124  		}
   125  		kubeVolumes = append(kubeVolumes, kubeVolume)
   126  	}
   127  	return kubeVolumes
   128  }
   129  
   130  func getKubeDiskName(hostname string, diskID string) string {
   131  	return fmt.Sprintf("%s-%s", hostname, diskID)
   132  }
   133  
   134  func getKubeDiskDevice(disk *model.VirtualMachineDisk) virtv1.DiskDevice {
   135  	diskDevice := virtv1.DiskDevice{}
   136  	diskBus := virtv1.DiskBus(disk.Bus)
   137  	switch disk.Type {
   138  	case model.DiskTypeCdrom:
   139  		diskDevice.CDRom = &virtv1.CDRomTarget{
   140  			Bus: diskBus,
   141  		}
   142  	case model.DiskTypeDisk:
   143  		diskDevice.Disk = &virtv1.DiskTarget{
   144  			Bus: diskBus,
   145  		}
   146  	}
   147  	return diskDevice
   148  }
   149  
   150  func getKubeDataVolumeSource(containerImageURL string) *virtbeta.DataVolumeSource {
   151  	if containerImageURL == "" {
   152  		return &virtbeta.DataVolumeSource{
   153  			Blank: &virtbeta.DataVolumeBlankImage{},
   154  		}
   155  	}
   156  
   157  	pullMethod := virtbeta.RegistryPullNode
   158  	return &virtbeta.DataVolumeSource{
   159  		Registry: &virtbeta.DataVolumeSourceRegistry{
   160  			URL:        &containerImageURL,
   161  			PullMethod: &pullMethod,
   162  		},
   163  	}
   164  }
   165  
   166  func getKubeVMDataVolumeTemplates(virtualMachine *model.VirtualMachine) ([]virtv1.DataVolumeTemplateSpec, error) {
   167  	storageClassName := storageTypeVM
   168  	volumeTemplates := []virtv1.DataVolumeTemplateSpec{}
   169  	for _, disk := range virtualMachine.Disks {
   170  		sizeQuantity, err := kr.ParseQuantity(disk.Size)
   171  		if err != nil {
   172  			return []virtv1.DataVolumeTemplateSpec{}, err
   173  		}
   174  		volumeTemplate := virtv1.DataVolumeTemplateSpec{
   175  			ObjectMeta: metav1.ObjectMeta{
   176  				Name: getKubeDiskName(virtualMachine.Hostname, disk.DiskID),
   177  				Annotations: map[string]string{
   178  					"linkerd.io/inject": "disabled",
   179  				},
   180  			},
   181  			Spec: virtbeta.DataVolumeSpec{
   182  				PVC: &corev1.PersistentVolumeClaimSpec{
   183  					AccessModes: []corev1.PersistentVolumeAccessMode{
   184  						corev1.ReadWriteOnce,
   185  					},
   186  					StorageClassName: &storageClassName,
   187  					Resources: corev1.VolumeResourceRequirements{
   188  						Requests: map[corev1.ResourceName]kr.Quantity{
   189  							corev1.ResourceStorage: sizeQuantity,
   190  						},
   191  					},
   192  				},
   193  				Source: getKubeDataVolumeSource(disk.ContainerImageURL),
   194  			},
   195  		}
   196  		volumeTemplates = append(volumeTemplates, volumeTemplate)
   197  	}
   198  	return volumeTemplates, nil
   199  }
   200  
   201  func getVirtualMachineSpec(virtualMachine *model.VirtualMachine) (virtv1.VirtualMachineSpec, error) {
   202  	kubeVMInstanceSpec, err := getKubeVMInstanceSpec(virtualMachine)
   203  	if err != nil {
   204  		return virtv1.VirtualMachineSpec{}, err
   205  	}
   206  	dataVolumeTemplates, err := getKubeVMDataVolumeTemplates(virtualMachine)
   207  	if err != nil {
   208  		return virtv1.VirtualMachineSpec{}, err
   209  	}
   210  	return virtv1.VirtualMachineSpec{
   211  		Running: &virtualMachine.TargetPowerState,
   212  		Template: &virtv1.VirtualMachineInstanceTemplateSpec{
   213  			ObjectMeta: metav1.ObjectMeta{
   214  				Labels: map[string]string{
   215  					"kubevirt.io/domain": virtualMachine.Hostname,
   216  				},
   217  				Annotations: map[string]string{
   218  					"linkerd.io/inject": "disabled",
   219  				},
   220  			},
   221  			Spec: kubeVMInstanceSpec,
   222  		},
   223  		DataVolumeTemplates: dataVolumeTemplates,
   224  	}, nil
   225  }
   226  
   227  func getVirtualMachineAffinity() *corev1.Affinity {
   228  	return &corev1.Affinity{
   229  		NodeAffinity: &corev1.NodeAffinity{
   230  			RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
   231  				NodeSelectorTerms: []corev1.NodeSelectorTerm{
   232  					{
   233  						MatchExpressions: []corev1.NodeSelectorRequirement{
   234  							{
   235  								Key:      nodeAffinityKeyVM,
   236  								Operator: corev1.NodeSelectorOpIn,
   237  								Values:   nodeAffinityValuesVM,
   238  							},
   239  						},
   240  					},
   241  				},
   242  			},
   243  		},
   244  	}
   245  }
   246  

View as plain text