167 lines
5.1 KiB
Go
167 lines
5.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 util
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
|
|
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
|
|
rolloutv1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
|
rolloutv1beta1 "github.com/openkruise/rollouts/api/v1beta1"
|
|
"github.com/openkruise/rollouts/pkg/util/client"
|
|
apps "k8s.io/api/apps/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/client-go/util/retry"
|
|
"k8s.io/klog/v2"
|
|
"sigs.k8s.io/controller-runtime/pkg/controller"
|
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
|
"sigs.k8s.io/controller-runtime/pkg/source"
|
|
)
|
|
|
|
// RolloutState is annotation[rollouts.kruise.io/in-progressing] value
|
|
type RolloutState struct {
|
|
RolloutName string `json:"rolloutName"`
|
|
}
|
|
|
|
func IsRollbackInBatchPolicy(rollout *rolloutv1beta1.Rollout, labels map[string]string) bool {
|
|
// currently, only support the case of no traffic routing
|
|
if len(rollout.Spec.Strategy.Canary.TrafficRoutings) > 0 {
|
|
return false
|
|
}
|
|
workloadRef := rollout.Spec.WorkloadRef
|
|
//currently, only CloneSet, StatefulSet support this policy
|
|
if workloadRef.Kind == ControllerKindSts.Kind ||
|
|
workloadRef.Kind == ControllerKruiseKindCS.Kind ||
|
|
strings.EqualFold(labels[WorkloadTypeLabel], ControllerKindSts.Kind) {
|
|
if rollout.Annotations[rolloutv1alpha1.RollbackInBatchAnnotation] == "true" {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func AddWorkloadWatcher(c controller.Controller, handler handler.EventHandler) error {
|
|
// Watch changes to Deployment
|
|
err := c.Watch(&source.Kind{Type: &apps.Deployment{}}, handler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Watch changes to Native StatefulSet, use unstructured informer
|
|
err = c.Watch(&source.Kind{Type: &apps.StatefulSet{}}, handler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Watch changes to CloneSet if it has the CRD
|
|
if DiscoverGVK(ControllerKruiseKindCS) {
|
|
err := c.Watch(&source.Kind{Type: &kruiseappsv1alpha1.CloneSet{}}, handler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// Watch changes to DaemonSet if it has the CRD
|
|
if DiscoverGVK(ControllerKruiseKindDS) {
|
|
err := c.Watch(&source.Kind{Type: &kruiseappsv1alpha1.DaemonSet{}}, handler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// Watch changes to Advanced StatefulSet if it has the CRD
|
|
if DiscoverGVK(ControllerKruiseKindSts) {
|
|
err := c.Watch(&source.Kind{Type: &kruiseappsv1beta1.StatefulSet{}}, handler)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func DiscoverGVK(gvk schema.GroupVersionKind) bool {
|
|
genericClient := client.GetGenericClient()
|
|
if genericClient == nil {
|
|
return true
|
|
}
|
|
discoveryClient := genericClient.DiscoveryClient
|
|
|
|
startTime := time.Now()
|
|
err := retry.OnError(retry.DefaultRetry, func(err error) bool { return true }, func() error {
|
|
resourceList, err := discoveryClient.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, r := range resourceList.APIResources {
|
|
if r.Kind == gvk.Kind {
|
|
return nil
|
|
}
|
|
}
|
|
return errors.NewNotFound(schema.GroupResource{Group: gvk.GroupVersion().String(), Resource: gvk.Kind}, "")
|
|
})
|
|
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
klog.Warningf("Not found kind %s in group version %s, waiting time %s", gvk.Kind, gvk.GroupVersion().String(), time.Since(startTime))
|
|
return false
|
|
}
|
|
|
|
// This might be caused by abnormal apiserver or etcd, ignore it
|
|
klog.Errorf("Failed to find resources in group version %s: %v, waiting time %s", gvk.GroupVersion().String(), err, time.Since(startTime))
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func GetGVKFrom(workloadRef *rolloutv1beta1.ObjectRef) schema.GroupVersionKind {
|
|
if workloadRef == nil {
|
|
return schema.GroupVersionKind{}
|
|
}
|
|
return schema.FromAPIVersionAndKind(workloadRef.APIVersion, workloadRef.Kind)
|
|
}
|
|
|
|
func AddWatcherDynamically(c controller.Controller, h handler.EventHandler, gvk schema.GroupVersionKind) (bool, error) {
|
|
if !DiscoverGVK(gvk) {
|
|
klog.Errorf("Failed to find GVK(%v) in cluster", gvk.String())
|
|
return false, nil
|
|
}
|
|
|
|
object := &unstructured.Unstructured{}
|
|
object.SetGroupVersionKind(gvk)
|
|
return true, c.Watch(&source.Kind{Type: object}, h)
|
|
}
|
|
|
|
func HashReleasePlanBatches(releasePlan *rolloutv1beta1.ReleasePlan) string {
|
|
by, _ := json.Marshal(releasePlan)
|
|
md5Hash := sha256.Sum256(by)
|
|
return hex.EncodeToString(md5Hash[:])
|
|
}
|
|
|
|
func DumpJSON(o interface{}) string {
|
|
by, _ := json.Marshal(o)
|
|
return string(by)
|
|
}
|
|
|
|
// hash hashes `data` with sha256 and returns the hex string
|
|
func EncodeHash(data string) string {
|
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
|
|
}
|