Skip to content

Commit

Permalink
Expose virtual size of VM images
Browse files Browse the repository at this point in the history
With this change, we can do this:

  # kubectl get vmimages
  NAME          DISPLAY-NAME                                         SIZE          VIRTUALSIZE   AGE
  image-26r4s   sles15-sp5-minimal-vm.x86_64-kvm-and-xen-qu1.qcow2   267845632     25769803776   6m36s
  image-bgnhb   sle-micro.x86_64-5.5.0-default-qcow-gm.qcow2         1001652224    21474836480   20m
  image-nmmvj   sle-15-sp5-full-x86_64-gm-media1.iso                 14548992000   14548992000   19m

This in turn means we can update the UI to take image virtual size into
account when creating VMs.

Note that this requires the following Longhorn PRs, which have been
backported to longhorn 1.5.5 and 1.6.2:

- longhorn/backing-image-manager#208
- longhorn/longhorn-manager#2680
- longhorn/longhorn#8267

Related issue: harvester#4905

Signed-off-by: Tim Serong <tserong@suse.com>
  • Loading branch information
tserong committed Jul 3, 2024
1 parent 9c0a3a1 commit 79f6cdc
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 4 deletions.
4 changes: 4 additions & 0 deletions api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -9547,6 +9547,10 @@
},
"storageClassName": {
"type": "string"
},
"virtualSize": {
"type": "integer",
"format": "int64"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ spec:
- jsonPath: .status.size
name: SIZE
type: integer
- jsonPath: .status.virtualSize
name: VIRTUALSIZE
type: integer
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
Expand Down Expand Up @@ -123,6 +126,9 @@ spec:
type: integer
storageClassName:
type: string
virtualSize:
format: int64
type: integer
type: object
required:
- spec
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/harvesterhci.io/v1beta1/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (
// +kubebuilder:resource:shortName=vmimage;vmimages,scope=Namespaced
// +kubebuilder:printcolumn:name="DISPLAY-NAME",type=string,JSONPath=`.spec.displayName`
// +kubebuilder:printcolumn:name="SIZE",type=integer,JSONPath=`.status.size`
// +kubebuilder:printcolumn:name="VIRTUALSIZE",type=integer,JSONPath=`.status.virtualSize`
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=`.metadata.creationTimestamp`

type VirtualMachineImage struct {
Expand Down Expand Up @@ -80,6 +81,9 @@ type VirtualMachineImageStatus struct {
// +optional
Size int64 `json:"size,omitempty"`

// +optional
VirtualSize int64 `json:"virtualSize,omitempty"`

// +optional
StorageClassName string `json:"storageClassName,omitempty"`

Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/harvesterhci.io/v1beta1/openapi_generated.go

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

32 changes: 28 additions & 4 deletions pkg/controller/master/image/backing_image_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,26 @@ func (h *backingImageHandler) OnChanged(_ string, backingImage *lhv1beta2.Backin
} else if err != nil {
return nil, err
}
if !harvesterv1beta1.ImageInitialized.IsTrue(vmImage) || !harvesterv1beta1.ImageImported.IsUnknown(vmImage) {
// There are two states that we care about here:
// - ImageInitialized
// - ImageImported
// If ImageInitialized isn't yet true, it means there's no backing
// image or storage class, so we've got nothing to work with yet and
// should return immediately.
if !harvesterv1beta1.ImageInitialized.IsTrue(vmImage) {
return nil, nil
}
// If ImageImported is not unknown, it means the backing image has
// been imported, and we think we know everything about it, i.e. we've
// now been through a series of progress updates during image download,
// and those are finally done, so let's not worry about further updates.
// The problem with this logic is that when we add new fields (e.g.
// VirtualSize), existing images won't pick up those newly added fields
// if we return here immediately. So, now there's an additional check
// for that new field. Another, simpler, alternative would be to just
// drop the ImageImported.IsUnknown check entirely, and let the following
// loop run through on every OnChanged event.
if !harvesterv1beta1.ImageImported.IsUnknown(vmImage) && vmImage.Status.VirtualSize == backingImage.Status.VirtualSize {
return nil, nil
}
toUpdate := vmImage.DeepCopy()
Expand All @@ -46,11 +65,16 @@ func (h *backingImageHandler) OnChanged(_ string, backingImage *lhv1beta2.Backin
toUpdate = handleFail(toUpdate, condition.Cond(harvesterv1beta1.ImageImported), fmt.Errorf(status.Message))
toUpdate.Status.Progress = status.Progress
} else if status.State == lhv1beta2.BackingImageStateReady || status.State == lhv1beta2.BackingImageStateReadyForTransfer {
harvesterv1beta1.ImageImported.True(toUpdate)
harvesterv1beta1.ImageImported.Reason(toUpdate, "Imported")
harvesterv1beta1.ImageImported.Message(toUpdate, status.Message)
toUpdate.Status.Progress = status.Progress
toUpdate.Status.Size = backingImage.Status.Size
toUpdate.Status.VirtualSize = backingImage.Status.VirtualSize
if toUpdate.Status.VirtualSize > 0 {
// We can't set ImageImported to True until we know the VirtualSize,
// which may happen one update after the image becomes ready.
harvesterv1beta1.ImageImported.True(toUpdate)
harvesterv1beta1.ImageImported.Reason(toUpdate, "Imported")
harvesterv1beta1.ImageImported.Message(toUpdate, status.Message)
}
} else if status.Progress != toUpdate.Status.Progress {
harvesterv1beta1.ImageImported.Unknown(toUpdate)
harvesterv1beta1.ImageImported.Reason(toUpdate, "Importing")
Expand Down

0 comments on commit 79f6cdc

Please sign in to comment.