Skip to content

Support Different Storage Targets for KubeVirt Provider #1855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 50 additions & 13 deletions pkg/cloudprovider/provider/kubevirt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type Config struct {
Memory string
Namespace string
OSImageSource *cdiv1beta1.DataVolumeSource
StorageTarget StorageTarget
StorageClassName string
StorageAccessType corev1.PersistentVolumeAccessMode
PVCSize resource.Quantity
Expand All @@ -108,6 +109,14 @@ type Config struct {
TopologySpreadConstraints []corev1.TopologySpreadConstraint
}

// StorageTarget represents targeted storage definition that will be used to provision VirtualMachine volumes. Currently,
// there are two definitions, PVC and Storage. Default value is PVC.
type StorageTarget string

const (
Storage StorageTarget = "storage"
)

type AffinityType string

const (
Expand Down Expand Up @@ -255,6 +264,12 @@ func (p *provider) getConfig(provSpec clusterv1alpha1.ProviderSpec) (*Config, *p
return nil, nil, fmt.Errorf(`failed to get value of "osImageSource" field: %w`, err)
}

storageTarget, err := p.configVarResolver.GetConfigVarStringValue(rawConfig.VirtualMachine.Template.PrimaryDisk.StorageTarget)
if err != nil {
return nil, nil, fmt.Errorf(`failed to get value of "storageTarget" field: %w`, err)
}
config.StorageTarget = StorageTarget(storageTarget)

pvcSize, err := p.configVarResolver.GetConfigVarStringValue(rawConfig.VirtualMachine.Template.PrimaryDisk.Size)
if err != nil {
return nil, nil, fmt.Errorf(`failed to get value of "pvcSize" field: %w`, err)
Expand Down Expand Up @@ -638,6 +653,7 @@ func (p *provider) newVirtualMachine(_ context.Context, c *Config, pc *providerc
var (
dataVolumeName = machine.Name
annotations = map[string]string{}
dvAnnotations = map[string]string{}
)
// Add machineName as prefix to secondaryDisks.
addPrefixToSecondaryDisk(c.SecondaryDisks, dataVolumeName)
Expand All @@ -649,6 +665,11 @@ func (p *provider) newVirtualMachine(_ context.Context, c *Config, pc *providerc
annotations["ovn.kubernetes.io/allow_live_migration"] = "true"

for k, v := range machine.Annotations {
if strings.HasPrefix(k, "cdi.kubevirt.io") {
dvAnnotations[k] = v
continue
}

annotations[k] = v
}

Expand Down Expand Up @@ -681,8 +702,8 @@ func (p *provider) newVirtualMachine(_ context.Context, c *Config, pc *providerc
},
Domain: kubevirtv1.DomainSpec{
Devices: kubevirtv1.Devices{
Disks: getVMDisks(c),
Interfaces: []kubevirtv1.Interface{*defaultBridgeNetwork},
Disks: getVMDisks(c),
},
Resources: resourceRequirements,
},
Expand All @@ -694,7 +715,7 @@ func (p *provider) newVirtualMachine(_ context.Context, c *Config, pc *providerc
TopologySpreadConstraints: getTopologySpreadConstraints(c, map[string]string{machineDeploymentLabelKey: labels[machineDeploymentLabelKey]}),
},
},
DataVolumeTemplates: getDataVolumeTemplates(c, dataVolumeName),
DataVolumeTemplates: getDataVolumeTemplates(c, dataVolumeName, dvAnnotations),
},
}
return virtualMachine, nil
Expand Down Expand Up @@ -831,27 +852,43 @@ func getVMVolumes(config *Config, dataVolumeName string, userDataSecretName stri
return volumes
}

func getDataVolumeTemplates(config *Config, dataVolumeName string) []kubevirtv1.DataVolumeTemplateSpec {
func getDataVolumeTemplates(config *Config, dataVolumeName string, annotations map[string]string) []kubevirtv1.DataVolumeTemplateSpec {
pvcRequest := corev1.ResourceList{corev1.ResourceStorage: config.PVCSize}
dataVolumeTemplates := []kubevirtv1.DataVolumeTemplateSpec{
{
ObjectMeta: metav1.ObjectMeta{
Name: dataVolumeName,
Name: dataVolumeName,
Annotations: annotations,
},
Spec: cdiv1beta1.DataVolumeSpec{
PVC: &corev1.PersistentVolumeClaimSpec{
StorageClassName: ptr.To(config.StorageClassName),
AccessModes: []corev1.PersistentVolumeAccessMode{
config.StorageAccessType,
},
Resources: corev1.VolumeResourceRequirements{
Requests: pvcRequest,
},
},
Source: config.OSImageSource,
},
},
}

switch config.StorageTarget {
case Storage:
dataVolumeTemplates[0].Spec.Storage = &cdiv1beta1.StorageSpec{
StorageClassName: ptr.To(config.StorageClassName),
AccessModes: []corev1.PersistentVolumeAccessMode{
config.StorageAccessType,
},
Resources: corev1.ResourceRequirements{
Requests: pvcRequest,
},
}
default:
dataVolumeTemplates[0].Spec.PVC = &corev1.PersistentVolumeClaimSpec{
StorageClassName: ptr.To(config.StorageClassName),
AccessModes: []corev1.PersistentVolumeAccessMode{
config.StorageAccessType,
},
Resources: corev1.VolumeResourceRequirements{
Requests: pvcRequest,
},
}
}

for _, sd := range config.SecondaryDisks {
dataVolumeTemplates = append(dataVolumeTemplates, kubevirtv1.DataVolumeTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Expand Down
7 changes: 7 additions & 0 deletions pkg/cloudprovider/provider/kubevirt/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type kubevirtProviderSpecConf struct {
OsImageDV string // if OsImage from DV and not from http source
Instancetype *kubevirtv1.InstancetypeMatcher
Preference *kubevirtv1.PreferenceMatcher
StorageTarget StorageTarget
OperatingSystem string
TopologySpreadConstraint bool
Affinity bool
Expand Down Expand Up @@ -123,6 +124,9 @@ func (k kubevirtProviderSpecConf) rawProviderSpec(t *testing.T) []byte {
"storageClassName": "longhorn3"}],
{{- end }}
"primaryDisk": {
{{- if .StorageTarget }}
"storageTarget": "{{ .StorageTarget }}",
{{- end }}
{{- if .OsImageDV }}
"osImage": "{{ .OsImageDV }}",
{{- else }}
Expand Down Expand Up @@ -217,6 +221,9 @@ func TestNewVirtualMachine(t *testing.T) {
{
name: "custom-local-disk",
specConf: kubevirtProviderSpecConf{OsImageDV: "ns/dvname"},
}, {
name: "use-storage-as-storage-target",
specConf: kubevirtProviderSpecConf{StorageTarget: Storage},
},
{
name: "http-image-source",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
annotations:
labels:
cluster.x-k8s.io/cluster-name: cluster-name
cluster.x-k8s.io/role: worker
kubevirt.io/vm: use-storage-as-storage-target
md: md-name
name: use-storage-as-storage-target
namespace: test-namespace
spec:
dataVolumeTemplates:
- metadata:
name: use-storage-as-storage-target
annotations: {}
spec:
source:
http:
url: "http://x.y.z.t/ubuntu.img"
storage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
runStrategy: Once
template:
metadata:
creationTimestamp: null
annotations:
"ovn.kubernetes.io/allow_live_migration": "true"
labels:
cluster.x-k8s.io/cluster-name: cluster-name
cluster.x-k8s.io/role: worker
kubevirt.io/vm: use-storage-as-storage-target
md: md-name
spec:
affinity: {}
domain:
devices:
disks:
- disk:
bus: virtio
name: datavolumedisk
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- macAddress: b6:f5:b4:fe:45:1d
name: default
bridge: {}
resources:
limits:
cpu: "2"
memory: 2Gi
requests:
cpu: "2"
memory: 2Gi
networks:
- name: default
pod: {}
terminationGracePeriodSeconds: 30
topologyspreadconstraints:
- maxskew: 1
topologykey: kubernetes.io/hostname
whenunsatisfiable: ScheduleAnyway
labelselector:
matchlabels:
md: md-name
volumes:
- dataVolume:
name: use-storage-as-storage-target
name: datavolumedisk
- cloudInitNoCloud:
secretRef:
name: udsn
name: cloudinitdisk
evictionStrategy: External
3 changes: 3 additions & 0 deletions pkg/cloudprovider/provider/kubevirt/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ type Template struct {
// PrimaryDisk.
type PrimaryDisk struct {
Disk
// StorageTarget describes which VirtualMachine storage target will be used in the DataVolumeTemplate.
StorageTarget providerconfigtypes.ConfigVarString `json:"storageTarget,omitempty"`
// OsImage describes the OS that will be installed on the VirtualMachine.
OsImage providerconfigtypes.ConfigVarString `json:"osImage,omitempty"`
// Source describes the VM Disk Image source.
Source providerconfigtypes.ConfigVarString `json:"source,omitempty"`
Expand Down