mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00
248 lines
8.1 KiB
Go
248 lines
8.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
k8sv1 "k8s.io/api/core/v1"
|
|
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
cdiv1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1alpha1"
|
|
cdiclientset "kubevirt.io/containerized-data-importer/pkg/client/clientset/versioned"
|
|
)
|
|
|
|
const (
|
|
dataVolumePollInterval = 3 * time.Second
|
|
dataVolumeCreateTime = 60 * time.Second
|
|
dataVolumeDeleteTime = 60 * time.Second
|
|
dataVolumePhaseTime = 60 * time.Second
|
|
)
|
|
|
|
const (
|
|
// TinyCoreIsoURL provides a test url for the tineyCore iso image
|
|
TinyCoreIsoURL = "http://cdi-file-host.%s/tinyCore.iso"
|
|
//TinyCoreIsoRegistryURL provides a test url for the tinycore.qcow2 image wrapped in docker container
|
|
TinyCoreIsoRegistryURL = "docker://cdi-docker-registry-host.%s/tinycoreqcow2"
|
|
// HTTPSTinyCoreIsoURL provides a test (https) url for the tineyCore iso image
|
|
HTTPSTinyCoreIsoURL = "https://cdi-file-host.%s/tinyCore.iso"
|
|
// TinyCoreQcow2URLRateLimit provides a test url for the tineyCore iso image
|
|
TinyCoreQcow2URLRateLimit = "http://cdi-file-host.%s:82/tinyCore.qcow2"
|
|
)
|
|
|
|
// CreateDataVolumeFromDefinition is used by tests to create a testable Data Volume
|
|
func CreateDataVolumeFromDefinition(clientSet *cdiclientset.Clientset, namespace string, def *cdiv1.DataVolume) (*cdiv1.DataVolume, error) {
|
|
var dataVolume *cdiv1.DataVolume
|
|
err := wait.PollImmediate(dataVolumePollInterval, dataVolumeCreateTime, func() (bool, error) {
|
|
var err error
|
|
dataVolume, err = clientSet.CdiV1alpha1().DataVolumes(namespace).Create(def)
|
|
if err == nil || apierrs.IsAlreadyExists(err) {
|
|
return true, nil
|
|
}
|
|
return false, err
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return dataVolume, nil
|
|
}
|
|
|
|
// DeleteDataVolume deletes the DataVolume with the given name
|
|
func DeleteDataVolume(clientSet *cdiclientset.Clientset, namespace, name string) error {
|
|
return wait.PollImmediate(dataVolumePollInterval, dataVolumeDeleteTime, func() (bool, error) {
|
|
err := clientSet.CdiV1alpha1().DataVolumes(namespace).Delete(name, nil)
|
|
if err == nil || apierrs.IsNotFound(err) {
|
|
return true, nil
|
|
}
|
|
return false, err
|
|
})
|
|
}
|
|
|
|
// NewCloningDataVolume initializes a DataVolume struct with PVC annotations
|
|
func NewCloningDataVolume(dataVolumeName string, size string, sourcePvc *k8sv1.PersistentVolumeClaim) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
PVC: &cdiv1.DataVolumeSourcePVC{
|
|
Name: sourcePvc.Name,
|
|
Namespace: sourcePvc.Namespace,
|
|
},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewDataVolumeWithHTTPImport initializes a DataVolume struct with HTTP annotations
|
|
func NewDataVolumeWithHTTPImport(dataVolumeName string, size string, httpURL string) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
HTTP: &cdiv1.DataVolumeSourceHTTP{
|
|
URL: httpURL,
|
|
},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewDataVolumeWithHTTPImportToBlockPV initializes a DataVolume struct with HTTP annotations to import to block PV
|
|
func NewDataVolumeWithHTTPImportToBlockPV(dataVolumeName string, size string, httpURL string) *cdiv1.DataVolume {
|
|
volumeMode := corev1.PersistentVolumeMode(corev1.PersistentVolumeBlock)
|
|
storageClassName := "manual"
|
|
dataVolume := &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
HTTP: &cdiv1.DataVolumeSourceHTTP{
|
|
URL: httpURL,
|
|
},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
VolumeMode: &volumeMode,
|
|
StorageClassName: &storageClassName,
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
return dataVolume
|
|
}
|
|
|
|
// NewDataVolumeForUpload initializes a DataVolume struct with Upload annotations
|
|
func NewDataVolumeForUpload(dataVolumeName string, size string) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
Upload: &cdiv1.DataVolumeSourceUpload{},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewDataVolumeForBlankRawImage initializes a DataVolume struct for creating blank raw image
|
|
func NewDataVolumeForBlankRawImage(dataVolumeName, size string) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
Blank: &cdiv1.DataVolumeBlankImage{},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewDataVolumeForImageCloning initializes a DataVolume struct for cloning disk image
|
|
func NewDataVolumeForImageCloning(dataVolumeName, size string, namespace, pvcName string) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
PVC: &cdiv1.DataVolumeSourcePVC{
|
|
Namespace: namespace,
|
|
Name: pvcName,
|
|
},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewDataVolumeWithRegistryImport initializes a DataVolume struct with registry annotations
|
|
func NewDataVolumeWithRegistryImport(dataVolumeName string, size string, registryURL string) *cdiv1.DataVolume {
|
|
return &cdiv1.DataVolume{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: dataVolumeName,
|
|
},
|
|
Spec: cdiv1.DataVolumeSpec{
|
|
Source: cdiv1.DataVolumeSource{
|
|
Registry: &cdiv1.DataVolumeSourceRegistry{
|
|
URL: registryURL,
|
|
},
|
|
},
|
|
PVC: &k8sv1.PersistentVolumeClaimSpec{
|
|
AccessModes: []k8sv1.PersistentVolumeAccessMode{k8sv1.ReadWriteOnce},
|
|
Resources: k8sv1.ResourceRequirements{
|
|
Requests: k8sv1.ResourceList{
|
|
k8sv1.ResourceName(k8sv1.ResourceStorage): resource.MustParse(size),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// WaitForDataVolumePhase waits for DV's phase to be in a particular phase (Pending, Bound, or Lost)
|
|
func WaitForDataVolumePhase(clientSet *cdiclientset.Clientset, namespace string, phase cdiv1.DataVolumePhase, dataVolumeName string) error {
|
|
err := wait.PollImmediate(dataVolumePollInterval, dataVolumePhaseTime, func() (bool, error) {
|
|
dataVolume, err := clientSet.CdiV1alpha1().DataVolumes(namespace).Get(dataVolumeName, metav1.GetOptions{})
|
|
if err != nil || dataVolume.Status.Phase != phase {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("DataVolume %s not in phase %s within %v", dataVolumeName, phase, dataVolumePhaseTime)
|
|
}
|
|
return nil
|
|
}
|