Skip to content

Commit

Permalink
feat(vi): add snapshot objectref
Browse files Browse the repository at this point in the history
Signed-off-by: Daniil Antoshin <[email protected]>

a

Signed-off-by: Daniil Antoshin <[email protected]>

feat

Signed-off-by: Daniil Antoshin <[email protected]>

f

Signed-off-by: Daniil Antoshin <[email protected]>

rename

Signed-off-by: Daniil Antoshin <[email protected]>

fix

Signed-off-by: Daniil Antoshin <[email protected]>

fix

Signed-off-by: Daniil Antoshin <[email protected]>

fix

Signed-off-by: Daniil Antoshin <[email protected]>
  • Loading branch information
danilrwx committed Jan 16, 2025
1 parent 1f3f55b commit cb449da
Show file tree
Hide file tree
Showing 15 changed files with 1,082 additions and 12 deletions.
9 changes: 5 additions & 4 deletions api/core/v1alpha2/virtual_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,22 @@ type VirtualImageContainerImage struct {
CABundle []byte `json:"caBundle,omitempty"`
}

// Use an existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk` to create an image.
// Use an existing `VirtualImage`, `ClusterVirtualImage`, `VirtualDisk` or `VirtualDiskSnapshot` to create an image.
type VirtualImageObjectRef struct {
// A kind of existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk`.
// A kind of existing `VirtualImage`, `ClusterVirtualImage`, `VirtualDisk` or `VirtualDiskSnapshot`.
Kind VirtualImageObjectRefKind `json:"kind"`
// A name of existing `VirtualImage`, `ClusterVirtualImage` or `VirtualDisk`.
// A name of existing `VirtualImage`, `ClusterVirtualImage`, `VirtualDisk` or `VirtualDiskSnapshot`.
Name string `json:"name"`
}

// +kubebuilder:validation:Enum:={ClusterVirtualImage,VirtualImage,VirtualDisk}
// +kubebuilder:validation:Enum:={ClusterVirtualImage,VirtualImage,VirtualDisk,VirtualDiskSnapshot}
type VirtualImageObjectRefKind string

const (
VirtualImageObjectRefKindVirtualImage VirtualImageObjectRefKind = "VirtualImage"
VirtualImageObjectRefKindClusterVirtualImage VirtualImageObjectRefKind = "ClusterVirtualImage"
VirtualImageObjectRefKindVirtualDisk VirtualImageObjectRefKind = "VirtualDisk"
VirtualImageObjectRefKindVirtualDiskSnapshot VirtualImageObjectRefKind = "VirtualDiskSnapshot"
)

// Storage type to store the image for current virtualization setup.
Expand Down
13 changes: 7 additions & 6 deletions crds/virtualimages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,22 +163,23 @@ spec:
type: object
objectRef:
description:
Use an existing `VirtualImage`, `ClusterVirtualImage`
or `VirtualDisk` to create an image.
Use an existing `VirtualImage`, `ClusterVirtualImage`,
`VirtualDisk` or `VirtualDiskSnapshot` to create an image.
properties:
kind:
description:
A kind of existing `VirtualImage`, `ClusterVirtualImage`
or `VirtualDisk`.
A kind of existing `VirtualImage`, `ClusterVirtualImage`,
`VirtualDisk` or `VirtualDiskSnapshot`.
enum:
- ClusterVirtualImage
- VirtualImage
- VirtualDisk
- VirtualDiskSnapshot
type: string
name:
description:
A name of existing `VirtualImage`, `ClusterVirtualImage`
or `VirtualDisk`.
A name of existing `VirtualImage`, `ClusterVirtualImage`,
`VirtualDisk` or `VirtualDiskSnapshot`.
type: string
required:
- kind
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func main() {
}

viLogger := logger.NewControllerLogger(vi.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList)
if _, err = vi.NewController(ctx, mgr, viLogger, importSettings.ImporterImage, importSettings.UploaderImage, importSettings.Requirements, dvcrSettings, viStorageClassSettings); err != nil {
if _, err = vi.NewController(ctx, mgr, viLogger, importSettings.ImporterImage, importSettings.UploaderImage, importSettings.BounderImage, importSettings.Requirements, dvcrSettings, viStorageClassSettings); err != nil {
log.Error(err.Error())
os.Exit(1)
}
Expand Down
4 changes: 4 additions & 0 deletions images/virtualization-artifact/pkg/common/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const (
// OwnerUID provides the UID of the owner entity (either PVC or DV)
OwnerUID = "OWNER_UID"

// BounderContainerName provides a constant to use as a name for bounder Container
BounderContainerName = "bounder"
// ImporterContainerName provides a constant to use as a name for importer Container
ImporterContainerName = "importer"
// UploaderContainerName provides a constant to use as a name for uploader Container
Expand All @@ -34,6 +36,8 @@ const (
ImporterPodImageNameVar = "IMPORTER_IMAGE"
// UploaderPodImageNameVar is a name of variable with the image name for the uploader Pod
UploaderPodImageNameVar = "UPLOADER_IMAGE"
// BounderPodImageNameVar is a name of variable with the image name for the bounder Pod
BounderPodImageNameVar = "BOUNDER_IMAGE"
// ImporterCertDir is where the configmap containing certs will be mounted
ImporterCertDir = "/certs"
// ImporterProxyCertDir is where the configmap containing proxy certs will be mounted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
type ImportSettings struct {
ImporterImage string
UploaderImage string
BounderImage string
Requirements corev1.ResourceRequirements
}

Expand All @@ -50,6 +51,11 @@ func LoadImportSettingsFromEnv() (ImportSettings, error) {
return ImportSettings{}, err
}

settings.BounderImage, err = GetRequiredEnvVar(common.BounderPodImageNameVar)
if err != nil {
return ImportSettings{}, err
}

limits := os.Getenv(ProvisioningPodLimitsVar)
if limits != "" {
err = json.Unmarshal([]byte(limits), &settings.Requirements.Limits)
Expand Down
164 changes: 164 additions & 0 deletions images/virtualization-artifact/pkg/controller/bounder/bounder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
Copyright 2024 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package bounder

import (
"context"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/deckhouse/virtualization-controller/pkg/common"
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
"github.com/deckhouse/virtualization-controller/pkg/common/object"
podutil "github.com/deckhouse/virtualization-controller/pkg/common/pod"
"github.com/deckhouse/virtualization-controller/pkg/common/provisioner"
)

type Bounder struct {
PodSettings *PodSettings
}

func NewBounder(podSettings *PodSettings) *Bounder {
return &Bounder{
PodSettings: podSettings,
}
}

type PodSettings struct {
Name string
Image string
PullPolicy string
Namespace string
OwnerReference metav1.OwnerReference
ControllerName string
InstallerLabels map[string]string
ResourceRequirements *corev1.ResourceRequirements
ImagePullSecrets []corev1.LocalObjectReference
PriorityClassName string
PVCName string
NodePlacement *provisioner.NodePlacement
}

// CreatePod creates and returns a pointer to a pod which is created based on the passed-in endpoint, secret
// name, etc. A nil secret means the endpoint credentials are not passed to the
// bounder pod.
func (imp *Bounder) CreatePod(ctx context.Context, client client.Client) (*corev1.Pod, error) {
pod, err := imp.makeBounderPodSpec()
if err != nil {
return nil, err
}

err = client.Create(ctx, pod)
if err != nil {
return nil, err
}

return pod, nil
}

// makeBounderPodSpec creates and return the bounder pod spec based on the passed-in endpoint, secret and pvc.
func (imp *Bounder) makeBounderPodSpec() (*corev1.Pod, error) {
pod := corev1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: imp.PodSettings.Name,
Namespace: imp.PodSettings.Namespace,
Annotations: map[string]string{
annotations.AnnCreatedBy: "yes",
},
OwnerReferences: []metav1.OwnerReference{
imp.PodSettings.OwnerReference,
},
},
Spec: corev1.PodSpec{
// Container and volumes will be added later.
Containers: []corev1.Container{},
Volumes: []corev1.Volume{},
RestartPolicy: corev1.RestartPolicyOnFailure,
PriorityClassName: imp.PodSettings.PriorityClassName,
ImagePullSecrets: imp.PodSettings.ImagePullSecrets,
},
}

if imp.PodSettings.NodePlacement != nil && len(imp.PodSettings.NodePlacement.Tolerations) > 0 {
pod.Spec.Tolerations = imp.PodSettings.NodePlacement.Tolerations

err := provisioner.KeepNodePlacementTolerations(imp.PodSettings.NodePlacement, &pod)
if err != nil {
return nil, err
}
}

annotations.SetRecommendedLabels(&pod, imp.PodSettings.InstallerLabels, imp.PodSettings.ControllerName)
podutil.SetRestrictedSecurityContext(&pod.Spec)

container := imp.makeBounderContainerSpec()
imp.addVolumes(&pod, container)
pod.Spec.Containers = append(pod.Spec.Containers, *container)

return &pod, nil
}

func (imp *Bounder) makeBounderContainerSpec() *corev1.Container {
container := &corev1.Container{
Name: common.BounderContainerName,
Image: imp.PodSettings.Image,
ImagePullPolicy: corev1.PullPolicy(imp.PodSettings.PullPolicy),
}

if imp.PodSettings.ResourceRequirements != nil {
container.Resources = *imp.PodSettings.ResourceRequirements
}

return container
}

// addVolumes fills Volumes in Pod spec and VolumeMounts and envs in container spec.
func (imp *Bounder) addVolumes(pod *corev1.Pod, container *corev1.Container) {
if imp.PodSettings.PVCName != "" {
podutil.AddVolumeDevice(
pod,
container,
corev1.Volume{
Name: "volume",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: imp.PodSettings.PVCName,
},
},
},
corev1.VolumeDevice{
Name: "volume",
DevicePath: "/dev/xvda",
},
)
}
}

type PodNamer interface {
BounderPod() types.NamespacedName
}

func FindPod(ctx context.Context, client client.Client, name PodNamer) (*corev1.Pod, error) {
return object.FetchObject(ctx, name.BounderPod(), client, &corev1.Pod{})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2024 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package bounder

import (
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)

func Test_MakePodSpec(t *testing.T) {
podSettings := &PodSettings{
Name: "bounder-pod",
Image: "localhost:5000/bounder:latest",
PullPolicy: string(corev1.PullAlways),
Namespace: "virt-controller",
PVCName: "bounder-pvc",
OwnerReference: metav1.OwnerReference{
APIVersion: "v1",
Kind: "Pod",
Name: "other-pod",
UID: "123-123",
Controller: ptr.To(true),
BlockOwnerDeletion: ptr.To(true),
},
ControllerName: "test-controller",
}

imp := NewBounder(podSettings)

pod, err := imp.makeBounderPodSpec()
require.NoError(t, err)

if pod.Namespace == "" {
t.Fatalf("pod.Namespace should not be empty!")
}
}
Loading

0 comments on commit cb449da

Please sign in to comment.