Skip to content

Commit

Permalink
Refactor vmbuilder
Browse files Browse the repository at this point in the history
Signed-off-by: futuretea <Hang.Yu@suse.com>
  • Loading branch information
futuretea authored and guangbochen committed Jun 21, 2021
1 parent 03ecd27 commit abc91f0
Show file tree
Hide file tree
Showing 9 changed files with 663 additions and 373 deletions.
83 changes: 83 additions & 0 deletions pkg/builder/cloudinit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package builder

import (
corev1 "k8s.io/api/core/v1"
kubevirtv1 "kubevirt.io/client-go/api/v1"
)

const (
CloudInitTypeNoCloud = "noCloud"
CloudInitTypeConfigDrive = "configDrive"
CloudInitDiskName = "cloudinitdisk"
)

type CloudInitSource struct {
CloudInitType string
UserDataSecretName string
UserDataBase64 string
UserData string
NetworkDataSecretName string
NetworkDataBase64 string
NetworkData string
}

func (v *VMBuilder) CloudInit(diskName string, cloudInitSource CloudInitSource) *VMBuilder {
var volume kubevirtv1.Volume
switch cloudInitSource.CloudInitType {
case CloudInitTypeNoCloud:
volume = kubevirtv1.Volume{
Name: diskName,
VolumeSource: kubevirtv1.VolumeSource{
CloudInitNoCloud: &kubevirtv1.CloudInitNoCloudSource{
UserData: cloudInitSource.UserData,
UserDataBase64: cloudInitSource.UserDataBase64,
NetworkData: cloudInitSource.NetworkData,
NetworkDataBase64: cloudInitSource.NetworkDataBase64,
},
},
}
if cloudInitSource.UserDataSecretName != "" {
volume.VolumeSource.CloudInitNoCloud.UserDataSecretRef = &corev1.LocalObjectReference{
Name: cloudInitSource.UserDataSecretName,
}
}
if cloudInitSource.NetworkDataSecretName != "" {
volume.VolumeSource.CloudInitNoCloud.UserDataSecretRef = &corev1.LocalObjectReference{
Name: cloudInitSource.NetworkDataSecretName,
}
}
case CloudInitTypeConfigDrive:
volume = kubevirtv1.Volume{
Name: diskName,
VolumeSource: kubevirtv1.VolumeSource{
CloudInitConfigDrive: &kubevirtv1.CloudInitConfigDriveSource{
UserData: cloudInitSource.UserData,
UserDataBase64: cloudInitSource.UserDataBase64,
NetworkData: cloudInitSource.NetworkData,
NetworkDataBase64: cloudInitSource.NetworkDataBase64,
},
},
}
if cloudInitSource.UserDataSecretName != "" {
volume.VolumeSource.CloudInitConfigDrive.UserDataSecretRef = &corev1.LocalObjectReference{
Name: cloudInitSource.UserDataSecretName,
}
}
if cloudInitSource.NetworkDataSecretName != "" {
volume.VolumeSource.CloudInitConfigDrive.UserDataSecretRef = &corev1.LocalObjectReference{
Name: cloudInitSource.NetworkDataSecretName,
}
}
}
v.Volume(diskName, volume)
return v
}

func (v *VMBuilder) CloudInitDisk(diskName, diskBus string, isCDRom bool, bootOrder int, cloudInitSource CloudInitSource) *VMBuilder {
return v.Disk(diskName, diskBus, isCDRom, bootOrder).CloudInit(diskName, cloudInitSource)
}

func (v *VMBuilder) SSHKey(sshKeyName string) *VMBuilder {
v.SSHNames = append(v.SSHNames, sshKeyName)
return v
}
208 changes: 208 additions & 0 deletions pkg/builder/disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package builder

import (
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
kubevirtv1 "kubevirt.io/client-go/api/v1"
cdiv1alpha1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1alpha1"
)

const (
StorageClassNamePrefix = "longhorn"

DiskTypeDisk = "disk"
DiskTypeCDRom = "cd-rom"

DiskBusVirtio = "virtio"
DiskBusScsi = "scsi"
DiskBusSata = "sata"

PersistentVolumeModeBlock = "Block"
PersistentVolumeModeFilesystem = "Filesystem"

PersistentVolumeAccessModeReadWriteOnce = "ReadWriteOnce"
PersistentVolumeAccessModeReadOnlyMany = "ReadOnlyMany"
PersistentVolumeAccessModeReadWriteMany = "ReadWriteMany"

DefaultDiskSize = "10Gi"
DefaultImagePullPolicy = "IfNotPresent"
)

type DataVolumeOption struct {
ImageID string
DownloadURL string
VolumeMode corev1.PersistentVolumeMode
AccessMode corev1.PersistentVolumeAccessMode
StorageClassName *string
}

func UintPtr(in int) *uint {
var out *uint
u := uint(in)
if in > 0 {
out = &u
}
return out
}

func BuildImageStorageClassName(namespace, name string) string {
if namespace != "" {
return StorageClassNamePrefix + "-" + namespace + "-" + name
}
return StorageClassNamePrefix + "-" + name
}

func (v *VMBuilder) Disk(diskName, diskBus string, isCDRom bool, bootOrder int) *VMBuilder {
var (
exist bool
index int
disks = v.VirtualMachine.Spec.Template.Spec.Domain.Devices.Disks
)
for i, disk := range disks {
if disk.Name == diskName {
exist = true
index = i
break
}
}
diskDevice := kubevirtv1.DiskDevice{
Disk: &kubevirtv1.DiskTarget{
Bus: diskBus,
},
}
if isCDRom {
diskDevice = kubevirtv1.DiskDevice{
CDRom: &kubevirtv1.CDRomTarget{
Bus: diskBus,
},
}
}
disk := kubevirtv1.Disk{
Name: diskName,
BootOrder: UintPtr(bootOrder),
DiskDevice: diskDevice,
}
if exist {
disks[index] = disk
} else {
disks = append(disks, disk)
}
v.VirtualMachine.Spec.Template.Spec.Domain.Devices.Disks = disks
return v
}

func (v *VMBuilder) Volume(diskName string, volume kubevirtv1.Volume) *VMBuilder {
var (
exist bool
index int
volumes = v.VirtualMachine.Spec.Template.Spec.Volumes
)
for i, e := range volumes {
if e.Name == diskName {
exist = true
index = i
break
}
}

if exist {
volumes[index] = volume
} else {
volumes = append(volumes, volume)
}
v.VirtualMachine.Spec.Template.Spec.Volumes = volumes
return v
}

func (v *VMBuilder) ExistingDataVolume(diskName, dataVolumeName string) *VMBuilder {
return v.Volume(diskName, kubevirtv1.Volume{
Name: diskName,
VolumeSource: kubevirtv1.VolumeSource{
DataVolume: &kubevirtv1.DataVolumeSource{
Name: dataVolumeName,
},
},
})
}

func (v *VMBuilder) ExistingVolumeDisk(diskName, diskBus string, isCDRom bool, bootOrder int, dataVolumeName string) *VMBuilder {
return v.Disk(diskName, diskBus, isCDRom, bootOrder).ExistingDataVolume(diskName, dataVolumeName)
}

func (v *VMBuilder) ContainerDiskVolume(diskName, imageName, ImagePullPolicy string) *VMBuilder {
return v.Volume(diskName, kubevirtv1.Volume{
Name: diskName,
VolumeSource: kubevirtv1.VolumeSource{
ContainerDisk: &kubevirtv1.ContainerDiskSource{
Image: imageName,
ImagePullPolicy: corev1.PullPolicy(ImagePullPolicy),
},
},
})
}

func (v *VMBuilder) ContainerDisk(diskName, diskBus string, isCDRom bool, bootOrder int, imageName, ImagePullPolicy string) *VMBuilder {
return v.Disk(diskName, diskBus, isCDRom, bootOrder).ContainerDiskVolume(diskName, imageName, ImagePullPolicy)
}

func (v *VMBuilder) DataVolume(diskName, diskSize, dataVolumeName string, opt *DataVolumeOption) *VMBuilder {
if opt == nil {
opt = &DataVolumeOption{
VolumeMode: corev1.PersistentVolumeBlock,
AccessMode: corev1.ReadWriteMany,
}
}
if dataVolumeName == "" {
dataVolumeName = fmt.Sprintf("%s-%s-%s", v.VirtualMachine.Name, diskName, rand.String(5))
}
// DataVolumeTemplates
dataVolumeTemplates := v.VirtualMachine.Spec.DataVolumeTemplates
dataVolumeSpecSource := cdiv1alpha1.DataVolumeSource{
Blank: &cdiv1alpha1.DataVolumeBlankImage{},
}

if opt.DownloadURL != "" {
dataVolumeSpecSource = cdiv1alpha1.DataVolumeSource{
HTTP: &cdiv1alpha1.DataVolumeSourceHTTP{
URL: opt.DownloadURL,
},
}
}
dataVolumeTemplate := kubevirtv1.DataVolumeTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: dataVolumeName,
},
Spec: cdiv1alpha1.DataVolumeSpec{
Source: dataVolumeSpecSource,
PVC: &corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{
opt.AccessMode,
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse(diskSize),
},
},
VolumeMode: &opt.VolumeMode,
StorageClassName: opt.StorageClassName,
},
},
}
if opt.ImageID != "" {
dataVolumeTemplate.Annotations = map[string]string{
AnnotationKeyImageID: opt.ImageID,
}
}
dataVolumeTemplates = append(dataVolumeTemplates, dataVolumeTemplate)
v.VirtualMachine.Spec.DataVolumeTemplates = dataVolumeTemplates

return v.ExistingDataVolume(diskName, dataVolumeName)
}

func (v *VMBuilder) DataVolumeDisk(diskName, diskBus string, isCDRom bool, bootOrder int, diskSize, dataVolumeName string, opt *DataVolumeOption) *VMBuilder {
return v.Disk(diskName, diskBus, isCDRom, bootOrder).DataVolume(diskName, diskSize, dataVolumeName, opt)
}
70 changes: 70 additions & 0 deletions pkg/builder/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package builder

import (
kubevirtv1 "kubevirt.io/client-go/api/v1"
)

const (
NetworkInterfaceTypeBridge = "bridge"
NetworkInterfaceTypeMasquerade = "masquerade"

LabelKeyNetworkType = "networks.harvesterhci.io/type"

NetworkTypeVLAN = "L2VlanNetwork"
NetworkTypeCustom = "Custom"

NetworkVLANConfigTemplate = `{"cniVersion":"0.3.1","name":"%s","type":"bridge","bridge":"harvester-br0","promiscMode":true,"vlan":%d,"ipam":{}}`
)

func (v *VMBuilder) NetworkInterface(interfaceName, interfaceModel, interfaceMACAddress, interfaceType, networkName string) *VMBuilder {
v.Interface(interfaceName, interfaceModel, interfaceMACAddress, interfaceType)
v.Network(interfaceName, networkName)
return v
}

func (v *VMBuilder) Network(interfaceName, networkName string) *VMBuilder {
networks := v.VirtualMachine.Spec.Template.Spec.Networks
network := kubevirtv1.Network{
Name: interfaceName,
}
if networkName != "" {
network.NetworkSource = kubevirtv1.NetworkSource{
Multus: &kubevirtv1.MultusNetwork{
NetworkName: networkName,
Default: false,
},
}
} else {
network.NetworkSource = kubevirtv1.NetworkSource{
Pod: &kubevirtv1.PodNetwork{},
}
}
networks = append(networks, network)
v.VirtualMachine.Spec.Template.Spec.Networks = networks
return v
}

func (v *VMBuilder) Interface(interfaceName, interfaceModel, interfaceMACAddress string, interfaceType string) *VMBuilder {
interfaces := v.VirtualMachine.Spec.Template.Spec.Domain.Devices.Interfaces
networkInterface := kubevirtv1.Interface{
Name: interfaceName,
Model: interfaceModel,
MacAddress: interfaceMACAddress,
InterfaceBindingMethod: kubevirtv1.InterfaceBindingMethod{
Bridge: &kubevirtv1.InterfaceBridge{},
},
}
switch interfaceType {
case NetworkInterfaceTypeBridge:
networkInterface.InterfaceBindingMethod = kubevirtv1.InterfaceBindingMethod{
Bridge: &kubevirtv1.InterfaceBridge{},
}
default:
networkInterface.InterfaceBindingMethod = kubevirtv1.InterfaceBindingMethod{
Masquerade: &kubevirtv1.InterfaceMasquerade{},
}
}
interfaces = append(interfaces, networkInterface)
v.VirtualMachine.Spec.Template.Spec.Domain.Devices.Interfaces = interfaces
return v
}
Loading

0 comments on commit abc91f0

Please sign in to comment.