Files
kubevela/pkg/webhook/core.oam.dev/v1alpha2/applicationrollout/validation.go
Jian.Li 6cbdbe84b2 Refactor application code to make it run as Dag workflow (#2236)
* Refactor: remove use of AppConfig in AppRevision

* Refactor: remove insert secret and configmap

* Feat(workflow): upgrade

* Fix(conflict): workflow cherry

* Feat(workflow): support DAG mode

* Feat(workflow): prepare steps in step

* Feat(tools): random string

* Fix(rand): gosec weak random

* Fix(ci): test passing

* Feat(workflow): generate steps

* Fix: fix rebase from master

* Fix: fix workflow ut

* Feat(test): add test cases

* Fix: fix lint and rebase from master

* Refactor: application code

* Fix: fix ci lint

* Fix: make code reviewable

* Fix: workflow_test.go

* Feat: collect services

* Fix(ci): unit tests

* Feat: make one

* Test: application with input/output and workflow

* Fix: trace test

* Fix: update step index falied

* Feat: refactor op.#Load

* Fix: delete dead code

* Refactor: op.xxx

* Fix: patch component

* Test: add generator test

* Fix: add license

* Fix: pending e2e plugin test

* Fix: disable test/e2e-test

* Fix: patch by script

Co-authored-by: 天元 <jianbo.sjb@alibaba-inc.com>
Co-authored-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-09-12 10:12:46 +08:00

117 lines
4.7 KiB
Go

/*
Copyright 2021 The KubeVela Authors.
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 applicationrollout
import (
"context"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
ktypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/klog/v2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/webhook/common/rollout"
)
// ValidateCreate validates the AppRollout on creation
func (h *ValidatingHandler) ValidateCreate(appRollout *v1beta1.AppRollout) field.ErrorList {
klog.InfoS("validate create", "name", appRollout.Name)
allErrs := apimachineryvalidation.ValidateObjectMeta(&appRollout.ObjectMeta, true,
apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
fldPath := field.NewPath("spec")
target := appRollout.Spec.TargetAppRevisionName
if len(target) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("targetApplicationName"),
"target application name cannot be empty"))
// can't continue without target
return allErrs
}
if appRollout.DeletionTimestamp.IsZero() {
var targetAppRevision v1beta1.ApplicationRevision
sourceAppRevision := &v1beta1.ApplicationRevision{}
targetAppName := appRollout.Spec.TargetAppRevisionName
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appRollout.Namespace, Name: targetAppName},
&targetAppRevision); err != nil {
klog.ErrorS(err, "cannot locate target application revision", "target application revision",
klog.KRef(appRollout.Namespace, targetAppName))
allErrs = append(allErrs, field.NotFound(fldPath.Child("targetAppRevisionName"), targetAppName))
// can't continue without target
return allErrs
}
sourceAppName := appRollout.Spec.SourceAppRevisionName
if sourceAppName != "" {
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appRollout.Namespace, Name: sourceAppName},
sourceAppRevision); err != nil {
klog.ErrorS(err, "cannot locate source application revision", "source application revision",
klog.KRef(appRollout.Namespace, sourceAppName))
allErrs = append(allErrs, field.NotFound(fldPath.Child("sourceAppRevisionName"), sourceAppName))
}
} else {
// nolint
sourceAppRevision = nil
}
/*
// TODO(wonderflow): refactor it and add component validate using appRevision
// 1. there can only be one component or less
// 2. if there are no components, make sure the applications has only one common component so that's the default
// 3. it is contained in both source and target application
// 4. the common component has the same type
*/
}
// validate the rollout plan spec
allErrs = append(allErrs, rollout.ValidateCreate(h, &appRollout.Spec.RolloutPlan, fldPath.Child("rolloutPlan"))...)
return allErrs
}
// ValidateUpdate validates the AppRollout on update
func (h *ValidatingHandler) ValidateUpdate(new, old *v1beta1.AppRollout) field.ErrorList {
klog.InfoS("validate update", "name", new.Name)
errList := h.ValidateCreate(new)
fldPath := field.NewPath("spec").Child("rolloutPlan")
if len(errList) > 0 {
return errList
}
// we can only reuse the rollout after reaching terminating state if the target and source has changed
if old.Status.RollingState == v1alpha1.RolloutSucceedState ||
old.Status.RollingState == v1alpha1.RolloutFailedState {
if old.Spec.SourceAppRevisionName == new.Spec.SourceAppRevisionName &&
old.Spec.TargetAppRevisionName == new.Spec.TargetAppRevisionName {
if !apiequality.Semantic.DeepEqual(&old.Spec.RolloutPlan, &new.Spec.RolloutPlan) {
// here we allow user restart a scale rollout by modifying rollout targetSize
if old.Spec.RolloutPlan.TargetSize != nil && new.Spec.RolloutPlan.TargetSize != nil &&
*old.Spec.RolloutPlan.TargetSize != *new.Spec.RolloutPlan.TargetSize {
return errList
}
errList = append(errList, field.Invalid(fldPath, new.Spec,
"a successful or failed rollout cannot be modified without changing the target or the source"))
return errList
}
}
}
return rollout.ValidateUpdate(h, &new.Spec.RolloutPlan, &old.Spec.RolloutPlan, fldPath)
}