Skip to content
This repository has been archived by the owner on Mar 29, 2022. It is now read-only.

Commit

Permalink
Add to import image from local
Browse files Browse the repository at this point in the history
- add localuploadproxy crd to import local image to pvc
- add local source to vmim
  • Loading branch information
hyoung-90 committed Sep 17, 2020
1 parent 1b64879 commit 9cac1db
Show file tree
Hide file tree
Showing 8 changed files with 1,337 additions and 60 deletions.
2 changes: 2 additions & 0 deletions dbox
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ g)
;;
da)
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachineimage_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachineimage_volume_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_virtualmachineimages_crd.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachinevolume_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_virtualmachinevolumes_crd.yaml --ignore-not-found=true
Expand All @@ -21,6 +22,7 @@ dcr)
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachineimage_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachinevolume_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachinevolumeexport_cr.yaml --ignore-not-found=true
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachineimage_volume_cr.yaml --ignore-not-found=true
;;
dcrd)
kubectl delete -f deploy/crds/hypercloud.tmaxanc.com_virtualmachineimages_crd.yaml --ignore-not-found=true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: hypercloud.tmaxanc.com/v1alpha1
kind: VirtualMachineImage
metadata:
name: localvmim
spec:
source:
volume:
name: test
hostPath:
path: /mnt/hy
nodeName: young
snapshotClassName: csi-rbdplugin-snapclass
pvc:
volumeMode: Block
accessModes:
- ReadWriteMany
resources:
requests:
storage: "3Gi"
storageClassName: rook-ceph-block
1,213 changes: 1,209 additions & 4 deletions deploy/crds/hypercloud.tmaxanc.com_virtualmachineimages_crd.yaml

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ kubevirt-image-service 3/3 3 3 23s

# Use Kubevirt-Image-Service

## Import image from HTTP source
## Import image

### 1. Import image from HTTP source

vmim is the shortname for `VirtualMachineImage`.

Expand All @@ -71,6 +73,19 @@ NAME STATE
myubuntu Available
```

### 2. Import image from Local source

```shell
# Create a qcow2 file of `disk.img` in host path (/mnt/data).
# Deploy volume image CR with host path volume.
$ kubectl apply -f deploy/crds/hypercloud.tmaxanc.com_v1alpha1_virtualmachineimage_volume_cr.yaml

# Wait until image state is ready to use
$ kubectl get vmim
NAME STATE
localvmim Available
```

## Create volume from image

vmv is the shortname for `VirtualMachineVolume`.
Expand Down
6 changes: 4 additions & 2 deletions pkg/apis/hypercloud/v1alpha1/virtualmachineimage_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// VirtualMachineImageSource provides parameters to create a VirtualMachineImage from an HTTP source
// VirtualMachineImageSource represents the source for our VirtualMachineImage, this can be HTTP or volume
type VirtualMachineImageSource struct {
HTTP string `json:"http"`
HTTP string `json:"http,omitempty"`
Volume *corev1.Volume `json:"volume,omitempty"`
}

// VirtualMachineImageSpec defines the desired state of VirtualMachineImage
type VirtualMachineImageSpec struct {
Source VirtualMachineImageSource `json:"source"`
PVC corev1.PersistentVolumeClaimSpec `json:"pvc"`
SnapshotClassName string `json:"snapshotClassName"`
NodeName string `json:"nodeName,omitempty"`
}

// VirtualMachineImageState is the current state of VirtualMachineImage
Expand Down
7 changes: 6 additions & 1 deletion pkg/apis/hypercloud/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 41 additions & 38 deletions pkg/controller/virtualmachineimage/importer_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ const (
ImporterImageSize = "IMPORTER_IMAGE_SIZE"
// InsecureTLSVar provides a constant to capture our env variable "INSECURE_TLS"
InsecureTLSVar = "INSECURE_TLS"
// SourceHTTP is the source type HTTP, if unspecified or invalid, it defaults to SourceHTTP
SourceHTTP = "http"
// ImageContentType is the content-type of the imported file
ImageContentType = "kubevirt"
// ImportPodImage and ImportPodVerbose should be modified to get value from vmi env
Expand All @@ -43,6 +41,13 @@ const (
ImportPodVerbose = "1"
)

var (
sourceTypeHTTP = "http"
sourceTypeVolume = "volume"
sourceVolumeName = "source-vol"
sourceVolumeMountPath = "/data/source"
)

func (r *ReconcileVirtualMachineImage) syncImporterPod() error {
imported, found, err := r.isPvcImported()
if err != nil {
Expand Down Expand Up @@ -94,13 +99,6 @@ func GetImporterPodNameFromVmiName(vmiName string) string {
}

func newImporterPod(vmi *hc.VirtualMachineImage, scheme *runtime.Scheme) (*corev1.Pod, error) {
source, endpoint, err := getSourceAndEndpoint(vmi)
if err != nil {
return nil, err
}

// virtual machine image spec의 pvc storage는 필수 값이다.
pvcSize := vmi.Spec.PVC.Resources.Requests[corev1.ResourceStorage]
ip := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: GetImporterPodNameFromVmiName(vmi.Name),
Expand All @@ -112,14 +110,6 @@ func newImporterPod(vmi *hc.VirtualMachineImage, scheme *runtime.Scheme) (*corev
{
Name: "importer",
Image: ImportPodImage,
Args: []string{"-v=" + ImportPodVerbose},
Env: []corev1.EnvVar{
{Name: ImporterSource, Value: source},
{Name: ImporterEndpoint, Value: endpoint},
{Name: ImporterContentType, Value: ImageContentType},
{Name: ImporterImageSize, Value: pvcSize.String()},
{Name: InsecureTLSVar, Value: "true"},
},
Resources: corev1.ResourceRequirements{
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("0"),
Expand All @@ -128,12 +118,6 @@ func newImporterPod(vmi *hc.VirtualMachineImage, scheme *runtime.Scheme) (*corev
corev1.ResourceCPU: resource.MustParse("0"),
corev1.ResourceMemory: resource.MustParse("0")},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: ScratchVolName,
MountPath: ScratchDataDir,
},
},
VolumeDevices: []corev1.VolumeDevice{
{Name: DataVolName, DevicePath: WriteBlockPath},
},
Expand All @@ -148,29 +132,48 @@ func newImporterPod(vmi *hc.VirtualMachineImage, scheme *runtime.Scheme) (*corev
},
},
},
{
Name: ScratchVolName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: getScratchPvcNameFromVmiName(vmi.Name),
},
},
},
},
SecurityContext: &corev1.PodSecurityContext{
RunAsUser: &[]int64{0}[0],
},
},
}

if vmi.Spec.Source.HTTP != "" {
pvcSize := vmi.Spec.PVC.Resources.Requests[corev1.ResourceStorage]

ip.Spec.Containers[0].Args = []string{"-v=" + ImportPodVerbose}
ip.Spec.Containers[0].Env = []corev1.EnvVar{
{Name: ImporterSource, Value: sourceTypeHTTP},
{Name: ImporterEndpoint, Value: vmi.Spec.Source.HTTP},
{Name: ImporterContentType, Value: ImageContentType},
{Name: ImporterImageSize, Value: pvcSize.String()},
{Name: InsecureTLSVar, Value: "true"},
}
ip.Spec.Volumes = append(ip.Spec.Volumes, corev1.Volume{
Name: ScratchVolName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: getScratchPvcNameFromVmiName(vmi.Name),
},
},
})
ip.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
{Name: ScratchVolName, MountPath: ScratchDataDir}}
} else if vmi.Spec.Source.Volume != nil {
if vmi.Spec.Source.Volume.HostPath != nil {
ip.Spec.NodeName = vmi.Spec.NodeName
}
ip.Spec.Containers[0].Command = []string{"qemu-img", "convert", "-f", "qcow2", "-O", "raw", sourceVolumeMountPath + "/disk.img", WriteBlockPath}
ip.Spec.Volumes = append(ip.Spec.Volumes, corev1.Volume{
Name: sourceVolumeName,
VolumeSource: vmi.Spec.Source.Volume.VolumeSource,
})
ip.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
{Name: sourceVolumeName, MountPath: sourceVolumeMountPath}}
}
if err := controllerutil.SetControllerReference(vmi, ip, scheme); err != nil {
return nil, err
}
return ip, nil
}

func getSourceAndEndpoint(vmi *hc.VirtualMachineImage) (source, endpoint string, err error) {
if vmi.Spec.Source.HTTP == "" {
return "", "", errors.NewBadRequest("Invalid spec.source. Must provide http source.")
}
return SourceHTTP, vmi.Spec.Source.HTTP, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,7 @@ func (r *ReconcileVirtualMachineImage) Reconcile(request reconcile.Request) (rec
if err := r.validateVirtualMachineImageSpec(); err != nil {
return err
}
// pvc가 없으면 상태를 업데이트하고 pvc를 생성한다.
if err := r.syncPvc(); err != nil {
return err
}
// imported=false인 경우 스크래치 pvc를 생성한다.
if err := r.syncScratchPvc(); err != nil {
return err
}
// imported=false인 경우 임포터파드가 없으면 만든다. 있으면 컴플리트인지 확인해서 imported=true로 변경한다.
if err := r.syncImporterPod(); err != nil {
return err
}
// imported=true인 경우 스냅샷이 없으면 만들고, readyToUse를 true로 변경한다.
if err := r.syncSnapshot(); err != nil {
if err := r.reconcileVirtualMachineImage(); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -126,5 +113,43 @@ func (r *ReconcileVirtualMachineImage) validateVirtualMachineImageSpec() error {
if !found {
return goerrors.New("storage request in pvc is missing")
}
src := r.getSource()
if src == "" {
return goerrors.New("no source set for vmim")
} else if src == sourceTypeVolume {
// check node name is not empty when source is hostPath volume
if r.vmi.Spec.Source.Volume.HostPath != nil && r.vmi.Spec.NodeName == "" {
return goerrors.New("when the source is hostPath volume, the node name must not be empty")
}
}
return nil
}

func (r *ReconcileVirtualMachineImage) reconcileVirtualMachineImage() error {
// If the pvc doesn't exist, create a pvc and update vmim's status to creating
if err := r.syncPvc(); err != nil {
return err
}
if r.getSource() != sourceTypeVolume {
if err := r.syncScratchPvc(); err != nil {
return err
}
}
if err := r.syncImporterPod(); err != nil {
return err
}
if err := r.syncSnapshot(); err != nil {
return err
}
return nil
}

func (r *ReconcileVirtualMachineImage) getSource() string {
if r.vmi.Spec.Source.HTTP != "" {
return sourceTypeHTTP
} else if r.vmi.Spec.Source.Volume != nil {
return sourceTypeVolume
} else {
return ""
}
}

0 comments on commit 9cac1db

Please sign in to comment.