2018-10-22 11:34:54 +03:00
|
|
|
// MIT License
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE
|
|
|
|
|
2019-07-26 15:09:05 +03:00
|
|
|
package internal
|
2018-10-22 11:34:54 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-08-01 09:44:26 +03:00
|
|
|
ci "github.com/microsoft/frameworkcontroller/pkg/apis/frameworkcontroller/v1"
|
2019-07-26 15:09:05 +03:00
|
|
|
frameworkClient "github.com/microsoft/frameworkcontroller/pkg/client/clientset/versioned"
|
2019-07-18 10:58:23 +03:00
|
|
|
"github.com/microsoft/frameworkcontroller/pkg/common"
|
2019-07-26 15:09:05 +03:00
|
|
|
core "k8s.io/api/core/v1"
|
2022-01-17 06:08:28 +03:00
|
|
|
apiExtensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
2018-10-22 11:34:54 +03:00
|
|
|
apiClient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
|
|
|
apiErrors "k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
2019-07-26 15:09:05 +03:00
|
|
|
kubeClient "k8s.io/client-go/kubernetes"
|
2018-10-22 11:34:54 +03:00
|
|
|
"k8s.io/client-go/rest"
|
2019-07-26 15:09:05 +03:00
|
|
|
"k8s.io/client-go/tools/cache"
|
|
|
|
"k8s.io/klog"
|
2019-07-18 10:58:23 +03:00
|
|
|
"reflect"
|
2019-09-19 12:54:25 +03:00
|
|
|
"time"
|
2018-10-22 11:34:54 +03:00
|
|
|
)
|
|
|
|
|
2019-07-26 15:09:05 +03:00
|
|
|
func CreateClients(kConfig *rest.Config) (
|
|
|
|
kubeClient.Interface, frameworkClient.Interface) {
|
|
|
|
kClient, err := kubeClient.NewForConfig(kConfig)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("Failed to create KubeClient: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
fClient, err := frameworkClient.NewForConfig(kConfig)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("Failed to create FrameworkClient: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return kClient, fClient
|
|
|
|
}
|
|
|
|
|
2018-10-22 11:34:54 +03:00
|
|
|
func PutCRD(
|
2019-07-18 10:58:23 +03:00
|
|
|
config *rest.Config, crd *apiExtensions.CustomResourceDefinition,
|
|
|
|
establishedCheckIntervalSec *int64, establishedCheckTimeoutSec *int64) {
|
2018-10-22 11:34:54 +03:00
|
|
|
client := createCRDClient(config)
|
|
|
|
|
|
|
|
err := putCRDInternal(client, crd, establishedCheckIntervalSec, establishedCheckTimeoutSec)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("Failed to put CRD: %v", err))
|
|
|
|
} else {
|
2019-07-26 15:09:05 +03:00
|
|
|
klog.Infof("Succeeded to put CRD")
|
2018-10-22 11:34:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeleteCRD(config *rest.Config, name string) {
|
|
|
|
client := createCRDClient(config)
|
|
|
|
|
2022-01-17 06:08:28 +03:00
|
|
|
err := client.ApiextensionsV1().CustomResourceDefinitions().Delete(name, meta.NewDeleteOptions(0))
|
2018-10-22 11:34:54 +03:00
|
|
|
if err != nil && !apiErrors.IsNotFound(err) {
|
|
|
|
panic(fmt.Errorf("Failed to delete CRD: %v", err))
|
|
|
|
} else {
|
2019-07-26 15:09:05 +03:00
|
|
|
klog.Infof("Succeeded to delete CRD")
|
2018-10-22 11:34:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createCRDClient(config *rest.Config) apiClient.Interface {
|
|
|
|
client, err := apiClient.NewForConfig(config)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("Failed to create CRDClient: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return client
|
|
|
|
}
|
|
|
|
|
|
|
|
func putCRDInternal(
|
2019-07-18 10:58:23 +03:00
|
|
|
client apiClient.Interface, newCRD *apiExtensions.CustomResourceDefinition,
|
|
|
|
establishedCheckIntervalSec *int64, establishedCheckTimeoutSec *int64) error {
|
2018-10-22 11:34:54 +03:00
|
|
|
|
2022-01-17 06:08:28 +03:00
|
|
|
remoteCRD, err := client.ApiextensionsV1().CustomResourceDefinitions().Get(newCRD.Name, meta.GetOptions{})
|
2018-10-22 11:34:54 +03:00
|
|
|
if err == nil {
|
2019-07-26 15:09:05 +03:00
|
|
|
klog.Infof("Update CRD %v", newCRD.Name)
|
2018-10-22 11:34:54 +03:00
|
|
|
if !reflect.DeepEqual(remoteCRD.Spec, newCRD.Spec) {
|
|
|
|
updateCRD := remoteCRD
|
|
|
|
updateCRD.Spec = newCRD.Spec
|
2022-01-17 06:08:28 +03:00
|
|
|
remoteCRD, err = client.ApiextensionsV1().CustomResourceDefinitions().Update(updateCRD)
|
2018-10-22 11:34:54 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if apiErrors.IsNotFound(err) {
|
2019-07-26 15:09:05 +03:00
|
|
|
klog.Infof("Create CRD %v", newCRD.Name)
|
2022-01-17 06:08:28 +03:00
|
|
|
remoteCRD, err = client.ApiextensionsV1().CustomResourceDefinitions().Create(newCRD)
|
2018-10-22 11:34:54 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if isCRDEstablished(remoteCRD) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return wait.Poll(
|
|
|
|
common.SecToDuration(establishedCheckIntervalSec),
|
|
|
|
common.SecToDuration(establishedCheckTimeoutSec),
|
|
|
|
func() (bool, error) {
|
2022-01-17 06:08:28 +03:00
|
|
|
remoteCRD, err = client.ApiextensionsV1().CustomResourceDefinitions().Get(newCRD.Name, meta.GetOptions{})
|
2018-10-22 11:34:54 +03:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return isCRDEstablished(remoteCRD), nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func isCRDEstablished(crd *apiExtensions.CustomResourceDefinition) bool {
|
|
|
|
for _, cond := range crd.Status.Conditions {
|
|
|
|
if cond.Status == apiExtensions.ConditionTrue &&
|
2019-07-18 10:58:23 +03:00
|
|
|
cond.Type == apiExtensions.Established {
|
2018-10-22 11:34:54 +03:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2019-07-26 15:09:05 +03:00
|
|
|
|
2020-01-13 08:57:28 +03:00
|
|
|
// obj should come from Framework SharedIndexInformer, otherwise may panic.
|
2019-08-01 09:44:26 +03:00
|
|
|
func ToFramework(obj interface{}) *ci.Framework {
|
|
|
|
f, ok := obj.(*ci.Framework)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-08-01 09:44:26 +03:00
|
|
|
"Failed to convert obj to Framework or DeletedFinalStateUnknown: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
obj))
|
2019-08-01 09:44:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
f, ok = deletedFinalStateUnknown.Obj.(*ci.Framework)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-08-01 09:44:26 +03:00
|
|
|
"Failed to convert DeletedFinalStateUnknown.Obj to Framework: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
deletedFinalStateUnknown))
|
2019-08-01 09:44:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return f
|
|
|
|
}
|
|
|
|
|
2020-01-13 08:57:28 +03:00
|
|
|
// obj should come from ConfigMap SharedIndexInformer, otherwise may panic.
|
2019-07-26 15:09:05 +03:00
|
|
|
func ToConfigMap(obj interface{}) *core.ConfigMap {
|
|
|
|
cm, ok := obj.(*core.ConfigMap)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-07-26 15:09:05 +03:00
|
|
|
"Failed to convert obj to ConfigMap or DeletedFinalStateUnknown: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
obj))
|
2019-07-26 15:09:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cm, ok = deletedFinalStateUnknown.Obj.(*core.ConfigMap)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-07-26 15:09:05 +03:00
|
|
|
"Failed to convert DeletedFinalStateUnknown.Obj to ConfigMap: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
deletedFinalStateUnknown))
|
2019-07-26 15:09:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cm
|
|
|
|
}
|
|
|
|
|
2020-01-13 08:57:28 +03:00
|
|
|
// obj should come from Pod SharedIndexInformer, otherwise may panic.
|
2019-07-26 15:09:05 +03:00
|
|
|
func ToPod(obj interface{}) *core.Pod {
|
|
|
|
pod, ok := obj.(*core.Pod)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-07-26 15:09:05 +03:00
|
|
|
"Failed to convert obj to Pod or DeletedFinalStateUnknown: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
obj))
|
2019-07-26 15:09:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pod, ok = deletedFinalStateUnknown.Obj.(*core.Pod)
|
|
|
|
if !ok {
|
2020-01-13 08:57:28 +03:00
|
|
|
panic(fmt.Errorf(
|
2019-07-26 15:09:05 +03:00
|
|
|
"Failed to convert DeletedFinalStateUnknown.Obj to Pod: %#v",
|
2020-01-13 08:57:28 +03:00
|
|
|
deletedFinalStateUnknown))
|
2019-07-26 15:09:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pod
|
|
|
|
}
|
2019-09-19 12:54:25 +03:00
|
|
|
|
|
|
|
func GetPodDeletionStartTime(pod *core.Pod) *meta.Time {
|
|
|
|
if pod.DeletionTimestamp == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var gracePeriod time.Duration
|
|
|
|
if pod.DeletionGracePeriodSeconds == nil {
|
|
|
|
gracePeriod = time.Duration(0)
|
|
|
|
} else {
|
|
|
|
gracePeriod = common.SecToDuration(pod.DeletionGracePeriodSeconds)
|
|
|
|
}
|
|
|
|
return common.PtrTime(meta.NewTime(pod.DeletionTimestamp.Add(-gracePeriod)))
|
|
|
|
}
|