Skip to content

Commit

Permalink
feat(api): add importer's requests and limits for virtualization conf…
Browse files Browse the repository at this point in the history
…ig (#266)

Signed-off-by: Isteb4k <[email protected]>
  • Loading branch information
Isteb4k authored Aug 9, 2024
1 parent da65e56 commit 363283d
Show file tree
Hide file tree
Showing 26 changed files with 333 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func main() {

var pprofBindAddr string
flag.StringVar(&pprofBindAddr, "pprof-bind-address", os.Getenv(pprofBindAddrEnv), "enable pprof")

flag.Parse()

log := logger.New(logger.Options{
Expand All @@ -97,25 +98,19 @@ func main() {

printVersion(log)

importerImage, err := getRequiredEnvVar(common.ImporterPodImageNameVar)
if err != nil {
log.Error(err.Error())
os.Exit(1)
}

uploaderImage, err := getRequiredEnvVar(common.UploaderPodImageNameVar)
controllerNamespace, err := appconfig.GetRequiredEnvVar(common.PodNamespaceVar)
if err != nil {
log.Error(err.Error())
os.Exit(1)
}

controllerNamespace, err := getRequiredEnvVar(common.PodNamespaceVar)
dvcrSettings, err := appconfig.LoadDVCRSettingsFromEnvs(controllerNamespace)
if err != nil {
log.Error(err.Error())
os.Exit(1)
}

dvcrSettings, err := appconfig.LoadDVCRSettingsFromEnvs(controllerNamespace)
importSettings, err := appconfig.LoadImportSettingsFromEnv()
if err != nil {
log.Error(err.Error())
os.Exit(1)
Expand Down Expand Up @@ -195,17 +190,17 @@ func main() {
os.Exit(1)
}

if _, err = cvi.NewController(ctx, mgr, log, importerImage, uploaderImage, dvcrSettings, controllerNamespace); err != nil {
if _, err = cvi.NewController(ctx, mgr, log, importSettings.ImporterImage, importSettings.UploaderImage, importSettings.Requirements, dvcrSettings, controllerNamespace); err != nil {
log.Error(err.Error())
os.Exit(1)
}

if _, err = vd.NewController(ctx, mgr, log, importerImage, uploaderImage, dvcrSettings); err != nil {
if _, err = vd.NewController(ctx, mgr, log, importSettings.ImporterImage, importSettings.UploaderImage, importSettings.Requirements, dvcrSettings); err != nil {
log.Error(err.Error())
os.Exit(1)
}

if _, err = vi.NewController(ctx, mgr, log, importerImage, uploaderImage, dvcrSettings); err != nil {
if _, err = vi.NewController(ctx, mgr, log, importSettings.ImporterImage, importSettings.UploaderImage, importSettings.Requirements, dvcrSettings); err != nil {
log.Error(err.Error())
os.Exit(1)
}
Expand Down Expand Up @@ -250,11 +245,3 @@ func printVersion(log *slog.Logger) {
log.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
}

func getRequiredEnvVar(name string) (string, error) {
val := os.Getenv(name)
if val == "" {
return "", fmt.Errorf("environment variable %q undefined", name)
}
return val, nil
}
3 changes: 3 additions & 0 deletions images/virtualization-artifact/pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ const (
KubevirtAPIServerEndpointVar = "KUBEVIRT_APISERVER_ENDPOINT"
KubevirtAPIServerCABundlePathVar = "KUBEVIRT_APISERVER_CABUNDLE"

ImporterLimitsVar = "IMPORTER_LIMITS"
ImporterRequestsVar = "IMPORTER_REQUESTS"

VirtualizationApiAuthServiceAccountNameVar = "VIRTUALIZATION_API_AUTH_SERVICE_ACCOUNT_NAME"
VirtualizationApiAuthServiceAccountNamespaceVar = "VIRTUALIZATION_API_AUTH_SERVICE_ACCOUNT_NAMESPACE"
)
72 changes: 72 additions & 0 deletions images/virtualization-artifact/pkg/config/load_import_settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
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 config

import (
"encoding/json"
"fmt"
"os"

corev1 "k8s.io/api/core/v1"

"github.com/deckhouse/virtualization-controller/pkg/common"
)

type ImportSettings struct {
ImporterImage string
UploaderImage string
Requirements corev1.ResourceRequirements
}

func LoadImportSettingsFromEnv() (ImportSettings, error) {
var settings ImportSettings
var err error
settings.ImporterImage, err = GetRequiredEnvVar(common.ImporterPodImageNameVar)
if err != nil {
return ImportSettings{}, err
}

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

limits := os.Getenv(common.ImporterLimitsVar)
if limits != "" {
err = json.Unmarshal([]byte(limits), &settings.Requirements.Limits)
if err != nil {
return ImportSettings{}, err
}
}
requests := os.Getenv(common.ImporterRequestsVar)
if requests != "" {
err = json.Unmarshal([]byte(requests), &settings.Requirements.Requests)
if err != nil {
return ImportSettings{}, err
}
}

return settings, nil
}

func GetRequiredEnvVar(name string) (string, error) {
val := os.Getenv(name)
if val == "" {
return "", fmt.Errorf("environment variable %q undefined", name)
}
return val, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ func NewController(
log *slog.Logger,
importerImage string,
uploaderImage string,
requirements corev1.ResourceRequirements,
dvcr *dvcr.Settings,
ns string,
) (controller.Controller, error) {
log = log.With(logger.SlogController(ControllerName))

stat := service.NewStatService(log)
protection := service.NewProtectionService(mgr.GetClient(), virtv2.FinalizerCVIProtection)
importer := service.NewImporterService(dvcr, mgr.GetClient(), importerImage, PodPullPolicy, PodVerbose, ControllerName, protection)
uploader := service.NewUploaderService(dvcr, mgr.GetClient(), uploaderImage, PodPullPolicy, PodVerbose, ControllerName, protection)
importer := service.NewImporterService(dvcr, mgr.GetClient(), importerImage, requirements, PodPullPolicy, PodVerbose, ControllerName, protection)
uploader := service.NewUploaderService(dvcr, mgr.GetClient(), uploaderImage, requirements, PodPullPolicy, PodVerbose, ControllerName, protection)

sources := source.NewSources()
sources.Set(virtv2.DataSourceTypeHTTP, source.NewHTTPDataSource(stat, importer, dvcr, ns))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,20 @@ func (ds HTTPDataSource) Sync(ctx context.Context, cvi *virtv2.ClusterVirtualIma

log.Info("Cleaning up...")
case pod == nil:
condition.Status = metav1.ConditionFalse
condition.Reason = cvicondition.Provisioning
condition.Message = "DVCR Provisioner not found: create the new one."

cvi.Status.Phase = virtv2.ImageProvisioning
cvi.Status.Progress = ds.statService.GetProgress(cvi.GetUID(), pod, cvi.Status.Progress)
cvi.Status.Target.RegistryURL = ds.dvcrSettings.RegistryImageForCVMI(cvi.Name)

envSettings := ds.getEnvSettings(cvi, supgen)
err = ds.importerService.Start(ctx, envSettings, cvi, supgen, datasource.NewCABundleForCVMI(cvi.Spec.DataSource))
var requeue bool
requeue, err = setPhaseConditionForImporterStart(&condition, &cvi.Status.Phase, err)
if err != nil {
return false, err
}

log.Info("Create importer pod...", "progress", cvi.Status.Progress, "pod.phase", "nil")

return requeue, nil
case common.IsPodComplete(pod):
err = ds.statService.CheckPod(pod)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ func (ds ObjectRefDataSource) Sync(ctx context.Context, cvi *virtv2.ClusterVirtu

log.Info("Cleaning up...")
case pod == nil:
condition.Status = metav1.ConditionFalse
condition.Reason = cvicondition.Provisioning
condition.Message = "DVCR Provisioner not found: create the new one."

var dvcrDataSource controller.DVCRDataSource
dvcrDataSource, err = controller.NewDVCRDataSourcesForCVMI(ctx, cvi.Spec.DataSource, ds.client)
if err != nil {
Expand All @@ -111,14 +107,17 @@ func (ds ObjectRefDataSource) Sync(ctx context.Context, cvi *virtv2.ClusterVirtu
}

err = ds.importerService.Start(ctx, envSettings, cvi, supgen, datasource.NewCABundleForCVMI(cvi.Spec.DataSource))
var requeue bool
requeue, err = setPhaseConditionForImporterStart(&condition, &cvi.Status.Phase, err)
if err != nil {
return false, err
}

cvi.Status.Phase = virtv2.ImageProvisioning
cvi.Status.Target.RegistryURL = ds.dvcrSettings.RegistryImageForCVMI(cvi.Name)

log.Info("Ready", "progress", cvi.Status.Progress, "pod.phase", "nil")

return requeue, nil
case common.IsPodComplete(pod):
err = ds.statService.CheckPod(pod)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,20 @@ func (ds RegistryDataSource) Sync(ctx context.Context, cvi *virtv2.ClusterVirtua

log.Info("Cleaning up...")
case pod == nil:
condition.Status = metav1.ConditionFalse
condition.Reason = cvicondition.Provisioning
condition.Message = "DVCR Provisioner not found: create the new one."

envSettings := ds.getEnvSettings(cvi, supgen)
err = ds.importerService.Start(ctx, envSettings, cvi, supgen, datasource.NewCABundleForCVMI(cvi.Spec.DataSource))
var requeue bool
requeue, err = setPhaseConditionForImporterStart(&condition, &cvi.Status.Phase, err)
if err != nil {
return false, err
}

cvi.Status.Phase = virtv2.ImageProvisioning
cvi.Status.Progress = "0%"
cvi.Status.Target.RegistryURL = ds.dvcrSettings.RegistryImageForCVMI(cvi.Name)

log.Info("Create importer pod...", "progress", cvi.Status.Progress, "pod.phase", "nil")

return requeue, nil
case common.IsPodComplete(pod):
err = ds.statService.CheckPod(pod)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package source

import (
"context"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -85,3 +86,34 @@ func CleanUp(ctx context.Context, cvi *virtv2.ClusterVirtualImage, c Cleaner) (b
func isDiskProvisioningFinished(c metav1.Condition) bool {
return c.Reason == cvicondition.Ready
}

func setPhaseConditionForImporterStart(ready *metav1.Condition, phase *virtv2.ImagePhase, err error) (bool, error) {
return setPhaseConditionForPodStart(ready, phase, err, virtv2.ImageProvisioning, cvicondition.Provisioning)
}

func setPhaseConditionForUploaderStart(ready *metav1.Condition, phase *virtv2.ImagePhase, err error) (bool, error) {
return setPhaseConditionForPodStart(ready, phase, err, virtv2.ImagePending, cvicondition.WaitForUserUpload)
}

func setPhaseConditionForPodStart(ready *metav1.Condition, phase *virtv2.ImagePhase, err error, okPhase virtv2.ImagePhase, okReason cvicondition.ReadyReason) (bool, error) {
switch {
case err == nil:
*phase = okPhase
ready.Status = metav1.ConditionFalse
ready.Reason = okReason
ready.Message = "DVCR Provisioner not found: create the new one."
return true, nil
case cc.ErrQuotaExceeded(err):
*phase = virtv2.ImageFailed
ready.Status = metav1.ConditionFalse
ready.Reason = cvicondition.ProvisioningFailed
ready.Message = fmt.Sprintf("Quota exceeded: please configure the `importerResourceRequirements` field in the virtualization module configuration; %s.", err)
return false, nil
default:
*phase = virtv2.ImageFailed
ready.Status = metav1.ConditionFalse
ready.Reason = cvicondition.ProvisioningFailed
ready.Message = fmt.Sprintf("Unexpected error: %s.", err)
return false, err
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,20 @@ func (ds UploadDataSource) Sync(ctx context.Context, cvi *virtv2.ClusterVirtualI
cvi.Status.Phase = virtv2.ImagePending

log.Info("Cleaning up...")
case pod == nil && svc == nil && ing == nil:
condition.Status = metav1.ConditionFalse
condition.Reason = cvicondition.Provisioning
condition.Message = "DVCR Provisioner not found: create the new one."

case pod == nil || svc == nil || ing == nil:
envSettings := ds.getEnvSettings(supgen)
err = ds.uploaderService.Start(ctx, envSettings, cvi, supgen, datasource.NewCABundleForCVMI(cvi.Spec.DataSource))
var requeue bool
requeue, err = setPhaseConditionForUploaderStart(&condition, &cvi.Status.Phase, err)
if err != nil {
return false, err
}

cvi.Status.Phase = virtv2.ImagePending
cvi.Status.Target.RegistryURL = ds.dvcrSettings.RegistryImageForCVMI(cvi.Name)

log.Info("Create uploader pod...", "progress", cvi.Status.Progress, "pod.phase", nil)

return requeue, nil
case common.IsPodComplete(pod):
err = ds.statService.CheckPod(pod)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ImporterService struct {
dvcrSettings *dvcr.Settings
client client.Client
image string
requirements corev1.ResourceRequirements
pullPolicy string
verbose string
controllerName string
Expand All @@ -45,6 +46,7 @@ func NewImporterService(
dvcrSettings *dvcr.Settings,
client client.Client,
image string,
requirements corev1.ResourceRequirements,
pullPolicy string,
verbose string,
controllerName string,
Expand All @@ -54,6 +56,7 @@ func NewImporterService(
dvcrSettings: dvcrSettings,
client: client,
image: image,
requirements: requirements,
pullPolicy: pullPolicy,
verbose: verbose,
controllerName: controllerName,
Expand Down Expand Up @@ -131,12 +134,13 @@ func (s ImporterService) GetPod(ctx context.Context, sup *supplements.Generator)
func (s ImporterService) getPodSettings(ownerRef *metav1.OwnerReference, sup *supplements.Generator) *importer.PodSettings {
importerPod := sup.ImporterPod()
return &importer.PodSettings{
Name: importerPod.Name,
Namespace: importerPod.Namespace,
Image: s.image,
PullPolicy: s.pullPolicy,
OwnerReference: *ownerRef,
ControllerName: s.controllerName,
InstallerLabels: map[string]string{},
Name: importerPod.Name,
Namespace: importerPod.Namespace,
Image: s.image,
PullPolicy: s.pullPolicy,
OwnerReference: *ownerRef,
ControllerName: s.controllerName,
InstallerLabels: map[string]string{},
ResourceRequirements: &s.requirements,
}
}
Loading

0 comments on commit 363283d

Please sign in to comment.