Skip to content

Commit

Permalink
add http source for kubevirt diskImage (#1470)
Browse files Browse the repository at this point in the history
Signed-off-by: Sankalp Rangare <sankalprangare786@gmail.com>

Signed-off-by: Sankalp Rangare <sankalprangare786@gmail.com>
  • Loading branch information
sankalp-r committed Nov 21, 2022
1 parent 5795007 commit 099b8e3
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 33 deletions.
80 changes: 47 additions & 33 deletions pkg/cloudprovider/provider/kubevirt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,18 @@ func init() {
}
}

type imageSource string

const (
// topologyKeyHostname defines the topology key for the node hostname.
topologyKeyHostname = "kubernetes.io/hostname"
// machineDeploymentLabelKey defines the label key used to contains as value the MachineDeployment name
// which machine comes from.
machineDeploymentLabelKey = "md"
// httpSource defines the http source type for VM Disk Image.
httpSource imageSource = "http"
// pvcSource defines the pvc source type for VM Disk Image.
pvcSource imageSource = "pvc"
)

var supportedOS = map[providerconfigtypes.OperatingSystem]*struct{}{
Expand Down Expand Up @@ -93,7 +99,7 @@ type Config struct {
CPUs string
Memory string
Namespace string
OsImage OSImage
OSImageSource *cdiv1beta1.DataVolumeSource
StorageClassName string
PVCSize resource.Quantity
FlavorName string
Expand Down Expand Up @@ -148,11 +154,6 @@ type SecondaryDisks struct {
StorageClassName string
}

type OSImage struct {
URL string
DataVolumeName string
}

type kubeVirtServer struct {
vmi kubevirtv1.VirtualMachineInstance
}
Expand Down Expand Up @@ -247,15 +248,12 @@ func (p *provider) getConfig(provSpec clusterv1alpha1.ProviderSpec) (*Config, *p
return nil, nil, fmt.Errorf(`failed to get value of "memory" field: %w`, err)
}
config.Namespace = getNamespace()
osImage, err := p.configVarResolver.GetConfigVarStringValue(rawConfig.VirtualMachine.Template.PrimaryDisk.OsImage)

config.OSImageSource, err = p.parseOSImageSource(rawConfig.VirtualMachine.Template.PrimaryDisk, config.Namespace)
if err != nil {
return nil, nil, fmt.Errorf(`failed to get value of "sourceURL" field: %w`, err)
}
if _, err = url.ParseRequestURI(osImage); err == nil {
config.OsImage.URL = osImage
} else {
config.OsImage.DataVolumeName = osImage
return nil, nil, fmt.Errorf(`failed to get value of "osImageSource" field: %w`, err)
}

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 @@ -374,6 +372,35 @@ func (p *provider) parseTopologySpreadConstraint(topologyConstraints []kubevirtt
return parsedTopologyConstraints, nil
}

func (p *provider) parseOSImageSource(primaryDisk kubevirttypes.PrimaryDisk, nameSpace string) (*cdiv1beta1.DataVolumeSource, error) {
osImage, err := p.configVarResolver.GetConfigVarStringValue(primaryDisk.OsImage)
if err != nil {
return nil, fmt.Errorf(`failed to get value of "primaryDisk.osImage" field: %w`, err)
}
osImageSource, err := p.configVarResolver.GetConfigVarStringValue(primaryDisk.Source)
if err != nil {
return nil, fmt.Errorf(`failed to get value of "primaryDisk.source" field: %w`, err)
}
switch imageSource(osImageSource) {
case httpSource:
return &cdiv1beta1.DataVolumeSource{HTTP: &cdiv1beta1.DataVolumeSourceHTTP{URL: osImage}}, nil
case pvcSource:
if namespaceAndName := strings.Split(osImage, "/"); len(namespaceAndName) >= 2 {
return &cdiv1beta1.DataVolumeSource{PVC: &cdiv1beta1.DataVolumeSourcePVC{Name: namespaceAndName[1], Namespace: namespaceAndName[0]}}, nil
}
return &cdiv1beta1.DataVolumeSource{PVC: &cdiv1beta1.DataVolumeSourcePVC{Name: osImage, Namespace: nameSpace}}, nil
default:
// handle old API for backward compatibility.
if _, err = url.ParseRequestURI(osImage); err == nil {
return &cdiv1beta1.DataVolumeSource{HTTP: &cdiv1beta1.DataVolumeSourceHTTP{URL: osImage}}, nil
}
if namespaceAndName := strings.Split(osImage, "/"); len(namespaceAndName) >= 2 {
return &cdiv1beta1.DataVolumeSource{PVC: &cdiv1beta1.DataVolumeSourcePVC{Name: namespaceAndName[1], Namespace: namespaceAndName[0]}}, nil
}
return &cdiv1beta1.DataVolumeSource{PVC: &cdiv1beta1.DataVolumeSourcePVC{Name: osImage, Namespace: nameSpace}}, nil
}
}

// getNamespace returns the namespace where the VM is created.
// VM is created in a dedicated namespace <cluster-id>
// which is the namespace where the machine-controller pod is running.
Expand Down Expand Up @@ -506,7 +533,11 @@ func (p *provider) MachineMetricsLabels(machine *clusterv1alpha1.Machine) (map[s
if err == nil {
labels["cpus"] = c.CPUs
labels["memoryMIB"] = c.Memory
labels["osImage"] = c.OsImage.URL
if c.OSImageSource.HTTP != nil {
labels["osImage"] = c.OSImageSource.HTTP.URL
} else if c.OSImageSource.PVC != nil {
labels["osImage"] = c.OSImageSource.PVC.Name
}
}

return labels, err
Expand Down Expand Up @@ -787,7 +818,6 @@ func getVMVolumes(config *Config, dataVolumeName string, userDataSecretName stri
}

func getDataVolumeTemplates(config *Config, dataVolumeName string) []kubevirtv1.DataVolumeTemplateSpec {
dataVolumeSource := getDataVolumeSource(config.OsImage)
pvcRequest := corev1.ResourceList{corev1.ResourceStorage: config.PVCSize}
dataVolumeTemplates := []kubevirtv1.DataVolumeTemplateSpec{
{
Expand All @@ -804,7 +834,7 @@ func getDataVolumeTemplates(config *Config, dataVolumeName string) []kubevirtv1.
Requests: pvcRequest,
},
},
Source: dataVolumeSource,
Source: config.OSImageSource,
},
},
}
Expand All @@ -823,29 +853,13 @@ func getDataVolumeTemplates(config *Config, dataVolumeName string) []kubevirtv1.
Requests: corev1.ResourceList{corev1.ResourceStorage: sd.Size},
},
},
Source: dataVolumeSource,
Source: config.OSImageSource,
},
})
}
return dataVolumeTemplates
}

// getDataVolumeSource returns DataVolumeSource, HTTP or PVC.
func getDataVolumeSource(osImage OSImage) *cdiv1beta1.DataVolumeSource {
dataVolumeSource := &cdiv1beta1.DataVolumeSource{}
if osImage.URL != "" {
dataVolumeSource.HTTP = &cdiv1beta1.DataVolumeSourceHTTP{URL: osImage.URL}
} else if osImage.DataVolumeName != "" {
if nameSpaceAndName := strings.Split(osImage.DataVolumeName, "/"); len(nameSpaceAndName) >= 2 {
dataVolumeSource.PVC = &cdiv1beta1.DataVolumeSourcePVC{
Namespace: nameSpaceAndName[0],
Name: nameSpaceAndName[1],
}
}
}
return dataVolumeSource
}

func getAffinity(config *Config, matchKey, matchValue string) *corev1.Affinity {
affinity := &corev1.Affinity{}

Expand Down
14 changes: 14 additions & 0 deletions pkg/cloudprovider/provider/kubevirt/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type kubevirtProviderSpecConf struct {
TopologySpreadConstraint bool
Affinity bool
SecondaryDisks bool
OsImageSource imageSource
}

func (k kubevirtProviderSpecConf) rawProviderSpec(t *testing.T) []byte {
Expand Down Expand Up @@ -167,7 +168,12 @@ func (k kubevirtProviderSpecConf) rawProviderSpec(t *testing.T) []byte {
"osImage": "http://x.y.z.t/ubuntu.img",
{{- end }}
"size": "10Gi",
{{- if .OsImageSource }}
"storageClassName": "longhorn",
"source": "{{ .OsImageSource }}"
{{- else }}
"storageClassName": "longhorn"
{{- end }}
}
}
}
Expand Down Expand Up @@ -267,6 +273,14 @@ func TestNewVirtualMachine(t *testing.T) {
name: "custom-local-disk",
specConf: kubevirtProviderSpecConf{OsImageDV: "ns/dvname"},
},
{
name: "http-image-source",
specConf: kubevirtProviderSpecConf{OsImageSource: httpSource},
},
{
name: "pvc-image-source",
specConf: kubevirtProviderSpecConf{OsImageSource: pvcSource, OsImageDV: "ns/dvname"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
annotations:
labels:
kubevirt.io/vm: http-image-source
md: md-name
name: http-image-source
namespace: test-namespace
spec:
dataVolumeTemplates:
- metadata:
name: http-image-source
spec:
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
source:
http:
url: http://x.y.z.t/ubuntu.img
running: true
template:
metadata:
creationTimestamp: null
labels:
kubevirt.io/vm: http-image-source
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: http-image-source
name: datavolumedisk
- cloudInitNoCloud:
secretRef:
name: udsn
name: cloudinitdisk
73 changes: 73 additions & 0 deletions pkg/cloudprovider/provider/kubevirt/testdata/pvc-image-source.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
annotations:
labels:
kubevirt.io/vm: pvc-image-source
md: md-name
name: pvc-image-source
namespace: test-namespace
spec:
dataVolumeTemplates:
- metadata:
name: pvc-image-source
spec:
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
source:
pvc:
namespace: ns
name: dvname
running: true
template:
metadata:
creationTimestamp: null
labels:
kubevirt.io/vm: pvc-image-source
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: pvc-image-source
name: datavolumedisk
- cloudInitNoCloud:
secretRef:
name: udsn
name: cloudinitdisk
2 changes: 2 additions & 0 deletions pkg/cloudprovider/provider/kubevirt/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ type Template struct {
type PrimaryDisk struct {
Disk
OsImage providerconfigtypes.ConfigVarString `json:"osImage,omitempty"`
// Source describes the VM Disk Image source.
Source providerconfigtypes.ConfigVarString `json:"source,omitempty"`
}

// SecondaryDisks.
Expand Down

0 comments on commit 099b8e3

Please sign in to comment.