97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
/*
|
|
Copyright 2022 The Kruise 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 deployment
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
apps "k8s.io/api/apps/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"github.com/openkruise/rollouts/api/v1beta1"
|
|
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control"
|
|
"github.com/openkruise/rollouts/pkg/util"
|
|
)
|
|
|
|
type realStableController struct {
|
|
stableInfo *util.WorkloadInfo
|
|
stableObject *apps.Deployment
|
|
stableClient client.Client
|
|
stableKey types.NamespacedName
|
|
}
|
|
|
|
func newStable(cli client.Client, key types.NamespacedName) realStableController {
|
|
return realStableController{stableClient: cli, stableKey: key}
|
|
}
|
|
|
|
func (rc *realStableController) GetStableInfo() *util.WorkloadInfo {
|
|
return rc.stableInfo
|
|
}
|
|
|
|
func (rc *realStableController) Initialize(release *v1beta1.BatchRelease) error {
|
|
if control.IsControlledByBatchRelease(release, rc.stableObject) {
|
|
return nil
|
|
}
|
|
|
|
d := util.GetEmptyObjectWithKey(rc.stableObject)
|
|
owner := control.BuildReleaseControlInfo(release)
|
|
|
|
body := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, util.BatchReleaseControlAnnotation, owner)
|
|
return rc.stableClient.Patch(context.TODO(), d, client.RawPatch(types.StrategicMergePatchType, []byte(body)))
|
|
}
|
|
|
|
func (rc *realStableController) Finalize(release *v1beta1.BatchRelease) error {
|
|
if rc.stableObject == nil {
|
|
return nil // no need to process deleted object
|
|
}
|
|
|
|
// if batchPartition == nil, workload should be promoted;
|
|
pause := release.Spec.ReleasePlan.BatchPartition != nil
|
|
body := fmt.Sprintf(`{"metadata":{"annotations":{"%s":null}},"spec":{"paused":%v}}`,
|
|
util.BatchReleaseControlAnnotation, pause)
|
|
|
|
d := util.GetEmptyObjectWithKey(rc.stableObject)
|
|
if err := rc.stableClient.Patch(context.TODO(), d, client.RawPatch(types.StrategicMergePatchType, []byte(body))); err != nil {
|
|
return err
|
|
}
|
|
if control.ShouldWaitResume(release) {
|
|
return waitAllUpdatedAndReady(d.(*apps.Deployment))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waitAllUpdatedAndReady(deployment *apps.Deployment) error {
|
|
if deployment.Spec.Paused {
|
|
return fmt.Errorf("promote error: deployment should not be paused")
|
|
}
|
|
|
|
createdReplicas := deployment.Status.Replicas
|
|
updatedReplicas := deployment.Status.UpdatedReplicas
|
|
if createdReplicas != updatedReplicas {
|
|
return fmt.Errorf("promote error: all replicas should be upgraded")
|
|
}
|
|
|
|
availableReplicas := deployment.Status.AvailableReplicas
|
|
allowedUnavailable := util.DeploymentMaxUnavailable(deployment)
|
|
if allowedUnavailable+availableReplicas < createdReplicas {
|
|
return fmt.Errorf("promote error: ready replicas should satisfy maxUnavailable")
|
|
}
|
|
return nil
|
|
}
|