Merge pull request #28 from qiujian16/empty-server

Fix issue  when externalserver is not set
This commit is contained in:
OpenShift Merge Robot
2020-06-09 18:22:58 -04:00
committed by GitHub
9 changed files with 469 additions and 12 deletions

1
go.sum
View File

@@ -51,6 +51,7 @@ github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.15+incompatible h1:+9RjdC18gMxNQVvSiXvObLu29mOFmkgdsB4cRTlV+EE=
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=

View File

@@ -25,7 +25,9 @@ spec:
- "agent"
- "--cluster-name={{ .ClusterName }}"
- "--bootstrap-kubeconfig=/spoke/bootstrap/kubeconfig"
{{if .ExternalServerURL}}
- "--spoke-external-server-urls={{ .ExternalServerURL }}"
{{end}}
volumeMounts:
- name: bootstrap-secret
mountPath: "/spoke/bootstrap"

View File

@@ -150,7 +150,9 @@ spec:
- "agent"
- "--cluster-name={{ .ClusterName }}"
- "--bootstrap-kubeconfig=/spoke/bootstrap/kubeconfig"
{{if .ExternalServerURL}}
- "--spoke-external-server-urls={{ .ExternalServerURL }}"
{{end}}
volumeMounts:
- name: bootstrap-secret
mountPath: "/spoke/bootstrap"

View File

@@ -251,6 +251,14 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
// TODO store this in the status of the klusterlet itself
n.registrationGeneration = generation
// If cluster name is empty, read cluster name from hub config secret
if config.ClusterName == "" {
clusterName := hubSecret.Data["cluster-name"]
if clusterName != nil {
config.ClusterName = string(clusterName)
}
}
// Deploy work agent
generation, err = helpers.ApplyDeployment(
n.kubeClient,
@@ -281,24 +289,20 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
// TODO this should be moved into a separate loop since it is independent of the application of the eventually consistent
// resources above
// If cluster name is empty, read cluster name from hub config secret
// If cluster name is empty, return err
if config.ClusterName == "" {
clusterName := hubSecret.Data["cluster-name"]
if clusterName == nil {
helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(operatorapiv1.StatusCondition{
Type: klusterletRegistrationDegraded, Status: metav1.ConditionTrue, Reason: "ClusterNameMissing",
Message: fmt.Sprintf("Failed to get cluster name from `kubectl get secret -n %q %q -ojsonpath='{.data.cluster-name}`. This is set by the klusterlet registration deployment.", hubSecret.Namespace, hubSecret.Name),
}))
return fmt.Errorf("Failed to get cluster name")
}
config.ClusterName = string(clusterName)
helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(operatorapiv1.StatusCondition{
Type: klusterletRegistrationDegraded, Status: metav1.ConditionTrue, Reason: "ClusterNameMissing",
Message: fmt.Sprintf("Failed to get cluster name from `kubectl get secret -n %q %q -ojsonpath='{.data.cluster-name}`. This is set by the klusterlet registration deployment.", hubSecret.Namespace, hubSecret.Name),
}))
return fmt.Errorf("Failed to get cluster name")
}
// If hub kubeconfig does not exist, return err.
if hubSecret.Data["kubeconfig"] == nil {
helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(operatorapiv1.StatusCondition{
Type: klusterletRegistrationDegraded, Status: metav1.ConditionTrue, Reason: "HubKubeconfigMissing",
Message: fmt.Sprintf("Failed to get cluster name from `kubectl get secret -n %q %q -ojsonpath='{.data.kubeconfig}`. This is set by the klusterlet registration deployment, but the CSR must be approved by the cluster-admin on the hub.", hubSecret.Namespace, hubSecret.Name),
Message: fmt.Sprintf("Failed to get kubeconfig from `kubectl get secret -n %q %q -ojsonpath='{.data.kubeconfig}`. This is set by the klusterlet registration deployment, but the CSR must be approved by the cluster-admin on the hub.", hubSecret.Namespace, hubSecret.Name),
}))
return fmt.Errorf("Failed to get kubeconfig from hub kubeconfig secret")
}

View File

@@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
fakekube "k8s.io/client-go/kubernetes/fake"
clienttesting "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
@@ -29,6 +30,7 @@ type testController struct {
controller *klusterletController
kubeClient *fakekube.Clientset
operatorClient *fakeoperatorclient.Clientset
operatorStore cache.Store
}
type fakeSyncContext struct {
@@ -101,6 +103,7 @@ func newTestController(klusterlet *opratorapiv1.Klusterlet, objects ...runtime.O
controller: hubController,
kubeClient: fakeKubeClient,
operatorClient: fakeOperatorClient,
operatorStore: store,
}
}
@@ -154,6 +157,95 @@ func ensureNameNamespace(t *testing.T, actualName, actualNamespace, name, namesp
}
}
func ensureDeployments(t *testing.T, actions []clienttesting.Action, verb, serverURL, registrationClusterName, workClusterName string) {
deployments := []*appsv1.Deployment{}
for _, action := range actions {
if action.GetVerb() != verb || action.GetResource().Resource != "deployments" {
continue
}
if verb == "create" {
object := action.(clienttesting.CreateActionImpl).Object
deployments = append(deployments, object.(*appsv1.Deployment))
}
if verb == "update" {
object := action.(clienttesting.UpdateActionImpl).Object
deployments = append(deployments, object.(*appsv1.Deployment))
}
}
if len(deployments) != 2 {
t.Errorf("Expect %s 2 deployment, actual %d", verb, len(deployments))
}
for _, deployment := range deployments {
if strings.HasSuffix(deployment.Name, "registration-agent") {
ensureRegistrationDeployment(t, deployment, serverURL, registrationClusterName)
} else if strings.HasSuffix(deployment.Name, "work-agent") {
ensureWorkDeployment(t, deployment, workClusterName)
} else {
t.Errorf("Unexpected deployment name %s", deployment.Name)
}
}
}
func ensureRegistrationDeployment(t *testing.T, deployment *appsv1.Deployment, serverURL, clusterName string) {
if len(deployment.Spec.Template.Spec.Containers) != 1 {
t.Errorf("Expect 1 containers in deployment spec, actual %d", len(deployment.Spec.Template.Spec.Containers))
}
args := deployment.Spec.Template.Spec.Containers[0].Args
if serverURL == "" && len(args) != 4 {
t.Errorf("Expect 4 args in container spec, actual %d", len(args))
}
if serverURL != "" && len(deployment.Spec.Template.Spec.Containers[0].Args) != 5 {
t.Errorf("Expect 5 args in container spec, actual %d", len(args))
}
clusterNameArg := ""
serverURLArg := ""
for _, arg := range args {
if strings.HasPrefix(arg, "--cluster-name=") {
clusterNameArg = arg
}
if strings.HasPrefix(arg, "--spoke-external-server-urls=") {
serverURLArg = arg
}
}
desiredServerURLArg := ""
if serverURL != "" {
desiredServerURLArg = fmt.Sprintf("--spoke-external-server-urls=%s", serverURL)
}
if serverURLArg != desiredServerURLArg {
t.Errorf("Server url args not correct, expect %q, actual %q", desiredServerURLArg, serverURLArg)
}
desiredClusterNameArg := fmt.Sprintf("--cluster-name=%s", clusterName)
if clusterNameArg != desiredClusterNameArg {
t.Errorf("Cluster name arg not correct, expect %q, actual %q", desiredClusterNameArg, clusterNameArg)
}
}
func ensureWorkDeployment(t *testing.T, deployment *appsv1.Deployment, clusterName string) {
if len(deployment.Spec.Template.Spec.Containers) != 1 {
t.Errorf("Expect 1 containers in deployment spec, actual %d", len(deployment.Spec.Template.Spec.Containers))
}
args := deployment.Spec.Template.Spec.Containers[0].Args
if len(args) != 4 {
t.Errorf("Expect 4 args in container spec, actual %d", len(args))
}
clusterNameArg := ""
for _, arg := range args {
if strings.HasPrefix(arg, "--spoke-cluster-name") {
clusterNameArg = arg
}
}
desiredClusterNameArg := fmt.Sprintf("--spoke-cluster-name=%s", clusterName)
if desiredClusterNameArg != clusterNameArg {
t.Errorf("Expect cluster namee arg is %q, actual %q", desiredClusterNameArg, clusterNameArg)
}
}
func ensureObject(t *testing.T, object runtime.Object, klusterlet *opratorapiv1.Klusterlet) {
access, err := meta.Accessor(object)
if err != nil {
@@ -390,3 +482,75 @@ func TestGetServersFromKlusterlet(t *testing.T) {
})
}
}
func TestClusterNameChange(t *testing.T) {
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
namespace := newNamespace("testns")
bootStrapSecret := newSecret(bootstrapHubKubeConfigSecret, "testns")
hubSecret := newSecret(hubKubeConfigSecret, "testns")
hubSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig")
hubSecret.Data["cluster-name"] = []byte("cluster1")
controller := newTestController(klusterlet, bootStrapSecret, hubSecret, namespace)
syncContext := newFakeSyncContext(t, "klusterlet")
err := controller.controller.sync(nil, syncContext)
if err != nil {
t.Errorf("Expected non error when sync, %v", err)
}
// Check if deployment has the right cluster name set
ensureDeployments(t, controller.kubeClient.Actions(), "create", "", "cluster1", "cluster1")
// Update klusterlet with unset cluster name and rerun sync
controller.kubeClient.ClearActions()
klusterlet = newKlusterlet("klusterlet", "testns", "")
controller.operatorStore.Update(klusterlet)
// Set generation to another number so we can force the update, we will read generatioin from status in the future
controller.controller.registrationGeneration = 100
controller.controller.workGeneration = 100
err = controller.controller.sync(nil, syncContext)
if err != nil {
t.Errorf("Expected non error when sync, %v", err)
}
ensureDeployments(t, controller.kubeClient.Actions(), "update", "", "", "cluster1")
// Update hubconfigsecret and sync again
hubSecret.Data["cluster-name"] = []byte("cluster2")
controller.kubeClient.PrependReactor("get", "secrets", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
if action.GetVerb() != "get" {
return false, nil, nil
}
getAction := action.(clienttesting.GetActionImpl)
if getAction.Name != hubKubeConfigSecret {
return false, nil, errors.NewNotFound(
corev1.Resource("secrets"), hubKubeConfigSecret)
}
return true, hubSecret, nil
})
controller.kubeClient.ClearActions()
// Set generation to another number so we can force the update, we will read generatioin from status in the future
controller.controller.registrationGeneration = 100
controller.controller.workGeneration = 100
err = controller.controller.sync(nil, syncContext)
if err != nil {
t.Errorf("Expected non error when sync, %v", err)
}
ensureDeployments(t, controller.kubeClient.Actions(), "update", "", "", "cluster2")
// Update klusterlet with different cluster name and rerun sync
klusterlet = newKlusterlet("klusterlet", "testns", "cluster3")
klusterlet.Spec.ExternalServerURLs = []opratorapiv1.ServerURL{{URL: "https://localhost"}}
controller.kubeClient.ClearActions()
controller.operatorStore.Update(klusterlet)
// Set generation to another number so we can force the update, we will read generatioin from status in the future
controller.controller.registrationGeneration = 100
controller.controller.workGeneration = 100
err = controller.controller.sync(nil, syncContext)
if err != nil {
t.Errorf("Expected non error when sync, %v", err)
}
ensureDeployments(t, controller.kubeClient.Actions(), "update", "https://localhost", "cluster3", "cluster3")
}

View File

@@ -26,7 +26,7 @@ func startHubOperator(ctx context.Context) {
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
var _ = ginkgo.Describe("HubCore", func() {
var _ = ginkgo.Describe("ClusterManager", func() {
var cancel context.CancelFunc
var err error
var clusterManagerName string
@@ -168,6 +168,8 @@ var _ = ginkgo.Describe("HubCore", func() {
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
util.AssertClusterManagerCondition(clusterManagerName, operatorClient, "Applied", metav1.ConditionTrue, eventuallyTimeout, eventuallyInterval)
err := operatorClient.OperatorV1().ClusterManagers().Delete(context.Background(), clusterManagerName, metav1.DeleteOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())

View File

@@ -0,0 +1,225 @@
package integration
import (
"context"
"fmt"
"strings"
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
"github.com/openshift/library-go/pkg/controller/controllercmd"
operatorapiv1 "github.com/open-cluster-management/api/operator/v1"
"github.com/open-cluster-management/registration-operator/pkg/operators"
"github.com/open-cluster-management/registration-operator/test/integration/util"
)
func startKlusterletOperator(ctx context.Context) {
err := operators.RunKlusterletOperator(ctx, &controllercmd.ControllerContext{
KubeConfig: restConfig,
EventRecorder: util.NewIntegrationTestEventRecorder("integration"),
})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
var _ = ginkgo.Describe("Klusterlet", func() {
var cancel context.CancelFunc
var klusterlet *operatorapiv1.Klusterlet
var klusterletNamespace string
var registrationRoleName string
var registrationDeploymentName string
var registrationSAName string
var workRoleName string
var workDeploymentName string
var workSAName string
ginkgo.BeforeEach(func() {
var ctx context.Context
klusterletNamespace = fmt.Sprintf("open-cluster-manager-%s", rand.String(6))
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: klusterletNamespace,
},
}
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
// Create a dummy bootstrap secret
bootStrapSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bootstrap-hub-kubeconfig",
Namespace: klusterletNamespace,
},
Data: map[string][]byte{
"kubeconfig": []byte("dummy"),
},
}
_, err = kubeClient.CoreV1().Secrets(klusterletNamespace).Create(context.Background(), bootStrapSecret, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
klusterlet = &operatorapiv1.Klusterlet{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("klusterlet-%s", rand.String(6)),
},
Spec: operatorapiv1.KlusterletSpec{
RegistrationImagePullSpec: "quay.io/open-cluster-management/registration",
WorkImagePullSpec: "quay.io/open-cluster-management/work",
ExternalServerURLs: []operatorapiv1.ServerURL{
{
URL: "https://localhost",
},
},
ClusterName: "testcluster",
Namespace: klusterletNamespace,
},
}
ctx, cancel = context.WithCancel(context.Background())
go startKlusterletOperator(ctx)
})
ginkgo.AfterEach(func() {
err := kubeClient.CoreV1().Namespaces().Delete(context.Background(), klusterletNamespace, metav1.DeleteOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
if cancel != nil {
cancel()
}
})
ginkgo.Context("Deploy and clean klusterlet component", func() {
ginkgo.BeforeEach(func() {
registrationDeploymentName = fmt.Sprintf("%s-registration-agent", klusterlet.Name)
workDeploymentName = fmt.Sprintf("%s-work-agent", klusterlet.Name)
registrationRoleName = fmt.Sprintf("system:open-cluster-management:%s", registrationDeploymentName)
workRoleName = fmt.Sprintf("system:open-cluster-management:%s", workDeploymentName)
registrationSAName = fmt.Sprintf("%s-registration-sa", klusterlet.Name)
workSAName = fmt.Sprintf("%s-work-sa", klusterlet.Name)
})
ginkgo.It("should have expected resource created successfully", func() {
_, err := operatorClient.OperatorV1().Klusterlets().Create(context.Background(), klusterlet, metav1.CreateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
// Check clusterrole/clusterrolebinding
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().ClusterRoles().Get(context.Background(), registrationRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().ClusterRoles().Get(context.Background(), workRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().ClusterRoleBindings().Get(context.Background(), registrationRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().ClusterRoleBindings().Get(context.Background(), workRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
// Check role/rolebinding
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().Roles(klusterletNamespace).Get(context.Background(), registrationRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.RbacV1().RoleBindings(klusterletNamespace).Get(context.Background(), registrationRoleName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
// Check service account
gomega.Eventually(func() bool {
if _, err := kubeClient.CoreV1().ServiceAccounts(klusterletNamespace).Get(context.Background(), registrationSAName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.CoreV1().ServiceAccounts(klusterletNamespace).Get(context.Background(), workSAName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
// Check deployment
gomega.Eventually(func() bool {
if _, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), registrationDeploymentName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() bool {
if _, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), workDeploymentName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
util.AssertKlusterletCondition(klusterlet.Name, operatorClient, "Applied", metav1.ConditionTrue, eventuallyTimeout, eventuallyInterval)
})
ginkgo.It("should have correct registration deployment when server url is empty", func() {
klusterlet.Spec.ExternalServerURLs = []operatorapiv1.ServerURL{}
_, err := operatorClient.OperatorV1().Klusterlets().Create(context.Background(), klusterlet, metav1.CreateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Eventually(func() bool {
if _, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), registrationDeploymentName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
deployment, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), registrationDeploymentName, metav1.GetOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(len(deployment.Spec.Template.Spec.Containers)).Should(gomega.Equal(1))
// external-server-url should not be set
for _, arg := range deployment.Spec.Template.Spec.Containers[0].Args {
gomega.Expect(strings.Contains(arg, "--spoke-external-server-urls")).NotTo(gomega.BeTrue())
}
})
ginkgo.It("should have correct work deployment when clusterName is empty", func() {
klusterlet.Spec.ClusterName = ""
_, err := operatorClient.OperatorV1().Klusterlets().Create(context.Background(), klusterlet, metav1.CreateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Eventually(func() bool {
if _, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), workDeploymentName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
deployment, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), workDeploymentName, metav1.GetOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(len(deployment.Spec.Template.Spec.Containers)).Should(gomega.Equal(1))
for _, arg := range deployment.Spec.Template.Spec.Containers[0].Args {
if strings.HasPrefix(arg, "--spoke-cluster-name") {
gomega.Expect(arg).Should(gomega.Equal("--spoke-cluster-name="))
}
}
})
})
})

View File

@@ -0,0 +1,37 @@
package util
import (
"context"
"github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
operatorclientset "github.com/open-cluster-management/api/client/operator/clientset/versioned"
)
func AssertKlusterletCondition(
name string, operatorClient operatorclientset.Interface, expectedType string, expectedWorkStatus metav1.ConditionStatus, eventuallyTimeout, eventuallyInterval int) {
gomega.Eventually(func() bool {
klusterlet, err := operatorClient.OperatorV1().Klusterlets().Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return false
}
// check work status condition
return HasCondition(klusterlet.Status.Conditions, expectedType, expectedWorkStatus)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func AssertClusterManagerCondition(
name string, operatorClient operatorclientset.Interface, expectedType string, expectedWorkStatus metav1.ConditionStatus, eventuallyTimeout, eventuallyInterval int) {
gomega.Eventually(func() bool {
klusterlet, err := operatorClient.OperatorV1().ClusterManagers().Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return false
}
// check work status condition
return HasCondition(klusterlet.Status.Conditions, expectedType, expectedWorkStatus)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}

View File

@@ -6,6 +6,9 @@ import (
"github.com/onsi/ginkgo"
"github.com/openshift/library-go/pkg/operator/events"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
operatorapiv1 "github.com/open-cluster-management/api/operator/v1"
)
func NewIntegrationTestEventRecorder(componet string) events.Recorder {
@@ -43,3 +46,20 @@ func (r *IntegrationTestEventRecorder) Warning(reason, message string) {
func (r *IntegrationTestEventRecorder) Warningf(reason, messageFmt string, args ...interface{}) {
r.Warning(reason, fmt.Sprintf(messageFmt, args...))
}
func HasCondition(conditions []operatorapiv1.StatusCondition, expectedType string, expectedStatus metav1.ConditionStatus) bool {
found := false
for _, condition := range conditions {
if condition.Type != expectedType {
continue
}
found = true
if condition.Status != expectedStatus {
return false
}
return true
}
return found
}