Skip to content

Commit

Permalink
feat(cvi/vi): generate crd (#507)
Browse files Browse the repository at this point in the history
Generate ClusterVirtualImage and VirtualImage CRD by controller-gen
---------

Signed-off-by: Daniil Antoshin <[email protected]>
  • Loading branch information
danilrwx authored Nov 15, 2024
1 parent a8849ba commit ed9244e
Show file tree
Hide file tree
Showing 28 changed files with 1,428 additions and 990 deletions.
2 changes: 1 addition & 1 deletion api/Taskfile.dist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ env:
sh: echo $(go env GOMODCACHE)/$(go list -f '{{`{{.Path}}@{{.Version}}`}}' -m k8s.io/code-generator)

vars:
CONTROLLER_GEN_VERSION: 0.14.0
CONTROLLER_GEN_VERSION: 0.16.4

tasks:
generate:
Expand Down
99 changes: 86 additions & 13 deletions api/core/v1alpha2/cluster_virtual_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,34 @@ package v1alpha2

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

const (
ClusterVirtualImageKind = "ClusterVirtualImage"
ClusterVirtualImageResource = "clustervirtualimages"
)

// +genclient:nonNamespaced

// ClusterVirtualImage is a cluster wide available image for virtual machines.
// Describes a virtual disk image that can be used as a data source for new `VirtualDisks` or an installation image (iso) to be mounted in `Virtuals` directly. This resource type is available for all namespaces in the cluster.
//
// > This resource cannot be modified once it has been created.
//
// A container image is created under the hood of this resource, which is stored in a dedicated deckhouse virtualization container registry (DVCR).
//
// +kubebuilder:object:root=true
// +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true}
// +kubebuilder:resource:categories={virtualization},scope=Cluster,shortName={cvi,cvis},singular=clustervirtualimage
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
// +kubebuilder:printcolumn:name="CDROM",type=boolean,JSONPath=`.status.cdrom`
// +kubebuilder:printcolumn:name="Progress",type=string,JSONPath=`.status.progress`
// +kubebuilder:printcolumn:name="StoredSize",type=string,JSONPath=`.status.size.stored`,priority=1
// +kubebuilder:printcolumn:name="UnpackedSize",type=string,JSONPath=`.status.size.unpacked`,priority=1
// +kubebuilder:printcolumn:name="Registry URL",type=string,JSONPath=`.status.target.registryURL`,priority=1
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
// +kubebuilder:validation:XValidation:rule="self.metadata.name.size() <= 128",message="The name must be no longer than 128 characters."
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ClusterVirtualImage struct {
metav1.TypeMeta `json:",inline"`
Expand All @@ -55,19 +72,43 @@ type ClusterVirtualImageSpec struct {
DataSource ClusterVirtualImageDataSource `json:"dataSource"`
}

// An origin of the image.
// +kubebuilder:validation:XValidation:rule="self.type == 'HTTP' ? has(self.http) && !has(self.containerImage) && !has(self.objectRef) : true",message="HTTP requires http and cannot have ContainerImage or ObjectRef"
// +kubebuilder:validation:XValidation:rule="self.type == 'ContainerImage' ? has(self.containerImage) && !has(self.http) && !has(self.objectRef) : true",message="ContainerImage requires containerImage and cannot have HTTP or ObjectRef"
// +kubebuilder:validation:XValidation:rule="self.type == 'ObjectRef' ? has(self.objectRef) && !has(self.http) && !has(self.containerImage) : true",message="ObjectRef requires objectRef and cannot have HTTP or ContainerImage"
type ClusterVirtualImageDataSource struct {
Type DataSourceType `json:"type,omitempty"`
HTTP *DataSourceHTTP `json:"http,omitempty"`
ContainerImage *DataSourceContainerRegistry `json:"containerImage,omitempty"`
ObjectRef *ClusterVirtualImageObjectRef `json:"objectRef,omitempty"`
Type DataSourceType `json:"type"`
HTTP *DataSourceHTTP `json:"http,omitempty"`
ContainerImage *ClusterVirtualImageContainerImage `json:"containerImage,omitempty"`
ObjectRef *ClusterVirtualImageObjectRef `json:"objectRef,omitempty"`
}

// Use an image stored in external container registry. Only TLS enabled registries are supported. Use caBundle field to provide custom CA chain if needed.
type ClusterVirtualImageContainerImage struct {
// The container registry address of an image.
// +kubebuilder:example:="registry.example.com/images/slackware:15"
// +kubebuilder:validation:Pattern:=`^(?P<name>(?:(?P<domain>(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P<image>[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P<tag>[\w][\w.-]{0,127}))?(?:@(?P<digest>[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$`
Image string `json:"image"`
ImagePullSecret ImagePullSecret `json:"imagePullSecret,omitempty"`
// The CA chain in base64 format to verify the container registry.
// +kubebuilder:example:="YWFhCg=="
CABundle []byte `json:"caBundle,omitempty"`
}

// Use an existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk` to create an image.
//
// +kubebuilder:validation:XValidation:rule="self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' ? has(self.__namespace__) && size(self.__namespace__) > 0 : true",message="The namespace is required for VirtualDisk and VirtualImage"
// +kubebuilder:validation:XValidation:rule="self.kind == 'VirtualImage' || self.kind == 'VirtualDisk' ? has(self.__namespace__) && size(self.__namespace__) < 64 : true",message="The namespace must be no longer than 63 characters."
type ClusterVirtualImageObjectRef struct {
Kind ClusterVirtualImageObjectRefKind `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
Kind ClusterVirtualImageObjectRefKind `json:"kind"`
// A name of existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk`.
Name string `json:"name"`
// A namespace where `VirtualImage` or `VirtualDisk` is located.
Namespace string `json:"namespace,omitempty"`
}

// A kind of existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk`.
// +kubebuilder:validation:Enum:={ClusterVirtualImage,VirtualImage,VirtualDisk}
type ClusterVirtualImageObjectRefKind string

const (
Expand All @@ -77,7 +118,39 @@ const (
)

type ClusterVirtualImageStatus struct {
ImageStatus `json:",inline"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Image download speed from an external source. Appears only during the `Provisioning` phase.
DownloadSpeed *StatusSpeed `json:"downloadSpeed,omitempty"`
// Discovered sizes of the image.
Size ImageStatusSize `json:"size,omitempty"`
// Discovered format of the image.
Format string `json:"format,omitempty"`
// Whether the image is a format that is supposed to be mounted as a cdrom, such as iso and so on.
CDROM bool `json:"cdrom,omitempty"`
// Current status of `ClusterVirtualImage` resource:
// * Pending - The resource has been created and is on a waiting queue.
// * Provisioning - The process of resource creation (copying/downloading/building the image) is in progress.
// * WaitForUserUpload - Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`.
// * Ready - The resource is created and ready to use.
// * Failed - There was a problem when creating a resource.
// * Terminating - The process of resource deletion is in progress.
// +kubebuilder:validation:Enum:={Pending,Provisioning,WaitForUserUpload,Ready,Failed,Terminating}
Phase ImagePhase `json:"phase,omitempty"`
// Progress of copying an image from source to DVCR. Appears only during the `Provisioning' phase.
Progress string `json:"progress,omitempty"`
// The UID of the source (`VirtualImage`, `ClusterVirtualImage` or `VirtualDisk`) used when creating the cluster virtual image.
SourceUID *types.UID `json:"sourceUID,omitempty"`
// The latest available observations of an object's current state.
Conditions []metav1.Condition `json:"conditions,omitempty"`
// The generation last processed by the controller.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Deprecated. Use imageUploadURLs instead.
UploadCommand string `json:"uploadCommand,omitempty"`
ImageUploadURLs *ImageUploadURLs `json:"imageUploadURLs,omitempty"`
Target ClusterVirtualImageStatusTarget `json:"target,omitempty"`
}

type ClusterVirtualImageStatusTarget struct {
// Created image in DVCR.
// +kubebuilder:example:="dvcr.<dvcr-namespace>.svc/cvi/<image-name>:latest"
RegistryURL string `json:"registryURL,omitempty"`
}
57 changes: 47 additions & 10 deletions api/core/v1alpha2/data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,65 @@ limitations under the License.

package v1alpha2

// Fill the image with data from some external url. Supported schemas are:
//
// * http
// * https
//
// For https schema there is an option to skip TLS verification.
type DataSourceHTTP struct {
URL string `json:"url"`
CABundle []byte `json:"caBundle"`
// A checksum of the file, provided by the url, to verify if it was downloaded correctly or wasn't changed. The file should match all specified checksums.
Checksum *Checksum `json:"checksum,omitempty"`
// The http url with an image. The following formats are supported:
// * qcow2
// * vmdk
// * vdi
// * iso
// * raw
// these formats can also be compressed with the following formats:
// * gz
// * xz
// +kubebuilder:example:="https://mirror.example.com/images/slackware-15.qcow.gz"
// +kubebuilder:validation:Pattern=`^http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$`
URL string `json:"url"`
// The CA chain in base64 format to verify the url.
// +kubebuilder:example:="YWFhCg=="
CABundle []byte `json:"caBundle,omitempty"`
}

type DataSourceContainerRegistry struct {
Image string `json:"image"`
ImagePullSecret ImagePullSecret `json:"imagePullSecret"`
CABundle []byte `json:"caBundle"`
type ImagePullSecret struct {
// A name of the secret containing registry credentials.
Name string `json:"name,omitempty"`
// A namespace where imagePullSecret is located.
Namespace string `json:"namespace,omitempty"`
}

type ImagePullSecret struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
type ImagePullSecretName struct {
// A name of the secret containing registry credentials which must be located in the same namespace.
Name string `json:"name,omitempty"`
}

type Checksum struct {
MD5 string `json:"md5,omitempty"`
// +kubebuilder:example:="f3b59bed9f91e32fac1210184fcff6f5"
// +kubebuilder:validation:Pattern="^[0-9a-fA-F]{32}$"
// +kubebuilder:validation:MinLength:=32
// +kubebuilder:validation:MaxLength:=32
MD5 string `json:"md5,omitempty"`
// +kubebuilder:example:="78be890d71dde316c412da2ce8332ba47b9ce7a29d573801d2777e01aa20b9b5"
// +kubebuilder:validation:Pattern="^[0-9a-fA-F]{64}$"
// +kubebuilder:validation:MinLength:=64
// +kubebuilder:validation:MaxLength:=64
SHA256 string `json:"sha256,omitempty"`
}

// The type of an origin of the image. Options are:
//
// * `HTTP` — create an image from a file published on http/https service at a given url
// * `ContainerImage` — create the image from image stored in container registry.
// * `ObjectRef` — fill the disk from another existing resource.
// * `Upload` — fill the image with data, uploaded by user via the special interface.
//
// +kubebuilder:validation:Enum:={HTTP,ContainerImage,ObjectRef,Upload}
type DataSourceType string

const (
Expand Down
56 changes: 27 additions & 29 deletions api/core/v1alpha2/image_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ limitations under the License.

package v1alpha2

import "k8s.io/apimachinery/pkg/types"

type ImagePhase string

const (
Expand All @@ -30,41 +28,41 @@ const (
ImageLost ImagePhase = "PVCLost"
)

type ImageStatus struct {
DownloadSpeed *StatusSpeed `json:"downloadSpeed"`
Size ImageStatusSize `json:"size"`
Format string `json:"format,omitempty"`
CDROM bool `json:"cdrom"`
Target ImageStatusTarget `json:"target"`
Phase ImagePhase `json:"phase,omitempty"`
Progress string `json:"progress,omitempty"`
SourceUID *types.UID `json:"sourceUID,omitempty"`
// Deprecated: use ImageUploadURLs instead.
UploadCommand string `json:"uploadCommand,omitempty"`
ImageUploadURLs *ImageUploadURLs `json:"imageUploadURLs,omitempty"`
}

type ImageUploadURLs struct {
External string `json:"external,omitempty"`
// Command to upload the image using `Ingress` from outside the cluster.
External string `json:"external,omitempty"`
// Command to upload the image using `Service` within the cluster.
InCluster string `json:"inCluster,omitempty"`
}

// Image download speed from an external source. Appears only during the `Provisioning` phase.
type StatusSpeed struct {
Avg string `json:"avg,omitempty"`
AvgBytes string `json:"avgBytes,omitempty"`
Current string `json:"current,omitempty"`
// Average download speed.
// +kubebuilder:example:="1 Mbps"
Avg string `json:"avg,omitempty"`
// Average download speed in bytes per second.
// +kubebuilder:example:=1012345
AvgBytes string `json:"avgBytes,omitempty"`
// Current download speed.
// +kubebuilder:example:="5 Mbps"
Current string `json:"current,omitempty"`
// Current download speed in bytes per second.
// +kubebuilder:example:=5123456
CurrentBytes string `json:"currentBytes,omitempty"`
}

// Discovered sizes of the image.
type ImageStatusSize struct {
Stored string `json:"stored,omitempty"`
StoredBytes string `json:"storedBytes,omitempty"`
Unpacked string `json:"unpacked,omitempty"`
// Image size in human-readable format.
// +kubebuilder:example:="199M"
Stored string `json:"stored,omitempty"`
// Image size in bytes.
// +kubebuilder:example:=199001234
StoredBytes string `json:"storedBytes,omitempty"`
// Unpacked image size in human-readable format.
// +kubebuilder:example:="1G"
Unpacked string `json:"unpacked,omitempty"`
// Unpacked image size in bytes.
// +kubebuilder:example:=1000000234
UnpackedBytes string `json:"unpackedBytes,omitempty"`
}

type ImageStatusTarget struct {
RegistryURL string `json:"registryURL,omitempty"`
// FIXME: create ClusterImageStatus without Capacity and PersistentVolumeClaim
PersistentVolumeClaim string `json:"persistentVolumeClaimName,omitempty"`
}
20 changes: 16 additions & 4 deletions api/core/v1alpha2/virtual_disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,22 @@ type AttachedVirtualMachine struct {
}

type VirtualDiskDataSource struct {
Type DataSourceType `json:"type,omitempty"`
HTTP *DataSourceHTTP `json:"http,omitempty"`
ContainerImage *DataSourceContainerRegistry `json:"containerImage,omitempty"`
ObjectRef *VirtualDiskObjectRef `json:"objectRef,omitempty"`
Type DataSourceType `json:"type,omitempty"`
HTTP *DataSourceHTTP `json:"http,omitempty"`
ContainerImage *VirtualDiskContainerImage `json:"containerImage,omitempty"`
ObjectRef *VirtualDiskObjectRef `json:"objectRef,omitempty"`
}

// Use an image stored in external container registry. Only TLS enabled registries are supported. Use caBundle field to provide custom CA chain if needed.
type VirtualDiskContainerImage struct {
// The container registry address of an image.
// +kubebuilder:example:="registry.example.com/images/slackware:15"
// +kubebuilder:validation:Pattern:=`^(?P<name>(?:(?P<domain>(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P<image>[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P<tag>[\w][\w.-]{0,127}))?(?:@(?P<digest>[A-Za-z][A-Za-z0-9]*(?:[+.-_][A-Za-z][A-Za-z0-9]*)*:[0-9a-fA-F]{32,}))?$`
Image string `json:"image"`
ImagePullSecret ImagePullSecretName `json:"imagePullSecret,omitempty"`
// The CA chain in base64 format to verify the container registry.
// +kubebuilder:example:="YWFhCg=="
CABundle []byte `json:"caBundle,omitempty"`
}

type VirtualDiskObjectRef struct {
Expand Down
Loading

0 comments on commit ed9244e

Please sign in to comment.