diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 99b1cdc5..28204a61 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/cmd/main.go b/cmd/main.go index 22cad934..1b62d497 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -39,6 +39,7 @@ import ( "github.com/kyma-project/kyma/components/eventing-controller/logger" "github.com/kyma-project/kyma/components/eventing-controller/options" backendmetrics "github.com/kyma-project/kyma/components/eventing-controller/pkg/backend/metrics" + apiclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -122,7 +123,15 @@ func main() { //nolint:funlen // main function needs to initialize many object // init custom kube client wrapper k8sClient := mgr.GetClient() - kubeClient := k8s.NewKubeClient(k8sClient, "eventing-manager") + + // init custom kube client wrapper + apiClientSet, err := apiclientset.NewForConfig(mgr.GetConfig()) + if err != nil { + setupLog.Error(err, "failed to create new k8s clientset") + os.Exit(1) + } + + kubeClient := k8s.NewKubeClient(k8sClient, apiClientSet, "eventing-manager") recorder := mgr.GetEventRecorderFor("eventing-manager") ctx := context.Background() diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 372ae7e5..fb52b857 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -4,7 +4,6 @@ resources: - bases/operator.kyma-project.io_eventings.yaml - external/subscriptions.eventing.kyma-project.io.crd.yaml -- external/applications.applicationconnector.crd.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index e5364aff..26254ce4 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -90,7 +90,7 @@ spec: - name: PUBLISHER_LIMITS_MEMORY value: 128Mi - name: PUBLISHER_IMAGE - value: "europe-docker.pkg.dev/kyma-project/prod/event-publisher-proxy:v20230817-c3e3291f" + value: "europe-docker.pkg.dev/kyma-project/dev/event-publisher-proxy:PR-18259" - name: PUBLISHER_IMAGE_PULL_POLICY value: "IfNotPresent" - name: PUBLISHER_REPLICAS diff --git a/go.mod b/go.mod index e72931ca..22ae609c 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 k8s.io/api v0.27.4 + k8s.io/apiextensions-apiserver v0.27.2 k8s.io/apimachinery v0.27.3 k8s.io/client-go v0.27.2 k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 @@ -85,7 +86,6 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.27.2 // indirect k8s.io/component-base v0.27.2 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect diff --git a/internal/controller/eventing/controller.go b/internal/controller/eventing/controller.go index 9c20a9d5..6834ee46 100644 --- a/internal/controller/eventing/controller.go +++ b/internal/controller/eventing/controller.go @@ -177,7 +177,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return r.handleEventingDeletion(ctx, eventing, log) } - // check if the Eveting CR is allowed to be created. + // check if the Eventing CR is allowed to be created. if r.allowedEventingCR != nil { if result, err := r.handleEventingCRAllowedCheck(ctx, eventing, log); !result || err != nil { return ctrl.Result{}, err @@ -333,6 +333,14 @@ func (r *Reconciler) handleEventingReconcile(ctx context.Context, // update ActiveBackend in status. eventing.SyncStatusActiveBackend() + // check if Application CRD is installed. + isApplicationCRDEnabled, err := r.kubeClient.ApplicationCRDExists(ctx) + if err != nil { + return ctrl.Result{}, r.syncStatusWithSubscriptionManagerErr(ctx, eventing, err, log) + } + r.backendConfig.PublisherConfig.ApplicationCRDEnabled = isApplicationCRDEnabled + r.eventingManager.SetBackendConfig(r.backendConfig) + // reconcile for specified backend. switch eventing.Spec.Backend.Type { case eventingv1alpha1.NatsBackendType: diff --git a/internal/controller/eventing/integrationtests/controller/integration_test.go b/internal/controller/eventing/integrationtests/controller/integration_test.go index 370c5aa1..3de330f5 100644 --- a/internal/controller/eventing/integrationtests/controller/integration_test.go +++ b/internal/controller/eventing/integrationtests/controller/integration_test.go @@ -661,6 +661,7 @@ func ensureEPPDeploymentAndHPAResources(t *testing.T, givenEventing *eventingv1a testEnvironment.EnsureEventingSpecPublisherReflected(t, givenEventing) testEnvironment.EnsureEventingReplicasReflected(t, givenEventing) testEnvironment.EnsureDeploymentOwnerReferenceSet(t, givenEventing) + testEnvironment.EnsurePublisherDeploymentENVSet(t, givenEventing) } func ensureK8sResources(t *testing.T, givenEventing *eventingv1alpha1.Eventing, testEnvironment *testutils.TestEnvironment) { diff --git a/internal/controller/eventing/mocks/controller.go b/internal/controller/eventing/mocks/controller.go index ad5f91df..38727445 100644 --- a/internal/controller/eventing/mocks/controller.go +++ b/internal/controller/eventing/mocks/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks diff --git a/internal/controller/eventing/mocks/manager.go b/internal/controller/eventing/mocks/manager.go index 9286f29b..0080ab91 100644 --- a/internal/controller/eventing/mocks/manager.go +++ b/internal/controller/eventing/mocks/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks diff --git a/internal/controller/eventing/mocks/nats_config_handler.go b/internal/controller/eventing/mocks/nats_config_handler.go index 88b6f69f..75479e12 100644 --- a/internal/controller/eventing/mocks/nats_config_handler.go +++ b/internal/controller/eventing/mocks/nats_config_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks diff --git a/internal/controller/eventing/nats.go b/internal/controller/eventing/nats.go index eb935c9a..d8006578 100644 --- a/internal/controller/eventing/nats.go +++ b/internal/controller/eventing/nats.go @@ -3,6 +3,7 @@ package eventing import ( "context" "fmt" + eventingv1alpha1 "github.com/kyma-project/eventing-manager/api/v1alpha1" ecenv "github.com/kyma-project/kyma/components/eventing-controller/pkg/env" diff --git a/internal/controller/eventing/unit_test.go b/internal/controller/eventing/unit_test.go index b23dc284..29413d47 100644 --- a/internal/controller/eventing/unit_test.go +++ b/internal/controller/eventing/unit_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + apiclientsetfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" + "github.com/kyma-project/eventing-manager/pkg/k8s" "github.com/kyma-project/eventing-manager/pkg/env" @@ -63,8 +65,9 @@ func NewMockedUnitTestEnvironment(t *testing.T, objs ...client.Object) *MockedUn // TODO: once controller-runtime version is upgraded to >=0.15.x, use the following. //fakeClient := fakeClientBuilder.WithObjects(objs...).WithStatusSubresource(objs...).Build() fakeClient := fakeClientBuilder.WithObjects(objs...).Build() + fakeClientSet := apiclientsetfake.NewSimpleClientset() recorder := &record.FakeRecorder{} - kubeClient := k8s.NewKubeClient(fakeClient, "eventing-manager") + kubeClient := k8s.NewKubeClient(fakeClient, fakeClientSet, "eventing-manager") // setup custom mocks eventingManager := new(managermocks.Manager) diff --git a/internal/controller/eventing/utils.go b/internal/controller/eventing/utils.go index 2543beea..cdbaeabd 100644 --- a/internal/controller/eventing/utils.go +++ b/internal/controller/eventing/utils.go @@ -2,6 +2,7 @@ package eventing import ( "context" + eventingv1alpha1 "github.com/kyma-project/eventing-manager/api/v1alpha1" "github.com/kyma-project/eventing-manager/pkg/env" ecenv "github.com/kyma-project/kyma/components/eventing-controller/pkg/env" diff --git a/pkg/env/backend_config.go b/pkg/env/backend_config.go index d29725b9..be7db39d 100644 --- a/pkg/env/backend_config.go +++ b/pkg/env/backend_config.go @@ -40,7 +40,8 @@ type PublisherConfig struct { RequestTimeout string `envconfig:"PUBLISHER_REQUEST_TIMEOUT" default:"5s"` PriorityClassName string `envconfig:"PUBLISHER_PRIORITY_CLASS_NAME" default:""` // publisher takes the controller values - AppLogFormat string `envconfig:"APP_LOG_FORMAT" default:"json"` + AppLogFormat string `envconfig:"APP_LOG_FORMAT" default:"json"` + ApplicationCRDEnabled bool } type DefaultSubscriptionConfig struct { diff --git a/pkg/eventing/deployment.go b/pkg/eventing/deployment.go index 1d174381..29fa5a3b 100644 --- a/pkg/eventing/deployment.go +++ b/pkg/eventing/deployment.go @@ -203,6 +203,7 @@ func getNATSEnvVars(natsConfig env.NATSConfig, publisherConfig env.PublisherConf {Name: "REQUEST_TIMEOUT", Value: publisherConfig.RequestTimeout}, {Name: "LEGACY_NAMESPACE", Value: "kyma"}, {Name: "EVENT_TYPE_PREFIX", Value: eventing.Spec.Backend.Config.EventTypePrefix}, + {Name: "APPLICATION_CRD_ENABLED", Value: strconv.FormatBool(publisherConfig.ApplicationCRDEnabled)}, // JetStream-specific config {Name: "JS_STREAM_NAME", Value: natsConfig.JSStreamName}, } @@ -312,6 +313,7 @@ func getEventMeshEnvVars(publisherName string, publisherConfig env.PublisherConf {Name: "BACKEND", Value: "beb"}, {Name: "PORT", Value: strconv.Itoa(int(publisherPortNum))}, {Name: "EVENT_TYPE_PREFIX", Value: eventing.Spec.Backend.Config.EventTypePrefix}, + {Name: "APPLICATION_CRD_ENABLED", Value: strconv.FormatBool(publisherConfig.ApplicationCRDEnabled)}, {Name: "REQUEST_TIMEOUT", Value: publisherConfig.RequestTimeout}, { Name: "CLIENT_ID", diff --git a/pkg/eventing/deployment_test.go b/pkg/eventing/deployment_test.go index 147dd3ff..caf2dce7 100644 --- a/pkg/eventing/deployment_test.go +++ b/pkg/eventing/deployment_test.go @@ -134,6 +134,7 @@ func Test_GetNATSEnvVars(t *testing.T) { {Name: "REQUEST_TIMEOUT", Value: "10s"}, {Name: "LEGACY_NAMESPACE", Value: "kyma"}, {Name: "EVENT_TYPE_PREFIX", Value: ""}, + {Name: "APPLICATION_CRD_ENABLED", Value: "false"}, {Name: "JS_STREAM_NAME", Value: ""}, }, }, @@ -154,6 +155,7 @@ func Test_GetNATSEnvVars(t *testing.T) { {Name: "REQUEST_TIMEOUT", Value: "10s"}, {Name: "LEGACY_NAMESPACE", Value: "kyma"}, {Name: "EVENT_TYPE_PREFIX", Value: ""}, + {Name: "APPLICATION_CRD_ENABLED", Value: "false"}, {Name: "JS_STREAM_NAME", Value: "sap"}, }, }, @@ -252,6 +254,17 @@ func Test_GetEventMeshEnvVars(t *testing.T) { "REQUEST_TIMEOUT": "10s", }, }, + { + name: "APPLICATION_CRD_ENABLED should be set", + givenEnvs: map[string]string{}, + givenEventing: testutils.NewEventingCR( + testutils.WithEventMeshBackend("test-namespace/test-name"), + testutils.WithEventingEventTypePrefix(eventTypePrefix), + ), + wantEnvs: map[string]string{ + "APPLICATION_CRD_ENABLED": "false", + }, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/eventing/manager.go b/pkg/eventing/manager.go index fddb731b..30cb5c08 100644 --- a/pkg/eventing/manager.go +++ b/pkg/eventing/manager.go @@ -38,6 +38,7 @@ type Manager interface { backendType v1alpha1.BackendType) (*appsv1.Deployment, error) DeployPublisherProxyResources(context.Context, *v1alpha1.Eventing, *appsv1.Deployment) error GetBackendConfig() *env.BackendConfig + SetBackendConfig(env.BackendConfig) } type EventingManager struct { @@ -57,7 +58,7 @@ func NewEventingManager( logger *logger.Logger, recorder record.EventRecorder, ) Manager { - return EventingManager{ + return &EventingManager{ ctx: ctx, Client: client, backendConfig: backendConfig, @@ -168,6 +169,10 @@ func (em EventingManager) GetBackendConfig() *env.BackendConfig { return &em.backendConfig } +func (em *EventingManager) SetBackendConfig(config env.BackendConfig) { + em.backendConfig = config +} + func (em EventingManager) DeployPublisherProxyResources( ctx context.Context, eventing *v1alpha1.Eventing, diff --git a/pkg/eventing/mocks/manager.go b/pkg/eventing/mocks/manager.go index 4fc6d764..ec99f2a6 100644 --- a/pkg/eventing/mocks/manager.go +++ b/pkg/eventing/mocks/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks @@ -224,6 +224,39 @@ func (_c *Manager_IsNATSAvailable_Call) RunAndReturn(run func(context.Context, s return _c } +// SetBackendConfig provides a mock function with given fields: _a0 +func (_m *Manager) SetBackendConfig(_a0 env.BackendConfig) { + _m.Called(_a0) +} + +// Manager_SetBackendConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetBackendConfig' +type Manager_SetBackendConfig_Call struct { + *mock.Call +} + +// SetBackendConfig is a helper method to define mock.On call +// - _a0 env.BackendConfig +func (_e *Manager_Expecter) SetBackendConfig(_a0 interface{}) *Manager_SetBackendConfig_Call { + return &Manager_SetBackendConfig_Call{Call: _e.mock.On("SetBackendConfig", _a0)} +} + +func (_c *Manager_SetBackendConfig_Call) Run(run func(_a0 env.BackendConfig)) *Manager_SetBackendConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(env.BackendConfig)) + }) + return _c +} + +func (_c *Manager_SetBackendConfig_Call) Return() *Manager_SetBackendConfig_Call { + _c.Call.Return() + return _c +} + +func (_c *Manager_SetBackendConfig_Call) RunAndReturn(run func(env.BackendConfig)) *Manager_SetBackendConfig_Call { + _c.Call.Return(run) + return _c +} + // NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewManager(t interface { diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index 27ce074a..651b897a 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -10,6 +10,8 @@ import ( v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + k8sclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,16 +31,20 @@ type Client interface { name string) (*admissionv1.MutatingWebhookConfiguration, error) GetValidatingWebHookConfiguration(ctx context.Context, name string) (*admissionv1.ValidatingWebhookConfiguration, error) + GetCRD(context.Context, string) (*apiextensionsv1.CustomResourceDefinition, error) + ApplicationCRDExists(context.Context) (bool, error) } type KubeClient struct { fieldManager string client client.Client + clientset k8sclientset.Interface } -func NewKubeClient(client client.Client, fieldManager string) Client { +func NewKubeClient(client client.Client, clientset k8sclientset.Interface, fieldManager string) Client { return &KubeClient{ client: client, + clientset: clientset, fieldManager: fieldManager, } } @@ -130,6 +136,18 @@ func (c *KubeClient) GetSecret(ctx context.Context, namespacedName string) (*cor return secret, nil } +func (c *KubeClient) GetCRD(ctx context.Context, name string) (*apiextensionsv1.CustomResourceDefinition, error) { + return c.clientset.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, name, metav1.GetOptions{}) +} + +func (c *KubeClient) ApplicationCRDExists(ctx context.Context) (bool, error) { + _, err := c.GetCRD(ctx, ApplicationCrdName) + if err != nil { + return false, client.IgnoreNotFound(err) + } + return true, nil +} + // GetMutatingWebHookConfiguration returns the MutatingWebhookConfiguration k8s resource. func (c *KubeClient) GetMutatingWebHookConfiguration(ctx context.Context, name string) (*admissionv1.MutatingWebhookConfiguration, error) { diff --git a/pkg/k8s/client_test.go b/pkg/k8s/client_test.go index d9f045e4..3ed8fbc8 100644 --- a/pkg/k8s/client_test.go +++ b/pkg/k8s/client_test.go @@ -6,9 +6,12 @@ import ( "errors" "testing" + "k8s.io/apimachinery/pkg/runtime" + testutils "github.com/kyma-project/eventing-manager/test/utils" admissionv1 "k8s.io/api/admissionregistration/v1" + apiclientsetfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" @@ -87,7 +90,7 @@ func Test_PatchApply(t *testing.T) { } fakeClientBuilder := fake.NewClientBuilder() fakeClient := fakeClientBuilder.WithObjects(objs...).Build() - kubeClient := NewKubeClient(fakeClient, testFieldManager) + kubeClient := NewKubeClient(fakeClient, nil, testFieldManager) // when err := kubeClient.PatchApply(context.Background(), tc.givenUpdateDeployment) @@ -535,3 +538,99 @@ func Test_GetValidatingWebHookConfiguration(t *testing.T) { }) } } + +func Test_GetCRD(t *testing.T) { + t.Parallel() + + // define test cases + testCases := []struct { + name string + givenCRDName string + wantNotFoundError bool + }{ + { + name: "should return correct CRD from k8s", + givenCRDName: ApplicationCrdName, + wantNotFoundError: false, + }, + { + name: "should return not found error when CRD is missing in k8s", + givenCRDName: "non-existing", + wantNotFoundError: true, + }, + } + + // run test cases + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + // given + sampleCRD := testutils.NewApplicationCRD() + var objs []runtime.Object + if !tc.wantNotFoundError { + objs = append(objs, sampleCRD) + } + + fakeClientSet := apiclientsetfake.NewSimpleClientset(objs...) + kubeClient := NewKubeClient(nil, fakeClientSet, testFieldManager) + + // when + gotCRD, err := kubeClient.GetCRD(context.Background(), tc.givenCRDName) + + // then + if tc.wantNotFoundError { + require.Error(t, err) + require.True(t, apierrors.IsNotFound(err)) + } else { + require.NoError(t, err) + require.Equal(t, sampleCRD.GetName(), gotCRD.Name) + } + }) + } +} + +func Test_ApplicationCRDExists(t *testing.T) { + t.Parallel() + + // define test cases + testCases := []struct { + name string + wantResult bool + }{ + { + name: "should return false when CRD is missing in k8s", + wantResult: false, + }, + { + name: "should return true when CRD exists in k8s", + wantResult: true, + }, + } + + // run test cases + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + // given + sampleCRD := testutils.NewApplicationCRD() + var objs []runtime.Object + if tc.wantResult { + objs = append(objs, sampleCRD) + } + + fakeClientSet := apiclientsetfake.NewSimpleClientset(objs...) + kubeClient := NewKubeClient(nil, fakeClientSet, testFieldManager) + + // when + gotResult, err := kubeClient.ApplicationCRDExists(context.Background()) + + // then + require.NoError(t, err) + require.Equal(t, tc.wantResult, gotResult) + }) + } +} diff --git a/pkg/k8s/mocks/client.go b/pkg/k8s/mocks/client.go index 4f0f0808..6772678f 100644 --- a/pkg/k8s/mocks/client.go +++ b/pkg/k8s/mocks/client.go @@ -1,9 +1,11 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks import ( admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + appsv1 "k8s.io/api/apps/v1" + client "sigs.k8s.io/controller-runtime/pkg/client" context "context" @@ -12,7 +14,7 @@ import ( mock "github.com/stretchr/testify/mock" - v1 "k8s.io/api/apps/v1" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" v1alpha1 "github.com/kyma-project/nats-manager/api/v1alpha1" ) @@ -30,6 +32,58 @@ func (_m *Client) EXPECT() *Client_Expecter { return &Client_Expecter{mock: &_m.Mock} } +// ApplicationCRDExists provides a mock function with given fields: _a0 +func (_m *Client) ApplicationCRDExists(_a0 context.Context) (bool, error) { + ret := _m.Called(_a0) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Client_ApplicationCRDExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplicationCRDExists' +type Client_ApplicationCRDExists_Call struct { + *mock.Call +} + +// ApplicationCRDExists is a helper method to define mock.On call +// - _a0 context.Context +func (_e *Client_Expecter) ApplicationCRDExists(_a0 interface{}) *Client_ApplicationCRDExists_Call { + return &Client_ApplicationCRDExists_Call{Call: _e.mock.On("ApplicationCRDExists", _a0)} +} + +func (_c *Client_ApplicationCRDExists_Call) Run(run func(_a0 context.Context)) *Client_ApplicationCRDExists_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *Client_ApplicationCRDExists_Call) Return(_a0 bool, _a1 error) *Client_ApplicationCRDExists_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Client_ApplicationCRDExists_Call) RunAndReturn(run func(context.Context) (bool, error)) *Client_ApplicationCRDExists_Call { + _c.Call.Return(run) + return _c +} + // DeleteClusterRole provides a mock function with given fields: _a0, _a1, _a2 func (_m *Client) DeleteClusterRole(_a0 context.Context, _a1 string, _a2 string) error { ret := _m.Called(_a0, _a1, _a2) @@ -162,20 +216,75 @@ func (_c *Client_DeleteDeployment_Call) RunAndReturn(run func(context.Context, s return _c } +// GetCRD provides a mock function with given fields: _a0, _a1 +func (_m *Client) GetCRD(_a0 context.Context, _a1 string) (*v1.CustomResourceDefinition, error) { + ret := _m.Called(_a0, _a1) + + var r0 *v1.CustomResourceDefinition + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*v1.CustomResourceDefinition, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *v1.CustomResourceDefinition); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1.CustomResourceDefinition) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Client_GetCRD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCRD' +type Client_GetCRD_Call struct { + *mock.Call +} + +// GetCRD is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 string +func (_e *Client_Expecter) GetCRD(_a0 interface{}, _a1 interface{}) *Client_GetCRD_Call { + return &Client_GetCRD_Call{Call: _e.mock.On("GetCRD", _a0, _a1)} +} + +func (_c *Client_GetCRD_Call) Run(run func(_a0 context.Context, _a1 string)) *Client_GetCRD_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *Client_GetCRD_Call) Return(_a0 *v1.CustomResourceDefinition, _a1 error) *Client_GetCRD_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Client_GetCRD_Call) RunAndReturn(run func(context.Context, string) (*v1.CustomResourceDefinition, error)) *Client_GetCRD_Call { + _c.Call.Return(run) + return _c +} + // GetDeployment provides a mock function with given fields: _a0, _a1, _a2 -func (_m *Client) GetDeployment(_a0 context.Context, _a1 string, _a2 string) (*v1.Deployment, error) { +func (_m *Client) GetDeployment(_a0 context.Context, _a1 string, _a2 string) (*appsv1.Deployment, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 *v1.Deployment + var r0 *appsv1.Deployment var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v1.Deployment, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*appsv1.Deployment, error)); ok { return rf(_a0, _a1, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) *v1.Deployment); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, string) *appsv1.Deployment); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1.Deployment) + r0 = ret.Get(0).(*appsv1.Deployment) } } @@ -208,12 +317,12 @@ func (_c *Client_GetDeployment_Call) Run(run func(_a0 context.Context, _a1 strin return _c } -func (_c *Client_GetDeployment_Call) Return(_a0 *v1.Deployment, _a1 error) *Client_GetDeployment_Call { +func (_c *Client_GetDeployment_Call) Return(_a0 *appsv1.Deployment, _a1 error) *Client_GetDeployment_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *Client_GetDeployment_Call) RunAndReturn(run func(context.Context, string, string) (*v1.Deployment, error)) *Client_GetDeployment_Call { +func (_c *Client_GetDeployment_Call) RunAndReturn(run func(context.Context, string, string) (*appsv1.Deployment, error)) *Client_GetDeployment_Call { _c.Call.Return(run) return _c } @@ -482,11 +591,11 @@ func (_c *Client_PatchApply_Call) RunAndReturn(run func(context.Context, client. } // UpdateDeployment provides a mock function with given fields: _a0, _a1 -func (_m *Client) UpdateDeployment(_a0 context.Context, _a1 *v1.Deployment) error { +func (_m *Client) UpdateDeployment(_a0 context.Context, _a1 *appsv1.Deployment) error { ret := _m.Called(_a0, _a1) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *v1.Deployment) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, *appsv1.Deployment) error); ok { r0 = rf(_a0, _a1) } else { r0 = ret.Error(0) @@ -502,14 +611,14 @@ type Client_UpdateDeployment_Call struct { // UpdateDeployment is a helper method to define mock.On call // - _a0 context.Context -// - _a1 *v1.Deployment +// - _a1 *appsv1.Deployment func (_e *Client_Expecter) UpdateDeployment(_a0 interface{}, _a1 interface{}) *Client_UpdateDeployment_Call { return &Client_UpdateDeployment_Call{Call: _e.mock.On("UpdateDeployment", _a0, _a1)} } -func (_c *Client_UpdateDeployment_Call) Run(run func(_a0 context.Context, _a1 *v1.Deployment)) *Client_UpdateDeployment_Call { +func (_c *Client_UpdateDeployment_Call) Run(run func(_a0 context.Context, _a1 *appsv1.Deployment)) *Client_UpdateDeployment_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*v1.Deployment)) + run(args[0].(context.Context), args[1].(*appsv1.Deployment)) }) return _c } @@ -519,7 +628,7 @@ func (_c *Client_UpdateDeployment_Call) Return(_a0 error) *Client_UpdateDeployme return _c } -func (_c *Client_UpdateDeployment_Call) RunAndReturn(run func(context.Context, *v1.Deployment) error) *Client_UpdateDeployment_Call { +func (_c *Client_UpdateDeployment_Call) RunAndReturn(run func(context.Context, *appsv1.Deployment) error) *Client_UpdateDeployment_Call { _c.Call.Return(run) return _c } diff --git a/pkg/k8s/types.go b/pkg/k8s/types.go new file mode 100644 index 00000000..2d261c9d --- /dev/null +++ b/pkg/k8s/types.go @@ -0,0 +1,10 @@ +package k8s + +const ( + // ApplicationCrdName defines the CRD name for Application of application-connector module. + ApplicationCrdName string = "applications.applicationconnector.kyma-project.io" + // ApplicationKind defines the Kind name for Application of application-connector module. + ApplicationKind string = "Application" + // ApplicationAPIVersion defines the API version for Application of application-connector module. + ApplicationAPIVersion string = "applicationconnector.kyma-project.io/v1alpha1" +) diff --git a/pkg/subscriptionmanager/mocks/ec/manager.go b/pkg/subscriptionmanager/mocks/ec/manager.go index 913f6b72..44007a8f 100644 --- a/pkg/subscriptionmanager/mocks/ec/manager.go +++ b/pkg/subscriptionmanager/mocks/ec/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks diff --git a/pkg/subscriptionmanager/mocks/manager_factory.go b/pkg/subscriptionmanager/mocks/manager_factory.go index 850d0973..16d0caf1 100644 --- a/pkg/subscriptionmanager/mocks/manager_factory.go +++ b/pkg/subscriptionmanager/mocks/manager_factory.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.30.16. DO NOT EDIT. +// Code generated by mockery v2.30.1. DO NOT EDIT. package mocks diff --git a/test/utils/integration/integration.go b/test/utils/integration/integration.go index b2c95498..a77795a7 100644 --- a/test/utils/integration/integration.go +++ b/test/utils/integration/integration.go @@ -12,6 +12,8 @@ import ( "testing" "time" + apiclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + "github.com/kyma-project/eventing-manager/pkg/subscriptionmanager" subscriptionmanagermocks "github.com/kyma-project/eventing-manager/pkg/subscriptionmanager/mocks" ecsubmanagermocks "github.com/kyma-project/eventing-manager/pkg/subscriptionmanager/mocks/ec" @@ -155,7 +157,11 @@ func NewTestEnvironment(projectRootDir string, celValidationEnabled bool, os.Setenv("DOMAIN", "my.test.domain") // create k8s clients. - kubeClient := k8s.NewKubeClient(ctrlMgr.GetClient(), "eventing-manager") + apiClientSet, err := apiclientset.NewForConfig(ctrlMgr.GetConfig()) + if err != nil { + return nil, err + } + kubeClient := k8s.NewKubeClient(ctrlMgr.GetClient(), apiClientSet, "eventing-manager") // get backend configs. backendConfig := env.GetBackendConfig() @@ -590,6 +596,18 @@ func (env TestEnvironment) EnsureEventingReplicasReflected(t *testing.T, eventin }, SmallTimeOut, SmallPollingInterval, "failed to ensure Eventing spec replicas is reflected") } +func (env TestEnvironment) EnsurePublisherDeploymentENVSet(t *testing.T, eventingCR *v1alpha1.Eventing) { + require.Eventually(t, func() bool { + deployment, err := env.GetDeploymentFromK8s(eventing.GetPublisherDeploymentName(*eventingCR), eventingCR.Namespace) + if err != nil { + env.Logger.WithContext().Errorw("failed to get Eventing resource", "error", err, + "name", eventingCR.Name, "namespace", eventingCR.Namespace) + } + gotValue := test.FindEnvVar(deployment.Spec.Template.Spec.Containers[0].Env, "APPLICATION_CRD_ENABLED") + return gotValue != nil && gotValue.Value == "true" + }, SmallTimeOut, SmallPollingInterval, "failed to verify APPLICATION_CRD_ENABLED ENV in Publisher deployment") +} + func (env TestEnvironment) EnsureDeploymentOwnerReferenceSet(t *testing.T, eventingCR *v1alpha1.Eventing) { require.Eventually(t, func() bool { deployment, err := env.GetDeploymentFromK8s(eventing.GetPublisherDeploymentName(*eventingCR), eventingCR.Namespace) diff --git a/test/utils/utils.go b/test/utils/utils.go index 726a934b..8a7026d3 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -7,6 +7,8 @@ import ( "reflect" "time" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + appsv1 "k8s.io/api/apps/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -47,6 +49,25 @@ func NewNamespace(name string) *v1.Namespace { return &namespace } +func NewApplicationCRD() *apiextensionsv1.CustomResourceDefinition { + result := &apiextensionsv1.CustomResourceDefinition{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1", + Kind: "CustomResourceDefinition", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "applications.applicationconnector.kyma-project.io", + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Names: apiextensionsv1.CustomResourceDefinitionNames{}, + Scope: "Namespaced", + PreserveUnknownFields: false, + }, + } + + return result +} + func NewEventingCR(opts ...EventingOption) *v1alpha1.Eventing { name := fmt.Sprintf(NameFormat, GetRandString(randomNameLen)) namespace := fmt.Sprintf(NamespaceFormat, GetRandString(randomNameLen))