From 27764235a83d040ad872be1ff312e303d3eab4a4 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 31 May 2024 10:54:59 +0200 Subject: [PATCH 01/24] initialize kedaClient --- api/alerting/handler.go | 8 +- api/alerting/handler_test.go | 4 +- .../applications_controller_test.go | 150 +++--- api/applications/applications_handler.go | 28 +- api/buildsecrets/buildsecrets_test.go | 22 +- .../build_status_controller_test.go | 20 +- api/deployments/component_controller_test.go | 224 ++++---- api/deployments/component_handler.go | 37 +- api/deployments/deployment_controller_test.go | 266 +++++----- ..._controller_externaldns_automation_test.go | 18 +- ...environment_controller_externaldns_test.go | 16 +- .../environment_controller_secrets_test.go | 2 +- .../environment_controller_test.go | 487 ++++++++++-------- api/environments/environment_handler.go | 4 +- .../env_vars_controller_test.go | 33 +- api/environmentvariables/env_vars_handler.go | 20 +- .../env_vars_handler_test.go | 18 +- api/jobs/job_controller_test.go | 19 +- api/jobs/job_handler_test.go | 11 +- api/models/horizontal_scaling_summary.go | 69 ++- api/privateimagehubs/internal/secrets.go | 11 +- .../privateimagehubs_controller.go | 2 +- .../privateimagehubs_handler.go | 8 +- .../privateimagehubs_handler_test.go | 18 +- api/secrets/secret_controller_test.go | 7 +- api/test/utils.go | 28 +- api/utils/kubernetes.go | 22 +- api/utils/radix_middleware.go | 10 +- api/utils/radixapplication.go | 2 +- api/utils/test.go | 34 +- go.mod | 39 +- go.sum | 122 +++-- models/account.go | 2 + models/accounts.go | 10 +- 34 files changed, 983 insertions(+), 788 deletions(-) diff --git a/api/alerting/handler.go b/api/alerting/handler.go index 3a29b53f..62d9c6e5 100644 --- a/api/alerting/handler.go +++ b/api/alerting/handler.go @@ -142,7 +142,7 @@ func (h *handler) updateRadixAlertFromAlertingConfig(ctx context.Context, radixA if err != nil { return nil, err } - if err := h.updateConfigSecret(*configSecret, &config); err != nil { + if err := h.updateConfigSecret(ctx, *configSecret, &config); err != nil { return nil, err } } @@ -152,7 +152,7 @@ func (h *handler) updateRadixAlertFromAlertingConfig(ctx context.Context, radixA return h.applyRadixAlert(ctx, &radixAlert) } -func (h *handler) updateConfigSecret(secret corev1.Secret, config *alertModels.UpdateAlertingConfig) error { +func (h *handler) updateConfigSecret(ctx context.Context, secret corev1.Secret, config *alertModels.UpdateAlertingConfig) error { if secret.Data == nil { secret.Data = make(map[string][]byte) } @@ -163,8 +163,8 @@ func (h *handler) updateConfigSecret(secret corev1.Secret, config *alertModels.U } } - kubeUtil, _ := kube.New(h.accounts.UserAccount.Client, h.accounts.UserAccount.RadixClient, h.accounts.UserAccount.SecretProviderClient) - _, err := kubeUtil.ApplySecret(h.namespace, &secret) + kubeUtil, _ := kube.New(h.accounts.UserAccount.Client, h.accounts.UserAccount.RadixClient, h.accounts.UserAccount.KedaClient, h.accounts.UserAccount.SecretProviderClient) + _, err := kubeUtil.ApplySecret(ctx, h.namespace, &secret) return err } diff --git a/api/alerting/handler_test.go b/api/alerting/handler_test.go index 499095ed..2d6c5cea 100644 --- a/api/alerting/handler_test.go +++ b/api/alerting/handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/kube" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" corev1 "k8s.io/api/core/v1" @@ -30,9 +31,10 @@ type HandlerTestSuite struct { func (s *HandlerTestSuite) SetupTest() { kubeClient := kubefake.NewSimpleClientset() radixClient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() secretProviderClient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() - s.accounts = models.NewAccounts(kubeClient, radixClient, secretProviderClient, nil, certClient, kubeClient, radixClient, secretProviderClient, nil, certClient, "", radixmodels.Impersonation{}) + s.accounts = models.NewAccounts(kubeClient, radixClient, kedaClient, secretProviderClient, nil, certClient, kubeClient, radixClient, kedaClient, secretProviderClient, nil, certClient, "", radixmodels.Impersonation{}) } func TestHandlerTestSuite(t *testing.T) { diff --git a/api/applications/applications_controller_test.go b/api/applications/applications_controller_test.go index 25ce605b..2e5f171f 100644 --- a/api/applications/applications_controller_test.go +++ b/api/applications/applications_controller_test.go @@ -33,6 +33,7 @@ import ( commontest "github.com/equinor/radix-operator/pkg/apis/test" builders "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" prometheusfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -49,7 +50,7 @@ const ( subscriptionId = "12347718-c8f8-4995-bfbb-02655ff1f89c" ) -func setupTest(t *testing.T, requireAppConfigurationItem, requireAppADGroups bool) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *fake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { +func setupTest(t *testing.T, requireAppConfigurationItem, requireAppADGroups bool) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *fake.Clientset, *kedafake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { return setupTestWithFactory(t, newTestApplicationHandlerFactory( ApplicationHandlerConfig{RequireAppConfigurationItem: requireAppConfigurationItem, RequireAppADGroups: requireAppADGroups}, func(ctx context.Context, kubeClient kubernetes.Interface, namespace string, configMapName string) (bool, error) { @@ -58,16 +59,17 @@ func setupTest(t *testing.T, requireAppConfigurationItem, requireAppADGroups boo )) } -func setupTestWithFactory(t *testing.T, handlerFactory ApplicationHandlerFactory) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *fake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { +func setupTestWithFactory(t *testing.T, handlerFactory ApplicationHandlerFactory) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *fake.Clientset, *kedafake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := fake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() prometheusclient := prometheusfake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) _ = os.Setenv(defaults.ActiveClusternameEnvironmentVariable, clusterName) @@ -76,6 +78,7 @@ func setupTestWithFactory(t *testing.T, handlerFactory ApplicationHandlerFactory controllerTestUtils := controllertest.NewTestUtils( kubeclient, radixclient, + kedaClient, secretproviderclient, certClient, NewApplicationController( @@ -86,11 +89,11 @@ func setupTestWithFactory(t *testing.T, handlerFactory ApplicationHandlerFactory ), ) - return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, prometheusclient, secretproviderclient, certClient + return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, kedaClient, prometheusclient, secretproviderclient, certClient } func TestGetApplications_HasAccessToSomeRR(t *testing.T) { - commonTestUtils, _, kubeclient, radixclient, _, secretproviderclient, certClient := setupTest(t, true, true) + commonTestUtils, _, kubeclient, radixclient, kedaClient, _, secretproviderclient, certClient := setupTest(t, true, true) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithCloneURL("git@github.com:Equinor/my-app.git")) @@ -103,6 +106,7 @@ func TestGetApplications_HasAccessToSomeRR(t *testing.T) { controllerTestUtils := controllertest.NewTestUtils( kubeclient, radixclient, + kedaClient, secretproviderclient, certClient, NewApplicationController( @@ -122,7 +126,7 @@ func TestGetApplications_HasAccessToSomeRR(t *testing.T) { }) t.Run("access to single app", func(t *testing.T) { - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, rr v1.RadixRegistration) (bool, error) { return rr.GetName() == "my-second-app", nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -139,7 +143,7 @@ func TestGetApplications_HasAccessToSomeRR(t *testing.T) { }) t.Run("access to all app", func(t *testing.T) { - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, _ v1.RadixRegistration) (bool, error) { return true, nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -158,7 +162,7 @@ func TestGetApplications_HasAccessToSomeRR(t *testing.T) { func TestGetApplications_WithFilterOnSSHRepo_Filter(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithCloneURL("git@github.com:Equinor/my-app.git")) require.NoError(t, err) @@ -197,7 +201,7 @@ func TestGetApplications_WithFilterOnSSHRepo_Filter(t *testing.T) { func TestSearchApplicationsPost(t *testing.T) { // Setup - commonTestUtils, _, kubeclient, radixclient, _, secretproviderclient, certClient := setupTest(t, true, true) + commonTestUtils, _, kubeclient, radixclient, kedaClient, _, secretproviderclient, certClient := setupTest(t, true, true) appNames := []string{"app-1", "app-2"} for _, appName := range appNames { @@ -209,6 +213,7 @@ func TestSearchApplicationsPost(t *testing.T) { err := createRadixJob(commonTestUtils, appNames[1], "app-2-job-1", app2Job1Started) require.NoError(t, err) _, err = commonTestUtils.ApplyDeployment( + context.Background(), builders. ARadixDeployment(). WithAppName(appNames[1]). @@ -219,7 +224,7 @@ func TestSearchApplicationsPost(t *testing.T) { ) require.NoError(t, err) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, _ v1.RadixRegistration) (bool, error) { return true, nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -301,7 +306,7 @@ func TestSearchApplicationsPost(t *testing.T) { }) t.Run("search for "+appNames[0]+" - no access", func(t *testing.T) { - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, _ v1.RadixRegistration) (bool, error) { return false, nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -321,7 +326,7 @@ func TestSearchApplicationsPost(t *testing.T) { func TestSearchApplicationsPost_WithJobs_ShouldOnlyHaveLatest(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t, true, true) apps := []applicationModels.Application{ {Name: "app-1", Jobs: []*jobModels.JobSummary{ {Name: "app-1-job-1", Started: "2018-11-12T11:45:26Z"}, @@ -374,7 +379,7 @@ func TestSearchApplicationsPost_WithJobs_ShouldOnlyHaveLatest(t *testing.T) { func TestSearchApplicationsGet(t *testing.T) { // Setup - commonTestUtils, _, kubeclient, radixclient, _, secretproviderclient, certClient := setupTest(t, true, true) + commonTestUtils, _, kubeclient, radixclient, kedaClient, _, secretproviderclient, certClient := setupTest(t, true, true) appNames := []string{"app-1", "app-2"} for _, appName := range appNames { @@ -386,6 +391,7 @@ func TestSearchApplicationsGet(t *testing.T) { err := createRadixJob(commonTestUtils, appNames[1], "app-2-job-1", app2Job1Started) require.NoError(t, err) _, err = commonTestUtils.ApplyDeployment( + context.Background(), builders. ARadixDeployment(). WithAppName(appNames[1]). @@ -396,7 +402,7 @@ func TestSearchApplicationsGet(t *testing.T) { ) require.NoError(t, err) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, _ v1.RadixRegistration) (bool, error) { return true, nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -468,7 +474,7 @@ func TestSearchApplicationsGet(t *testing.T) { }) t.Run("search for "+appNames[0]+" - no access", func(t *testing.T) { - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewApplicationController( + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewApplicationController( func(_ context.Context, _ kubernetes.Interface, _ v1.RadixRegistration) (bool, error) { return false, nil }, newTestApplicationHandlerFactory(ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: true}, @@ -488,7 +494,7 @@ func TestSearchApplicationsGet(t *testing.T) { func TestSearchApplicationsGet_WithJobs_ShouldOnlyHaveLatest(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t, true, true) apps := []applicationModels.Application{ {Name: "app-1", Jobs: []*jobModels.JobSummary{ {Name: "app-1-job-1", Started: "2018-11-12T11:45:26Z"}, @@ -539,7 +545,7 @@ func TestSearchApplicationsGet_WithJobs_ShouldOnlyHaveLatest(t *testing.T) { func TestCreateApplication_NoName_ValidationError(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test parameters := buildApplicationRegistrationRequest( @@ -556,7 +562,7 @@ func TestCreateApplication_NoName_ValidationError(t *testing.T) { func TestCreateApplication_WhenRequiredConfigurationItemIsNotSet_ReturnError(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test parameters := buildApplicationRegistrationRequest( @@ -577,7 +583,7 @@ func TestCreateApplication_WhenRequiredConfigurationItemIsNotSet_ReturnError(t * func TestCreateApplication_WhenOptionalConfigurationItemIsNotSet_ReturnSuccess(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, false, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, false, true) // Test parameters := buildApplicationRegistrationRequest( @@ -595,7 +601,7 @@ func TestCreateApplication_WhenOptionalConfigurationItemIsNotSet_ReturnSuccess(t func TestCreateApplication_WhenRequiredAdGroupsIsNotSet_ReturnError(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test parameters := buildApplicationRegistrationRequest( @@ -616,7 +622,7 @@ func TestCreateApplication_WhenRequiredAdGroupsIsNotSet_ReturnError(t *testing.T func TestCreateApplication_WhenOptionalAdGroupsIsNotSet_ReturnSuccess(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, false) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, false) // Test parameters := buildApplicationRegistrationRequest( @@ -635,7 +641,7 @@ func TestCreateApplication_WhenOptionalAdGroupsIsNotSet_ReturnSuccess(t *testing func TestCreateApplication_WhenConfigBranchIsNotSet_ReturnError(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test parameters := buildApplicationRegistrationRequest( @@ -657,7 +663,7 @@ func TestCreateApplication_WhenConfigBranchIsNotSet_ReturnError(t *testing.T) { func TestCreateApplication_WhenConfigBranchIsInvalid_ReturnError(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test configBranch := "main.." @@ -701,7 +707,7 @@ func TestCreateApplication_WithRadixConfigFullName(t *testing.T) { for _, scenario := range scenarios { t.Run(fmt.Sprintf("Test for radixConfigFullName: '%s'", scenario.radixConfigFullName), func(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test configBranch := "main" @@ -735,7 +741,7 @@ func TestCreateApplication_WithRadixConfigFullName(t *testing.T) { func TestCreateApplication_DuplicateRepo_ShouldWarn(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -769,7 +775,7 @@ func TestCreateApplication_DuplicateRepo_ShouldWarn(t *testing.T) { func TestCreateApplication_DuplicateRepoWithAcknowledgeWarning_ShouldSuccess(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -802,7 +808,7 @@ func TestCreateApplication_DuplicateRepoWithAcknowledgeWarning_ShouldSuccess(t * func TestGetApplication_AllFieldsAreSet(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -839,7 +845,7 @@ func TestGetApplication_AllFieldsAreSet(t *testing.T) { func TestGetApplication_WithJobs(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t, true, true) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithName("any-name")) require.NoError(t, err) @@ -868,7 +874,7 @@ func TestGetApplication_WithJobs(t *testing.T) { func TestGetApplication_WithEnvironments(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, radix, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, _, radix, _, _, _, _ := setupTest(t, true, true) anyAppName := "any-app" anyOrphanedEnvironment := "feature" @@ -885,18 +891,20 @@ func TestGetApplication_WithEnvironments(t *testing.T) { WithEnvironment("prod", "release")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. + _, err = commonTestUtils.ApplyDeployment(context.Background(), builders. NewDeploymentBuilder(). WithAppName(anyAppName). WithEnvironment("dev"). WithImageTag("someimageindev")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyOrphanedEnvironment). - WithImageTag("someimageinfeature")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyOrphanedEnvironment). + WithImageTag("someimageinfeature")) require.NoError(t, err) // Set RE statuses @@ -946,7 +954,7 @@ func TestGetApplication_WithEnvironments(t *testing.T) { func TestUpdateApplication_DuplicateRepo_ShouldWarn(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -991,7 +999,7 @@ func TestUpdateApplication_DuplicateRepo_ShouldWarn(t *testing.T) { func TestUpdateApplication_DuplicateRepoWithAcknowledgeWarnings_ShouldSuccess(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -1038,7 +1046,7 @@ func TestUpdateApplication_DuplicateRepoWithAcknowledgeWarnings_ShouldSuccess(t func TestUpdateApplication_MismatchingNameOrNotExists_ShouldFailAsIllegalOperation(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest(anApplicationRegistration().WithName("any-name").Build(), false) responseChannel := controllerTestUtils.ExecuteRequestWithParameters("POST", "/api/v1/applications", parameters) @@ -1069,7 +1077,7 @@ func TestUpdateApplication_MismatchingNameOrNotExists_ShouldFailAsIllegalOperati func TestUpdateApplication_AbleToSetAnySpecField(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) builder := anApplicationRegistration(). @@ -1144,7 +1152,7 @@ func TestUpdateApplication_AbleToSetAnySpecField(t *testing.T) { func TestModifyApplication_AbleToSetField(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) builder := anApplicationRegistration(). WithName("any-name"). @@ -1279,7 +1287,7 @@ func TestModifyApplication_AbleToSetField(t *testing.T) { func TestModifyApplication_AbleToUpdateRepository(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) builder := anApplicationRegistration(). WithName("any-name"). @@ -1310,7 +1318,7 @@ func TestModifyApplication_AbleToUpdateRepository(t *testing.T) { func TestModifyApplication_ConfigBranchSetToFallbackHack(t *testing.T) { // Setup appName := "any-name" - _, controllerTestUtils, _, radixClient, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, radixClient, _, _, _, _ := setupTest(t, true, true) rr := builders.ARadixRegistration(). WithName(appName). WithConfigurationItem("any"). @@ -1340,7 +1348,7 @@ func TestModifyApplication_ConfigBranchSetToFallbackHack(t *testing.T) { func TestModifyApplication_IgnoreRequireCIValidationWhenRequiredButCurrentIsEmpty(t *testing.T) { // Setup - _, controllerTestUtils, _, radixClient, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, radixClient, _, _, _, _ := setupTest(t, true, true) rr, err := anApplicationRegistration(). WithName("any-name"). @@ -1364,7 +1372,7 @@ func TestModifyApplication_IgnoreRequireCIValidationWhenRequiredButCurrentIsEmpt func TestModifyApplication_IgnoreRequireADGroupValidationWhenRequiredButCurrentIsEmpty(t *testing.T) { // Setup - _, controllerTestUtils, _, radixClient, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, radixClient, _, _, _, _ := setupTest(t, true, true) rr, err := anApplicationRegistration(). WithName("any-name"). @@ -1455,7 +1463,7 @@ func TestModifyApplication_UpdateADGroupValidation(t *testing.T) { for _, ts := range scenarios { t.Run(ts.name, func(t *testing.T) { - _, controllerTestUtils, _, radixClient, _, _, _ := setupTestWithFactory(t, newTestApplicationHandlerFactory( + _, controllerTestUtils, _, radixClient, _, _, _, _ := setupTestWithFactory(t, newTestApplicationHandlerFactory( ApplicationHandlerConfig{RequireAppConfigurationItem: true, RequireAppADGroups: ts.requireAppADGroups}, func(ctx context.Context, kubeClient kubernetes.Interface, namespace string, configMapName string) (bool, error) { return ts.hasAccessToAdGroups, nil @@ -1486,7 +1494,7 @@ func TestModifyApplication_UpdateADGroupValidation(t *testing.T) { func TestHandleTriggerPipeline_ForNonMappedAndMappedAndMagicBranchEnvironment_JobIsNotCreatedForUnmapped(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) anyAppName := "any-app" configBranch := "magic" @@ -1529,7 +1537,7 @@ func TestHandleTriggerPipeline_ForNonMappedAndMappedAndMagicBranchEnvironment_Jo func TestHandleTriggerPipeline_ExistingAndNonExistingApplication_JobIsCreatedForExisting(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) registerAppParam := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -1600,7 +1608,7 @@ func TestHandleTriggerPipeline_Deploy_JobHasCorrectParameters(t *testing.T) { for _, ts := range scenarios { t.Run(ts.name, func(t *testing.T) { - _, controllerTestUtils, _, radixclient, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, radixclient, _, _, _, _ := setupTest(t, true, true) registerAppParam := buildApplicationRegistrationRequest(anApplicationRegistration().WithName(appName).Build(), false) <-controllerTestUtils.ExecuteRequestWithParameters("POST", "/api/v1/applications", registerAppParam) responseChannel := controllerTestUtils.ExecuteRequestWithParameters("POST", fmt.Sprintf("/api/v1/applications/%s/pipelines/%s", appName, v1.Deploy), ts.params) @@ -1616,7 +1624,7 @@ func TestHandleTriggerPipeline_Deploy_JobHasCorrectParameters(t *testing.T) { } func TestHandleTriggerPipeline_Promote_JobHasCorrectParameters(t *testing.T) { - commonTestUtils, controllerTestUtils, _, radixclient, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, _, radixclient, _, _, _, _ := setupTest(t, true, true) const ( appName = "an-app" @@ -1631,13 +1639,15 @@ func TestHandleTriggerPipeline_Promote_JobHasCorrectParameters(t *testing.T) { ToEnvironment: toEnvironment, DeploymentName: deploymentName, } - _, err := commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAppName(appName). - WithDeploymentName(deploymentName). - WithEnvironment(fromEnvironment). - WithLabel(kube.RadixCommitLabel, commitId). - WithCondition(v1.DeploymentInactive)) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAppName(appName). + WithDeploymentName(deploymentName). + WithEnvironment(fromEnvironment). + WithLabel(kube.RadixCommitLabel, commitId). + WithCondition(v1.DeploymentInactive)) require.NoError(t, err) registerAppParam := buildApplicationRegistrationRequest(anApplicationRegistration().WithName(appName).Build(), false) @@ -1658,7 +1668,7 @@ func TestHandleTriggerPipeline_Promote_JobHasCorrectParameters(t *testing.T) { func TestIsDeployKeyValid(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t, true, true) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithName("some-app"). WithPublicKey("some-public-key"). @@ -1728,7 +1738,7 @@ func TestIsDeployKeyValid(t *testing.T) { func TestDeleteApplication_ApplicationIsDeleted(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) parameters := buildApplicationRegistrationRequest( anApplicationRegistration(). @@ -1757,8 +1767,8 @@ func TestDeleteApplication_ApplicationIsDeleted(t *testing.T) { func TestGetApplication_WithAppAlias_ContainsAppAlias(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretproviderclient, certClient := setupTest(t, true, true) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretproviderclient, certClient, builders.ARadixDeployment(). + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretproviderclient, certClient := setupTest(t, true, true) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretproviderclient, certClient, builders.ARadixDeployment(). WithAppName("any-app"). WithEnvironment("prod"). WithComponents( @@ -1789,7 +1799,7 @@ func TestListPipeline_ReturnesAvailablePipelines(t *testing.T) { supportedPipelines := jobPipeline.GetSupportedPipelines() // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithName("some-app"). WithPublicKey("some-public-key"). @@ -1808,7 +1818,7 @@ func TestListPipeline_ReturnesAvailablePipelines(t *testing.T) { func TestRegenerateDeployKey_WhenApplicationNotExist_Fail(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t, true, true) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t, true, true) // Test parameters := buildApplicationRegistrationRequest( @@ -1837,12 +1847,12 @@ func TestRegenerateDeployKey_WhenApplicationNotExist_Fail(t *testing.T) { func TestRegenerateDeployKey_NoSecretInParam_SecretIsReCreated(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeUtil, radixClient, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeUtil, radixClient, kedaClient, _, _, _ := setupTest(t, true, true) appName := "any-name" rrBuilder := builders.ARadixRegistration().WithName(appName).WithCloneURL("git@github.com:Equinor/my-app.git") // Creating RR and syncing it - err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, commonTestUtils, rrBuilder) + err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, kedaClient, commonTestUtils, rrBuilder) require.NoError(t, err) // Check that secret has been created @@ -1857,7 +1867,7 @@ func TestRegenerateDeployKey_NoSecretInParam_SecretIsReCreated(t *testing.T) { assert.Equal(t, http.StatusNoContent, response.Code) // forcing resync of RR - err = utils.ApplyRegistrationWithSync(kubeUtil, radixClient, commonTestUtils, rrBuilder) + err = utils.ApplyRegistrationWithSync(kubeUtil, radixClient, kedaClient, commonTestUtils, rrBuilder) require.NoError(t, err) // Check that secret has been re-created and is different from first secret @@ -1869,12 +1879,12 @@ func TestRegenerateDeployKey_NoSecretInParam_SecretIsReCreated(t *testing.T) { func TestRegenerateDeployKey_PrivateKeyInParam_SavedPrivateKeyIsEqualToWebParam(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeUtil, radixClient, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeUtil, radixClient, kedaClient, _, _, _ := setupTest(t, true, true) appName := "any-name" rrBuilder := builders.ARadixRegistration().WithName(appName).WithCloneURL("git@github.com:Equinor/my-app.git") // Creating RR and syncing it - err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, commonTestUtils, rrBuilder) + err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, kedaClient, commonTestUtils, rrBuilder) require.NoError(t, err) // make some valid private key @@ -1888,7 +1898,7 @@ func TestRegenerateDeployKey_PrivateKeyInParam_SavedPrivateKeyIsEqualToWebParam( assert.Equal(t, http.StatusNoContent, response.Code) // forcing resync of RR - err = utils.ApplyRegistrationWithSync(kubeUtil, radixClient, commonTestUtils, rrBuilder) + err = utils.ApplyRegistrationWithSync(kubeUtil, radixClient, kedaClient, commonTestUtils, rrBuilder) require.NoError(t, err) // Check that secret has been re-created and is equal to the one in the web parameter @@ -1899,12 +1909,12 @@ func TestRegenerateDeployKey_PrivateKeyInParam_SavedPrivateKeyIsEqualToWebParam( func TestRegenerateDeployKey_InvalidKeyInParam_ErrorIsReturned(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeUtil, radixClient, _, _, _ := setupTest(t, true, true) + commonTestUtils, controllerTestUtils, kubeUtil, radixClient, kedaClient, _, _, _ := setupTest(t, true, true) appName := "any-name" rrBuilder := builders.ARadixRegistration().WithName(appName).WithCloneURL("git@github.com:Equinor/my-app.git") // Creating RR and syncing it - err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, commonTestUtils, rrBuilder) + err := utils.ApplyRegistrationWithSync(kubeUtil, radixClient, kedaClient, commonTestUtils, rrBuilder) require.NoError(t, err) // calling regenerate-deploy-key with invalid private key, expecting error diff --git a/api/applications/applications_handler.go b/api/applications/applications_handler.go index d345825c..3005fef8 100644 --- a/api/applications/applications_handler.go +++ b/api/applications/applications_handler.go @@ -156,13 +156,13 @@ func (ah *ApplicationHandler) RegisterApplication(ctx context.Context, applicati return nil, err } - err = ah.isValidRegistrationInsert(radixRegistration) + err = ah.isValidRegistrationInsert(ctx, radixRegistration) if err != nil { return nil, err } if !applicationRegistrationRequest.AcknowledgeWarnings { - if upsertResponse, err := ah.getRegistrationInsertResponseForWarnings(radixRegistration); upsertResponse != nil || err != nil { + if upsertResponse, err := ah.getRegistrationInsertResponseForWarnings(ctx, radixRegistration); upsertResponse != nil || err != nil { return upsertResponse, err } } @@ -182,8 +182,8 @@ func (ah *ApplicationHandler) RegisterApplication(ctx context.Context, applicati }, nil } -func (ah *ApplicationHandler) getRegistrationInsertResponseForWarnings(radixRegistration *v1.RadixRegistration) (*applicationModels.ApplicationRegistrationUpsertResponse, error) { - warnings, err := ah.getRegistrationInsertWarnings(radixRegistration) +func (ah *ApplicationHandler) getRegistrationInsertResponseForWarnings(ctx context.Context, radixRegistration *v1.RadixRegistration) (*applicationModels.ApplicationRegistrationUpsertResponse, error) { + warnings, err := ah.getRegistrationInsertWarnings(ctx, radixRegistration) if err != nil { return nil, err } @@ -193,8 +193,8 @@ func (ah *ApplicationHandler) getRegistrationInsertResponseForWarnings(radixRegi return nil, nil } -func (ah *ApplicationHandler) getRegistrationUpdateResponseForWarnings(radixRegistration *v1.RadixRegistration) (*applicationModels.ApplicationRegistrationUpsertResponse, error) { - warnings, err := ah.getRegistrationUpdateWarnings(radixRegistration) +func (ah *ApplicationHandler) getRegistrationUpdateResponseForWarnings(ctx context.Context, radixRegistration *v1.RadixRegistration) (*applicationModels.ApplicationRegistrationUpsertResponse, error) { + warnings, err := ah.getRegistrationUpdateWarnings(ctx, radixRegistration) if err != nil { return nil, err } @@ -245,7 +245,7 @@ func (ah *ApplicationHandler) ChangeRegistrationDetails(ctx context.Context, app needToRevalidateWarnings := updatedRegistration.Spec.CloneURL != currentRegistration.Spec.CloneURL if needToRevalidateWarnings && !applicationRegistrationRequest.AcknowledgeWarnings { - if upsertResponse, err := ah.getRegistrationUpdateResponseForWarnings(radixRegistration); upsertResponse != nil || err != nil { + if upsertResponse, err := ah.getRegistrationUpdateResponseForWarnings(ctx, radixRegistration); upsertResponse != nil || err != nil { return upsertResponse, err } } @@ -348,7 +348,7 @@ func (ah *ApplicationHandler) ModifyRegistrationDetails(ctx context.Context, app needToRevalidateWarnings := currentRegistration.Spec.CloneURL != updatedRegistration.Spec.CloneURL if needToRevalidateWarnings && !applicationRegistrationPatchRequest.AcknowledgeWarnings { - if upsertResponse, err := ah.getRegistrationUpdateResponseForWarnings(updatedRegistration); upsertResponse != nil || err != nil { + if upsertResponse, err := ah.getRegistrationUpdateResponseForWarnings(ctx, updatedRegistration); upsertResponse != nil || err != nil { return upsertResponse, err } } @@ -563,18 +563,18 @@ func (ah *ApplicationHandler) triggerPipelineBuildOrBuildDeploy(ctx context.Cont return jobSummary, nil } -func (ah *ApplicationHandler) getRegistrationInsertWarnings(radixRegistration *v1.RadixRegistration) ([]string, error) { - return radixvalidators.GetRadixRegistrationBeInsertedWarnings(ah.getServiceAccount().RadixClient, radixRegistration) +func (ah *ApplicationHandler) getRegistrationInsertWarnings(ctx context.Context, radixRegistration *v1.RadixRegistration) ([]string, error) { + return radixvalidators.GetRadixRegistrationBeInsertedWarnings(ctx, ah.getServiceAccount().RadixClient, radixRegistration) } -func (ah *ApplicationHandler) getRegistrationUpdateWarnings(radixRegistration *v1.RadixRegistration) ([]string, error) { - return radixvalidators.GetRadixRegistrationBeUpdatedWarnings(ah.getServiceAccount().RadixClient, radixRegistration) +func (ah *ApplicationHandler) getRegistrationUpdateWarnings(ctx context.Context, radixRegistration *v1.RadixRegistration) ([]string, error) { + return radixvalidators.GetRadixRegistrationBeUpdatedWarnings(ctx, ah.getServiceAccount().RadixClient, radixRegistration) } -func (ah *ApplicationHandler) isValidRegistrationInsert(radixRegistration *v1.RadixRegistration) error { +func (ah *ApplicationHandler) isValidRegistrationInsert(ctx context.Context, radixRegistration *v1.RadixRegistration) error { // Need to use in-cluster client of the API server, because the user might not have enough privileges // to run a full validation - return radixvalidators.CanRadixRegistrationBeInserted(ah.getServiceAccount().RadixClient, radixRegistration, ah.getAdditionalRadixRegistrationInsertValidators()...) + return radixvalidators.CanRadixRegistrationBeInserted(ctx, ah.getServiceAccount().RadixClient, radixRegistration, ah.getAdditionalRadixRegistrationInsertValidators()...) } func (ah *ApplicationHandler) isValidRegistrationUpdate(updatedRegistration, currentRegistration *v1.RadixRegistration) error { diff --git a/api/buildsecrets/buildsecrets_test.go b/api/buildsecrets/buildsecrets_test.go index 13833cbb..3d5f2bba 100644 --- a/api/buildsecrets/buildsecrets_test.go +++ b/api/buildsecrets/buildsecrets_test.go @@ -6,6 +6,7 @@ import ( "testing" environmentModels "github.com/equinor/radix-api/api/secrets/models" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/require" secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" @@ -27,21 +28,22 @@ const ( subscriptionId = "12347718-c8f8-4995-bfbb-02655ff1f89c" ) -func setupTest(t *testing.T) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *radixfake.Clientset) { +func setupTest(t *testing.T) (*commontest.Utils, *controllertest.Utils, *kubefake.Clientset, *radixfake.Clientset, *kedafake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) // controllerTestUtils is used for issuing HTTP request and processing responses - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildSecretsController()) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildSecretsController()) - return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient + return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, kedaClient } func TestGetBuildSecrets_ListsAll(t *testing.T) { @@ -50,9 +52,9 @@ func TestGetBuildSecrets_ListsAll(t *testing.T) { anyBuildSecret3 := "secret3" // Setup - commonTestUtils, controllerTestUtils, client, radixclient := setupTest(t) + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient := setupTest(t) - err := utils.ApplyApplicationWithSync(client, radixclient, commonTestUtils, + err := utils.ApplyApplicationWithSync(client, radixclient, kedaClient, commonTestUtils, builders.ARadixApplication(). WithAppName(anyAppName). WithBuildSecrets(anyBuildSecret1, anyBuildSecret2)) @@ -69,7 +71,7 @@ func TestGetBuildSecrets_ListsAll(t *testing.T) { assert.Equal(t, anyBuildSecret1, buildSecrets[0].Name) assert.Equal(t, anyBuildSecret2, buildSecrets[1].Name) - err = utils.ApplyApplicationWithSync(client, radixclient, commonTestUtils, + err = utils.ApplyApplicationWithSync(client, radixclient, kedaClient, commonTestUtils, builders.ARadixApplication(). WithAppName(anyAppName). WithBuildSecrets(anyBuildSecret1, anyBuildSecret2, anyBuildSecret3)) @@ -86,7 +88,7 @@ func TestGetBuildSecrets_ListsAll(t *testing.T) { assert.Equal(t, anyBuildSecret2, buildSecrets[1].Name) assert.Equal(t, anyBuildSecret3, buildSecrets[2].Name) - err = utils.ApplyApplicationWithSync(client, radixclient, commonTestUtils, + err = utils.ApplyApplicationWithSync(client, radixclient, kedaClient, commonTestUtils, builders.ARadixApplication(). WithAppName(anyAppName). WithBuildSecrets(anyBuildSecret1, anyBuildSecret3)) @@ -107,9 +109,9 @@ func TestUpdateBuildSecret_UpdatedOk(t *testing.T) { anyBuildSecret1 := "secret1" // Setup - commonTestUtils, controllerTestUtils, client, radixclient := setupTest(t) + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient := setupTest(t) - err := utils.ApplyApplicationWithSync(client, radixclient, commonTestUtils, + err := utils.ApplyApplicationWithSync(client, radixclient, kedaClient, commonTestUtils, builders.ARadixApplication(). WithAppName(anyAppName). WithBuildSecrets(anyBuildSecret1)) diff --git a/api/buildstatus/build_status_controller_test.go b/api/buildstatus/build_status_controller_test.go index 69ecdb73..e588fd28 100644 --- a/api/buildstatus/build_status_controller_test.go +++ b/api/buildstatus/build_status_controller_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/require" secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" @@ -29,24 +30,25 @@ const ( subscriptionId = "12347718-c8f8-4995-bfbb-02655ff1f89c" ) -func setupTest(t *testing.T) (*commontest.Utils, *kubefake.Clientset, *radixfake.Clientset, *secretproviderfake.Clientset, *certclientfake.Clientset) { +func setupTest(t *testing.T) (*commontest.Utils, *kubefake.Clientset, *radixfake.Clientset, *kedafake.Clientset, *secretproviderfake.Clientset, *certclientfake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) _ = os.Setenv(defaults.ActiveClusternameEnvironmentVariable, clusterName) - return &commonTestUtils, kubeclient, radixclient, secretproviderclient, certClient + return &commonTestUtils, kubeclient, radixclient, kedaClient, secretproviderclient, certClient } func TestGetBuildStatus(t *testing.T) { - commonTestUtils, kubeclient, radixclient, secretproviderclient, certClient := setupTest(t) + commonTestUtils, kubeclient, radixclient, kedaClient, secretproviderclient, certClient := setupTest(t) jobStartReferenceTime := time.Date(2020, 1, 10, 0, 0, 0, 0, time.UTC) _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration()) @@ -103,7 +105,7 @@ func TestGetBuildStatus(t *testing.T) { Return(expected, nil). Times(1) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) responseChannel := controllerTestUtils.ExecuteUnAuthorizedRequest("GET", "/api/v1/applications/my-app/environments/test/buildstatus") response := <-responseChannel @@ -132,7 +134,7 @@ func TestGetBuildStatus(t *testing.T) { return nil, nil }) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) responseChannel := controllerTestUtils.ExecuteUnAuthorizedRequest("GET", "/api/v1/applications/my-app/environments/test/buildstatus") response := <-responseChannel @@ -160,7 +162,7 @@ func TestGetBuildStatus(t *testing.T) { return nil, nil }) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) responseChannel := controllerTestUtils.ExecuteUnAuthorizedRequest("GET", "/api/v1/applications/my-app/environments/test/buildstatus?pipeline=deploy") response := <-responseChannel @@ -188,7 +190,7 @@ func TestGetBuildStatus(t *testing.T) { return nil, nil }) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) responseChannel := controllerTestUtils.ExecuteUnAuthorizedRequest("GET", "/api/v1/applications/my-app/environments/test/buildstatus?pipeline=promote") response := <-responseChannel @@ -210,7 +212,7 @@ func TestGetBuildStatus(t *testing.T) { Return(nil, errors.New("error")). Times(1) - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewBuildStatusController(fakeBuildStatus)) responseChannel := controllerTestUtils.ExecuteUnAuthorizedRequest("GET", "/api/v1/applications/my-app/environments/test/buildstatus") response := <-responseChannel diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index 72e174fb..bcfc2648 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -30,7 +30,7 @@ func createGetComponentsEndpoint(appName, deployName string) string { func TestGetComponents_non_existing_app(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -43,7 +43,7 @@ func TestGetComponents_non_existing_app(t *testing.T) { } func TestGetComponents_non_existing_deployment(t *testing.T) { - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) _, err := commonTestUtils.ApplyApplication(operatorUtils. ARadixApplication(). WithAppName(anyAppName)) @@ -63,16 +63,18 @@ func TestGetComponents_non_existing_deployment(t *testing.T) { func TestGetComponents_active_deployment(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job")). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app")). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName(anyDeployName)) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job")). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app")). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName(anyDeployName)) require.NoError(t, err) err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app") @@ -102,8 +104,8 @@ func TestGetComponents_active_deployment(t *testing.T) { func TestGetComponents_WithVolumeMount_ContainsVolumeMountSecrets(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName("any-app"). WithEnvironment("prod"). WithDeploymentName(anyDeployName). @@ -161,8 +163,8 @@ func TestGetComponents_WithVolumeMount_ContainsVolumeMountSecrets(t *testing.T) func TestGetComponents_WithTwoVolumeMounts_ContainsTwoVolumeMountSecrets(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName("any-app"). WithEnvironment("prod"). WithDeploymentName(anyDeployName). @@ -210,8 +212,8 @@ func TestGetComponents_WithTwoVolumeMounts_ContainsTwoVolumeMountSecrets(t *test func TestGetComponents_OAuth2(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName("any-app"). WithEnvironment("prod"). WithDeploymentName(anyDeployName). @@ -255,42 +257,46 @@ func TestGetComponents_OAuth2(t *testing.T) { func TestGetComponents_inactive_deployment(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) initialDeploymentCreated, _ := radixutils.ParseTimestamp("2018-11-12T11:45:26Z") activeDeploymentCreated, _ := radixutils.ParseTimestamp("2018-11-14T11:45:26Z") - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName("initial-deployment"). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app"), - ). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"), - ). - WithCreated(initialDeploymentCreated). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(initialDeploymentCreated). - WithActiveTo(activeDeploymentCreated)) - require.NoError(t, err) - - _, err = commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName("active-deployment"). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app"), - ). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"), - ). - WithCreated(activeDeploymentCreated). - WithCondition(v1.DeploymentActive). - WithActiveFrom(activeDeploymentCreated)) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName("initial-deployment"). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app"), + ). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"), + ). + WithCreated(initialDeploymentCreated). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(initialDeploymentCreated). + WithActiveTo(activeDeploymentCreated)) + require.NoError(t, err) + + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName("active-deployment"). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app"), + ). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"), + ). + WithCreated(activeDeploymentCreated). + WithCondition(v1.DeploymentActive). + WithActiveFrom(activeDeploymentCreated)) require.NoError(t, err) err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app") @@ -335,11 +341,13 @@ func getPodSpec(podName, radixComponentLabel string) *corev1.Pod { func TestGetComponents_success(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithDeploymentName(anyDeployName)) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithDeploymentName(anyDeployName)) require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -360,16 +368,18 @@ func TestGetComponents_success(t *testing.T) { func TestGetComponents_ReplicaStatus_Failing(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName(anyDeployName). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app")). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName(anyDeployName). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app")). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) require.NoError(t, err) message1 := "Couldn't find key TEST_SECRET in Secret radix-demo-hello-nodejs-dev/www" @@ -406,16 +416,18 @@ func TestGetComponents_ReplicaStatus_Failing(t *testing.T) { func TestGetComponents_ReplicaStatus_Running(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName(anyDeployName). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app")). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName(anyDeployName). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app")). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) require.NoError(t, err) message := "" @@ -451,16 +463,18 @@ func TestGetComponents_ReplicaStatus_Running(t *testing.T) { func TestGetComponents_ReplicaStatus_Starting(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName(anyDeployName). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app")). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName(anyDeployName). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app")). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) require.NoError(t, err) message := "" @@ -496,16 +510,18 @@ func TestGetComponents_ReplicaStatus_Starting(t *testing.T) { func TestGetComponents_ReplicaStatus_Pending(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _ := setupTest(t) - _, err := commonTestUtils.ApplyDeployment(operatorUtils. - ARadixDeployment(). - WithAppName(anyAppName). - WithEnvironment("dev"). - WithDeploymentName(anyDeployName). - WithComponents( - operatorUtils.NewDeployComponentBuilder().WithName("app")). - WithJobComponents( - operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) + commonTestUtils, controllerTestUtils, kubeclient, _, _, _, _, _ := setupTest(t) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorUtils. + ARadixDeployment(). + WithAppName(anyAppName). + WithEnvironment("dev"). + WithDeploymentName(anyDeployName). + WithComponents( + operatorUtils.NewDeployComponentBuilder().WithName("app")). + WithJobComponents( + operatorUtils.NewDeployJobComponentBuilder().WithName("job"))) require.NoError(t, err) message := "" @@ -542,7 +558,7 @@ func TestGetComponents_ReplicaStatus_Pending(t *testing.T) { func TestGetComponents_WithHorizontalScaling(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t) + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) testScenarios := []struct { name string deploymentName string @@ -560,7 +576,15 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { for _, scenario := range testScenarios { t.Run(scenario.name, func(t *testing.T) { - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). + horizontalScaling := operatorUtils.NewHorizontalScalingBuilder().WithMinReplicas(scenario.minReplicas).WithMaxReplicas(scenario.maxReplicas) + if scenario.targetCpu != nil { + horizontalScaling.WithCPUTrigger(int(*scenario.targetCpu)) + } + if scenario.targetMemory != nil { + horizontalScaling.WithMemoryTrigger(int(*scenario.targetMemory)) + } + + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName(anyAppName). WithEnvironment("prod"). WithDeploymentName(scenario.deploymentName). @@ -570,7 +594,7 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { WithName("frontend"). WithPort("http", 8080). WithPublicPort("http"). - WithHorizontalScaling(&scenario.minReplicas, scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory))) + WithHorizontalScaling(horizontalScaling.Build()))) require.NoError(t, err) // Test @@ -597,9 +621,9 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { func TestGetComponents_WithIdentity(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t) + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName("any-app"). WithEnvironment("prod"). WithDeploymentName(anyDeployName). diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index bdc32a06..13cb43f8 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -131,25 +131,28 @@ func (deploy *deployHandler) getHpaSummary(ctx context.Context, component v1.Rad } func getHpaMetrics(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { - currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) - - // find resource utilization target - var targetResourceUtil *int32 - targetResourceMetric := crdUtils.GetHpaMetric(hpa, resourceName) - if targetResourceMetric != nil { - targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization - } - return currentResourceUtil, targetResourceUtil + // currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) + return nil, nil + + // TODO: FIX + + // // find resource utilization target + // var targetResourceUtil *int32 + // targetResourceMetric := crdUtils.GetHpaMetric(hpa, resourceName) + // if targetResourceMetric != nil { + // targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization + // } + // return currentResourceUtil, targetResourceUtil } -func getHpaCurrentMetric(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { - for _, metric := range hpa.Status.CurrentMetrics { - if metric.Resource != nil && metric.Resource.Name == resourceName { - return metric.Resource.Current.AverageUtilization - } - } - return nil -} +// func getHpaCurrentMetric(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { +// for _, metric := range hpa.Status.CurrentMetrics { +// if metric.Resource != nil && metric.Resource.Name == resourceName { +// return metric.Resource.Current.AverageUtilization +// } +// } +// return nil +// } // GetComponentStateFromSpec Returns a component with the current state func GetComponentStateFromSpec( diff --git a/api/deployments/deployment_controller_test.go b/api/deployments/deployment_controller_test.go index 0129cceb..2e8db687 100644 --- a/api/deployments/deployment_controller_test.go +++ b/api/deployments/deployment_controller_test.go @@ -1,6 +1,7 @@ package deployments import ( + "context" "fmt" "net/http" "testing" @@ -8,6 +9,7 @@ import ( certfake "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/fake" "github.com/equinor/radix-operator/pkg/apis/kube" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" "github.com/stretchr/testify/require" "k8s.io/client-go/kubernetes" @@ -35,15 +37,15 @@ func createGetLogEndpoint(appName, podName string) string { return fmt.Sprintf("/api/v1/applications/%s/deployments/any/components/any/replicas/%s/logs", appName, podName) } -func setupTest(t *testing.T) (*commontest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, prometheusclient.Interface, secretsstorevclient.Interface, *certfake.Clientset) { - commonTestUtils, kubeclient, radixClient, prometheusClient, secretproviderclient, certClient := apiUtils.SetupTest(t) +func setupTest(t *testing.T) (*commontest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, kedav2.Interface, prometheusclient.Interface, secretsstorevclient.Interface, *certfake.Clientset) { + commonTestUtils, kubeclient, radixClient, kedaClient, prometheusClient, secretproviderclient, certClient := apiUtils.SetupTest(t) // controllerTestUtils is used for issuing HTTP request and processing responses - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixClient, secretproviderclient, certClient, NewDeploymentController()) - return commonTestUtils, &controllerTestUtils, kubeclient, radixClient, prometheusClient, secretproviderclient, certClient + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixClient, kedaClient, secretproviderclient, certClient, NewDeploymentController()) + return commonTestUtils, &controllerTestUtils, kubeclient, radixClient, kedaClient, prometheusClient, secretproviderclient, certClient } func TestGetPodLog_no_radixconfig(t *testing.T) { // Setup - _, controllerTestUtils, _, _, _, _, _ := setupTest(t) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) endpoint := createGetLogEndpoint(anyAppName, anyPodName) @@ -57,7 +59,7 @@ func TestGetPodLog_no_radixconfig(t *testing.T) { } func TestGetPodLog_No_Pod(t *testing.T) { - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) endpoint := createGetLogEndpoint(anyAppName, anyPodName) _, err := commonTestUtils.ApplyApplication(builders. @@ -78,45 +80,53 @@ func TestGetPodLog_No_Pod(t *testing.T) { func TestGetDeployments_Filter_FilterIsApplied(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) - - _, err := commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAppName("any-app-1"). - WithEnvironment("prod"). - WithImageTag("abcdef"). - WithCondition(v1.DeploymentInactive)) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) + + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAppName("any-app-1"). + WithEnvironment("prod"). + WithImageTag("abcdef"). + WithCondition(v1.DeploymentInactive)) require.NoError(t, err) // Ensure the second image is considered the latest version firstDeploymentActiveFrom := time.Now() secondDeploymentActiveFrom := time.Now().AddDate(0, 0, 1) - _, err = commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAppName("any-app-2"). - WithEnvironment("dev"). - WithImageTag("ghijklm"). - WithCreated(firstDeploymentActiveFrom). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(firstDeploymentActiveFrom). - WithActiveTo(secondDeploymentActiveFrom)) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAppName("any-app-2"). + WithEnvironment("dev"). + WithImageTag("ghijklm"). + WithCreated(firstDeploymentActiveFrom). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(firstDeploymentActiveFrom). + WithActiveTo(secondDeploymentActiveFrom)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAppName("any-app-2"). - WithEnvironment("dev"). - WithImageTag("nopqrst"). - WithCondition(v1.DeploymentActive). - WithActiveFrom(secondDeploymentActiveFrom)) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAppName("any-app-2"). + WithEnvironment("dev"). + WithImageTag("nopqrst"). + WithCondition(v1.DeploymentActive). + WithActiveFrom(secondDeploymentActiveFrom)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAppName("any-app-2"). - WithEnvironment("prod"). - WithImageTag("uvwxyza")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAppName("any-app-2"). + WithEnvironment("prod"). + WithImageTag("uvwxyza")) require.NoError(t, err) // Test @@ -165,7 +175,7 @@ func TestGetDeployments_Filter_FilterIsApplied(t *testing.T) { } func TestGetDeployments_NoApplicationRegistered(t *testing.T) { - _, controllerTestUtils, _, _, _, _, _ := setupTest(t) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) responseChannel := controllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/deployments", anyAppName)) response := <-responseChannel @@ -189,7 +199,7 @@ func TestGetDeployments_OneEnvironment_SortedWithFromTo(t *testing.T) { annotations := make(map[string]string) annotations[kube.RadixGitTagsAnnotation] = gitTags annotations[kube.RadixCommitAnnotation] = gitCommitHash - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) err := setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, []string{"dev"}, annotations) require.NoError(t, err) @@ -229,7 +239,7 @@ func TestGetDeployments_OneEnvironment_Latest(t *testing.T) { annotations := make(map[string]string) annotations[kube.RadixGitTagsAnnotation] = "some tags go here" annotations[kube.RadixCommitAnnotation] = "gfsjrgnsdkfgnlnfgdsMYCOMMIT" - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) err := setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, []string{"dev"}, annotations) require.NoError(t, err) @@ -259,7 +269,7 @@ func TestGetDeployments_TwoEnvironments_SortedWithFromTo(t *testing.T) { annotations := make(map[string]string) annotations[kube.RadixGitTagsAnnotation] = "some tags go here" annotations[kube.RadixCommitAnnotation] = "gfsjrgnsdkfgnlnfgdsMYCOMMIT" - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) err := setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, []string{"dev", "prod"}, annotations) require.NoError(t, err) @@ -297,7 +307,7 @@ func TestGetDeployments_TwoEnvironments_Latest(t *testing.T) { annotations := make(map[string]string) annotations[kube.RadixGitTagsAnnotation] = "some tags go here" annotations[kube.RadixCommitAnnotation] = "gfsjrgnsdkfgnlnfgdsMYCOMMIT" - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) err := setupGetDeploymentsTest(commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, []string{"dev", "prod"}, annotations) require.NoError(t, err) @@ -319,7 +329,7 @@ func TestGetDeployments_TwoEnvironments_Latest(t *testing.T) { } func TestGetDeployment_NoApplicationRegistered(t *testing.T) { - _, controllerTestUtils, _, _, _, _, _ := setupTest(t) + _, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) responseChannel := controllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/deployments/%s", anyAppName, anyDeployName)) response := <-responseChannel @@ -330,7 +340,7 @@ func TestGetDeployment_NoApplicationRegistered(t *testing.T) { func TestGetDeployment_TwoDeploymentsFirstDeployment_ReturnsDeploymentWithComponents(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest(t) + commonTestUtils, controllerTestUtils, _, _, _, _, _, _ := setupTest(t) anyAppName := "any-app" anyEnvironment := "dev" anyDeployment1Name := "abcdef" @@ -342,57 +352,61 @@ func TestGetDeployment_TwoDeploymentsFirstDeployment_ReturnsDeploymentWithCompon _, err := commonTestUtils.ApplyJob(builders.ARadixBuildDeployJob().WithAppName(anyAppName).WithJobName(jobName1).WithCommitID(commitID1)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. - NewDeploymentBuilder(). - WithRadixApplication( - builders.ARadixApplication(). - WithAppName(anyAppName)). - WithAppName(anyAppName). - WithLabel(kube.RadixJobNameLabel, jobName1). - WithDeploymentName(anyDeployment1Name). - WithCreated(appDeployment1Created). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(appDeployment1Created). - WithActiveTo(appDeployment2Created). - WithEnvironment(anyEnvironment). - WithImageTag(anyDeployment1Name). - WithJobComponents( - builders.NewDeployJobComponentBuilder().WithName("job1"), - builders.NewDeployJobComponentBuilder().WithName("job2"), - ). - WithComponents( - builders.NewDeployComponentBuilder(). - WithImage("radixdev.azurecr.io/some-image:imagetag"). - WithName("frontend"). - WithPort("http", 8080). - WithReplicas(commontest.IntPtr(1)), - builders.NewDeployComponentBuilder(). - WithImage("radixdev.azurecr.io/another-image:imagetag"). - WithName("backend"). - WithReplicas(commontest.IntPtr(1)))) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + NewDeploymentBuilder(). + WithRadixApplication( + builders.ARadixApplication(). + WithAppName(anyAppName)). + WithAppName(anyAppName). + WithLabel(kube.RadixJobNameLabel, jobName1). + WithDeploymentName(anyDeployment1Name). + WithCreated(appDeployment1Created). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(appDeployment1Created). + WithActiveTo(appDeployment2Created). + WithEnvironment(anyEnvironment). + WithImageTag(anyDeployment1Name). + WithJobComponents( + builders.NewDeployJobComponentBuilder().WithName("job1"), + builders.NewDeployJobComponentBuilder().WithName("job2"), + ). + WithComponents( + builders.NewDeployComponentBuilder(). + WithImage("radixdev.azurecr.io/some-image:imagetag"). + WithName("frontend"). + WithPort("http", 8080). + WithReplicas(commontest.IntPtr(1)), + builders.NewDeployComponentBuilder(). + WithImage("radixdev.azurecr.io/another-image:imagetag"). + WithName("backend"). + WithReplicas(commontest.IntPtr(1)))) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(builders. - NewDeploymentBuilder(). - WithRadixApplication( - builders.ARadixApplication(). - WithAppName(anyAppName)). - WithAppName(anyAppName). - WithLabel(kube.RadixJobNameLabel, jobName2). - WithDeploymentName(anyDeployment2Name). - WithCreated(appDeployment2Created). - WithCondition(v1.DeploymentActive). - WithActiveFrom(appDeployment2Created). - WithEnvironment(anyEnvironment). - WithImageTag(anyDeployment2Name). - WithJobComponents( - builders.NewDeployJobComponentBuilder().WithName("job1"), - ). - WithComponents( - builders.NewDeployComponentBuilder(). - WithImage("radixdev.azurecr.io/another-second-image:imagetag"). - WithName("backend"). - WithReplicas(commontest.IntPtr(1)))) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + NewDeploymentBuilder(). + WithRadixApplication( + builders.ARadixApplication(). + WithAppName(anyAppName)). + WithAppName(anyAppName). + WithLabel(kube.RadixJobNameLabel, jobName2). + WithDeploymentName(anyDeployment2Name). + WithCreated(appDeployment2Created). + WithCondition(v1.DeploymentActive). + WithActiveFrom(appDeployment2Created). + WithEnvironment(anyEnvironment). + WithImageTag(anyDeployment2Name). + WithJobComponents( + builders.NewDeployJobComponentBuilder().WithName("job1"), + ). + WithComponents( + builders.NewDeployComponentBuilder(). + WithImage("radixdev.azurecr.io/another-second-image:imagetag"). + WithName("backend"). + WithReplicas(commontest.IntPtr(1)))) require.NoError(t, err) // Test @@ -431,46 +445,52 @@ func setupGetDeploymentsTest(commonTestUtils *commontest.Utils, appName, deploym deploymentTwoCondition = v1.DeploymentActive } - _, err := commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAnnotations(annotations). - WithDeploymentName(deploymentOneImage). - WithAppName(appName). - WithEnvironment(environmentOne). - WithImageTag(deploymentOneImage). - WithCreated(deploymentOneCreated). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(deploymentOneCreated). - WithActiveTo(deploymentOneActiveTo)) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAnnotations(annotations). + WithDeploymentName(deploymentOneImage). + WithAppName(appName). + WithEnvironment(environmentOne). + WithImageTag(deploymentOneImage). + WithCreated(deploymentOneCreated). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(deploymentOneCreated). + WithActiveTo(deploymentOneActiveTo)) if err != nil { return err } - _, err = commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAnnotations(annotations). - WithDeploymentName(deploymentTwoImage). - WithAppName(appName). - WithEnvironment(environmentTwo). - WithImageTag(deploymentTwoImage). - WithCreated(deploymentTwoCreated). - WithCondition(deploymentTwoCondition). - WithActiveFrom(deploymentTwoCreated). - WithActiveTo(deploymentTwoActiveTo)) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAnnotations(annotations). + WithDeploymentName(deploymentTwoImage). + WithAppName(appName). + WithEnvironment(environmentTwo). + WithImageTag(deploymentTwoImage). + WithCreated(deploymentTwoCreated). + WithCondition(deploymentTwoCondition). + WithActiveFrom(deploymentTwoCreated). + WithActiveTo(deploymentTwoActiveTo)) if err != nil { return err } - _, err = commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithAnnotations(annotations). - WithDeploymentName(deploymentThreeImage). - WithAppName(appName). - WithEnvironment(environmentOne). - WithImageTag(deploymentThreeImage). - WithCreated(deploymentThreeCreated). - WithCondition(v1.DeploymentActive). - WithActiveFrom(deploymentThreeCreated)) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithAnnotations(annotations). + WithDeploymentName(deploymentThreeImage). + WithAppName(appName). + WithEnvironment(environmentOne). + WithImageTag(deploymentThreeImage). + WithCreated(deploymentThreeCreated). + WithCondition(v1.DeploymentActive). + WithActiveFrom(deploymentThreeCreated)) if err != nil { return err } diff --git a/api/environments/environment_controller_externaldns_automation_test.go b/api/environments/environment_controller_externaldns_automation_test.go index 5bf8d3a6..c64f5a1b 100644 --- a/api/environments/environment_controller_externaldns_automation_test.go +++ b/api/environments/environment_controller_externaldns_automation_test.go @@ -41,18 +41,20 @@ func (s *externalDnsAutomationTestSuite) SetupTest() { ctrl := gomock.NewController(s.T()) tlsValidator := tlsvalidationmock.NewMockValidator(ctrl) tlsValidator.EXPECT().ValidateX509Certificate(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes() - s.commonTestUtils, s.environmentTestUtils, _, _, _, _, _, s.certClient = setupTest(s.T(), []EnvironmentHandlerOptions{WithTLSValidator(tlsValidator)}) + s.commonTestUtils, s.environmentTestUtils, _, _, _, _, _, _, s.certClient = setupTest(s.T(), []EnvironmentHandlerOptions{WithTLSValidator(tlsValidator)}) s.appName, s.environmentName, s.fqdn = "any-app", "dev", "any.alias.com" componentName := "backend" - _, err := s.commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithAppName(s.appName). - WithEnvironment(s.environmentName). - WithComponents(operatorutils.NewDeployComponentBuilder().WithName(componentName).WithExternalDNS(radixv1.RadixDeployExternalDNS{FQDN: s.fqdn, UseCertificateAutomation: true})). - WithJobComponents(). - WithImageTag("master")) + _, err := s.commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithAppName(s.appName). + WithEnvironment(s.environmentName). + WithComponents(operatorutils.NewDeployComponentBuilder().WithName(componentName).WithExternalDNS(radixv1.RadixDeployExternalDNS{FQDN: s.fqdn, UseCertificateAutomation: true})). + WithJobComponents(). + WithImageTag("master")) require.NoError(s.T(), err) _, err = s.commonTestUtils.ApplyApplication(operatorutils. diff --git a/api/environments/environment_controller_externaldns_test.go b/api/environments/environment_controller_externaldns_test.go index c5071620..f540ef6e 100644 --- a/api/environments/environment_controller_externaldns_test.go +++ b/api/environments/environment_controller_externaldns_test.go @@ -78,17 +78,19 @@ func (s *externalDnsTestSuite) buildCertificate(certCN, issuerCN string, dnsName func (s *externalDnsTestSuite) SetupTest() { ctrl := gomock.NewController(s.T()) s.tlsValidator = tlsvalidationmock.NewMockValidator(ctrl) - s.commonTestUtils, s.environmentTestUtils, _, s.kubeClient, _, _, _, s.certClient = setupTest(s.T(), []EnvironmentHandlerOptions{WithTLSValidator(s.tlsValidator)}) + s.commonTestUtils, s.environmentTestUtils, _, s.kubeClient, _, _, _, _, s.certClient = setupTest(s.T(), []EnvironmentHandlerOptions{WithTLSValidator(s.tlsValidator)}) s.appName, s.environmentName, s.alias = "any-app", "dev", "cdn.myalias.com" componentName := "backend" - _, err := s.commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithAppName(s.appName). - WithEnvironment(s.environmentName). - WithComponents(operatorutils.NewDeployComponentBuilder().WithName(componentName).WithExternalDNS(v1.RadixDeployExternalDNS{FQDN: s.alias})). - WithImageTag("master")) + _, err := s.commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithAppName(s.appName). + WithEnvironment(s.environmentName). + WithComponents(operatorutils.NewDeployComponentBuilder().WithName(componentName).WithExternalDNS(v1.RadixDeployExternalDNS{FQDN: s.alias})). + WithImageTag("master")) require.NoError(s.T(), err) _, err = s.commonTestUtils.ApplyApplication(operatorutils. diff --git a/api/environments/environment_controller_secrets_test.go b/api/environments/environment_controller_secrets_test.go index 22fd04ad..a6bbc29b 100644 --- a/api/environments/environment_controller_secrets_test.go +++ b/api/environments/environment_controller_secrets_test.go @@ -780,7 +780,7 @@ func (s *secretHandlerTestSuite) assertSecrets(scenario *getSecretScenario, secr } func (s *secretHandlerTestSuite) prepareTestRun(scenario *getSecretScenario, appName, envName, deploymentName string) *controllertest.Utils { - _, environmentControllerTestUtils, _, kubeClient, radixClient, _, secretClient, _ := setupTest(s.T(), nil) + _, environmentControllerTestUtils, _, kubeClient, radixClient, _, _, secretClient, _ := setupTest(s.T(), nil) _, err := radixClient.RadixV1().RadixRegistrations().Create(context.Background(), &v1.RadixRegistration{ObjectMeta: metav1.ObjectMeta{Name: appName}}, metav1.CreateOptions{}) require.NoError(s.T(), err) appAppNamespace := operatorutils.GetAppNamespace(appName) diff --git a/api/environments/environment_controller_test.go b/api/environments/environment_controller_test.go index 2d1e36da..acfb2654 100644 --- a/api/environments/environment_controller_test.go +++ b/api/environments/environment_controller_test.go @@ -37,6 +37,8 @@ import ( radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" "github.com/golang/mock/gomock" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" prometheusclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" prometheusfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake" "github.com/stretchr/testify/assert" @@ -64,25 +66,26 @@ const ( subscriptionId = "12347718-c8f8-4995-bfbb-02655ff1f89c" ) -func setupTest(t *testing.T, envHandlerOpts []EnvironmentHandlerOptions) (*commontest.Utils, *controllertest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, prometheusclient.Interface, secretsstorevclient.Interface, *certclientfake.Clientset) { +func setupTest(t *testing.T, envHandlerOpts []EnvironmentHandlerOptions) (*commontest.Utils, *controllertest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, kedav2.Interface, prometheusclient.Interface, secretsstorevclient.Interface, *certclientfake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := fake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() prometheusclient := prometheusfake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) // secretControllerTestUtils is used for issuing HTTP request and processing responses - secretControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, secrets.NewSecretController(nil)) + secretControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, secrets.NewSecretController(nil)) // controllerTestUtils is used for issuing HTTP request and processing responses - environmentControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewEnvironmentController(NewEnvironmentHandlerFactory(envHandlerOpts...))) + environmentControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewEnvironmentController(NewEnvironmentHandlerFactory(envHandlerOpts...))) - return &commonTestUtils, &environmentControllerTestUtils, &secretControllerTestUtils, kubeclient, radixclient, prometheusclient, secretproviderclient, certClient + return &commonTestUtils, &environmentControllerTestUtils, &secretControllerTestUtils, kubeclient, radixclient, kedaClient, prometheusclient, secretproviderclient, certClient } func TestGetEnvironmentDeployments_SortedWithFromTo(t *testing.T) { @@ -95,7 +98,7 @@ func TestGetEnvironmentDeployments_SortedWithFromTo(t *testing.T) { deploymentThreeCreated, _ := time.Parse(layout, "2018-11-20T09:00:00.000Z") // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments", anyAppName, anyEnvironment)) @@ -129,7 +132,7 @@ func TestGetEnvironmentDeployments_Latest(t *testing.T) { deploymentThreeCreated, _ := time.Parse(layout, "2018-11-20T09:00:00.000Z") // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments?latest=true", anyAppName, anyEnvironment)) @@ -149,7 +152,7 @@ func TestGetEnvironmentSummary_ApplicationWithNoDeployments_EnvironmentPending(t envName1, envName2 := "dev", "master" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithRadixRegistration(operatorutils.ARadixRegistration()). @@ -173,16 +176,18 @@ func TestGetEnvironmentSummary_ApplicationWithNoDeployments_EnvironmentPending(t func TestGetEnvironmentSummary_ApplicationWithDeployment_EnvironmentConsistent(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) - _, err := commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithRadixApplication(operatorutils. - NewRadixApplicationBuilder(). - WithRadixRegistration(operatorutils.ARadixRegistration()). + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithRadixApplication(operatorutils. + NewRadixApplicationBuilder(). + WithRadixRegistration(operatorutils.ARadixRegistration()). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment, "master")). WithAppName(anyAppName). - WithEnvironment(anyEnvironment, "master")). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment)) + WithEnvironment(anyEnvironment)) require.NoError(t, err) re, err := radixClient.RadixV1().RadixEnvironments().Get(context.Background(), operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment), metav1.GetOptions{}) @@ -207,7 +212,7 @@ func TestGetEnvironmentSummary_RemoveEnvironmentFromConfig_OrphanedEnvironment(t anyOrphanedEnvironment := "feature-1" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -218,17 +223,21 @@ func TestGetEnvironmentSummary_RemoveEnvironmentFromConfig_OrphanedEnvironment(t WithEnvironment(envName1, envName2). WithEnvironment(anyOrphanedEnvironment, "feature")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(envName1). - WithImageTag("someimageindev")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(envName1). + WithImageTag("someimageindev")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyOrphanedEnvironment). - WithImageTag("someimageinfeature")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyOrphanedEnvironment). + WithImageTag("someimageinfeature")) require.NoError(t, err) // Remove feature environment from application config @@ -257,7 +266,7 @@ func TestGetEnvironmentSummary_OrphanedEnvironmentWithDash_OrphanedEnvironmentIs anyOrphanedEnvironment := "feature-1" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) rr, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -302,7 +311,7 @@ func TestDeleteEnvironment_OneOrphanedEnvironment_OnlyOrphanedCanBeDeleted(t *te anyOrphanedEnvironment := "feature-1" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithAppName(anyAppName). @@ -356,7 +365,7 @@ func TestGetEnvironment_NoExistingEnvironment_ReturnsAnError(t *testing.T) { anyNonExistingEnvironment := "non-existing-environment" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName). @@ -376,7 +385,7 @@ func TestGetEnvironment_NoExistingEnvironment_ReturnsAnError(t *testing.T) { func TestGetEnvironment_ExistingEnvironmentInConfig_ReturnsAPendingEnvironment(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName). @@ -398,41 +407,47 @@ func TestGetEnvironment_ExistingEnvironmentInConfig_ReturnsAPendingEnvironment(t } func setupGetDeploymentsTest(t *testing.T, commonTestUtils *commontest.Utils, appName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage string, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated time.Time, environment string) { - _, err := commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithDeploymentName(deploymentOneImage). - WithAppName(appName). - WithEnvironment(environment). - WithImageTag(deploymentOneImage). - WithCreated(deploymentOneCreated). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(deploymentOneCreated). - WithActiveTo(deploymentTwoCreated)) - require.NoError(t, err) - require.NoError(t, err) - - _, err = commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithDeploymentName(deploymentTwoImage). - WithAppName(appName). - WithEnvironment(environment). - WithImageTag(deploymentTwoImage). - WithCreated(deploymentTwoCreated). - WithCondition(v1.DeploymentInactive). - WithActiveFrom(deploymentTwoCreated). - WithActiveTo(deploymentThreeCreated)) - require.NoError(t, err) - require.NoError(t, err) - - _, err = commonTestUtils.ApplyDeployment(operatorutils. - ARadixDeployment(). - WithDeploymentName(deploymentThreeImage). - WithAppName(appName). - WithEnvironment(environment). - WithImageTag(deploymentThreeImage). - WithCreated(deploymentThreeCreated). - WithCondition(v1.DeploymentActive). - WithActiveFrom(deploymentThreeCreated)) + _, err := commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithDeploymentName(deploymentOneImage). + WithAppName(appName). + WithEnvironment(environment). + WithImageTag(deploymentOneImage). + WithCreated(deploymentOneCreated). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(deploymentOneCreated). + WithActiveTo(deploymentTwoCreated)) + require.NoError(t, err) + require.NoError(t, err) + + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithDeploymentName(deploymentTwoImage). + WithAppName(appName). + WithEnvironment(environment). + WithImageTag(deploymentTwoImage). + WithCreated(deploymentTwoCreated). + WithCondition(v1.DeploymentInactive). + WithActiveFrom(deploymentTwoCreated). + WithActiveTo(deploymentThreeCreated)) + require.NoError(t, err) + require.NoError(t, err) + + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + ARadixDeployment(). + WithDeploymentName(deploymentThreeImage). + WithAppName(appName). + WithEnvironment(environment). + WithImageTag(deploymentThreeImage). + WithCreated(deploymentThreeCreated). + WithCondition(v1.DeploymentActive). + WithActiveFrom(deploymentThreeCreated)) require.NoError(t, err) require.NoError(t, err) } @@ -442,7 +457,7 @@ func TestRestartComponent_ApplicationWithDeployment_EnvironmentConsistent(t *tes stoppedComponent, startedComponent := "stoppedComponent", "startedComponent" // Setup - commonTestUtils, environmentControllerTestUtils, _, client, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, client, radixclient, _, _, _, _ := setupTest(t, nil) rd, _ := createRadixDeploymentWithReplicas(commonTestUtils, anyAppName, anyEnvironment, []ComponentCreatorStruct{ {name: stoppedComponent, number: 0}, {name: startedComponent, number: 1}, @@ -499,7 +514,7 @@ func TestStartComponent_ApplicationWithDeployment_EnvironmentConsistent(t *testi stoppedComponent1, stoppedComponent2 := "stoppedComponent1", "stoppedComponent2" // Setup - commonTestUtils, environmentControllerTestUtils, _, client, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, client, radixclient, _, _, _, _ := setupTest(t, nil) rd, _ := createRadixDeploymentWithReplicas(commonTestUtils, anyAppName, anyEnvironment, []ComponentCreatorStruct{ {name: stoppedComponent1, number: 0}, {name: stoppedComponent2, number: 0}, @@ -547,7 +562,7 @@ func TestStopComponent_ApplicationWithDeployment_EnvironmentConsistent(t *testin runningComponent, stoppedComponent := "runningComp", "stoppedComponent" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _, _ := setupTest(t, nil) rd, _ := createRadixDeploymentWithReplicas(commonTestUtils, anyAppName, anyEnvironment, []ComponentCreatorStruct{ {name: runningComponent, number: 3}, {name: stoppedComponent, number: 0}, @@ -592,7 +607,7 @@ func TestRestartEnvrionment_ApplicationWithDeployment_EnvironmentConsistent(t *t zeroReplicas := 0 // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _, _ := setupTest(t, nil) // Test t.Run("Restart Environment", func(t *testing.T) { @@ -647,7 +662,7 @@ func TestStartEnvrionment_ApplicationWithDeployment_EnvironmentConsistent(t *tes zeroReplicas := 0 // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _, _ := setupTest(t, nil) // Test t.Run("Start Environment", func(t *testing.T) { @@ -702,7 +717,7 @@ func TestStopEnvrionment_ApplicationWithDeployment_EnvironmentConsistent(t *test zeroReplicas := 0 // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixclient, _, _, _, _ := setupTest(t, nil) // Test t.Run("Stop Environment", func(t *testing.T) { @@ -753,7 +768,7 @@ func TestStopEnvrionment_ApplicationWithDeployment_EnvironmentConsistent(t *test func TestCreateEnvironment(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName)) @@ -769,7 +784,7 @@ func Test_GetEnvironmentEvents_Controller(t *testing.T) { envName := "dev" // Setup - commonTestUtils, environmentControllerTestUtils, _, kubeClient, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, kubeClient, _, _, _, _, _ := setupTest(t, nil) createEvent := func(namespace, eventName string) { _, err := kubeClient.CoreV1().Events(namespace).CreateWithEventNamespace(&corev1.Event{ ObjectMeta: metav1.ObjectMeta{ @@ -823,8 +838,8 @@ func Test_GetEnvironmentEvents_Controller(t *testing.T) { func TestUpdateSecret_AccountSecretForComponentVolumeMount_UpdatedOk(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t, nil) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.ARadixDeployment(). + commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t, nil) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.ARadixDeployment(). WithAppName(anyAppName). WithEnvironment(anyEnvironment). WithRadixApplication(operatorutils.ARadixApplication(). @@ -864,8 +879,8 @@ func TestUpdateSecret_AccountSecretForComponentVolumeMount_UpdatedOk(t *testing. func TestUpdateSecret_AccountSecretForJobVolumeMount_UpdatedOk(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t, nil) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.ARadixDeployment(). + commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t, nil) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.ARadixDeployment(). WithAppName(anyAppName). WithEnvironment(anyEnvironment). WithRadixApplication(operatorutils.ARadixApplication(). @@ -904,8 +919,8 @@ func TestUpdateSecret_AccountSecretForJobVolumeMount_UpdatedOk(t *testing.T) { func TestUpdateSecret_OAuth2_UpdatedOk(t *testing.T) { // Setup envNs := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) - commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, promclient, secretProviderClient, certClient := setupTest(t, nil) - err := utils.ApplyDeploymentWithSync(client, radixclient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.NewDeploymentBuilder(). + commonTestUtils, environmentControllerTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t, nil) + err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorutils.NewDeploymentBuilder(). WithAppName(anyAppName). WithEnvironment(anyEnvironment). WithRadixApplication(operatorutils.ARadixApplication(). @@ -982,7 +997,7 @@ func TestGetSecretDeployments_SortedWithFromTo(t *testing.T) { deploymentThreeCreated, _ := time.Parse(layout, "2018-11-20T09:00:00.000Z") // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments", anyAppName, anyEnvironment)) @@ -1016,7 +1031,7 @@ func TestGetSecretDeployments_Latest(t *testing.T) { deploymentThreeCreated, _ := time.Parse(layout, "2018-11-20T09:00:00.000Z") // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) setupGetDeploymentsTest(t, commonTestUtils, anyAppName, deploymentOneImage, deploymentTwoImage, deploymentThreeImage, deploymentOneCreated, deploymentTwoCreated, deploymentThreeCreated, anyEnvironment) responseChannel := environmentControllerTestUtils.ExecuteRequest("GET", fmt.Sprintf("/api/v1/applications/%s/environments/%s/deployments?latest=true", anyAppName, anyEnvironment)) @@ -1036,7 +1051,7 @@ func TestGetEnvironmentSummary_ApplicationWithNoDeployments_SecretPending(t *tes envName1, envName2 := "dev", "master" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. NewRadixApplicationBuilder(). WithRadixRegistration(operatorutils.ARadixRegistration()). @@ -1063,7 +1078,7 @@ func TestGetEnvironmentSummary_RemoveSecretFromConfig_OrphanedSecret(t *testing. orphanedEnvironment := "feature-1" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1074,17 +1089,21 @@ func TestGetEnvironmentSummary_RemoveSecretFromConfig_OrphanedSecret(t *testing. WithEnvironment(envName1, envName2). WithEnvironment(orphanedEnvironment, "feature")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(envName1). - WithImageTag("someimageindev")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(envName1). + WithImageTag("someimageindev")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(orphanedEnvironment). - WithImageTag("someimageinfeature")) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(orphanedEnvironment). + WithImageTag("someimageinfeature")) require.NoError(t, err) // Remove feature environment from application config @@ -1113,7 +1132,7 @@ func TestGetEnvironmentSummary_OrphanedSecretWithDash_OrphanedSecretIsListedOk(t orphanedEnvironment := "feature-1" // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) rr, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1154,7 +1173,7 @@ func TestGetEnvironmentSummary_OrphanedSecretWithDash_OrphanedSecretIsListedOk(t func TestGetSecret_ExistingSecretInConfig_ReturnsAPendingSecret(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName). @@ -1176,7 +1195,7 @@ func TestGetSecret_ExistingSecretInConfig_ReturnsAPendingSecret(t *testing.T) { func TestCreateSecret(t *testing.T) { // Setup - commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyApplication(operatorutils. ARadixApplication(). WithAppName(anyAppName)) @@ -1189,11 +1208,11 @@ func TestCreateSecret(t *testing.T) { } func Test_GetEnvironmentEvents_Handler(t *testing.T) { - commonTestUtils, _, _, kubeclient, radixclient, _, secretproviderclient, certClient := setupTest(t, nil) + commonTestUtils, _, _, kubeclient, radixclient, kedaClient, _, secretproviderclient, certClient := setupTest(t, nil) ctrl := gomock.NewController(t) defer ctrl.Finish() eventHandler := eventMock.NewMockEventHandler(ctrl) - handler := initHandler(kubeclient, radixclient, secretproviderclient, certClient, WithEventHandler(eventHandler)) + handler := initHandler(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, WithEventHandler(eventHandler)) raBuilder := operatorutils.ARadixApplication().WithAppName(anyAppName).WithEnvironment(anyEnvironment, "master") _, err := commonTestUtils.ApplyApplication(raBuilder) @@ -1213,7 +1232,7 @@ func TestRestartAuxiliaryResource(t *testing.T) { auxType := "oauth" // Setup - commonTestUtils, environmentControllerTestUtils, _, kubeClient, _, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, kubeClient, _, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1223,15 +1242,17 @@ func TestRestartAuxiliaryResource(t *testing.T) { WithAppName(anyAppName). WithEnvironment(anyEnvironment, "master")) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithComponent(operatorutils. - NewDeployComponentBuilder(). - WithName(anyComponentName). - WithAuthentication(&v1.Authentication{OAuth2: &v1.OAuth2{}})). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithComponent(operatorutils. + NewDeployComponentBuilder(). + WithName(anyComponentName). + WithAuthentication(&v1.Authentication{OAuth2: &v1.OAuth2{}})). + WithActiveFrom(time.Now())) require.NoError(t, err) envNs := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) @@ -1259,7 +1280,7 @@ func Test_GetJobs(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1268,12 +1289,14 @@ func Test_GetJobs(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1334,7 +1357,7 @@ func Test_GetJobs_Status(t *testing.T) { // Setup ctrl := gomock.NewController(t) jobSchedulerFactoryMock := mock.NewMockHandlerFactoryInterface(ctrl) - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, []EnvironmentHandlerOptions{WithJobSchedulerHandlerFactory(jobSchedulerFactoryMock)}) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, []EnvironmentHandlerOptions{WithJobSchedulerHandlerFactory(jobSchedulerFactoryMock)}) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1343,12 +1366,14 @@ func Test_GetJobs_Status(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1429,7 +1454,7 @@ func Test_GetJobs_Status_StopIsTrue(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1438,12 +1463,14 @@ func Test_GetJobs_Status_StopIsTrue(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1513,7 +1540,7 @@ func Test_GetJob(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1522,12 +1549,14 @@ func Test_GetJob(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1612,7 +1641,7 @@ func Test_GetJob_AllProps(t *testing.T) { defaultBackoffLimit := numbers.Int32Ptr(3) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1621,19 +1650,21 @@ func Test_GetJob_AllProps(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithDeploymentName(anyDeployment). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils. - NewDeployJobComponentBuilder(). - WithName(anyJobName). - WithTimeLimitSeconds(numbers.Int64Ptr(123)). - WithNodeGpu("gpu1"). - WithNodeGpuCount("2"). - WithResource(map[string]string{"cpu": "50Mi", "memory": "250M"}, map[string]string{"cpu": "100Mi", "memory": "500M"})). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithDeploymentName(anyDeployment). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils. + NewDeployJobComponentBuilder(). + WithName(anyJobName). + WithTimeLimitSeconds(numbers.Int64Ptr(123)). + WithNodeGpu("gpu1"). + WithNodeGpuCount("2"). + WithResource(map[string]string{"cpu": "50Mi", "memory": "250M"}, map[string]string{"cpu": "100Mi", "memory": "500M"})). + WithActiveFrom(time.Now())) require.NoError(t, err) // HACK: Missing WithBackoffLimit in DeploymentBuild, so we''' have to update the RD manually @@ -1749,7 +1780,7 @@ func Test_GetJobPayload(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, kubeClient, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, kubeClient, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1758,14 +1789,16 @@ func Test_GetJobPayload(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils. - NewDeployJobComponentBuilder(). - WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils. + NewDeployJobComponentBuilder(). + WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1835,7 +1868,7 @@ func Test_GetBatch_JobList(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1844,12 +1877,14 @@ func Test_GetBatch_JobList(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1912,7 +1947,7 @@ func Test_GetBatch_JobList_StopFlag(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1921,12 +1956,14 @@ func Test_GetBatch_JobList_StopFlag(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -1987,7 +2024,7 @@ func Test_GetBatches_Status(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -1996,12 +2033,14 @@ func Test_GetBatches_Status(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -2206,7 +2245,7 @@ func Test_GetBatches_JobListShouldHaveJobWithStatusWaiting(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(anyAppName, anyEnvironment) // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -2215,12 +2254,14 @@ func Test_GetBatches_JobListShouldHaveJobWithStatusWaiting(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -2278,7 +2319,7 @@ func Test_StopJob(t *testing.T) { } // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -2287,12 +2328,14 @@ func Test_StopJob(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) jobSpecList := append( @@ -2382,7 +2425,7 @@ func Test_DeleteJob(t *testing.T) { } // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -2391,12 +2434,14 @@ func Test_DeleteJob(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -2500,7 +2545,7 @@ func Test_StopBatch(t *testing.T) { } // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -2509,12 +2554,14 @@ func Test_StopBatch(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -2604,7 +2651,7 @@ func Test_DeleteBatch(t *testing.T) { } // Setup - commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _ := setupTest(t, nil) + commonTestUtils, environmentControllerTestUtils, _, _, radixClient, _, _, _, _ := setupTest(t, nil) _, err := commonTestUtils.ApplyRegistration(operatorutils. NewRegistrationBuilder(). WithName(anyAppName)) @@ -2613,12 +2660,14 @@ func Test_DeleteBatch(t *testing.T) { NewRadixApplicationBuilder(). WithAppName(anyAppName)) require.NoError(t, err) - _, err = commonTestUtils.ApplyDeployment(operatorutils. - NewDeploymentBuilder(). - WithAppName(anyAppName). - WithEnvironment(anyEnvironment). - WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). - WithActiveFrom(time.Now())) + _, err = commonTestUtils.ApplyDeployment( + context.Background(), + operatorutils. + NewDeploymentBuilder(). + WithAppName(anyAppName). + WithEnvironment(anyEnvironment). + WithJobComponents(operatorutils.NewDeployJobComponentBuilder().WithName(anyJobName)). + WithActiveFrom(time.Now())) require.NoError(t, err) // Insert test data @@ -2696,10 +2745,11 @@ func Test_DeleteBatch(t *testing.T) { func initHandler(client kubernetes.Interface, radixclient radixclient.Interface, + kedaClient kedav2.Interface, secretproviderclient secretsstorevclient.Interface, certClient certclient.Interface, handlerConfig ...EnvironmentHandlerOptions) EnvironmentHandler { - accounts := models.NewAccounts(client, radixclient, secretproviderclient, nil, certClient, client, radixclient, secretproviderclient, nil, certClient, "", radixmodels.Impersonation{}) + accounts := models.NewAccounts(client, radixclient, kedaClient, secretproviderclient, nil, certClient, client, radixclient, kedaClient, secretproviderclient, nil, certClient, "", radixmodels.Impersonation{}) options := []EnvironmentHandlerOptions{WithAccounts(accounts)} options = append(options, handlerConfig...) return Init(options...) @@ -2723,6 +2773,7 @@ func createRadixDeploymentWithReplicas(tu *commontest.Utils, appName, envName st } rd, err := tu.ApplyDeployment( + context.Background(), operatorutils. ARadixDeployment(). WithComponents(comps...). diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 9d9d22ef..4e5aa43e 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -45,9 +45,9 @@ func WithAccounts(accounts models.Accounts) EnvironmentHandlerOptions { eh.deployHandler = deployments.Init(accounts) eh.eventHandler = events.Init(accounts.UserAccount.Client) eh.accounts = accounts - kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.SecretProviderClient) + kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.UserAccount.SecretProviderClient) eh.kubeUtil = kubeUtil - kubeUtilsForServiceAccount, _ := kube.New(accounts.ServiceAccount.Client, accounts.ServiceAccount.RadixClient, accounts.ServiceAccount.SecretProviderClient) + kubeUtilsForServiceAccount, _ := kube.New(accounts.ServiceAccount.Client, accounts.ServiceAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.ServiceAccount.SecretProviderClient) eh.kubeUtilForServiceAccount = kubeUtilsForServiceAccount eh.jobSchedulerHandlerFactory = jobscheduler.NewFactory(kubeUtil) } diff --git a/api/environmentvariables/env_vars_controller_test.go b/api/environmentvariables/env_vars_controller_test.go index a4bba51e..09464018 100644 --- a/api/environmentvariables/env_vars_controller_test.go +++ b/api/environmentvariables/env_vars_controller_test.go @@ -1,6 +1,7 @@ package environmentvariables import ( + "context" "fmt" "testing" @@ -12,8 +13,9 @@ import ( commontest "github.com/equinor/radix-operator/pkg/apis/test" builders "github.com/equinor/radix-operator/pkg/apis/utils" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" - "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" + radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" "github.com/golang/mock/gomock" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" prometheusclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" prometheusfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake" "github.com/stretchr/testify/assert" @@ -33,31 +35,32 @@ const ( ) func setupTestWithMockHandler(t *testing.T, mockCtrl *gomock.Controller) (*commontest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, prometheusclient.Interface, *MockEnvVarsHandler) { - kubeclient, radixclient, prometheusclient, commonTestUtils, _, secretproviderclient, certClient := setupTest(t) + kubeclient, radixclient, kedaClient, prometheusclient, commonTestUtils, _, secretproviderclient, certClient := setupTest(t) handler := NewMockEnvVarsHandler(mockCtrl) handlerFactory := NewMockenvVarsHandlerFactory(mockCtrl) handlerFactory.EXPECT().createHandler(gomock.Any()).Return(handler) controller := (&envVarsController{}).withHandlerFactory(handlerFactory) // controllerTestUtils is used for issuing HTTP request and processing responses - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, controller) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, controller) return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, prometheusclient, handler } -func setupTest(t *testing.T) (*kubefake.Clientset, *fake.Clientset, *prometheusfake.Clientset, commontest.Utils, *kube.Kube, *secretproviderfake.Clientset, *certclientfake.Clientset) { +func setupTest(t *testing.T) (*kubefake.Clientset, *radixfake.Clientset, *kedafake.Clientset, *prometheusfake.Clientset, commontest.Utils, *kube.Kube, *secretproviderfake.Clientset, *certclientfake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() - radixclient := fake.NewSimpleClientset() + radixclient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() prometheusclient := prometheusfake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) - return kubeclient, radixclient, prometheusclient, commonTestUtils, commonTestUtils.GetKubeUtil(), secretproviderclient, certClient + return kubeclient, radixclient, kedaClient, prometheusclient, commonTestUtils, commonTestUtils.GetKubeUtil(), secretproviderclient, certClient } func Test_GetComponentEnvVars(t *testing.T) { @@ -191,11 +194,13 @@ func setupDeployment(commonTestUtils *commontest.Utils, appName, environmentName if modifyComponentBuilder != nil { modifyComponentBuilder(componentBuilder) } - return commonTestUtils.ApplyDeployment(builders. - ARadixDeployment(). - WithDeploymentName("some-depl"). - WithAppName(appName). - WithEnvironment(environmentName). - WithComponent(componentBuilder). - WithImageTag("1234")) + return commonTestUtils.ApplyDeployment( + context.Background(), + builders. + ARadixDeployment(). + WithDeploymentName("some-depl"). + WithAppName(appName). + WithEnvironment(environmentName). + WithComponent(componentBuilder). + WithImageTag("1234")) } diff --git a/api/environmentvariables/env_vars_handler.go b/api/environmentvariables/env_vars_handler.go index 6d48c215..4f5b84d8 100644 --- a/api/environmentvariables/env_vars_handler.go +++ b/api/environmentvariables/env_vars_handler.go @@ -28,7 +28,7 @@ type EnvVarsHandlerOptions func(*envVarsHandler) // WithAccounts configures all EnvVarsHandler fields func WithAccounts(accounts models.Accounts) EnvVarsHandlerOptions { return func(eh *envVarsHandler) { - kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.SecretProviderClient) + kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.UserAccount.SecretProviderClient) eh.kubeUtil = kubeUtil eh.inClusterClient = accounts.ServiceAccount.Client eh.accounts = accounts @@ -56,7 +56,7 @@ func Init(opts ...EnvVarsHandlerOptions) EnvVarsHandler { // GetComponentEnvVars Get environment variables with metadata for the component func (eh *envVarsHandler) GetComponentEnvVars(ctx context.Context, appName string, envName string, componentName string) ([]envvarsmodels.EnvVar, error) { namespace := crdUtils.GetEnvironmentNamespace(appName, envName) - rd, err := eh.kubeUtil.GetActiveDeployment(namespace) + rd, err := eh.kubeUtil.GetActiveDeployment(ctx, namespace) if err != nil { return nil, err } @@ -64,11 +64,11 @@ func (eh *envVarsHandler) GetComponentEnvVars(ctx context.Context, appName strin if radixDeployComponent == nil { return nil, fmt.Errorf("RadixDeployComponent not found by name") } - envVarsConfigMap, _, envVarsMetadataMap, err := eh.kubeUtil.GetEnvVarsConfigMapAndMetadataMap(namespace, componentName) + envVarsConfigMap, _, envVarsMetadataMap, err := eh.kubeUtil.GetEnvVarsConfigMapAndMetadataMap(ctx, namespace, componentName) if err != nil { return nil, err } - envVars, err := deployment.GetEnvironmentVariables(eh.kubeUtil, appName, rd, radixDeployComponent) + envVars, err := deployment.GetEnvironmentVariables(ctx, eh.kubeUtil, appName, rd, radixDeployComponent) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func (eh *envVarsHandler) GetComponentEnvVars(ctx context.Context, appName strin continue } if _, ok := secretNamesMap[envVar.Name]; ok { - continue //skip secrets + continue // skip secrets } if envVarsConfigMap.Data == nil { continue @@ -122,7 +122,7 @@ func appendSecretRefsKeysToMap(namesMap map[string]interface{}, secretRefs v1.Ra // ChangeEnvVar Change environment variables func (eh *envVarsHandler) ChangeEnvVar(ctx context.Context, appName, envName, componentName string, envVarsParams []envvarsmodels.EnvVarParameter) error { namespace := crdUtils.GetEnvironmentNamespace(appName, envName) - currentEnvVarsConfigMap, envVarsMetadataConfigMap, envVarsMetadataMap, err := eh.kubeUtil.GetEnvVarsConfigMapAndMetadataMap(namespace, componentName) + currentEnvVarsConfigMap, envVarsMetadataConfigMap, envVarsMetadataMap, err := eh.kubeUtil.GetEnvVarsConfigMapAndMetadataMap(ctx, namespace, componentName) desiredEnvVarsConfigMap := currentEnvVarsConfigMap.DeepCopy() if err != nil { return err @@ -146,22 +146,22 @@ func (eh *envVarsHandler) ChangeEnvVar(ctx context.Context, appName, envName, co metadata, foundMetadata := envVarsMetadataMap[envVarParam.Name] if foundMetadata { if strings.EqualFold(metadata.RadixConfigValue, newEnvVarValue) { - delete(envVarsMetadataMap, envVarParam.Name) //delete metadata for equal value in radixconfig + delete(envVarsMetadataMap, envVarParam.Name) // delete metadata for equal value in radixconfig } continue } - if !strings.EqualFold(currentEnvVarValue, newEnvVarValue) { //create metadata for changed env-var + if !strings.EqualFold(currentEnvVarValue, newEnvVarValue) { // create metadata for changed env-var envVarsMetadataMap[envVarParam.Name] = kube.EnvVarMetadata{RadixConfigValue: currentEnvVarValue} } } if !hasChanges { return nil } - err = eh.kubeUtil.ApplyConfigMap(namespace, currentEnvVarsConfigMap, desiredEnvVarsConfigMap) + err = eh.kubeUtil.ApplyConfigMap(ctx, namespace, currentEnvVarsConfigMap, desiredEnvVarsConfigMap) if err != nil { return err } - return eh.kubeUtil.ApplyEnvVarsMetadataConfigMap(namespace, envVarsMetadataConfigMap, envVarsMetadataMap) + return eh.kubeUtil.ApplyEnvVarsMetadataConfigMap(ctx, namespace, envVarsMetadataConfigMap, envVarsMetadataMap) } func getComponent(rd *v1.RadixDeployment, componentName string) v1.RadixCommonDeployComponent { diff --git a/api/environmentvariables/env_vars_handler_test.go b/api/environmentvariables/env_vars_handler_test.go index f37b66d7..0bba9a14 100644 --- a/api/environmentvariables/env_vars_handler_test.go +++ b/api/environmentvariables/env_vars_handler_test.go @@ -16,7 +16,7 @@ func Test_GetEnvVars(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(appName, environmentName) t.Run("Get existing env vars", func(t *testing.T) { t.Parallel() - _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) + _, _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) envVarsMap := map[string]string{ "VAR1": "val1", @@ -33,10 +33,10 @@ func Test_GetEnvVars(t *testing.T) { accounts: models.Accounts{}, } - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsConfigMapName(componentName)) require.NoError(t, err) - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) require.NoError(t, err) envVars, err := handler.GetComponentEnvVars(context.Background(), appName, environmentName, componentName) @@ -55,7 +55,7 @@ func Test_ChangeGetEnvVars(t *testing.T) { namespace := operatorutils.GetEnvironmentNamespace(appName, environmentName) t.Run("Change existing env var", func(t *testing.T) { t.Parallel() - _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) + _, _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) envVarsMap := map[string]string{ "VAR1": "val1", @@ -72,10 +72,10 @@ func Test_ChangeGetEnvVars(t *testing.T) { accounts: models.Accounts{}, } - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsConfigMapName(componentName)) require.NoError(t, err) - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) require.NoError(t, err) params := []envvarsmodels.EnvVarParameter{ @@ -105,7 +105,7 @@ func Test_ChangeGetEnvVars(t *testing.T) { }) t.Run("Skipped changing not-existing env vars", func(t *testing.T) { t.Parallel() - _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) + _, _, _, _, commonTestUtils, kubeUtil, _, _ := setupTest(t) envVarsMap := map[string]string{ "VAR1": "val1", @@ -121,10 +121,10 @@ func Test_ChangeGetEnvVars(t *testing.T) { accounts: models.Accounts{}, } - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsConfigMapName(componentName)) require.NoError(t, err) - _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) + _, err = kubeUtil.GetConfigMap(context.Background(), namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) require.NoError(t, err) params := []envvarsmodels.EnvVarParameter{ diff --git a/api/jobs/job_controller_test.go b/api/jobs/job_controller_test.go index 9c2b2bb7..379abc52 100644 --- a/api/jobs/job_controller_test.go +++ b/api/jobs/job_controller_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/require" secretsstorevclient "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned" secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" @@ -41,25 +43,26 @@ const ( anyUser = "a_user@equinor.com" ) -func setupTest() (*commontest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, secretsstorevclient.Interface, *certclientfake.Clientset) { +func setupTest() (*commontest.Utils, *controllertest.Utils, kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretsstorevclient.Interface, *certclientfake.Clientset) { // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := fake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) // controllerTestUtils is used for issuing HTTP request and processing responses - controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewJobController()) + controllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewJobController()) - return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, secretproviderclient, certClient + return &commonTestUtils, &controllerTestUtils, kubeclient, radixclient, kedaClient, secretproviderclient, certClient } func TestGetApplicationJob(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, secretproviderclient, certClient := setupTest() + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, secretproviderclient, certClient := setupTest() _, err := commonTestUtils.ApplyRegistration(builders.ARadixRegistration(). WithName(anyAppName). @@ -73,7 +76,7 @@ func TestGetApplicationJob(t *testing.T) { TriggeredBy: anyUser, } - accounts := models.NewAccounts(client, radixclient, secretproviderclient, nil, certClient, client, radixclient, secretproviderclient, nil, certClient, "", radixmodels.Impersonation{}) + accounts := models.NewAccounts(client, radixclient, kedaClient, secretproviderclient, nil, certClient, client, radixclient, kedaClient, secretproviderclient, nil, certClient, "", radixmodels.Impersonation{}) handler := Init(accounts, deployments.Init(accounts)) anyPipeline, _ := pipeline.GetPipelineFromName(anyPipelineName) @@ -124,7 +127,7 @@ func TestGetApplicationJob_RadixJobSpecExists(t *testing.T) { anyJobName := "any-job" // Setup - commonTestUtils, controllerTestUtils, _, _, _, _ := setupTest() + commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest() job, _ := commonTestUtils.ApplyJob(builders.AStartedBuildDeployJob().WithAppName(anyAppName).WithJobName(anyJobName)) // Test @@ -142,7 +145,7 @@ func TestGetApplicationJob_RadixJobSpecExists(t *testing.T) { } func TestGetPipelineJobLogsError(t *testing.T) { - commonTestUtils, controllerTestUtils, _, _, _, _ := setupTest() + commonTestUtils, controllerTestUtils, _, _, _, _, _ := setupTest() t.Run("job doesn't exist", func(t *testing.T) { aJobName := "aJobName" diff --git a/api/jobs/job_handler_test.go b/api/jobs/job_handler_test.go index 647a1961..25045e95 100644 --- a/api/jobs/job_handler_test.go +++ b/api/jobs/job_handler_test.go @@ -17,6 +17,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/utils/slice" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" "github.com/golang/mock/gomock" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -32,6 +33,7 @@ type JobHandlerTestSuite struct { radixClient *radixfake.Clientset secretProviderClient *secretproviderfake.Clientset certClient *certclientfake.Clientset + kedaClient *kedafake.Clientset } type jobCreatedScenario struct { @@ -72,17 +74,18 @@ func (s *JobHandlerTestSuite) SetupTest() { } func (s *JobHandlerTestSuite) setupTest() { - s.kubeClient, s.radixClient, s.secretProviderClient, s.certClient = s.getUtils() - accounts := models.NewAccounts(s.kubeClient, s.radixClient, s.secretProviderClient, nil, s.certClient, s.kubeClient, s.radixClient, s.secretProviderClient, nil, s.certClient, "", radixmodels.Impersonation{}) + s.kubeClient, s.radixClient, s.kedaClient, s.secretProviderClient, s.certClient = s.getUtils() + accounts := models.NewAccounts(s.kubeClient, s.radixClient, s.kedaClient, s.secretProviderClient, nil, s.certClient, s.kubeClient, s.radixClient, s.kedaClient, s.secretProviderClient, nil, s.certClient, "", radixmodels.Impersonation{}) s.accounts = accounts } -func (s *JobHandlerTestSuite) getUtils() (*kubefake.Clientset, *radixfake.Clientset, *secretproviderfake.Clientset, *certclientfake.Clientset) { +func (s *JobHandlerTestSuite) getUtils() (*kubefake.Clientset, *radixfake.Clientset, *kedafake.Clientset, *secretproviderfake.Clientset, *certclientfake.Clientset) { kubeClient := kubefake.NewSimpleClientset() radixClient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() secretProviderClient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() - return kubeClient, radixClient, secretProviderClient, certClient + return kubeClient, radixClient, kedaClient, secretProviderClient, certClient } func (s *JobHandlerTestSuite) Test_GetApplicationJob() { diff --git a/api/models/horizontal_scaling_summary.go b/api/models/horizontal_scaling_summary.go index d2fa1c05..d72986df 100644 --- a/api/models/horizontal_scaling_summary.go +++ b/api/models/horizontal_scaling_summary.go @@ -4,7 +4,6 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" "github.com/equinor/radix-api/api/utils/predicate" "github.com/equinor/radix-common/utils/slice" - operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" ) @@ -36,22 +35,58 @@ func getHpaSummary(appName, componentName string, hpaList []autoscalingv2.Horizo } func getHpaMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { - currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) + // TODO: FIX - // find resource utilization target - var targetResourceUtil *int32 - targetResourceMetric := operatorutils.GetHpaMetric(hpa, resourceName) - if targetResourceMetric != nil { - targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization - } - return currentResourceUtil, targetResourceUtil + return nil, nil + // currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) + // + // // find resource utilization target + // var targetResourceUtil *int32 + // targetResourceMetric := operatorutils.GetHpaMetric(hpa, resourceName) + // if targetResourceMetric != nil { + // targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization + // } + // return currentResourceUtil, targetResourceUtil } -func getHpaCurrentMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { - for _, metric := range hpa.Status.CurrentMetrics { - if metric.Resource != nil && metric.Resource.Name == resourceName { - return metric.Resource.Current.AverageUtilization - } - } - return nil -} +// func getHpaCurrentMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { +// for _, metric := range hpa.Status.CurrentMetrics { +// if metric.Resource != nil && metric.Resource.Name == resourceName { +// return metric.Resource.Current.AverageUtilization +// } +// } +// return nil +// } + +// The original function +// func getHpaMetrics(cpuTarget *int32, memoryTarget *int32) []autoscalingv2.MetricSpec { +// var metrics []autoscalingv2.MetricSpec +// if cpuTarget != nil { +// metrics = []autoscalingv2.MetricSpec{ +// { +// Type: autoscalingv2.ResourceMetricSourceType, +// Resource: &autoscalingv2.ResourceMetricSource{ +// Name: corev1.ResourceCPU, +// Target: autoscalingv2.MetricTarget{ +// Type: autoscalingv2.UtilizationMetricType, +// AverageUtilization: cpuTarget, +// }, +// }, +// }, +// } +// } +// +// if memoryTarget != nil { +// metrics = append(metrics, autoscalingv2.MetricSpec{ +// Type: autoscalingv2.ResourceMetricSourceType, +// Resource: &autoscalingv2.ResourceMetricSource{ +// Name: corev1.ResourceMemory, +// Target: autoscalingv2.MetricTarget{ +// Type: autoscalingv2.UtilizationMetricType, +// AverageUtilization: memoryTarget, +// }, +// }, +// }) +// } +// return metrics +// } diff --git a/api/privateimagehubs/internal/secrets.go b/api/privateimagehubs/internal/secrets.go index f892455c..da930f53 100644 --- a/api/privateimagehubs/internal/secrets.go +++ b/api/privateimagehubs/internal/secrets.go @@ -1,6 +1,7 @@ package internal import ( + "context" "fmt" "github.com/equinor/radix-operator/pkg/apis/applicationconfig" @@ -12,9 +13,9 @@ import ( ) // UpdatePrivateImageHubsSecretsPassword update secret password -func UpdatePrivateImageHubsSecretsPassword(kubeUtil *kube.Kube, appName, server, password string) error { +func UpdatePrivateImageHubsSecretsPassword(ctx context.Context, kubeUtil *kube.Kube, appName, server, password string) error { namespace := operatorutils.GetAppNamespace(appName) - secret, _ := kubeUtil.GetSecret(namespace, defaults.PrivateImageHubSecretName) + secret, _ := kubeUtil.GetSecret(ctx, namespace, defaults.PrivateImageHubSecretName) if secret == nil { return fmt.Errorf("private image hub secret does not exist for app %s", appName) } @@ -31,16 +32,16 @@ func UpdatePrivateImageHubsSecretsPassword(kubeUtil *kube.Kube, appName, server, if err != nil { return err } - return applicationconfig.ApplyPrivateImageHubSecret(kubeUtil, namespace, appName, secretValue) + return applicationconfig.ApplyPrivateImageHubSecret(ctx, kubeUtil, namespace, appName, secretValue) } return fmt.Errorf("private image hub secret does not contain config for server %s", server) } // GetPendingPrivateImageHubSecrets returns a list of private image hubs where secret value is not set -func GetPendingPrivateImageHubSecrets(kubeUtil *kube.Kube, appName string) ([]string, error) { +func GetPendingPrivateImageHubSecrets(ctx context.Context, kubeUtil *kube.Kube, appName string) ([]string, error) { pendingSecrets := []string{} ns := operatorutils.GetAppNamespace(appName) - secret, err := kubeUtil.GetSecret(ns, defaults.PrivateImageHubSecretName) + secret, err := kubeUtil.GetSecret(ctx, ns, defaults.PrivateImageHubSecretName) if err != nil && !errors.IsNotFound(err) { return nil, err } diff --git a/api/privateimagehubs/privateimagehubs_controller.go b/api/privateimagehubs/privateimagehubs_controller.go index 61cb4d90..7b1d4bf4 100644 --- a/api/privateimagehubs/privateimagehubs_controller.go +++ b/api/privateimagehubs/privateimagehubs_controller.go @@ -138,7 +138,7 @@ func (dc *privateImageHubController) ChangePrivateImageHubSecret(accounts models } privateImageHubHandler := Init(accounts) - err := privateImageHubHandler.UpdatePrivateImageHubValue(appName, serverName, secretParameters.SecretValue) + err := privateImageHubHandler.UpdatePrivateImageHubValue(r.Context(), appName, serverName, secretParameters.SecretValue) if err != nil { dc.ErrorResponse(w, r, err) diff --git a/api/privateimagehubs/privateimagehubs_handler.go b/api/privateimagehubs/privateimagehubs_handler.go index 2ea25ae3..2107de06 100644 --- a/api/privateimagehubs/privateimagehubs_handler.go +++ b/api/privateimagehubs/privateimagehubs_handler.go @@ -19,7 +19,7 @@ type PrivateImageHubHandler struct { // Init Constructor func Init(accounts sharedModels.Accounts) PrivateImageHubHandler { - kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.SecretProviderClient) + kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.UserAccount.SecretProviderClient) return PrivateImageHubHandler{ userAccount: accounts.UserAccount, serviceAccount: accounts.ServiceAccount, @@ -34,7 +34,7 @@ func (ph PrivateImageHubHandler) GetPrivateImageHubs(ctx context.Context, appNam if err != nil { return []models.ImageHubSecret{}, nil } - pendingImageHubSecrets, err := internal.GetPendingPrivateImageHubSecrets(ph.kubeUtil, appName) + pendingImageHubSecrets, err := internal.GetPendingPrivateImageHubSecrets(ctx, ph.kubeUtil, appName) if err != nil { return nil, err } @@ -53,8 +53,8 @@ func (ph PrivateImageHubHandler) GetPrivateImageHubs(ctx context.Context, appNam } // UpdatePrivateImageHubValue updates the private image hub value with new password -func (ph PrivateImageHubHandler) UpdatePrivateImageHubValue(appName, server, password string) error { - return internal.UpdatePrivateImageHubsSecretsPassword(ph.kubeUtil, appName, server, password) +func (ph PrivateImageHubHandler) UpdatePrivateImageHubValue(ctx context.Context, appName, server, password string) error { + return internal.UpdatePrivateImageHubsSecretsPassword(ctx, ph.kubeUtil, appName, server, password) } func getImageHubSecretStatus(pendingImageHubSecrets []string, server string) models.ImageHubSecretStatus { diff --git a/api/privateimagehubs/privateimagehubs_handler_test.go b/api/privateimagehubs/privateimagehubs_handler_test.go index 882b4af3..4120997d 100644 --- a/api/privateimagehubs/privateimagehubs_handler_test.go +++ b/api/privateimagehubs/privateimagehubs_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/utils" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -29,7 +30,7 @@ const ( func Test_WithPrivateImageHubSet_SecretsCorrectly_NoImageHubs(t *testing.T) { client, _, kubeUtil, err := applyRadixAppWithPrivateImageHub(radixv1.PrivateImageHubEntries{}) require.NoError(t, err) - pendingSecrets, _ := internal.GetPendingPrivateImageHubSecrets(kubeUtil, "any-app") + pendingSecrets, _ := internal.GetPendingPrivateImageHubSecrets(context.Background(), kubeUtil, "any-app") secret, _ := client.CoreV1().Secrets("any-app-app").Get(context.TODO(), defaults.PrivateImageHubSecretName, metav1.GetOptions{}) @@ -38,7 +39,7 @@ func Test_WithPrivateImageHubSet_SecretsCorrectly_NoImageHubs(t *testing.T) { "{\"auths\":{}}", string(secret.Data[corev1.DockerConfigJsonKey])) assert.Equal(t, 0, len(pendingSecrets)) - assert.Error(t, internal.UpdatePrivateImageHubsSecretsPassword(kubeUtil, "any-app", "privaterepodeleteme.azurecr.io", "a-password")) + assert.Error(t, internal.UpdatePrivateImageHubsSecretsPassword(context.Background(), kubeUtil, "any-app", "privaterepodeleteme.azurecr.io", "a-password")) } func Test_WithPrivateImageHubSet_SecretsCorrectly_SetPassword(t *testing.T) { @@ -49,15 +50,15 @@ func Test_WithPrivateImageHubSet_SecretsCorrectly_SetPassword(t *testing.T) { }, }) require.NoError(t, err) - pendingSecrets, _ := internal.GetPendingPrivateImageHubSecrets(kubeUtil, "any-app") + pendingSecrets, _ := internal.GetPendingPrivateImageHubSecrets(context.Background(), kubeUtil, "any-app") assert.Equal(t, "privaterepodeleteme.azurecr.io", pendingSecrets[0]) - if err := internal.UpdatePrivateImageHubsSecretsPassword(kubeUtil, "any-app", "privaterepodeleteme.azurecr.io", "a-password"); err != nil { + if err := internal.UpdatePrivateImageHubsSecretsPassword(context.Background(), kubeUtil, "any-app", "privaterepodeleteme.azurecr.io", "a-password"); err != nil { require.NoError(t, err) } secret, _ := client.CoreV1().Secrets("any-app-app").Get(context.TODO(), defaults.PrivateImageHubSecretName, metav1.GetOptions{}) - pendingSecrets, _ = internal.GetPendingPrivateImageHubSecrets(kubeUtil, "any-app") + pendingSecrets, _ = internal.GetPendingPrivateImageHubSecrets(context.Background(), kubeUtil, "any-app") assert.Equal(t, "{\"auths\":{\"privaterepodeleteme.azurecr.io\":{\"username\":\"814607e6-3d71-44a7-8476-50e8b281abbc\",\"password\":\"a-password\",\"email\":\"radix@equinor.com\",\"auth\":\"ODE0NjA3ZTYtM2Q3MS00NGE3LTg0NzYtNTBlOGIyODFhYmJjOmEtcGFzc3dvcmQ=\"}}}", @@ -88,8 +89,9 @@ func setupTest() (*test.Utils, kubernetes.Interface, *kube.Kube, radixclient.Int kubeClient := kubefake.NewSimpleClientset() radixClient := radixfake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() - kubeUtil, _ := kube.New(kubeClient, radixClient, secretproviderclient) - handlerTestUtils := test.NewTestUtils(kubeClient, radixClient, secretproviderclient) + kedaClient := kedafake.NewSimpleClientset() + kubeUtil, _ := kube.New(kubeClient, radixClient, kedaClient, secretproviderclient) + handlerTestUtils := test.NewTestUtils(kubeClient, radixClient, kedaClient, secretproviderclient) if err := handlerTestUtils.CreateClusterPrerequisites(clusterName, "0.0.0.0", "anysubid"); err != nil { return nil, nil, nil, nil, err } @@ -111,7 +113,7 @@ func applyApplicationWithSync(tu *test.Utils, client kubernetes.Interface, kubeU applicationConfig := applicationconfig.NewApplicationConfig(client, kubeUtil, radixClient, radixRegistration, ra, nil) - err = applicationConfig.OnSync() + err = applicationConfig.OnSync(context.Background()) if err != nil { return err } diff --git a/api/secrets/secret_controller_test.go b/api/secrets/secret_controller_test.go index d2f46a1c..022cd8b6 100644 --- a/api/secrets/secret_controller_test.go +++ b/api/secrets/secret_controller_test.go @@ -19,6 +19,7 @@ import ( radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" "github.com/golang/mock/gomock" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" prometheusclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" prometheusfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake" "github.com/stretchr/testify/assert" @@ -47,16 +48,17 @@ func setupTest(t *testing.T, tlsValidator tlsvalidation.Validator) (*commontest. // Setup kubeclient := kubefake.NewSimpleClientset() radixclient := fake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() prometheusclient := prometheusfake.NewSimpleClientset() secretproviderclient := secretproviderfake.NewSimpleClientset() certClient := certclientfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, secretproviderclient) + commonTestUtils := commontest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) // secretControllerTestUtils is used for issuing HTTP request and processing responses - secretControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, secretproviderclient, certClient, NewSecretController(tlsValidator)) + secretControllerTestUtils := controllertest.NewTestUtils(kubeclient, radixclient, kedaClient, secretproviderclient, certClient, NewSecretController(tlsValidator)) return &commonTestUtils, &secretControllerTestUtils, kubeclient, radixclient, prometheusclient, secretproviderclient } @@ -271,6 +273,7 @@ func (s *externalDNSSecretTestSuite) SetupTest() { func (s *externalDNSSecretTestSuite) setupTestResources(appName, envName, componentName string, externalAliases []radixv1.RadixDeployExternalDNS, rdCondition radixv1.RadixDeployCondition) error { _, err := s.commonTestUtils.ApplyDeployment( + context.Background(), operatorutils.NewDeploymentBuilder(). WithRadixApplication( operatorutils.NewRadixApplicationBuilder(). diff --git a/api/test/utils.go b/api/test/utils.go index 79e7aeb5..beb80900 100644 --- a/api/test/utils.go +++ b/api/test/utils.go @@ -7,6 +7,8 @@ import ( "net/http" "net/http/httptest" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" "github.com/rs/zerolog/log" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" secretsstorevclient "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned" @@ -29,16 +31,18 @@ import ( type Utils struct { kubeClient *kubernetesfake.Clientset radixClient *radixclientfake.Clientset + kedaClient *kedafake.Clientset secretProviderClient *secretsstorevclientfake.Clientset certClient *certclientfake.Clientset controllers []models.Controller } // NewTestUtils Constructor -func NewTestUtils(kubeClient *kubernetesfake.Clientset, radixClient *radixclientfake.Clientset, secretProviderClient *secretsstorevclientfake.Clientset, certClient *certclientfake.Clientset, controllers ...models.Controller) Utils { +func NewTestUtils(kubeClient *kubernetesfake.Clientset, radixClient *radixclientfake.Clientset, kedaClient *kedafake.Clientset, secretProviderClient *secretsstorevclientfake.Clientset, certClient *certclientfake.Clientset, controllers ...models.Controller) Utils { return Utils{ kubeClient: kubeClient, radixClient: radixClient, + kedaClient: kedaClient, secretProviderClient: secretProviderClient, certClient: certClient, controllers: controllers, @@ -59,7 +63,7 @@ func (tu *Utils) ExecuteUnAuthorizedRequest(method, endpoint string) <-chan *htt go func() { rr := httptest.NewRecorder() defer close(response) - router.NewAPIHandler("anyClusterName", NewKubeUtilMock(tu.kubeClient, tu.radixClient, tu.secretProviderClient, tu.certClient), tu.controllers...).ServeHTTP(rr, req) + router.NewAPIHandler("anyClusterName", NewKubeUtilMock(tu.kubeClient, tu.radixClient, tu.kedaClient, tu.secretProviderClient, tu.certClient), tu.controllers...).ServeHTTP(rr, req) response <- rr }() @@ -83,7 +87,7 @@ func (tu *Utils) ExecuteRequestWithParameters(method, endpoint string, parameter go func() { rr := httptest.NewRecorder() defer close(response) - router.NewAPIHandler("anyClusterName", NewKubeUtilMock(tu.kubeClient, tu.radixClient, tu.secretProviderClient, tu.certClient), tu.controllers...).ServeHTTP(rr, req) + router.NewAPIHandler("anyClusterName", NewKubeUtilMock(tu.kubeClient, tu.radixClient, tu.kedaClient, tu.secretProviderClient, tu.certClient), tu.controllers...).ServeHTTP(rr, req) response <- rr }() @@ -110,7 +114,7 @@ func GetErrorResponse(response *httptest.ResponseRecorder) (*radixhttp.Error, er // GetResponseBody Gets response payload as type func GetResponseBody(response *httptest.ResponseRecorder, target interface{}) error { - reader := bytes.NewReader(response.Body.Bytes()) //To allow read from response body multiple times + reader := bytes.NewReader(response.Body.Bytes()) // To allow read from response body multiple times body, _ := io.ReadAll(reader) return json.Unmarshal(body, target) } @@ -120,6 +124,7 @@ type kubeUtilMock struct { radixClient *radixclientfake.Clientset secretProviderClient *secretsstorevclientfake.Clientset certClient *certclientfake.Clientset + kedaClient *kedafake.Clientset } func (ku *kubeUtilMock) IsUseOutClusterClient() bool { @@ -127,26 +132,27 @@ func (ku *kubeUtilMock) IsUseOutClusterClient() bool { } // NewKubeUtilMock Constructor -func NewKubeUtilMock(kubeClient *kubernetesfake.Clientset, radixClient *radixclientfake.Clientset, secretProviderClient *secretsstorevclientfake.Clientset, certClient *certclientfake.Clientset) utils.KubeUtil { +func NewKubeUtilMock(kubeClient *kubernetesfake.Clientset, radixClient *radixclientfake.Clientset, kedaClient *kedafake.Clientset, secretProviderClient *secretsstorevclientfake.Clientset, certClient *certclientfake.Clientset) utils.KubeUtil { return &kubeUtilMock{ kubeClient: kubeClient, radixClient: radixClient, + kedaClient: kedaClient, secretProviderClient: secretProviderClient, certClient: certClient, } } // GetOutClusterKubernetesClient Gets a kubefake client using the bearer token from the radix api client -func (ku *kubeUtilMock) GetOutClusterKubernetesClient(_ string, _ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { - return ku.kubeClient, ku.radixClient, ku.secretProviderClient, nil, ku.certClient +func (ku *kubeUtilMock) GetOutClusterKubernetesClient(_ string, _ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { + return ku.kubeClient, ku.radixClient, ku.kedaClient, ku.secretProviderClient, nil, ku.certClient } // GetOutClusterKubernetesClientWithImpersonation Gets a kubefake client -func (ku *kubeUtilMock) GetOutClusterKubernetesClientWithImpersonation(_ string, impersonation radixmodels.Impersonation, _ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { - return ku.kubeClient, ku.radixClient, ku.secretProviderClient, nil, ku.certClient +func (ku *kubeUtilMock) GetOutClusterKubernetesClientWithImpersonation(_ string, impersonation radixmodels.Impersonation, _ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { + return ku.kubeClient, ku.radixClient, ku.kedaClient, ku.secretProviderClient, nil, ku.certClient } // GetInClusterKubernetesClient Gets a kubefake client using the config of the running pod -func (ku *kubeUtilMock) GetInClusterKubernetesClient(_ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { - return ku.kubeClient, ku.radixClient, ku.secretProviderClient, nil, ku.certClient +func (ku *kubeUtilMock) GetInClusterKubernetesClient(_ ...utils.RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretsstorevclient.Interface, tektonclient.Interface, certclient.Interface) { + return ku.kubeClient, ku.radixClient, ku.kedaClient, ku.secretProviderClient, nil, ku.certClient } diff --git a/api/utils/kubernetes.go b/api/utils/kubernetes.go index e0d0df28..bb64e90b 100644 --- a/api/utils/kubernetes.go +++ b/api/utils/kubernetes.go @@ -8,6 +8,7 @@ import ( "github.com/equinor/radix-api/api/metrics" radixmodels "github.com/equinor/radix-common/models" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -35,9 +36,9 @@ func WithBurst(burst int) RestClientConfigOption { // KubeUtil Interface to be mocked in tests type KubeUtil interface { - GetOutClusterKubernetesClient(string, ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) - GetOutClusterKubernetesClientWithImpersonation(string, radixmodels.Impersonation, ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) - GetInClusterKubernetesClient(...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) + GetOutClusterKubernetesClient(string, ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) + GetOutClusterKubernetesClientWithImpersonation(string, radixmodels.Impersonation, ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) + GetInClusterKubernetesClient(...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) IsUseOutClusterClient() bool } @@ -65,12 +66,12 @@ func NewKubeUtil(useOutClusterClient bool) KubeUtil { } // GetOutClusterKubernetesClient Gets a kubernetes client using the bearer token from the radix api client -func (ku *kubeUtil) GetOutClusterKubernetesClient(token string, options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { +func (ku *kubeUtil) GetOutClusterKubernetesClient(token string, options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { return ku.GetOutClusterKubernetesClientWithImpersonation(token, radixmodels.Impersonation{}, options...) } // GetOutClusterKubernetesClientWithImpersonation Gets a kubernetes client using the bearer token from the radix api client -func (ku *kubeUtil) GetOutClusterKubernetesClientWithImpersonation(token string, impersonation radixmodels.Impersonation, options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { +func (ku *kubeUtil) GetOutClusterKubernetesClientWithImpersonation(token string, impersonation radixmodels.Impersonation, options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { if ku.useOutClusterClient { config := getOutClusterClientConfig(token, impersonation, options) return getKubernetesClientFromConfig(config) @@ -80,7 +81,7 @@ func (ku *kubeUtil) GetOutClusterKubernetesClientWithImpersonation(token string, } // GetInClusterKubernetesClient Gets a kubernetes client using the config of the running pod -func (ku *kubeUtil) GetInClusterKubernetesClient(options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { +func (ku *kubeUtil) GetInClusterKubernetesClient(options ...RestClientConfigOption) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { config := getInClusterClientConfig(options) return getKubernetesClientFromConfig(config) } @@ -135,7 +136,7 @@ func addCommonConfigs(config *restclient.Config, options []RestClientConfigOptio return config } -func getKubernetesClientFromConfig(config *restclient.Config) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { +func getKubernetesClientFromConfig(config *restclient.Config) (kubernetes.Interface, radixclient.Interface, kedav2.Interface, secretproviderclient.Interface, tektonclient.Interface, certclient.Interface) { client, err := kubernetes.NewForConfig(config) if err != nil { log.Fatal().Err(err).Msg("getClusterConfig k8s client") @@ -146,6 +147,11 @@ func getKubernetesClientFromConfig(config *restclient.Config) (kubernetes.Interf log.Fatal().Err(err).Msg("getClusterConfig radix client") } + kedaClient, err := kedav2.NewForConfig(config) + if err != nil { + log.Fatal().Err(err).Msg("getClusterConfig keda client") + } + secretProviderClient, err := secretproviderclient.NewForConfig(config) if err != nil { log.Fatal().Err(err).Msg("getClusterConfig secret provider client client") @@ -160,5 +166,5 @@ func getKubernetesClientFromConfig(config *restclient.Config) (kubernetes.Interf if err != nil { log.Fatal().Err(err).Msg("getClusterConfig Tekton client client") } - return client, radixClient, secretProviderClient, tektonClient, certClient + return client, radixClient, kedaClient, secretProviderClient, tektonClient, certClient } diff --git a/api/utils/radix_middleware.go b/api/utils/radix_middleware.go index a3813917..b8796d8b 100644 --- a/api/utils/radix_middleware.go +++ b/api/utils/radix_middleware.go @@ -78,17 +78,19 @@ func (handler *RadixMiddleware) handleAuthorization(w http.ResponseWriter, r *ht } restOptions := handler.getRestClientOptions() - inClusterClient, inClusterRadixClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient := handler.kubeUtil.GetInClusterKubernetesClient(restOptions...) - outClusterClient, outClusterRadixClient, outClusterSecretProviderClient, outClusterTektonClient, outClusterCertManagerClient := handler.kubeUtil.GetOutClusterKubernetesClientWithImpersonation(token, impersonation, restOptions...) + inClusterClient, inClusterRadixClient, inClusterKedaClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient := handler.kubeUtil.GetInClusterKubernetesClient(restOptions...) + outClusterClient, outClusterRadixClient, outClusterKedaClient, outClusterSecretProviderClient, outClusterTektonClient, outClusterCertManagerClient := handler.kubeUtil.GetOutClusterKubernetesClientWithImpersonation(token, impersonation, restOptions...) accounts := models.NewAccounts( inClusterClient, inClusterRadixClient, + inClusterKedaClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient, outClusterClient, outClusterRadixClient, + outClusterKedaClient, outClusterSecretProviderClient, outClusterTektonClient, outClusterCertManagerClient, @@ -125,9 +127,9 @@ func (handler *RadixMiddleware) getRestClientOptions() []RestClientConfigOption func (handler *RadixMiddleware) handleAnonymous(w http.ResponseWriter, r *http.Request) { restOptions := handler.getRestClientOptions() - inClusterClient, inClusterRadixClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient := handler.kubeUtil.GetInClusterKubernetesClient(restOptions...) + inClusterClient, inClusterRadixClient, inClusterKedaClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient := handler.kubeUtil.GetInClusterKubernetesClient(restOptions...) - sa := models.NewServiceAccount(inClusterClient, inClusterRadixClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient) + sa := models.NewServiceAccount(inClusterClient, inClusterRadixClient, inClusterKedaClient, inClusterSecretProviderClient, inClusterTektonClient, inClusterCertManagerClient) accounts := models.Accounts{ServiceAccount: sa} handler.next(accounts, w, r) diff --git a/api/utils/radixapplication.go b/api/utils/radixapplication.go index ec2dddc9..2eb13a1b 100644 --- a/api/utils/radixapplication.go +++ b/api/utils/radixapplication.go @@ -26,7 +26,7 @@ func CreateApplicationConfig(ctx context.Context, user *models.Account, appName return nil, err } - kubeUtils, _ := kube.New(user.Client, user.RadixClient, user.SecretProviderClient) + kubeUtils, _ := kube.New(user.Client, user.RadixClient, user.KedaClient, user.SecretProviderClient) return applicationconfig.NewApplicationConfig(user.Client, kubeUtils, user.RadixClient, registration, radixApp, &dnsalias.DNSConfig{}), nil } diff --git a/api/utils/test.go b/api/utils/test.go index e85dae21..33b00840 100644 --- a/api/utils/test.go +++ b/api/utils/test.go @@ -1,6 +1,7 @@ package utils import ( + "context" "testing" certfake "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/fake" @@ -15,6 +16,8 @@ import ( operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" prometheusclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" prometheusfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake" "github.com/stretchr/testify/require" @@ -30,42 +33,43 @@ const ( subscriptionId = "bd9f9eaa-2703-47c6-b5e0-faf4e058df73" ) -func SetupTest(t *testing.T) (*commontest.Utils, *kubefake.Clientset, *radixfake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { +func SetupTest(t *testing.T) (*commontest.Utils, *kubefake.Clientset, *radixfake.Clientset, *kedafake.Clientset, *prometheusfake.Clientset, *secretproviderfake.Clientset, *certfake.Clientset) { kubeClient := kubefake.NewSimpleClientset() radixClient := radixfake.NewSimpleClientset() + kedaClient := kedafake.NewSimpleClientset() prometheusClient := prometheusfake.NewSimpleClientset() secretProviderClient := secretproviderfake.NewSimpleClientset() certClient := certfake.NewSimpleClientset() // commonTestUtils is used for creating CRDs - commonTestUtils := commontest.NewTestUtils(kubeClient, radixClient, secretProviderClient) + commonTestUtils := commontest.NewTestUtils(kubeClient, radixClient, kedaClient, secretProviderClient) err := commonTestUtils.CreateClusterPrerequisites(clusterName, egressIps, subscriptionId) require.NoError(t, err) - return &commonTestUtils, kubeClient, radixClient, prometheusClient, secretProviderClient, certClient + return &commonTestUtils, kubeClient, radixClient, kedaClient, prometheusClient, secretProviderClient, certClient } // ApplyRegistrationWithSync syncs based on registration builder -func ApplyRegistrationWithSync(client kubernetes.Interface, radixclient radixclient.Interface, commonTestUtils *commontest.Utils, registrationBuilder operatorutils.RegistrationBuilder) error { - kubeUtils, _ := kube.New(client, radixclient, nil) +func ApplyRegistrationWithSync(client kubernetes.Interface, radixclient radixclient.Interface, kedaClient kedav2.Interface, commonTestUtils *commontest.Utils, registrationBuilder operatorutils.RegistrationBuilder) error { + kubeUtils, _ := kube.New(client, radixclient, kedaClient, nil) _, err := commonTestUtils.ApplyRegistration(registrationBuilder) if err != nil { return err } registration, _ := application.NewApplication(client, kubeUtils, radixclient, registrationBuilder.BuildRR()) - return registration.OnSync() + return registration.OnSync(context.Background()) } // ApplyApplicationWithSync syncs based on application builder, and default builder for registration. -func ApplyApplicationWithSync(client kubernetes.Interface, radixclient radixclient.Interface, commonTestUtils *commontest.Utils, applicationBuilder operatorutils.ApplicationBuilder) error { +func ApplyApplicationWithSync(client kubernetes.Interface, radixclient radixclient.Interface, kedaClient kedav2.Interface, commonTestUtils *commontest.Utils, applicationBuilder operatorutils.ApplicationBuilder) error { registrationBuilder := applicationBuilder.GetRegistrationBuilder() - err := ApplyRegistrationWithSync(client, radixclient, commonTestUtils, registrationBuilder) + err := ApplyRegistrationWithSync(client, radixclient, kedaClient, commonTestUtils, registrationBuilder) if err != nil { return err } - kubeUtils, _ := kube.New(client, radixclient, nil) + kubeUtils, _ := kube.New(client, radixclient, kedaClient, nil) _, err = commonTestUtils.ApplyApplication(applicationBuilder) if err != nil { panic(err) @@ -76,21 +80,21 @@ func ApplyApplicationWithSync(client kubernetes.Interface, radixclient radixclie } applicationConfig := applicationconfig.NewApplicationConfig(client, kubeUtils, radixclient, registrationBuilder.BuildRR(), applicationBuilder.BuildRA(), &dnsalias.DNSConfig{DNSZone: "dev.radix.equinor.com"}) - return applicationConfig.OnSync() + return applicationConfig.OnSync(context.Background()) } // ApplyDeploymentWithSync syncs based on deployment builder, and default builders for application and registration. -func ApplyDeploymentWithSync(client kubernetes.Interface, radixclient radixclient.Interface, prometheusClient prometheusclient.Interface, commonTestUtils *commontest.Utils, secretproviderclient secretsstorevclient.Interface, certClient *certfake.Clientset, deploymentBuilder operatorutils.DeploymentBuilder) error { +func ApplyDeploymentWithSync(client kubernetes.Interface, radixclient radixclient.Interface, kedaClient kedav2.Interface, prometheusClient prometheusclient.Interface, commonTestUtils *commontest.Utils, secretproviderclient secretsstorevclient.Interface, certClient *certfake.Clientset, deploymentBuilder operatorutils.DeploymentBuilder) error { applicationBuilder := deploymentBuilder.GetApplicationBuilder() registrationBuilder := applicationBuilder.GetRegistrationBuilder() - err := ApplyApplicationWithSync(client, radixclient, commonTestUtils, applicationBuilder) + err := ApplyApplicationWithSync(client, radixclient, kedaClient, commonTestUtils, applicationBuilder) if err != nil { return err } - kubeUtils, _ := kube.New(client, radixclient, secretproviderclient) - rd, _ := commonTestUtils.ApplyDeployment(deploymentBuilder) + kubeUtils, _ := kube.New(client, radixclient, kedaClient, secretproviderclient) + rd, _ := commonTestUtils.ApplyDeployment(context.Background(), deploymentBuilder) deploymentSyncer := deployment.NewDeploymentSyncer(client, kubeUtils, radixclient, prometheusClient, certClient, registrationBuilder.BuildRR(), rd, []ingress.AnnotationProvider{}, []deployment.AuxiliaryResourceManager{}, &config.Config{}) - return deploymentSyncer.OnSync() + return deploymentSyncer.OnSync(context.Background()) } diff --git a/go.mod b/go.mod index 3753abe9..2680f522 100644 --- a/go.mod +++ b/go.mod @@ -7,13 +7,14 @@ toolchain go1.22.1 require ( github.com/cert-manager/cert-manager v1.14.5 github.com/equinor/radix-common v1.9.2 - github.com/equinor/radix-job-scheduler v1.9.1 - github.com/equinor/radix-operator v1.52.1 + github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c + github.com/equinor/radix-operator v1.55.2 github.com/evanphx/json-patch/v5 v5.9.0 github.com/felixge/httpsnoop v1.0.4 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang/mock v1.6.0 github.com/gorilla/mux v1.8.1 + github.com/kedacore/keda/v2 v2.13.1 github.com/marstr/guid v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus-operator/prometheus-operator/pkg/client v0.74.0 @@ -30,7 +31,7 @@ require ( k8s.io/api v0.30.1 k8s.io/apimachinery v0.30.1 k8s.io/client-go v0.30.1 - knative.dev/pkg v0.0.0-20231219072704-d513e487961e + knative.dev/pkg v0.0.0-20240116073220-b488e7be5902 sigs.k8s.io/secrets-store-csi-driver v1.4.0 ) @@ -38,7 +39,7 @@ require ( contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect dario.cat/mergo v1.0.0 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect @@ -47,6 +48,7 @@ require ( github.com/elnormous/contenttype v1.0.4 // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect + github.com/expr-lang/expr v1.15.8 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect @@ -58,13 +60,13 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.18.1 // indirect + github.com/google/cel-go v0.18.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-containerregistry v0.16.1 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect @@ -74,19 +76,20 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.53.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -98,29 +101,29 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.21.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/api v0.154.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect + google.golang.org/api v0.156.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/grpc v1.60.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.29.5 // indirect + k8s.io/apiextensions-apiserver v0.30.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 // indirect k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect - sigs.k8s.io/controller-runtime v0.17.2 // indirect + sigs.k8s.io/controller-runtime v0.18.2 // indirect sigs.k8s.io/gateway-api v1.0.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index d0a20862..66b34b41 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -89,22 +89,24 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/equinor/radix-common v1.9.2 h1:pOYN/mSAoPe6KO/Nvudfd5DUETbLv4nLTLzFPr62ADw= github.com/equinor/radix-common v1.9.2/go.mod h1:ekn86U68NT4ccSdt3GT+ukpiclzfuhr96a7zBJKv/jw= -github.com/equinor/radix-job-scheduler v1.9.1 h1:B71xs8ucCG0yD6Zy2z7MVwaC0RknJOXe+EHEEfAN9AU= -github.com/equinor/radix-job-scheduler v1.9.1/go.mod h1:R2c3jrcKA7cLhHBY+3UDLZ6shEeA399JI19qMS/E4xg= -github.com/equinor/radix-operator v1.52.1 h1:mOLSkSCXtSGdgwJ/CfUZf3qxfW+yrbxHEbNd669JXk4= -github.com/equinor/radix-operator v1.52.1/go.mod h1:TNiQU+SSJGc+jrAS/s2117odswDYicwiJRdJceY7d5Q= +github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c h1:V55QleN4K0el34asLq9jN8zlLpI4oMksTJQoFYf6vSo= +github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c/go.mod h1:1z3jBg/X1UVoKrfmnaN2xIWfGAPYJ6lB1oSNEevrhVQ= +github.com/equinor/radix-operator v1.55.2 h1:VENKV3iK63ymHF5lO0UodePvULIywnHgh8sQ5/VEBmo= +github.com/equinor/radix-operator v1.55.2/go.mod h1:0KwN3ZEACZWhHrJZIuSxVYVeHhFgUBaRoeDyGiAljRs= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI= +github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -126,6 +128,8 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -136,11 +140,11 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= +github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= -github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= +github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= +github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -188,8 +192,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/cel-go v0.18.1 h1:V/lAXKq4C3BYLDy/ARzMtpkEEYfHQpZzVyzy69nEUjs= -github.com/google/cel-go v0.18.1/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4= +github.com/google/cel-go v0.18.2 h1:L0B6sNBSVmt0OyECi8v6VOS74KOc9W/tLiWKfZABvf4= +github.com/google/cel-go v0.18.2/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -220,8 +224,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -231,8 +235,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -259,6 +263,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kedacore/keda/v2 v2.13.1 h1:8y4Mp4iWyiqHoedVT3q2g5xvWDe494TRH3sUCZPpn/o= +github.com/kedacore/keda/v2 v2.13.1/go.mod h1:AZTRgxWpK5/6pq+DqJ15y3Bl/C8sl9C7tUVF4phzGDQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -286,8 +292,9 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -303,14 +310,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= -github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -335,16 +342,16 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= +github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -355,6 +362,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -414,7 +423,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -440,7 +448,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -453,8 +460,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= -golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -476,9 +483,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -510,12 +516,10 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -525,8 +529,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -539,7 +543,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -585,7 +588,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -602,7 +604,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -653,9 +654,8 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -679,16 +679,14 @@ google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.154.0 h1:X7QkVKZBskztmpPKWQXgjJRPA2dJYrL6r+sYPRLj050= -google.golang.org/api v0.154.0/go.mod h1:qhSMkM85hgqiokIYsrRyKxrjfBeIhgl4Z2JmeRkYylc= +google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ= +google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -720,12 +718,12 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -789,8 +787,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY= k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM= -k8s.io/apiextensions-apiserver v0.29.5 h1:njDywexhE6n+1NEl3A4axT0TMQHREnndrk3/ztdWcNE= -k8s.io/apiextensions-apiserver v0.29.5/go.mod h1:pfIvij+MH9a8NQKtW7MD4EFnzvUjJ1ZQsDL8wuP8fnc= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U= k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q= @@ -801,13 +799,13 @@ k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 h1:qVoMaQV5t62UUvHe16Q3eb k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/pkg v0.0.0-20231219072704-d513e487961e h1:br9VUyN8M4ZUaWsmKifLg5lIAy6JmNw2MdeHd6wgp9g= -knative.dev/pkg v0.0.0-20231219072704-d513e487961e/go.mod h1:YWJGsIxySXQehfkslagVEpJJwHgSScUc21+KpEgBXcY= +knative.dev/pkg v0.0.0-20240116073220-b488e7be5902 h1:H6+JJN23fhwYWCHY1339sY6uhIyoUwDy1a8dN233fdk= +knative.dev/pkg v0.0.0-20240116073220-b488e7be5902/go.mod h1:NYk8mMYoLkO7CQWnNkti4YGGnvLxN6MIDbUvtgeo0C0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= -sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= +sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q= +sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/models/account.go b/models/account.go index 5146a448..19c2550d 100644 --- a/models/account.go +++ b/models/account.go @@ -3,6 +3,7 @@ package models import ( certclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" "k8s.io/client-go/kubernetes" secretProviderClient "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned" @@ -15,4 +16,5 @@ type Account struct { SecretProviderClient secretProviderClient.Interface TektonClient tektonclient.Interface CertManagerClient certclient.Interface + KedaClient kedav2.Interface // TODO Initialize? } diff --git a/models/accounts.go b/models/accounts.go index fb1a0c29..60ceee10 100644 --- a/models/accounts.go +++ b/models/accounts.go @@ -3,6 +3,7 @@ package models import ( "fmt" + kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" certclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" @@ -15,14 +16,15 @@ import ( // NewAccounts creates a new Accounts struct func NewAccounts( - inClusterClient kubernetes.Interface, inClusterRadixClient radixclient.Interface, inClusterSecretProviderClient secretProviderClient.Interface, inClusterTektonClient tektonclient.Interface, inClusterCertManagerClient certclient.Interface, - outClusterClient kubernetes.Interface, outClusterRadixClient radixclient.Interface, outClusterSecretProviderClient secretProviderClient.Interface, outClusterTektonClient tektonclient.Interface, outClusterCertManagerClient certclient.Interface, + inClusterClient kubernetes.Interface, inClusterRadixClient radixclient.Interface, inClusterKedaClient kedav2.Interface, inClusterSecretProviderClient secretProviderClient.Interface, inClusterTektonClient tektonclient.Interface, inClusterCertManagerClient certclient.Interface, + outClusterClient kubernetes.Interface, outClusterRadixClient radixclient.Interface, outClusterKedaClient kedav2.Interface, outClusterSecretProviderClient secretProviderClient.Interface, outClusterTektonClient tektonclient.Interface, outClusterCertManagerClient certclient.Interface, token string, impersonation radixmodels.Impersonation) Accounts { return Accounts{ UserAccount: Account{ Client: outClusterClient, RadixClient: outClusterRadixClient, + KedaClient: outClusterKedaClient, SecretProviderClient: outClusterSecretProviderClient, TektonClient: outClusterTektonClient, CertManagerClient: outClusterCertManagerClient, @@ -30,6 +32,7 @@ func NewAccounts( ServiceAccount: Account{ Client: inClusterClient, RadixClient: inClusterRadixClient, + KedaClient: inClusterKedaClient, SecretProviderClient: inClusterSecretProviderClient, TektonClient: inClusterTektonClient, CertManagerClient: inClusterCertManagerClient, @@ -39,13 +42,14 @@ func NewAccounts( } } -func NewServiceAccount(inClusterClient kubernetes.Interface, inClusterRadixClient radixclient.Interface, inClusterSecretProviderClient secretProviderClient.Interface, inClusterTektonClient tektonclient.Interface, inClusterCertManagerClient certclient.Interface) Account { +func NewServiceAccount(inClusterClient kubernetes.Interface, inClusterRadixClient radixclient.Interface, inClusterKedaClient kedav2.Interface, inClusterSecretProviderClient secretProviderClient.Interface, inClusterTektonClient tektonclient.Interface, inClusterCertManagerClient certclient.Interface) Account { return Account{ Client: inClusterClient, RadixClient: inClusterRadixClient, SecretProviderClient: inClusterSecretProviderClient, TektonClient: inClusterTektonClient, CertManagerClient: inClusterCertManagerClient, + KedaClient: inClusterKedaClient, } } From de280c278d33f6fe31f446f92491ee8252d15209 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 31 May 2024 12:13:39 +0200 Subject: [PATCH 02/24] fix hpa metrics --- api/deployments/component_handler.go | 37 ++++++------- api/models/horizontal_scaling_summary.go | 69 ++++++------------------ api/utils/horizontalscaling/hpa.go | 15 ++++++ go.mod | 2 +- go.sum | 4 +- models/account.go | 2 +- 6 files changed, 53 insertions(+), 76 deletions(-) create mode 100644 api/utils/horizontalscaling/hpa.go diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index 13cb43f8..facb9049 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -9,6 +9,7 @@ import ( "github.com/equinor/radix-api/api/kubequery" "github.com/equinor/radix-api/api/utils" "github.com/equinor/radix-api/api/utils/event" + "github.com/equinor/radix-api/api/utils/horizontalscaling" "github.com/equinor/radix-api/api/utils/labelselector" radixutils "github.com/equinor/radix-common/utils" "github.com/equinor/radix-common/utils/slice" @@ -131,28 +132,24 @@ func (deploy *deployHandler) getHpaSummary(ctx context.Context, component v1.Rad } func getHpaMetrics(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { - // currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) - return nil, nil - - // TODO: FIX - - // // find resource utilization target - // var targetResourceUtil *int32 - // targetResourceMetric := crdUtils.GetHpaMetric(hpa, resourceName) - // if targetResourceMetric != nil { - // targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization - // } - // return currentResourceUtil, targetResourceUtil + currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) + // find resource utilization target + var targetResourceUtil *int32 + targetResourceMetric := horizontalscaling.GetHpaMetric(hpa, resourceName) + if targetResourceMetric != nil { + targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization + } + return currentResourceUtil, targetResourceUtil } -// func getHpaCurrentMetric(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { -// for _, metric := range hpa.Status.CurrentMetrics { -// if metric.Resource != nil && metric.Resource.Name == resourceName { -// return metric.Resource.Current.AverageUtilization -// } -// } -// return nil -// } +func getHpaCurrentMetric(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { + for _, metric := range hpa.Status.CurrentMetrics { + if metric.Resource != nil && metric.Resource.Name == resourceName { + return metric.Resource.Current.AverageUtilization + } + } + return nil +} // GetComponentStateFromSpec Returns a component with the current state func GetComponentStateFromSpec( diff --git a/api/models/horizontal_scaling_summary.go b/api/models/horizontal_scaling_summary.go index d72986df..d273e258 100644 --- a/api/models/horizontal_scaling_summary.go +++ b/api/models/horizontal_scaling_summary.go @@ -2,6 +2,7 @@ package models import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" + "github.com/equinor/radix-api/api/utils/horizontalscaling" "github.com/equinor/radix-api/api/utils/predicate" "github.com/equinor/radix-common/utils/slice" autoscalingv2 "k8s.io/api/autoscaling/v2" @@ -35,58 +36,22 @@ func getHpaSummary(appName, componentName string, hpaList []autoscalingv2.Horizo } func getHpaMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { - // TODO: FIX + currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) - return nil, nil - // currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) - // - // // find resource utilization target - // var targetResourceUtil *int32 - // targetResourceMetric := operatorutils.GetHpaMetric(hpa, resourceName) - // if targetResourceMetric != nil { - // targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization - // } - // return currentResourceUtil, targetResourceUtil + // find resource utilization target + var targetResourceUtil *int32 + targetResourceMetric := horizontalscaling.GetHpaMetric(hpa, resourceName) + if targetResourceMetric != nil { + targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization + } + return currentResourceUtil, targetResourceUtil } -// func getHpaCurrentMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { -// for _, metric := range hpa.Status.CurrentMetrics { -// if metric.Resource != nil && metric.Resource.Name == resourceName { -// return metric.Resource.Current.AverageUtilization -// } -// } -// return nil -// } - -// The original function -// func getHpaMetrics(cpuTarget *int32, memoryTarget *int32) []autoscalingv2.MetricSpec { -// var metrics []autoscalingv2.MetricSpec -// if cpuTarget != nil { -// metrics = []autoscalingv2.MetricSpec{ -// { -// Type: autoscalingv2.ResourceMetricSourceType, -// Resource: &autoscalingv2.ResourceMetricSource{ -// Name: corev1.ResourceCPU, -// Target: autoscalingv2.MetricTarget{ -// Type: autoscalingv2.UtilizationMetricType, -// AverageUtilization: cpuTarget, -// }, -// }, -// }, -// } -// } -// -// if memoryTarget != nil { -// metrics = append(metrics, autoscalingv2.MetricSpec{ -// Type: autoscalingv2.ResourceMetricSourceType, -// Resource: &autoscalingv2.ResourceMetricSource{ -// Name: corev1.ResourceMemory, -// Target: autoscalingv2.MetricTarget{ -// Type: autoscalingv2.UtilizationMetricType, -// AverageUtilization: memoryTarget, -// }, -// }, -// }) -// } -// return metrics -// } +func getHpaCurrentMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { + for _, metric := range hpa.Status.CurrentMetrics { + if metric.Resource != nil && metric.Resource.Name == resourceName { + return metric.Resource.Current.AverageUtilization + } + } + return nil +} diff --git a/api/utils/horizontalscaling/hpa.go b/api/utils/horizontalscaling/hpa.go new file mode 100644 index 00000000..59dd1dad --- /dev/null +++ b/api/utils/horizontalscaling/hpa.go @@ -0,0 +1,15 @@ +package horizontalscaling + +import ( + autoscalingv2 "k8s.io/api/autoscaling/v2" + corev1 "k8s.io/api/core/v1" +) + +func GetHpaMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *autoscalingv2.MetricSpec { + for _, metric := range hpa.Spec.Metrics { + if metric.Resource != nil && metric.Resource.Name == resourceName { + return &metric + } + } + return nil +} diff --git a/go.mod b/go.mod index 2680f522..934f098e 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.1 require ( github.com/cert-manager/cert-manager v1.14.5 github.com/equinor/radix-common v1.9.2 - github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c + github.com/equinor/radix-job-scheduler v1.9.2 github.com/equinor/radix-operator v1.55.2 github.com/evanphx/json-patch/v5 v5.9.0 github.com/felixge/httpsnoop v1.0.4 diff --git a/go.sum b/go.sum index 66b34b41..86ce94f6 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/equinor/radix-common v1.9.2 h1:pOYN/mSAoPe6KO/Nvudfd5DUETbLv4nLTLzFPr62ADw= github.com/equinor/radix-common v1.9.2/go.mod h1:ekn86U68NT4ccSdt3GT+ukpiclzfuhr96a7zBJKv/jw= -github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c h1:V55QleN4K0el34asLq9jN8zlLpI4oMksTJQoFYf6vSo= -github.com/equinor/radix-job-scheduler v1.9.2-0.20240531081248-0981ca89653c/go.mod h1:1z3jBg/X1UVoKrfmnaN2xIWfGAPYJ6lB1oSNEevrhVQ= +github.com/equinor/radix-job-scheduler v1.9.2 h1:p2wZGNmarDZhvaQhGk0F9ioZA8baRUGlYwxuHNwNURQ= +github.com/equinor/radix-job-scheduler v1.9.2/go.mod h1:1z3jBg/X1UVoKrfmnaN2xIWfGAPYJ6lB1oSNEevrhVQ= github.com/equinor/radix-operator v1.55.2 h1:VENKV3iK63ymHF5lO0UodePvULIywnHgh8sQ5/VEBmo= github.com/equinor/radix-operator v1.55.2/go.mod h1:0KwN3ZEACZWhHrJZIuSxVYVeHhFgUBaRoeDyGiAljRs= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= diff --git a/models/account.go b/models/account.go index 19c2550d..6f293604 100644 --- a/models/account.go +++ b/models/account.go @@ -16,5 +16,5 @@ type Account struct { SecretProviderClient secretProviderClient.Interface TektonClient tektonclient.Interface CertManagerClient certclient.Interface - KedaClient kedav2.Interface // TODO Initialize? + KedaClient kedav2.Interface } From 658069125fe8f64fb33755fb7726b5797c0f251f Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 31 May 2024 13:12:16 +0200 Subject: [PATCH 03/24] log request errors as warnings --- models/controller.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/models/controller.go b/models/controller.go index 3d2251f4..52b7b0af 100644 --- a/models/controller.go +++ b/models/controller.go @@ -1,6 +1,8 @@ package models import ( + "context" + "errors" "io" "net/http" @@ -22,12 +24,25 @@ type DefaultController struct { // ErrorResponse Marshals error for user requester func (c *DefaultController) ErrorResponse(w http.ResponseWriter, r *http.Request, err error) { + + logError(r.Context(), err) err = radixhttp.ErrorResponse(w, r, err) if err != nil { - log.Ctx(r.Context()).Err(err).Msg("failed to write response") + log.Ctx(r.Context()).Error().Err(err).Msg("failed to write response") } } +func logError(ctx context.Context, err error) { + event := log.Ctx(ctx).Warn().Err(err) + + var httpErr *radixhttp.Error + if errors.As(err, &httpErr) { + event.Str("user_message", httpErr.Message) + } + + event.Msg("controller error") +} + // JSONResponse Marshals response with header func (c *DefaultController) JSONResponse(w http.ResponseWriter, r *http.Request, result interface{}) { err := radixhttp.JSONResponse(w, r, result) From 9f1290741f04d0bf83a42a2cc9673afa88a48e91 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 31 May 2024 15:04:07 +0200 Subject: [PATCH 04/24] insert HPA for controller test --- api/deployments/component_controller_test.go | 91 ++++++++++++++------ 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index bcfc2648..b101540d 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -6,19 +6,20 @@ import ( "strings" "testing" - "github.com/equinor/radix-operator/pkg/apis/utils/numbers" - "github.com/stretchr/testify/require" - deploymentModels "github.com/equinor/radix-api/api/deployments/models" "github.com/equinor/radix-api/api/secrets/suffix" controllertest "github.com/equinor/radix-api/api/test" "github.com/equinor/radix-api/api/utils" + "github.com/equinor/radix-api/api/utils/labelselector" radixhttp "github.com/equinor/radix-common/net/http" radixutils "github.com/equinor/radix-common/utils" "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/equinor/radix-operator/pkg/apis/utils/numbers" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -558,32 +559,23 @@ func TestGetComponents_ReplicaStatus_Pending(t *testing.T) { func TestGetComponents_WithHorizontalScaling(t *testing.T) { // Setup - commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) testScenarios := []struct { - name string - deploymentName string - minReplicas int32 - maxReplicas int32 - targetCpu *int32 - targetMemory *int32 - expectedTargetCpu *int32 + name string + deploymentName string + minReplicas int32 + maxReplicas int32 + targetCpu *int32 + targetMemory *int32 }{ - {"targetCpu and targetMemory are nil", "dep1", 2, 6, nil, nil, numbers.Int32Ptr(defaultTargetCPUUtilization)}, - {"targetCpu is nil, targetMemory is non-nil", "dep2", 2, 6, nil, numbers.Int32Ptr(75), nil}, - {"targetCpu is non-nil, targetMemory is nil", "dep3", 2, 6, numbers.Int32Ptr(60), nil, numbers.Int32Ptr(60)}, - {"targetCpu and targetMemory are non-nil", "dep4", 2, 6, numbers.Int32Ptr(62), numbers.Int32Ptr(79), numbers.Int32Ptr(62)}, + {"targetCpu and targetMemory are nil", "dep1", 2, 6, nil, nil}, + {"targetCpu is nil, targetMemory is non-nil", "dep2", 2, 6, nil, numbers.Int32Ptr(75)}, + {"targetCpu is non-nil, targetMemory is nil", "dep3", 2, 6, numbers.Int32Ptr(60), nil}, + {"targetCpu and targetMemory are non-nil", "dep4", 2, 6, numbers.Int32Ptr(62), numbers.Int32Ptr(79)}, } for _, scenario := range testScenarios { t.Run(scenario.name, func(t *testing.T) { - horizontalScaling := operatorUtils.NewHorizontalScalingBuilder().WithMinReplicas(scenario.minReplicas).WithMaxReplicas(scenario.maxReplicas) - if scenario.targetCpu != nil { - horizontalScaling.WithCPUTrigger(int(*scenario.targetCpu)) - } - if scenario.targetMemory != nil { - horizontalScaling.WithMemoryTrigger(int(*scenario.targetMemory)) - } - + commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) err := utils.ApplyDeploymentWithSync(client, radixclient, kedaClient, promclient, commonTestUtils, secretProviderClient, certClient, operatorUtils.ARadixDeployment(). WithAppName(anyAppName). WithEnvironment("prod"). @@ -593,8 +585,12 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { operatorUtils.NewDeployComponentBuilder(). WithName("frontend"). WithPort("http", 8080). - WithPublicPort("http"). - WithHorizontalScaling(horizontalScaling.Build()))) + WithPublicPort("http"))) + require.NoError(t, err) + + ns := operatorUtils.GetEnvironmentNamespace(anyAppName, "prod") + autoscaler := createAutoscaler("frontend", numbers.Int32Ptr(scenario.minReplicas), scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory) + _, err = client.AutoscalingV2().HorizontalPodAutoscalers(ns).Create(context.Background(), &autoscaler, metav1.CreateOptions{}) require.NoError(t, err) // Test @@ -607,18 +603,59 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { var components []deploymentModels.Component err = controllertest.GetResponseBody(response, &components) require.NoError(t, err) + require.NotNil(t, components[0].HorizontalScalingSummary) - assert.NotNil(t, components[0].HorizontalScalingSummary) assert.Equal(t, scenario.minReplicas, components[0].HorizontalScalingSummary.MinReplicas) assert.Equal(t, scenario.maxReplicas, components[0].HorizontalScalingSummary.MaxReplicas) assert.True(t, nil == components[0].HorizontalScalingSummary.CurrentCPUUtilizationPercentage) // using assert.Equal() fails because simple nil and *int32 typed nil do not pass equality test - assert.Equal(t, scenario.expectedTargetCpu, components[0].HorizontalScalingSummary.TargetCPUUtilizationPercentage) + assert.Equal(t, scenario.targetCpu, components[0].HorizontalScalingSummary.TargetCPUUtilizationPercentage) assert.True(t, nil == components[0].HorizontalScalingSummary.CurrentMemoryUtilizationPercentage) assert.Equal(t, scenario.targetMemory, components[0].HorizontalScalingSummary.TargetMemoryUtilizationPercentage) }) } } +func createAutoscaler(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32) v2.HorizontalPodAutoscaler { + var metrics []v2.MetricSpec + + if targetCpu != nil { + metrics = append(metrics, v2.MetricSpec{ + Resource: &v2.ResourceMetricSource{ + Name: "cpu", + Target: v2.MetricTarget{ + Type: "cpu", + AverageUtilization: targetCpu, + }, + }, + }) + } + + if targetMemory != nil { + metrics = append(metrics, v2.MetricSpec{ + Resource: &v2.ResourceMetricSource{ + Name: "memory", + Target: v2.MetricTarget{ + Type: "memory", + AverageUtilization: targetMemory, + }, + }, + }) + } + + autoscaler := v2.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labelselector.ForComponent(anyAppName, "frontend"), + }, + Spec: v2.HorizontalPodAutoscalerSpec{ + MinReplicas: minReplicas, + MaxReplicas: maxReplicas, + Metrics: metrics, + }, + } + return autoscaler +} + func TestGetComponents_WithIdentity(t *testing.T) { // Setup commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) From 2a82aacbd8bbe3e0c8f4c171052c39209206ccf0 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 31 May 2024 15:08:22 +0200 Subject: [PATCH 05/24] remove unused constant --- api/deployments/component_handler.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index facb9049..3c5a0594 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -26,10 +26,6 @@ import ( "k8s.io/client-go/kubernetes" ) -const ( - defaultTargetCPUUtilization = int32(80) -) - // GetComponentsForDeployment Gets a list of components for a given deployment func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, appName string, deployment *deploymentModels.DeploymentSummary) ([]*deploymentModels.Component, error) { envNs := crdUtils.GetEnvironmentNamespace(appName, deployment.Environment) From c4008cec29c9010b0be9862f44082a23b86d9e1b Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 7 Jun 2024 11:21:58 +0200 Subject: [PATCH 06/24] add client request logging --- api/utils/kubernetes.go | 8 +++++ api/utils/logs/roundtrip_logger.go | 56 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 api/utils/logs/roundtrip_logger.go diff --git a/api/utils/kubernetes.go b/api/utils/kubernetes.go index bb64e90b..395d3d79 100644 --- a/api/utils/kubernetes.go +++ b/api/utils/kubernetes.go @@ -6,12 +6,14 @@ import ( certclient "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned" "github.com/equinor/radix-api/api/metrics" + "github.com/equinor/radix-api/api/utils/logs" radixmodels "github.com/equinor/radix-common/models" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" kedav2 "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" "k8s.io/client-go/kubernetes" @@ -108,6 +110,9 @@ func getOutClusterClientConfig(token string, impersonation radixmodels.Impersona kubeConfig.Impersonate = impersonationConfig } + kubeConfig.Wrap(logs.Logger(func(e *zerolog.Event) { + e.Str("client", "out-cluster").Bool("impersonated", impersonation.PerformImpersonation()) + })) return addCommonConfigs(kubeConfig, options) } @@ -121,6 +126,9 @@ func getInClusterClientConfig(options []RestClientConfigOption) *restclient.Conf log.Fatal().Err(err).Msg("getClusterConfig InClusterConfig") } } + config.Wrap(logs.Logger(func(e *zerolog.Event) { + e.Str("client", "in-cluster") + })) return addCommonConfigs(config, options) } diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go new file mode 100644 index 00000000..e74c658b --- /dev/null +++ b/api/utils/logs/roundtrip_logger.go @@ -0,0 +1,56 @@ +package logs + +import ( + "net/http" + "time" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +// RoundTripperFunc implements http.RoundTripper for convenient usage. +type RoundTripperFunc func(*http.Request) (*http.Response, error) + +// RoundTrip satisfies http.RoundTripper and calls fn. +func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return fn(req) +} + +type WithFunc func(e *zerolog.Event) + +func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { + return func(t http.RoundTripper) http.RoundTripper { + return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + start := time.Now() + logger := log.Ctx(r.Context()) + + resp, err := t.RoundTrip(r) + + var ev *zerolog.Event + switch { + case err != nil: + logger.Error().Err(err) + case resp.StatusCode >= 400 && resp.StatusCode <= 499: + ev = logger.Warn() + case resp.StatusCode >= 500: + ev = logger.Error() + default: + ev = logger.Trace() + } + + if !ev.Enabled() { + return resp, err + } + + for _, fn := range fns { + ev.Func(fn) + } + ev. + Str("method", r.Method). + Stringer("path", r.URL). + Int64("ellapsed_ms", time.Since(start).Milliseconds()). + Msg(http.StatusText(resp.StatusCode)) + return resp, err + }) + } +} From c037a942de4d9aadc1e000d4a35149ba3351b952 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 7 Jun 2024 11:25:15 +0200 Subject: [PATCH 07/24] add client request logging (simplified) --- api/environments/utils.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/environments/utils.go b/api/environments/utils.go index dc012c6c..a7b8e5d7 100644 --- a/api/environments/utils.go +++ b/api/environments/utils.go @@ -6,6 +6,7 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" + v2 "k8s.io/api/autoscaling/v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -30,3 +31,13 @@ func (eh EnvironmentHandler) getRadixApplicationInAppNamespace(ctx context.Conte func (eh EnvironmentHandler) getRadixEnvironment(ctx context.Context, name string) (*v1.RadixEnvironment, error) { return eh.getServiceAccount().RadixClient.RadixV1().RadixEnvironments().Get(ctx, name, metav1.GetOptions{}) } + +func (eh EnvironmentHandler) getHPAsInEnvironment(ctx context.Context, appName, envName string) ([]v2.HorizontalPodAutoscaler, error) { + envNs := operatorutils.GetEnvironmentNamespace(appName, envName) + hpas, err := eh.accounts.UserAccount.Client.AutoscalingV2().HorizontalPodAutoscalers(envNs).List(ctx, metav1.ListOptions{}) + if err != nil { + return nil, err + } + + return hpas.Items, nil +} From 1782c7c21cd6ac14fe435086d1d3d9c2b1a6781e Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 7 Jun 2024 11:26:32 +0200 Subject: [PATCH 08/24] add client request logging (simplified) --- api/utils/kubernetes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/utils/kubernetes.go b/api/utils/kubernetes.go index 395d3d79..c4083cae 100644 --- a/api/utils/kubernetes.go +++ b/api/utils/kubernetes.go @@ -111,7 +111,7 @@ func getOutClusterClientConfig(token string, impersonation radixmodels.Impersona kubeConfig.Impersonate = impersonationConfig } kubeConfig.Wrap(logs.Logger(func(e *zerolog.Event) { - e.Str("client", "out-cluster").Bool("impersonated", impersonation.PerformImpersonation()) + e.Str("client", "out-cluster") })) return addCommonConfigs(kubeConfig, options) From 416eac74e34dfde7e35706069884cfa4f8e88d02 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 7 Jun 2024 11:33:24 +0200 Subject: [PATCH 09/24] add client request logging (simplified) --- api/utils/logs/roundtrip_logger.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go index e74c658b..aa3e25b4 100644 --- a/api/utils/logs/roundtrip_logger.go +++ b/api/utils/logs/roundtrip_logger.go @@ -38,10 +38,6 @@ func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { ev = logger.Trace() } - if !ev.Enabled() { - return resp, err - } - for _, fn := range fns { ev.Func(fn) } From a34ed4413cc8c037b1bc9378b5598923232fd34a Mon Sep 17 00:00:00 2001 From: Richard87 Date: Mon, 10 Jun 2024 09:36:18 +0200 Subject: [PATCH 10/24] refactor GetComponentsForDeployment --- api/applications/get_applications_handler.go | 2 +- api/deployments/component_controller_test.go | 49 +++--- api/deployments/component_handler.go | 143 ++++++------------ api/deployments/deployment_handler.go | 4 +- .../mock/deployment_handler_mock.go | 8 +- api/environments/component_handler.go | 2 +- .../environment_controller_test.go | 7 +- api/environments/environment_handler.go | 7 +- api/models/component.go | 17 ++- api/models/deployment.go | 8 +- api/models/horizontal_scaling_summary.go | 2 +- api/utils/logs/roundtrip_logger.go | 3 + 12 files changed, 105 insertions(+), 147 deletions(-) diff --git a/api/applications/get_applications_handler.go b/api/applications/get_applications_handler.go index 2b5eb56e..04afd6ce 100644 --- a/api/applications/get_applications_handler.go +++ b/api/applications/get_applications_handler.go @@ -133,7 +133,7 @@ func getComponentsForActiveDeploymentsInEnvironments(ctx context.Context, deploy envName := env.Name g.Go(func() error { - componentModels, err := deploy.GetComponentsForDeployment(ctx, appName, deployment) + componentModels, err := deploy.GetComponentsForDeployment(ctx, appName, deployment.Name, deployment.Environment) if err == nil { chanData <- &ChannelData{key: envName, components: componentModels} } diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index b101540d..1bb3649f 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -78,11 +78,11 @@ func TestGetComponents_active_deployment(t *testing.T) { WithDeploymentName(anyDeployName)) require.NoError(t, err) - err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app") + err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app") require.NoError(t, err) - err = createComponentPod(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app") + err = createComponentPod(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app") require.NoError(t, err) - err = createComponentPod(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job") + err = createComponentPod(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job") require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -300,9 +300,9 @@ func TestGetComponents_inactive_deployment(t *testing.T) { WithActiveFrom(activeDeploymentCreated)) require.NoError(t, err) - err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app") + err = createComponentPod(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app") require.NoError(t, err) - err = createComponentPod(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job") + err = createComponentPod(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job") require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, "initial-deployment") @@ -323,18 +323,19 @@ func TestGetComponents_inactive_deployment(t *testing.T) { assert.Equal(t, 0, len(job.Replicas)) } -func createComponentPod(kubeclient kubernetes.Interface, podName, namespace, radixComponentLabel string) error { - podSpec := getPodSpec(podName, radixComponentLabel) +func createComponentPod(kubeclient kubernetes.Interface, podName, namespace, radixAppLabel, radixComponentLabel string) error { + podSpec := getPodSpec(podName, radixAppLabel, radixComponentLabel) _, err := kubeclient.CoreV1().Pods(namespace).Create(context.Background(), podSpec, metav1.CreateOptions{}) return err } -func getPodSpec(podName, radixComponentLabel string) *corev1.Pod { +func getPodSpec(podName, radixAppLabel, radixComponentLabel string) *corev1.Pod { return &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: podName, Labels: map[string]string{ kube.RadixComponentLabel: radixComponentLabel, + kube.RadixAppLabel: radixAppLabel, }, }, } @@ -384,12 +385,12 @@ func TestGetComponents_ReplicaStatus_Failing(t *testing.T) { require.NoError(t, err) message1 := "Couldn't find key TEST_SECRET in Secret radix-demo-hello-nodejs-dev/www" - err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message1, deploymentModels.Failing, true) + err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message1, deploymentModels.Failing, true) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message1, deploymentModels.Failing, true) + err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message1, deploymentModels.Failing, true) require.NoError(t, err) message2 := "Couldn't find key TEST_SECRET in Secret radix-demo-hello-nodejs-dev/job" - err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job", message2, deploymentModels.Failing, true) + err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job", message2, deploymentModels.Failing, true) require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -405,12 +406,12 @@ func TestGetComponents_ReplicaStatus_Failing(t *testing.T) { assert.Equal(t, 2, len(components)) app := getComponentByName("app", components) - assert.Equal(t, 2, len(app.ReplicaList)) + require.Equal(t, 2, len(app.ReplicaList)) assert.Equal(t, deploymentModels.Failing.String(), app.ReplicaList[0].Status.Status) assert.Equal(t, message1, app.ReplicaList[0].StatusMessage) job := getComponentByName("job", components) - assert.Equal(t, 1, len(job.ReplicaList)) + require.Equal(t, 1, len(job.ReplicaList)) assert.Equal(t, deploymentModels.Failing.String(), job.ReplicaList[0].Status.Status) assert.Equal(t, message2, job.ReplicaList[0].StatusMessage) } @@ -432,11 +433,11 @@ func TestGetComponents_ReplicaStatus_Running(t *testing.T) { require.NoError(t, err) message := "" - err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Running, true) + err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Running, true) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Running, true) + err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Running, true) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job", message, deploymentModels.Running, true) + err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job", message, deploymentModels.Running, true) require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -479,11 +480,11 @@ func TestGetComponents_ReplicaStatus_Starting(t *testing.T) { require.NoError(t, err) message := "" - err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Running, false) + err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Running, false) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Running, false) + err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Running, false) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job", message, deploymentModels.Running, false) + err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job", message, deploymentModels.Running, false) require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -526,11 +527,11 @@ func TestGetComponents_ReplicaStatus_Pending(t *testing.T) { require.NoError(t, err) message := "" - err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Pending, true) + err = createComponentPodWithContainerState(kubeclient, "pod1", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Pending, true) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "app", message, deploymentModels.Pending, true) + err = createComponentPodWithContainerState(kubeclient, "pod2", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "app", message, deploymentModels.Pending, true) require.NoError(t, err) - err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), "job", message, deploymentModels.Pending, true) + err = createComponentPodWithContainerState(kubeclient, "pod3", operatorUtils.GetEnvironmentNamespace(anyAppName, "dev"), anyAppName, "job", message, deploymentModels.Pending, true) require.NoError(t, err) endpoint := createGetComponentsEndpoint(anyAppName, anyDeployName) @@ -702,8 +703,8 @@ func TestGetComponents_WithIdentity(t *testing.T) { assert.Nil(t, getComponentByName("comp2", components).Identity) } -func createComponentPodWithContainerState(kubeclient kubernetes.Interface, podName, namespace, radixComponentLabel, message string, status deploymentModels.ContainerStatus, ready bool) error { - podSpec := getPodSpec(podName, radixComponentLabel) +func createComponentPodWithContainerState(kubeclient kubernetes.Interface, podName, namespace, radixAppLabel, radixComponentLabel, message string, status deploymentModels.ContainerStatus, ready bool) error { + podSpec := getPodSpec(podName, radixAppLabel, radixComponentLabel) containerState := getContainerState(message, status) podStatus := corev1.PodStatus{ ContainerStatuses: []corev1.ContainerStatus{ diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index 3c5a0594..1c420f02 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -2,14 +2,12 @@ package deployments import ( "context" - "fmt" "strings" deploymentModels "github.com/equinor/radix-api/api/deployments/models" "github.com/equinor/radix-api/api/kubequery" - "github.com/equinor/radix-api/api/utils" + "github.com/equinor/radix-api/api/models" "github.com/equinor/radix-api/api/utils/event" - "github.com/equinor/radix-api/api/utils/horizontalscaling" "github.com/equinor/radix-api/api/utils/labelselector" radixutils "github.com/equinor/radix-common/utils" "github.com/equinor/radix-common/utils/slice" @@ -18,7 +16,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" - v2 "k8s.io/api/autoscaling/v2" + autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -27,124 +25,65 @@ import ( ) // GetComponentsForDeployment Gets a list of components for a given deployment -func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, appName string, deployment *deploymentModels.DeploymentSummary) ([]*deploymentModels.Component, error) { - envNs := crdUtils.GetEnvironmentNamespace(appName, deployment.Environment) - rd, err := deploy.accounts.UserAccount.RadixClient.RadixV1().RadixDeployments(envNs).Get(ctx, deployment.Name, metav1.GetOptions{}) +func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, appName, deploymentName, envName string) ([]*deploymentModels.Component, error) { + rd, err := kubequery.GetRadixDeploymentByName(ctx, deploy.accounts.UserAccount.RadixClient, appName, envName, deploymentName) if err != nil { return nil, err } - - ra, _ := deploy.accounts.UserAccount.RadixClient.RadixV1().RadixApplications(crdUtils.GetAppNamespace(appName)).Get(ctx, appName, metav1.GetOptions{}) - var components []*deploymentModels.Component - - for _, component := range rd.Spec.Components { - componentModel, err := deploy.getComponent(ctx, &component, ra, rd, deployment) - if err != nil { - return nil, err - } - components = append(components, componentModel) - } - - for _, component := range rd.Spec.Jobs { - componentModel, err := deploy.getComponent(ctx, &component, ra, rd, deployment) - if err != nil { - return nil, err - } - components = append(components, componentModel) + ra, err := kubequery.GetRadixApplication(ctx, deploy.accounts.UserAccount.RadixClient, appName) + if err != nil { + return nil, err } - - return components, nil -} - -// GetComponentsForDeploymentName handler for GetDeployments -func (deploy *deployHandler) GetComponentsForDeploymentName(ctx context.Context, appName, deploymentName string) ([]*deploymentModels.Component, error) { - deployments, err := deploy.GetDeploymentsForApplication(ctx, appName) + deploymentList, err := kubequery.GetDeploymentsForEnvironment(ctx, deploy.accounts.UserAccount.Client, appName, envName) if err != nil { return nil, err } - - for _, depl := range deployments { - if strings.EqualFold(depl.Name, deploymentName) { - return deploy.GetComponentsForDeployment(ctx, appName, depl) - } + podList, err := kubequery.GetPodsForEnvironmentComponents(ctx, deploy.accounts.UserAccount.Client, appName, envName) + if err != nil { + return nil, err } - - return nil, deploymentModels.NonExistingDeployment(nil, deploymentName) -} - -func (deploy *deployHandler) getComponent(ctx context.Context, component v1.RadixCommonDeployComponent, ra *v1.RadixApplication, rd *v1.RadixDeployment, deployment *deploymentModels.DeploymentSummary) (*deploymentModels.Component, error) { - envNs := crdUtils.GetEnvironmentNamespace(ra.Name, deployment.Environment) - - // TODO: Add interface for RA + EnvConfig - environmentConfig := utils.GetComponentEnvironmentConfig(ra, deployment.Environment, component.GetName()) - - deploymentComponent, err := GetComponentStateFromSpec(ctx, deploy.accounts.UserAccount.Client, ra.Name, deployment, rd.Status, environmentConfig, component) + hpas, err := kubequery.GetHorizontalPodAutoscalersForEnvironment(ctx, deploy.accounts.UserAccount.Client, appName, envName) if err != nil { return nil, err } - - if component.GetType() == v1.RadixComponentTypeComponent { - hpaSummary, err := deploy.getHpaSummary(ctx, component, ra.Name, envNs) - if err != nil { - return nil, err - } - deploymentComponent.HorizontalScalingSummary = hpaSummary + noJobPayloadReq, err := labels.NewRequirement(kube.RadixSecretTypeLabel, selection.NotEquals, []string{string(kube.RadixSecretJobPayload)}) + if err != nil { + return nil, err } - return deploymentComponent, nil -} - -func (deploy *deployHandler) getHpaSummary(ctx context.Context, component v1.RadixCommonDeployComponent, appName, envNs string) (*deploymentModels.HorizontalScalingSummary, error) { - selector := labelselector.ForComponent(appName, component.GetName()).String() - hpas, err := deploy.accounts.UserAccount.Client.AutoscalingV2().HorizontalPodAutoscalers(envNs).List(ctx, metav1.ListOptions{LabelSelector: selector}) + secretList, err := kubequery.GetSecretsForEnvironment(ctx, deploy.accounts.UserAccount.Client, appName, envName, *noJobPayloadReq) if err != nil { return nil, err } - if len(hpas.Items) == 0 { - return nil, nil + eventList, err := kubequery.GetEventsForEnvironment(ctx, deploy.accounts.UserAccount.Client, appName, envName) + if err != nil { + return nil, err } - if len(hpas.Items) > 1 { - return nil, fmt.Errorf("found more than 1 HPA for component %s", component.GetName()) + certs, err := kubequery.GetCertificatesForEnvironment(ctx, deploy.accounts.UserAccount.CertManagerClient, appName, envName) + if err != nil { + return nil, err } - hpa := &hpas.Items[0] - - minReplicas := int32(1) - if hpa.Spec.MinReplicas != nil { - minReplicas = *hpa.Spec.MinReplicas + certRequests, err := kubequery.GetCertificateRequestsForEnvironment(ctx, deploy.accounts.UserAccount.CertManagerClient, appName, envName) + if err != nil { + return nil, err } - maxReplicas := hpa.Spec.MaxReplicas - - currentCpuUtil, targetCpuUtil := getHpaMetrics(hpa, corev1.ResourceCPU) - currentMemoryUtil, targetMemoryUtil := getHpaMetrics(hpa, corev1.ResourceMemory) - hpaSummary := deploymentModels.HorizontalScalingSummary{ - MinReplicas: minReplicas, - MaxReplicas: maxReplicas, - CurrentCPUUtilizationPercentage: currentCpuUtil, - TargetCPUUtilizationPercentage: targetCpuUtil, - CurrentMemoryUtilizationPercentage: currentMemoryUtil, - TargetMemoryUtilizationPercentage: targetMemoryUtil, - } - return &hpaSummary, nil + return models.BuildComponents(ra, rd, deploymentList, podList, hpas, secretList, eventList, certs, certRequests, nil), nil } -func getHpaMetrics(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { - currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) - // find resource utilization target - var targetResourceUtil *int32 - targetResourceMetric := horizontalscaling.GetHpaMetric(hpa, resourceName) - if targetResourceMetric != nil { - targetResourceUtil = targetResourceMetric.Resource.Target.AverageUtilization +// GetComponentsForDeploymentName handler for GetDeployments +func (deploy *deployHandler) GetComponentsForDeploymentName(ctx context.Context, appName, deploymentName string) ([]*deploymentModels.Component, error) { + deployments, err := deploy.GetDeploymentsForApplication(ctx, appName) + if err != nil { + return nil, err } - return currentResourceUtil, targetResourceUtil -} -func getHpaCurrentMetric(hpa *v2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) *int32 { - for _, metric := range hpa.Status.CurrentMetrics { - if metric.Resource != nil && metric.Resource.Name == resourceName { - return metric.Resource.Current.AverageUtilization + for _, depl := range deployments { + if strings.EqualFold(depl.Name, deploymentName) { + return deploy.GetComponentsForDeployment(ctx, appName, depl.Name, depl.Environment) } } - return nil + + return nil, deploymentModels.NonExistingDeployment(nil, deploymentName) } // GetComponentStateFromSpec Returns a component with the current state @@ -155,12 +94,15 @@ func GetComponentStateFromSpec( deployment *deploymentModels.DeploymentSummary, deploymentStatus v1.RadixDeployStatus, environmentConfig v1.RadixCommonEnvironmentConfig, - component v1.RadixCommonDeployComponent) (*deploymentModels.Component, error) { + component v1.RadixCommonDeployComponent, + hpas []autoscalingv2.HorizontalPodAutoscaler, +) (*deploymentModels.Component, error) { var componentPodNames []string var environmentVariables map[string]string var replicaSummaryList []deploymentModels.ReplicaSummary var auxResource deploymentModels.AuxiliaryResource + var horizontalScalingSummary *deploymentModels.HorizontalScalingSummary envNs := crdUtils.GetEnvironmentNamespace(appName, deployment.Environment) status := deploymentModels.ConsistentComponent @@ -200,6 +142,10 @@ func GetComponentStateFromSpec( componentBuilder.WithNotifications(jobComponent.Notifications) } + if component.GetType() == v1.RadixComponentTypeComponent { + horizontalScalingSummary = models.GetHpaSummary(appName, component.GetName(), hpas) + } + return componentBuilder. WithComponent(component). WithStatus(status). @@ -207,6 +153,7 @@ func GetComponentStateFromSpec( WithReplicaSummaryList(replicaSummaryList). WithRadixEnvironmentVariables(environmentVariables). WithAuxiliaryResource(auxResource). + WithHorizontalScalingSummary(horizontalScalingSummary). BuildComponent() } diff --git a/api/deployments/deployment_handler.go b/api/deployments/deployment_handler.go index 30028d82..9d4a906d 100644 --- a/api/deployments/deployment_handler.go +++ b/api/deployments/deployment_handler.go @@ -27,7 +27,7 @@ type DeployHandler interface { GetDeploymentWithName(ctx context.Context, appName, deploymentName string) (*deploymentModels.Deployment, error) GetDeploymentsForApplicationEnvironment(ctx context.Context, appName, environment string, latest bool) ([]*deploymentModels.DeploymentSummary, error) GetComponentsForDeploymentName(ctx context.Context, appName, deploymentID string) ([]*deploymentModels.Component, error) - GetComponentsForDeployment(ctx context.Context, appName string, deployment *deploymentModels.DeploymentSummary) ([]*deploymentModels.Component, error) + GetComponentsForDeployment(ctx context.Context, appName, deploymentName, envName string) ([]*deploymentModels.Component, error) GetLatestDeploymentForApplicationEnvironment(ctx context.Context, appName, environment string) (*deploymentModels.DeploymentSummary, error) GetDeploymentsForPipelineJob(context.Context, string, string) ([]*deploymentModels.DeploymentSummary, error) GetJobComponentDeployments(context.Context, string, string, string) ([]*deploymentModels.DeploymentItem, error) @@ -171,7 +171,7 @@ func (deploy *deployHandler) GetDeploymentWithName(ctx context.Context, appName, return nil, err } - components, err := deploy.GetComponentsForDeployment(ctx, appName, deploymentSummary) + components, err := deploy.GetComponentsForDeployment(ctx, appName, deploymentName, deploymentSummary.Environment) if err != nil { return nil, err } diff --git a/api/deployments/mock/deployment_handler_mock.go b/api/deployments/mock/deployment_handler_mock.go index b4cacf14..59e36e79 100644 --- a/api/deployments/mock/deployment_handler_mock.go +++ b/api/deployments/mock/deployment_handler_mock.go @@ -38,18 +38,18 @@ func (m *MockDeployHandler) EXPECT() *MockDeployHandlerMockRecorder { } // GetComponentsForDeployment mocks base method. -func (m *MockDeployHandler) GetComponentsForDeployment(ctx context.Context, appName string, deployment *models.DeploymentSummary) ([]*models.Component, error) { +func (m *MockDeployHandler) GetComponentsForDeployment(ctx context.Context, appName, deploymentName, envName string) ([]*models.Component, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetComponentsForDeployment", ctx, appName, deployment) + ret := m.ctrl.Call(m, "GetComponentsForDeployment", ctx, appName, deploymentName, envName) ret0, _ := ret[0].([]*models.Component) ret1, _ := ret[1].(error) return ret0, ret1 } // GetComponentsForDeployment indicates an expected call of GetComponentsForDeployment. -func (mr *MockDeployHandlerMockRecorder) GetComponentsForDeployment(ctx, appName, deployment interface{}) *gomock.Call { +func (mr *MockDeployHandlerMockRecorder) GetComponentsForDeployment(ctx, appName, deploymentName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponentsForDeployment", reflect.TypeOf((*MockDeployHandler)(nil).GetComponentsForDeployment), ctx, appName, deployment) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponentsForDeployment", reflect.TypeOf((*MockDeployHandler)(nil).GetComponentsForDeployment), ctx, appName, deploymentName, envName) } // GetComponentsForDeploymentName mocks base method. diff --git a/api/environments/component_handler.go b/api/environments/component_handler.go index 6a309007..9f89dda2 100644 --- a/api/environments/component_handler.go +++ b/api/environments/component_handler.go @@ -92,7 +92,7 @@ func (eh EnvironmentHandler) RestartComponentAuxiliaryResource(ctx context.Conte return err } - componentsDto, err := eh.deployHandler.GetComponentsForDeployment(ctx, appName, deploySummary) + componentsDto, err := eh.deployHandler.GetComponentsForDeployment(ctx, appName, deploySummary.Name, envName) if err != nil { return err } diff --git a/api/environments/environment_controller_test.go b/api/environments/environment_controller_test.go index acfb2654..613e96c2 100644 --- a/api/environments/environment_controller_test.go +++ b/api/environments/environment_controller_test.go @@ -2743,12 +2743,7 @@ func Test_DeleteBatch(t *testing.T) { } } -func initHandler(client kubernetes.Interface, - radixclient radixclient.Interface, - kedaClient kedav2.Interface, - secretproviderclient secretsstorevclient.Interface, - certClient certclient.Interface, - handlerConfig ...EnvironmentHandlerOptions) EnvironmentHandler { +func initHandler(client kubernetes.Interface, radixclient radixclient.Interface, kedaClient kedav2.Interface, secretproviderclient secretsstorevclient.Interface, certClient certclient.Interface, handlerConfig ...EnvironmentHandlerOptions) EnvironmentHandler { accounts := models.NewAccounts(client, radixclient, kedaClient, secretproviderclient, nil, certClient, client, radixclient, kedaClient, secretproviderclient, nil, certClient, "", radixmodels.Impersonation{}) options := []EnvironmentHandlerOptions{WithAccounts(accounts)} options = append(options, handlerConfig...) diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 4e5aa43e..09034d0d 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -449,12 +449,17 @@ func (eh EnvironmentHandler) getRadixCommonComponentUpdater(ctx context.Context, updater = &radixDeployJobComponentUpdater{base: baseUpdater} } + hpas, err := eh.getHPAsInEnvironment(ctx, appName, envName) + if err != nil { + return nil, err + } + baseUpdater.componentIndex = componentIndex baseUpdater.componentToPatch = componentToPatch ra, _ := eh.getRadixApplicationInAppNamespace(ctx, appName) baseUpdater.environmentConfig = utils.GetComponentEnvironmentConfig(ra, envName, componentName) - baseUpdater.componentState, err = deployments.GetComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch) + baseUpdater.componentState, err = deployments.GetComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas) if err != nil { return nil, err } diff --git a/api/models/component.go b/api/models/component.go index 696a1220..b1fe7c0e 100644 --- a/api/models/component.go +++ b/api/models/component.go @@ -33,9 +33,11 @@ const ( ) // BuildComponents builds a list of Component models. -func BuildComponents(ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, - hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, - tlsValidator tlsvalidation.Validator) []*deploymentModels.Component { +func BuildComponents( + ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, + hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, certs []cmv1.Certificate, + certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, +) []*deploymentModels.Component { lastEventWarnings := event.ConvertToEventWarnings(eventList) var components []*deploymentModels.Component for _, component := range rd.Spec.Components { @@ -49,13 +51,16 @@ func BuildComponents(ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, return components } -func buildComponent(radixComponent radixv1.RadixCommonDeployComponent, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, +func buildComponent( + radixComponent radixv1.RadixCommonDeployComponent, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, - secretList []corev1.Secret, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, lastEventWarnings map[string]string, tlsValidator tlsvalidation.Validator) *deploymentModels.Component { + secretList []corev1.Secret, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, lastEventWarnings map[string]string, + tlsValidator tlsvalidation.Validator, +) *deploymentModels.Component { builder := deploymentModels.NewComponentBuilder(). WithComponent(radixComponent). WithStatus(deploymentModels.ConsistentComponent). - WithHorizontalScalingSummary(getHpaSummary(ra.Name, radixComponent.GetName(), hpaList)). + WithHorizontalScalingSummary(GetHpaSummary(ra.Name, radixComponent.GetName(), hpaList)). WithExternalDNS(getComponentExternalDNS(ra.Name, radixComponent, secretList, certs, certRequests, tlsValidator)) componentPods := slice.FindAll(podList, predicate.IsPodForComponent(ra.Name, radixComponent.GetName())) diff --git a/api/models/deployment.go b/api/models/deployment.go index 0778969a..5a2def62 100644 --- a/api/models/deployment.go +++ b/api/models/deployment.go @@ -13,9 +13,11 @@ import ( ) // BuildDeployment builds a Deployment model. -func BuildDeployment(rr *radixv1.RadixRegistration, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, - podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, rjList []radixv1.RadixJob, - certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator) *deploymentModels.Deployment { +func BuildDeployment( + rr *radixv1.RadixRegistration, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, + podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, + rjList []radixv1.RadixJob, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, +) *deploymentModels.Deployment { components := BuildComponents(ra, rd, deploymentList, podList, hpaList, secretList, eventList, certs, certRequests, tlsValidator) // The only error that can be returned from DeploymentBuilder is related to errors from github.com/imdario/mergo diff --git a/api/models/horizontal_scaling_summary.go b/api/models/horizontal_scaling_summary.go index d273e258..83a29156 100644 --- a/api/models/horizontal_scaling_summary.go +++ b/api/models/horizontal_scaling_summary.go @@ -9,7 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" ) -func getHpaSummary(appName, componentName string, hpaList []autoscalingv2.HorizontalPodAutoscaler) *deploymentModels.HorizontalScalingSummary { +func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.HorizontalPodAutoscaler) *deploymentModels.HorizontalScalingSummary { hpa, ok := slice.FindFirst(hpaList, predicate.IsHpaForComponent(appName, componentName)) if !ok { return nil diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go index aa3e25b4..5097b839 100644 --- a/api/utils/logs/roundtrip_logger.go +++ b/api/utils/logs/roundtrip_logger.go @@ -18,6 +18,9 @@ func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) type WithFunc func(e *zerolog.Event) +// Logger returns a http.RoundTripper that logs failed requests, and add traces for successfull requests +// +// nolint Zerolog complains about potential unsent event, but we send the event on line 50 func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { return func(t http.RoundTripper) http.RoundTripper { return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { From aaae0cdaa43b3cf8fdb59b0ad317fbfcb4a8d12d Mon Sep 17 00:00:00 2001 From: Richard87 Date: Wed, 12 Jun 2024 16:03:10 +0200 Subject: [PATCH 11/24] test responses from scaledobjects and hpa --- api/deployments/component_controller_test.go | 84 +++++++++++- api/deployments/component_handler.go | 10 +- .../models/component_deployment.go | 39 ++++++ api/environments/environment_handler.go | 13 +- api/environments/utils.go | 11 ++ api/kubequery/scaledobject_test.go | 27 ++++ api/kubequery/scaledobjects.go | 21 +++ api/models/component.go | 13 +- api/models/deployment.go | 4 +- api/models/environment.go | 6 +- api/models/horizontal_scaling_summary.go | 129 +++++++++++++++++- api/utils/predicate/kubernetes.go | 7 + 12 files changed, 337 insertions(+), 27 deletions(-) create mode 100644 api/kubequery/scaledobject_test.go create mode 100644 api/kubequery/scaledobjects.go diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index 1bb3649f..ca834617 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -13,10 +13,12 @@ import ( "github.com/equinor/radix-api/api/utils/labelselector" radixhttp "github.com/equinor/radix-common/net/http" radixutils "github.com/equinor/radix-common/utils" + "github.com/equinor/radix-common/utils/slice" "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/numbers" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" v2 "k8s.io/api/autoscaling/v2" @@ -590,8 +592,10 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { require.NoError(t, err) ns := operatorUtils.GetEnvironmentNamespace(anyAppName, "prod") - autoscaler := createAutoscaler("frontend", numbers.Int32Ptr(scenario.minReplicas), scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory) - _, err = client.AutoscalingV2().HorizontalPodAutoscalers(ns).Create(context.Background(), &autoscaler, metav1.CreateOptions{}) + scaler, hpa := createHorizontalScalingObjects("frontend", numbers.Int32Ptr(scenario.minReplicas), scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory) + _, err = kedaClient.KedaV1alpha1().ScaledObjects(ns).Create(context.Background(), &scaler, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = client.AutoscalingV2().HorizontalPodAutoscalers(ns).Create(context.Background(), &hpa, metav1.CreateOptions{}) require.NoError(t, err) // Test @@ -608,18 +612,58 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { assert.Equal(t, scenario.minReplicas, components[0].HorizontalScalingSummary.MinReplicas) assert.Equal(t, scenario.maxReplicas, components[0].HorizontalScalingSummary.MaxReplicas) - assert.True(t, nil == components[0].HorizontalScalingSummary.CurrentCPUUtilizationPercentage) // using assert.Equal() fails because simple nil and *int32 typed nil do not pass equality test + assert.Nil(t, components[0].HorizontalScalingSummary.CurrentCPUUtilizationPercentage) assert.Equal(t, scenario.targetCpu, components[0].HorizontalScalingSummary.TargetCPUUtilizationPercentage) - assert.True(t, nil == components[0].HorizontalScalingSummary.CurrentMemoryUtilizationPercentage) + assert.Nil(t, components[0].HorizontalScalingSummary.CurrentMemoryUtilizationPercentage) assert.Equal(t, scenario.targetMemory, components[0].HorizontalScalingSummary.TargetMemoryUtilizationPercentage) + + memoryTrigger, ok := slice.FindFirst(components[0].HorizontalScalingSummary.Triggers, func(s deploymentModels.HorizontalScalingSummaryTriggerStatus) bool { + return s.Name == "memory" + }) + if scenario.targetMemory == nil { + assert.False(t, ok) + } else { + require.True(t, ok) + assert.Equal(t, string(*scenario.targetMemory), memoryTrigger.TargetUtilization) + assert.Empty(t, memoryTrigger.CurrentUtilization) + assert.Empty(t, memoryTrigger.Error) + assert.Equal(t, "memory", memoryTrigger.Type) + } + + cpuTrigger, ok := slice.FindFirst(components[0].HorizontalScalingSummary.Triggers, func(s deploymentModels.HorizontalScalingSummaryTriggerStatus) bool { + return s.Name == "cpu" + }) + if scenario.targetCpu == nil { + assert.False(t, ok) + } else { + require.True(t, ok) + assert.Equal(t, string(*scenario.targetCpu), cpuTrigger.TargetUtilization) + assert.Empty(t, cpuTrigger.CurrentUtilization) + assert.Empty(t, cpuTrigger.Error) + assert.Equal(t, "cpu", cpuTrigger.Type) + } + + // todo: test CRON trigger and AzureServiceBus }) } } -func createAutoscaler(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32) v2.HorizontalPodAutoscaler { +func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32) (v1alpha1.ScaledObject, v2.HorizontalPodAutoscaler) { + var triggers []v1alpha1.ScaleTriggers var metrics []v2.MetricSpec + resourceMetricNames := []string{} if targetCpu != nil { + resourceMetricNames = append(resourceMetricNames, "cpu") + triggers = append(triggers, v1alpha1.ScaleTriggers{ + Type: "cpu", + Name: "cpu", + Metadata: map[string]string{ + "value": string(*targetCpu), + }, + AuthenticationRef: nil, + MetricType: "Utilization", + }) metrics = append(metrics, v2.MetricSpec{ Resource: &v2.ResourceMetricSource{ Name: "cpu", @@ -632,6 +676,15 @@ func createAutoscaler(name string, minReplicas *int32, maxReplicas int32, target } if targetMemory != nil { + resourceMetricNames = append(resourceMetricNames, "memory") + triggers = append(triggers, v1alpha1.ScaleTriggers{ + Type: "memory", + Name: "memory", + Metadata: map[string]string{ + "value": string(*targetMemory), + }, + MetricType: "Utilization", + }) metrics = append(metrics, v2.MetricSpec{ Resource: &v2.ResourceMetricSource{ Name: "memory", @@ -643,18 +696,35 @@ func createAutoscaler(name string, minReplicas *int32, maxReplicas int32, target }) } - autoscaler := v2.HorizontalPodAutoscaler{ + scaler := v1alpha1.ScaledObject{ ObjectMeta: metav1.ObjectMeta{ Name: name, Labels: labelselector.ForComponent(anyAppName, "frontend"), }, + Spec: v1alpha1.ScaledObjectSpec{ + MinReplicaCount: minReplicas, + MaxReplicaCount: &maxReplicas, + Triggers: triggers, + }, + Status: v1alpha1.ScaledObjectStatus{ + HpaName: fmt.Sprintf("hpa-%s", name), + ResourceMetricNames: resourceMetricNames, + }, + } + + hpa := v2.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("hpa-%s", name), + Labels: labelselector.ForComponent(anyAppName, "frontend"), + }, Spec: v2.HorizontalPodAutoscalerSpec{ MinReplicas: minReplicas, MaxReplicas: maxReplicas, Metrics: metrics, }, } - return autoscaler + + return scaler, hpa } func TestGetComponents_WithIdentity(t *testing.T) { diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index 1c420f02..bd9ddf83 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -16,6 +16,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,6 +47,10 @@ func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, app if err != nil { return nil, err } + scaledObjects, err := kubequery.GetScaledObjectsForEnvironment(ctx, deploy.accounts.UserAccount.KedaClient, appName, envName) + if err != nil { + return nil, err + } noJobPayloadReq, err := labels.NewRequirement(kube.RadixSecretTypeLabel, selection.NotEquals, []string{string(kube.RadixSecretJobPayload)}) if err != nil { return nil, err @@ -67,7 +72,7 @@ func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, app return nil, err } - return models.BuildComponents(ra, rd, deploymentList, podList, hpas, secretList, eventList, certs, certRequests, nil), nil + return models.BuildComponents(ra, rd, deploymentList, podList, hpas, secretList, eventList, certs, certRequests, nil, scaledObjects), nil } // GetComponentsForDeploymentName handler for GetDeployments @@ -96,6 +101,7 @@ func GetComponentStateFromSpec( environmentConfig v1.RadixCommonEnvironmentConfig, component v1.RadixCommonDeployComponent, hpas []autoscalingv2.HorizontalPodAutoscaler, + scaledObjects []v1alpha1.ScaledObject, ) (*deploymentModels.Component, error) { var componentPodNames []string @@ -143,7 +149,7 @@ func GetComponentStateFromSpec( } if component.GetType() == v1.RadixComponentTypeComponent { - horizontalScalingSummary = models.GetHpaSummary(appName, component.GetName(), hpas) + horizontalScalingSummary = models.GetHpaSummary(appName, component.GetName(), hpas, scaledObjects) } return componentBuilder. diff --git a/api/deployments/models/component_deployment.go b/api/deployments/models/component_deployment.go index d6649291..9b0b5559 100644 --- a/api/deployments/models/component_deployment.go +++ b/api/deployments/models/component_deployment.go @@ -422,31 +422,70 @@ type HorizontalScalingSummary struct { // example: 5 MaxReplicas int32 `json:"maxReplicas"` + // CooldownPeriod in seconds. From radixconfig.yaml + // + // required: false + // example: 300 + CooldownPeriod int32 `json:"cooldownPeriod"` + + // PollingInterval in seconds. From radixconfig.yaml + // + // required: false + // example: 30 + PollingInterval int32 `json:"pollingInterval"` + + // Triggers lists status of all triggers found in radixconfig.yaml + // + // required: false + // example: 30 + Triggers []HorizontalScalingSummaryTriggerStatus `json:"triggers"` + // Component current average CPU utilization over all pods, represented as a percentage of requested CPU // // required: false // example: 70 + // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. CurrentCPUUtilizationPercentage *int32 `json:"currentCPUUtilizationPercentage"` // Component target average CPU utilization over all pods // // required: false // example: 80 + // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage"` // Component current average memory utilization over all pods, represented as a percentage of requested memory // // required: false // example: 80 + // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. CurrentMemoryUtilizationPercentage *int32 `json:"currentMemoryUtilizationPercentage"` // Component target average memory utilization over all pods // // required: false // example: 80 + // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. TargetMemoryUtilizationPercentage *int32 `json:"targetMemoryUtilizationPercentage"` } +type HorizontalScalingSummaryTriggerStatus struct { + // Name of trigger + Name string `json:"name"` + + // CurrentUtilization is the last measured utilization + CurrentUtilization string `json:"current_utilization"` + + // TargetUtilization is the average target across replicas + TargetUtilization string `json:"target_utilization"` + + // Type of trigger + Type string `json:"type"` + + // Error contains short description if trigger have problems + Error string `json:"error,omitempty"` +} + // Node Defines node attributes, where pod should be scheduled type Node struct { // Gpu Holds lists of node GPU types, with dashed types to exclude diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 09034d0d..50e9d617 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -190,7 +190,10 @@ func (eh EnvironmentHandler) GetEnvironment(ctx context.Context, appName, envNam if err != nil { return nil, err } - + scaledObjects, err := kubequery.GetScaledObjectsForEnvironment(ctx, eh.accounts.UserAccount.KedaClient, appName, envName) + if err != nil { + return nil, err + } noJobPayloadReq, err := labels.NewRequirement(kube.RadixSecretTypeLabel, selection.NotEquals, []string{string(kube.RadixSecretJobPayload)}) if err != nil { return nil, err @@ -216,7 +219,7 @@ func (eh EnvironmentHandler) GetEnvironment(ctx context.Context, appName, envNam return nil, err } - env := apimodels.BuildEnvironment(rr, ra, re, rdList, rjList, deploymentList, componentPodList, hpaList, secretList, secretProviderClassList, eventList, certs, certRequests, eh.tlsValidator) + env := apimodels.BuildEnvironment(rr, ra, re, rdList, rjList, deploymentList, componentPodList, hpaList, secretList, secretProviderClassList, eventList, certs, certRequests, eh.tlsValidator, scaledObjects) return env, nil } @@ -453,13 +456,17 @@ func (eh EnvironmentHandler) getRadixCommonComponentUpdater(ctx context.Context, if err != nil { return nil, err } + scalers, err := eh.getScaledObjectsInEnvironment(ctx, appName, envName) + if err != nil { + return nil, err + } baseUpdater.componentIndex = componentIndex baseUpdater.componentToPatch = componentToPatch ra, _ := eh.getRadixApplicationInAppNamespace(ctx, appName) baseUpdater.environmentConfig = utils.GetComponentEnvironmentConfig(ra, envName, componentName) - baseUpdater.componentState, err = deployments.GetComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas) + baseUpdater.componentState, err = deployments.GetComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas, scalers) if err != nil { return nil, err } diff --git a/api/environments/utils.go b/api/environments/utils.go index a7b8e5d7..3b813168 100644 --- a/api/environments/utils.go +++ b/api/environments/utils.go @@ -6,6 +6,7 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" v2 "k8s.io/api/autoscaling/v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -41,3 +42,13 @@ func (eh EnvironmentHandler) getHPAsInEnvironment(ctx context.Context, appName, return hpas.Items, nil } + +func (eh EnvironmentHandler) getScaledObjectsInEnvironment(ctx context.Context, appName, envName string) ([]v1alpha1.ScaledObject, error) { + envNs := operatorutils.GetEnvironmentNamespace(appName, envName) + scaledObjects, err := eh.accounts.UserAccount.KedaClient.KedaV1alpha1().ScaledObjects(envNs).List(ctx, metav1.ListOptions{}) + if err != nil { + return nil, err + } + + return scaledObjects.Items, nil +} diff --git a/api/kubequery/scaledobject_test.go b/api/kubequery/scaledobject_test.go new file mode 100644 index 00000000..7d47d6a2 --- /dev/null +++ b/api/kubequery/scaledobject_test.go @@ -0,0 +1,27 @@ +package kubequery_test + +import ( + "context" + "testing" + + "github.com/equinor/radix-api/api/kubequery" + "github.com/equinor/radix-operator/pkg/apis/utils/labels" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" + kedafake "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned/fake" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func Test_GetScaledObjectsForEnvironment(t *testing.T) { + matched1 := v1alpha1.ScaledObject{ObjectMeta: metav1.ObjectMeta{Name: "matched1", Namespace: "app1-env1", Labels: labels.ForApplicationName("app1")}} + matched2 := v1alpha1.ScaledObject{ObjectMeta: metav1.ObjectMeta{Name: "matched2", Namespace: "app1-env1", Labels: labels.ForApplicationName("app1")}} + unmatched1 := v1alpha1.ScaledObject{ObjectMeta: metav1.ObjectMeta{Name: "unmatched1", Namespace: "app1-env1"}} + unmatched2 := v1alpha1.ScaledObject{ObjectMeta: metav1.ObjectMeta{Name: "unmatched2", Namespace: "app1-env1", Labels: labels.ForApplicationName("app2")}} + unmatched3 := v1alpha1.ScaledObject{ObjectMeta: metav1.ObjectMeta{Name: "unmatched3", Namespace: "app1-env2", Labels: labels.ForApplicationName("app1")}} + client := kedafake.NewSimpleClientset(&matched1, &matched2, &unmatched1, &unmatched2, &unmatched3) + expected := []v1alpha1.ScaledObject{matched1, matched2} + actual, err := kubequery.GetScaledObjectsForEnvironment(context.Background(), client, "app1", "env1") + require.NoError(t, err) + assert.ElementsMatch(t, expected, actual) +} diff --git a/api/kubequery/scaledobjects.go b/api/kubequery/scaledobjects.go new file mode 100644 index 00000000..571a1270 --- /dev/null +++ b/api/kubequery/scaledobjects.go @@ -0,0 +1,21 @@ +package kubequery + +import ( + "context" + + operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/equinor/radix-operator/pkg/apis/utils/labels" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" + "github.com/kedacore/keda/v2/pkg/generated/clientset/versioned" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GetScaledObjectsForEnvironment returns all ScaledObjects for the specified application and environment. +func GetScaledObjectsForEnvironment(ctx context.Context, kedaClient versioned.Interface, appName, envName string) ([]v1alpha1.ScaledObject, error) { + ns := operatorUtils.GetEnvironmentNamespace(appName, envName) + scaledObjects, err := kedaClient.KedaV1alpha1().ScaledObjects(ns).List(ctx, metav1.ListOptions{LabelSelector: labels.ForApplicationName(appName).String()}) + if err != nil { + return nil, err + } + return scaledObjects.Items, nil +} diff --git a/api/models/component.go b/api/models/component.go index b1fe7c0e..6f2ef9dd 100644 --- a/api/models/component.go +++ b/api/models/component.go @@ -20,6 +20,7 @@ import ( radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" @@ -36,16 +37,16 @@ const ( func BuildComponents( ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, certs []cmv1.Certificate, - certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, + certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, scaledObjects []v1alpha1.ScaledObject, ) []*deploymentModels.Component { lastEventWarnings := event.ConvertToEventWarnings(eventList) var components []*deploymentModels.Component for _, component := range rd.Spec.Components { - components = append(components, buildComponent(&component, ra, rd, deploymentList, podList, hpaList, secretList, certs, certRequests, lastEventWarnings, tlsValidator)) + components = append(components, buildComponent(&component, ra, rd, deploymentList, podList, hpaList, secretList, certs, certRequests, lastEventWarnings, tlsValidator, scaledObjects)) } for _, job := range rd.Spec.Jobs { - components = append(components, buildComponent(&job, ra, rd, deploymentList, podList, hpaList, secretList, certs, certRequests, lastEventWarnings, tlsValidator)) + components = append(components, buildComponent(&job, ra, rd, deploymentList, podList, hpaList, secretList, certs, certRequests, lastEventWarnings, tlsValidator, scaledObjects)) } return components @@ -54,13 +55,13 @@ func BuildComponents( func buildComponent( radixComponent radixv1.RadixCommonDeployComponent, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, - secretList []corev1.Secret, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, lastEventWarnings map[string]string, - tlsValidator tlsvalidation.Validator, + secretList []corev1.Secret, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, + lastEventWarnings map[string]string, tlsValidator tlsvalidation.Validator, scaledObjects []v1alpha1.ScaledObject, ) *deploymentModels.Component { builder := deploymentModels.NewComponentBuilder(). WithComponent(radixComponent). WithStatus(deploymentModels.ConsistentComponent). - WithHorizontalScalingSummary(GetHpaSummary(ra.Name, radixComponent.GetName(), hpaList)). + WithHorizontalScalingSummary(GetHpaSummary(ra.Name, radixComponent.GetName(), hpaList, scaledObjects)). WithExternalDNS(getComponentExternalDNS(ra.Name, radixComponent, secretList, certs, certRequests, tlsValidator)) componentPods := slice.FindAll(podList, predicate.IsPodForComponent(ra.Name, radixComponent.GetName())) diff --git a/api/models/deployment.go b/api/models/deployment.go index 5a2def62..832ee0eb 100644 --- a/api/models/deployment.go +++ b/api/models/deployment.go @@ -7,6 +7,7 @@ import ( "github.com/equinor/radix-common/utils/slice" "github.com/equinor/radix-operator/pkg/apis/kube" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" @@ -17,8 +18,9 @@ func BuildDeployment( rr *radixv1.RadixRegistration, ra *radixv1.RadixApplication, rd *radixv1.RadixDeployment, deploymentList []appsv1.Deployment, podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, eventList []corev1.Event, rjList []radixv1.RadixJob, certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, + scaledObjects []v1alpha1.ScaledObject, ) *deploymentModels.Deployment { - components := BuildComponents(ra, rd, deploymentList, podList, hpaList, secretList, eventList, certs, certRequests, tlsValidator) + components := BuildComponents(ra, rd, deploymentList, podList, hpaList, secretList, eventList, certs, certRequests, tlsValidator, scaledObjects) // The only error that can be returned from DeploymentBuilder is related to errors from github.com/imdario/mergo // This type of error will only happen if incorrect objects (e.g. incompatible structs) are sent as arguments to mergo, diff --git a/api/models/environment.go b/api/models/environment.go index 5e883af8..f15d0a51 100644 --- a/api/models/environment.go +++ b/api/models/environment.go @@ -8,6 +8,7 @@ import ( "github.com/equinor/radix-api/api/utils/tlsvalidation" "github.com/equinor/radix-common/utils/slice" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" @@ -18,7 +19,8 @@ import ( func BuildEnvironment(rr *radixv1.RadixRegistration, ra *radixv1.RadixApplication, re *radixv1.RadixEnvironment, rdList []radixv1.RadixDeployment, rjList []radixv1.RadixJob, deploymentList []appsv1.Deployment, podList []corev1.Pod, hpaList []autoscalingv2.HorizontalPodAutoscaler, secretList []corev1.Secret, secretProviderClassList []secretsstorev1.SecretProviderClass, eventList []corev1.Event, - certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator) *environmentModels.Environment { + certs []cmv1.Certificate, certRequests []cmv1.CertificateRequest, tlsValidator tlsvalidation.Validator, scaledObjects []v1alpha1.ScaledObject, +) *environmentModels.Environment { var buildFromBranch string var activeDeployment *deploymentModels.Deployment var secrets []secretModels.Secret @@ -28,7 +30,7 @@ func BuildEnvironment(rr *radixv1.RadixRegistration, ra *radixv1.RadixApplicatio } if activeRd, ok := slice.FindFirst(rdList, isActiveDeploymentForAppAndEnv(ra.Name, re.Spec.EnvName)); ok { - activeDeployment = BuildDeployment(rr, ra, &activeRd, deploymentList, podList, hpaList, secretList, eventList, rjList, certs, certRequests, tlsValidator) + activeDeployment = BuildDeployment(rr, ra, &activeRd, deploymentList, podList, hpaList, secretList, eventList, rjList, certs, certRequests, tlsValidator, scaledObjects) secrets = BuildSecrets(secretList, secretProviderClassList, &activeRd) } diff --git a/api/models/horizontal_scaling_summary.go b/api/models/horizontal_scaling_summary.go index 83a29156..35d766c2 100644 --- a/api/models/horizontal_scaling_summary.go +++ b/api/models/horizontal_scaling_summary.go @@ -1,40 +1,157 @@ package models import ( + "fmt" + "regexp" + "strconv" + deploymentModels "github.com/equinor/radix-api/api/deployments/models" "github.com/equinor/radix-api/api/utils/horizontalscaling" "github.com/equinor/radix-api/api/utils/predicate" "github.com/equinor/radix-common/utils/slice" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" ) -func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.HorizontalPodAutoscaler) *deploymentModels.HorizontalScalingSummary { - hpa, ok := slice.FindFirst(hpaList, predicate.IsHpaForComponent(appName, componentName)) +var triggerIndexRegex = regexp.MustCompile(`/^s(\d+)-/`) + +func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.HorizontalPodAutoscaler, scalerList []v1alpha1.ScaledObject) *deploymentModels.HorizontalScalingSummary { + scaler, ok := slice.FindFirst(scalerList, predicate.IsScaledObjectForComponent(appName, componentName)) + if !ok { + return nil + } + hpa, ok := slice.FindFirst(hpaList, func(s autoscalingv2.HorizontalPodAutoscaler) bool { + return s.Name == scaler.Status.HpaName + }) if !ok { return nil } - minReplicas := int32(1) - if hpa.Spec.MinReplicas != nil { - minReplicas = *hpa.Spec.MinReplicas + var minReplicas, maxReplicas, cooldownPeriod, pollingInterval int32 + if scaler.Spec.MinReplicaCount != nil { + minReplicas = *scaler.Spec.MinReplicaCount + } + if scaler.Spec.MaxReplicaCount != nil { + maxReplicas = *scaler.Spec.MaxReplicaCount + } + if scaler.Spec.CooldownPeriod != nil { + cooldownPeriod = *scaler.Spec.CooldownPeriod + } + if scaler.Spec.PollingInterval != nil { + pollingInterval = *scaler.Spec.PollingInterval } - maxReplicas := hpa.Spec.MaxReplicas currentCpuUtil, targetCpuUtil := getHpaMetrics(&hpa, corev1.ResourceCPU) currentMemoryUtil, targetMemoryUtil := getHpaMetrics(&hpa, corev1.ResourceMemory) + var triggers []deploymentModels.HorizontalScalingSummaryTriggerStatus + + // ResourceMetricNames lists resource types, not metric names + for _, resourceType := range scaler.Status.ResourceMetricNames { + trigger, ok := slice.FindFirst(scaler.Spec.Triggers, func(t v1alpha1.ScaleTriggers) bool { + return t.Type == resourceType + }) + if !ok { + continue + } + + triggers = append(triggers, getResourceStatus(corev1.ResourceName(trigger.Type), trigger, &hpa)) + } + + for _, triggerName := range scaler.Status.ExternalMetricNames { + index, err := strconv.Atoi(triggerIndexRegex.FindString(triggerName)) + if err != nil { + continue + } + + trigger := scaler.Spec.Triggers[index] + metricStatus, ok := slice.FindFirst(hpa.Status.CurrentMetrics, func(s autoscalingv2.MetricStatus) bool { + return s.External != nil && s.External.Metric.Name == triggerName + }) + if !ok { + continue + } + health, ok := scaler.Status.Health[triggerName] + if !ok { + continue + } + + switch trigger.Type { + case "cron": + triggers = append(triggers, getCronStatus(trigger, metricStatus, health)) + case "azure-servicebus": + triggers = append(triggers, getAzureServiceBusStatus(trigger, metricStatus, health)) + } + } + hpaSummary := deploymentModels.HorizontalScalingSummary{ MinReplicas: minReplicas, MaxReplicas: maxReplicas, + CooldownPeriod: cooldownPeriod, + PollingInterval: pollingInterval, CurrentCPUUtilizationPercentage: currentCpuUtil, TargetCPUUtilizationPercentage: targetCpuUtil, CurrentMemoryUtilizationPercentage: currentMemoryUtil, TargetMemoryUtilizationPercentage: targetMemoryUtil, + Triggers: triggers, } return &hpaSummary } +func getResourceStatus(triggerType corev1.ResourceName, trigger v1alpha1.ScaleTriggers, hpa *autoscalingv2.HorizontalPodAutoscaler) deploymentModels.HorizontalScalingSummaryTriggerStatus { + var current, target string + + if c := getHpaCurrentMetric(hpa, triggerType); c != nil { + current = strconv.Itoa(int(*c)) + } + if t := horizontalscaling.GetHpaMetric(hpa, triggerType); t != nil { + target = trigger.Metadata["value"] + } + + return deploymentModels.HorizontalScalingSummaryTriggerStatus{ + Name: trigger.Name, + CurrentUtilization: current, + TargetUtilization: target, + Type: string(triggerType), + Error: "", + } +} +func getCronStatus(trigger v1alpha1.ScaleTriggers, metricStatus autoscalingv2.MetricStatus, health v1alpha1.HealthStatus) deploymentModels.HorizontalScalingSummaryTriggerStatus { + var err string + + current := metricStatus.External.Current.AverageValue.String() + target := trigger.Metadata["desiredReplicas"] + + if health.Status != "Happy" { + err = fmt.Sprintf("%s: number of failurs: %d", health.Status, health.NumberOfFailures) + } + return deploymentModels.HorizontalScalingSummaryTriggerStatus{ + Name: trigger.Name, + CurrentUtilization: current, + TargetUtilization: target, + Type: trigger.Type, + Error: err, + } +} +func getAzureServiceBusStatus(trigger v1alpha1.ScaleTriggers, metricStatus autoscalingv2.MetricStatus, health v1alpha1.HealthStatus) deploymentModels.HorizontalScalingSummaryTriggerStatus { + var err string + + current := metricStatus.External.Current.AverageValue.String() + target := trigger.Metadata["messageCount"] + + if health.Status != "Happy" { + err = fmt.Sprintf("%s: number of failurs: %d", health.Status, health.NumberOfFailures) + } + return deploymentModels.HorizontalScalingSummaryTriggerStatus{ + Name: trigger.Name, + CurrentUtilization: current, + TargetUtilization: target, + Type: trigger.Type, + Error: err, + } +} + func getHpaMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { currentResourceUtil := getHpaCurrentMetric(hpa, resourceName) diff --git a/api/utils/predicate/kubernetes.go b/api/utils/predicate/kubernetes.go index 16d56731..cc3bbb3c 100644 --- a/api/utils/predicate/kubernetes.go +++ b/api/utils/predicate/kubernetes.go @@ -3,6 +3,7 @@ package predicate import ( "github.com/equinor/radix-api/api/utils/labelselector" radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" @@ -45,6 +46,12 @@ func IsHpaForComponent(appName, componentName string) func(autoscalingv2.Horizon return selector.Matches(labels.Set(hpa.Labels)) } } +func IsScaledObjectForComponent(appName, componentName string) func(object v1alpha1.ScaledObject) bool { + selector := labels.SelectorFromSet(radixlabels.Merge(radixlabels.ForApplicationName(appName), radixlabels.ForComponentName(componentName))) + return func(object v1alpha1.ScaledObject) bool { + return selector.Matches(labels.Set(object.Labels)) + } +} func IsSecretForSecretStoreProviderClass(secret corev1.Secret) bool { return labels.Set{secretStoreCsiManagedLabel: "true"}.AsSelector().Matches(labels.Set(secret.Labels)) From d387e152efecf495fedf3ac033ea53de7f1f19c2 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Thu, 13 Jun 2024 11:56:23 +0200 Subject: [PATCH 12/24] test responses from scaledobjects and hpa --- api/deployments/component_controller_test.go | 129 ++++++++++++++++--- api/models/horizontal_scaling_summary.go | 96 ++++++-------- 2 files changed, 152 insertions(+), 73 deletions(-) diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index ca834617..8df1e8c7 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -13,6 +13,7 @@ import ( "github.com/equinor/radix-api/api/utils/labelselector" radixhttp "github.com/equinor/radix-common/net/http" radixutils "github.com/equinor/radix-common/utils" + "github.com/equinor/radix-common/utils/pointers" "github.com/equinor/radix-common/utils/slice" "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" @@ -23,6 +24,7 @@ import ( "github.com/stretchr/testify/require" v2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) @@ -563,17 +565,21 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { // Setup testScenarios := []struct { - name string - deploymentName string - minReplicas int32 - maxReplicas int32 - targetCpu *int32 - targetMemory *int32 + name string + deploymentName string + minReplicas int32 + maxReplicas int32 + targetCpu *int32 + targetMemory *int32 + targetCron *int32 + targetAzureServiceBus *int32 }{ - {"targetCpu and targetMemory are nil", "dep1", 2, 6, nil, nil}, - {"targetCpu is nil, targetMemory is non-nil", "dep2", 2, 6, nil, numbers.Int32Ptr(75)}, - {"targetCpu is non-nil, targetMemory is nil", "dep3", 2, 6, numbers.Int32Ptr(60), nil}, - {"targetCpu and targetMemory are non-nil", "dep4", 2, 6, numbers.Int32Ptr(62), numbers.Int32Ptr(79)}, + {"targetCpu and targetMemory are nil", "dep1", 2, 6, nil, nil, nil, nil}, + {"targetCpu is nil, targetMemory is non-nil", "dep2", 2, 6, nil, pointers.Ptr[int32](75), nil, nil}, + {"targetCpu is non-nil, targetMemory is nil", "dep3", 2, 6, pointers.Ptr[int32](60), nil, nil, nil}, + {"targetCpu and targetMemory are non-nil", "dep4", 2, 6, pointers.Ptr[int32](62), pointers.Ptr[int32](79), nil, nil}, + {"Test CRON trigger is found", "dep5", 2, 6, nil, nil, pointers.Ptr[int32](5), nil}, + {"Test Azure trigger is found", "dep6", 2, 6, nil, nil, nil, pointers.Ptr[int32](15)}, } for _, scenario := range testScenarios { @@ -592,7 +598,7 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { require.NoError(t, err) ns := operatorUtils.GetEnvironmentNamespace(anyAppName, "prod") - scaler, hpa := createHorizontalScalingObjects("frontend", numbers.Int32Ptr(scenario.minReplicas), scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory) + scaler, hpa := createHorizontalScalingObjects("frontend", numbers.Int32Ptr(scenario.minReplicas), scenario.maxReplicas, scenario.targetCpu, scenario.targetMemory, scenario.targetCron, scenario.targetAzureServiceBus) _, err = kedaClient.KedaV1alpha1().ScaledObjects(ns).Create(context.Background(), &scaler, metav1.CreateOptions{}) require.NoError(t, err) _, err = client.AutoscalingV2().HorizontalPodAutoscalers(ns).Create(context.Background(), &hpa, metav1.CreateOptions{}) @@ -624,7 +630,7 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { assert.False(t, ok) } else { require.True(t, ok) - assert.Equal(t, string(*scenario.targetMemory), memoryTrigger.TargetUtilization) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetMemory), memoryTrigger.TargetUtilization) assert.Empty(t, memoryTrigger.CurrentUtilization) assert.Empty(t, memoryTrigger.Error) assert.Equal(t, "memory", memoryTrigger.Type) @@ -637,21 +643,48 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { assert.False(t, ok) } else { require.True(t, ok) - assert.Equal(t, string(*scenario.targetCpu), cpuTrigger.TargetUtilization) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetCpu), cpuTrigger.TargetUtilization) assert.Empty(t, cpuTrigger.CurrentUtilization) assert.Empty(t, cpuTrigger.Error) assert.Equal(t, "cpu", cpuTrigger.Type) } - // todo: test CRON trigger and AzureServiceBus + cronTrigger, ok := slice.FindFirst(components[0].HorizontalScalingSummary.Triggers, func(s deploymentModels.HorizontalScalingSummaryTriggerStatus) bool { + return s.Name == "cron" + }) + if scenario.targetCron == nil { + assert.False(t, ok) + } else { + require.True(t, ok) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetCron), cronTrigger.TargetUtilization) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetCron), cronTrigger.CurrentUtilization) + assert.Empty(t, cronTrigger.Error) + assert.Equal(t, "cron", cronTrigger.Type) + } + + azureTrigger, ok := slice.FindFirst(components[0].HorizontalScalingSummary.Triggers, func(s deploymentModels.HorizontalScalingSummaryTriggerStatus) bool { + return s.Name == "azure-servicebus" + }) + if scenario.targetAzureServiceBus == nil { + assert.False(t, ok) + } else { + require.True(t, ok) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetAzureServiceBus), azureTrigger.TargetUtilization) + assert.Equal(t, fmt.Sprintf("%d", *scenario.targetAzureServiceBus), azureTrigger.CurrentUtilization) + assert.Empty(t, azureTrigger.Error) + assert.Equal(t, "azure-servicebus", azureTrigger.Type) + } }) } } -func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32) (v1alpha1.ScaledObject, v2.HorizontalPodAutoscaler) { +func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32, targetCron *int32, targetAzureServiceBus *int32) (v1alpha1.ScaledObject, v2.HorizontalPodAutoscaler) { var triggers []v1alpha1.ScaleTriggers var metrics []v2.MetricSpec resourceMetricNames := []string{} + externalMetricNames := []string{} + health := map[string]v1alpha1.HealthStatus{} + metricStatus := []v2.MetricStatus{} if targetCpu != nil { resourceMetricNames = append(resourceMetricNames, "cpu") @@ -659,7 +692,7 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas Type: "cpu", Name: "cpu", Metadata: map[string]string{ - "value": string(*targetCpu), + "value": fmt.Sprintf("%d", *targetCpu), }, AuthenticationRef: nil, MetricType: "Utilization", @@ -681,7 +714,7 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas Type: "memory", Name: "memory", Metadata: map[string]string{ - "value": string(*targetMemory), + "value": fmt.Sprintf("%d", *targetMemory), }, MetricType: "Utilization", }) @@ -696,6 +729,63 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas }) } + if targetCron != nil { + externalMetricName := fmt.Sprintf("s%d-cron-Europe-Oslo-08xx1-5-016xx1-5", len(triggers)) + externalMetricNames = append(externalMetricNames, externalMetricName) + triggers = append(triggers, v1alpha1.ScaleTriggers{ + Type: "cron", + Name: "cron", + Metadata: map[string]string{ + "end": "0 16 * * 1-5", + "start": "0 8 * * 1-5", + "timezone": "Europe/Oslo", + "desiredReplicas": fmt.Sprintf("%d", *targetCron), + }, + }) + health[externalMetricName] = v1alpha1.HealthStatus{ + NumberOfFailures: pointers.Ptr[int32](0), + Status: "Happy", + } + metricStatus = append(metricStatus, v2.MetricStatus{ + Type: "External", + External: &v2.ExternalMetricStatus{ + Current: v2.MetricValueStatus{ + AverageValue: resource.NewQuantity(int64(*targetCron), resource.DecimalSI), + }, + Metric: v2.MetricIdentifier{ + Name: externalMetricName, + }, + }, + }) + } + + if targetAzureServiceBus != nil { + externalMetricName := fmt.Sprintf("s%d-azure-servicebus-orders", len(triggers)) + externalMetricNames = append(externalMetricNames, externalMetricName) + triggers = append(triggers, v1alpha1.ScaleTriggers{ + Type: "azure-servicebus", + Name: "azure-servicebus", + Metadata: map[string]string{ + "messageCount": fmt.Sprintf("%d", *targetAzureServiceBus), + }, + }) + health[externalMetricName] = v1alpha1.HealthStatus{ + NumberOfFailures: pointers.Ptr[int32](0), + Status: "Happy", + } + metricStatus = append(metricStatus, v2.MetricStatus{ + Type: "External", + External: &v2.ExternalMetricStatus{ + Current: v2.MetricValueStatus{ + AverageValue: resource.NewQuantity(int64(*targetAzureServiceBus), resource.DecimalSI), + }, + Metric: v2.MetricIdentifier{ + Name: externalMetricName, + }, + }, + }) + } + scaler := v1alpha1.ScaledObject{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -708,7 +798,9 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas }, Status: v1alpha1.ScaledObjectStatus{ HpaName: fmt.Sprintf("hpa-%s", name), + Health: health, ResourceMetricNames: resourceMetricNames, + ExternalMetricNames: externalMetricNames, }, } @@ -722,6 +814,9 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas MaxReplicas: maxReplicas, Metrics: metrics, }, + Status: v2.HorizontalPodAutoscalerStatus{ + CurrentMetrics: metricStatus, + }, } return scaler, hpa diff --git a/api/models/horizontal_scaling_summary.go b/api/models/horizontal_scaling_summary.go index 35d766c2..acf71282 100644 --- a/api/models/horizontal_scaling_summary.go +++ b/api/models/horizontal_scaling_summary.go @@ -14,7 +14,7 @@ import ( corev1 "k8s.io/api/core/v1" ) -var triggerIndexRegex = regexp.MustCompile(`/^s(\d+)-/`) +var triggerIndexRegex = regexp.MustCompile(`^s(\d+)-`) func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.HorizontalPodAutoscaler, scalerList []v1alpha1.ScaledObject) *deploymentModels.HorizontalScalingSummary { scaler, ok := slice.FindFirst(scalerList, predicate.IsScaledObjectForComponent(appName, componentName)) @@ -49,40 +49,29 @@ func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.Horizo // ResourceMetricNames lists resource types, not metric names for _, resourceType := range scaler.Status.ResourceMetricNames { - trigger, ok := slice.FindFirst(scaler.Spec.Triggers, func(t v1alpha1.ScaleTriggers) bool { + var trigger v1alpha1.ScaleTriggers + + if trigger, ok = slice.FindFirst(scaler.Spec.Triggers, func(t v1alpha1.ScaleTriggers) bool { return t.Type == resourceType - }) - if !ok { + }); !ok { continue } - triggers = append(triggers, getResourceStatus(corev1.ResourceName(trigger.Type), trigger, &hpa)) + triggers = append(triggers, getResourceMetricStatus(hpa, trigger)) } for _, triggerName := range scaler.Status.ExternalMetricNames { - index, err := strconv.Atoi(triggerIndexRegex.FindString(triggerName)) - if err != nil { - continue - } - - trigger := scaler.Spec.Triggers[index] - metricStatus, ok := slice.FindFirst(hpa.Status.CurrentMetrics, func(s autoscalingv2.MetricStatus) bool { - return s.External != nil && s.External.Metric.Name == triggerName - }) - if !ok { + match := triggerIndexRegex.FindStringSubmatch(triggerName) + if len(match) != 2 { continue } - health, ok := scaler.Status.Health[triggerName] - if !ok { + index, err := strconv.Atoi(match[1]) + if err != nil { continue } - switch trigger.Type { - case "cron": - triggers = append(triggers, getCronStatus(trigger, metricStatus, health)) - case "azure-servicebus": - triggers = append(triggers, getAzureServiceBusStatus(trigger, metricStatus, health)) - } + trigger := scaler.Spec.Triggers[index] + triggers = append(triggers, getExternalMetricStatus(hpa, triggerName, scaler, trigger)) } hpaSummary := deploymentModels.HorizontalScalingSummary{ @@ -99,57 +88,52 @@ func GetHpaSummary(appName, componentName string, hpaList []autoscalingv2.Horizo return &hpaSummary } -func getResourceStatus(triggerType corev1.ResourceName, trigger v1alpha1.ScaleTriggers, hpa *autoscalingv2.HorizontalPodAutoscaler) deploymentModels.HorizontalScalingSummaryTriggerStatus { - var current, target string - - if c := getHpaCurrentMetric(hpa, triggerType); c != nil { - current = strconv.Itoa(int(*c)) - } - if t := horizontalscaling.GetHpaMetric(hpa, triggerType); t != nil { - target = trigger.Metadata["value"] +func getResourceMetricStatus(hpa autoscalingv2.HorizontalPodAutoscaler, trigger v1alpha1.ScaleTriggers) deploymentModels.HorizontalScalingSummaryTriggerStatus { + var current string + if metricStatus, ok := slice.FindFirst(hpa.Status.CurrentMetrics, func(s autoscalingv2.MetricStatus) bool { + return s.Resource != nil && s.Resource.Name.String() == trigger.Type + }); ok && metricStatus.Resource != nil { + current = fmt.Sprintf("%d", *metricStatus.Resource.Current.AverageUtilization) } - return deploymentModels.HorizontalScalingSummaryTriggerStatus{ + status := deploymentModels.HorizontalScalingSummaryTriggerStatus{ Name: trigger.Name, CurrentUtilization: current, - TargetUtilization: target, - Type: string(triggerType), + TargetUtilization: trigger.Metadata["value"], + Type: trigger.Type, Error: "", } + return status } -func getCronStatus(trigger v1alpha1.ScaleTriggers, metricStatus autoscalingv2.MetricStatus, health v1alpha1.HealthStatus) deploymentModels.HorizontalScalingSummaryTriggerStatus { - var err string - current := metricStatus.External.Current.AverageValue.String() - target := trigger.Metadata["desiredReplicas"] +func getExternalMetricStatus(hpa autoscalingv2.HorizontalPodAutoscaler, triggerName string, scaler v1alpha1.ScaledObject, trigger v1alpha1.ScaleTriggers) deploymentModels.HorizontalScalingSummaryTriggerStatus { + var current, target, errStr string - if health.Status != "Happy" { - err = fmt.Sprintf("%s: number of failurs: %d", health.Status, health.NumberOfFailures) - } - return deploymentModels.HorizontalScalingSummaryTriggerStatus{ - Name: trigger.Name, - CurrentUtilization: current, - TargetUtilization: target, - Type: trigger.Type, - Error: err, + if metricStatus, ok := slice.FindFirst(hpa.Status.CurrentMetrics, func(s autoscalingv2.MetricStatus) bool { + return s.External != nil && s.External.Metric.Name == triggerName + }); ok && metricStatus.External != nil { + current = metricStatus.External.Current.AverageValue.String() } -} -func getAzureServiceBusStatus(trigger v1alpha1.ScaleTriggers, metricStatus autoscalingv2.MetricStatus, health v1alpha1.HealthStatus) deploymentModels.HorizontalScalingSummaryTriggerStatus { - var err string - current := metricStatus.External.Current.AverageValue.String() - target := trigger.Metadata["messageCount"] + if health, ok := scaler.Status.Health[triggerName]; ok && health.Status != "Happy" { + errStr = fmt.Sprintf("%s: number of failurs: %d", health.Status, *health.NumberOfFailures) + } - if health.Status != "Happy" { - err = fmt.Sprintf("%s: number of failurs: %d", health.Status, health.NumberOfFailures) + switch trigger.Type { + case "cron": + target = trigger.Metadata["desiredReplicas"] + case "azure-servicebus": + target = trigger.Metadata["messageCount"] } - return deploymentModels.HorizontalScalingSummaryTriggerStatus{ + + status := deploymentModels.HorizontalScalingSummaryTriggerStatus{ Name: trigger.Name, CurrentUtilization: current, TargetUtilization: target, Type: trigger.Type, - Error: err, + Error: errStr, } + return status } func getHpaMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, resourceName corev1.ResourceName) (*int32, *int32) { From 0c55bd47f5f534f64ee3a66e61e1b71b9f09a27d Mon Sep 17 00:00:00 2001 From: Richard87 Date: Thu, 13 Jun 2024 12:04:27 +0200 Subject: [PATCH 13/24] fix unused import --- api/deployments/component_handler.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index b84802ca..bd9ddf83 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -8,7 +8,6 @@ import ( "github.com/equinor/radix-api/api/kubequery" "github.com/equinor/radix-api/api/models" "github.com/equinor/radix-api/api/utils/event" - "github.com/equinor/radix-api/api/utils/horizontalscaling" "github.com/equinor/radix-api/api/utils/labelselector" radixutils "github.com/equinor/radix-common/utils" "github.com/equinor/radix-common/utils/slice" From 26a99a49a1d60a9159f73771785d7bf1e1e43b4f Mon Sep 17 00:00:00 2001 From: Richard87 Date: Thu, 13 Jun 2024 12:06:49 +0200 Subject: [PATCH 14/24] update swaggerui --- swaggerui/html/swagger.json | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/swaggerui/html/swagger.json b/swaggerui/html/swagger.json index 011aefc8..6a0f26e0 100644 --- a/swaggerui/html/swagger.json +++ b/swaggerui/html/swagger.json @@ -6301,6 +6301,13 @@ "description": "HorizontalScalingSummary describe the summary of horizontal scaling of a component", "type": "object", "properties": { + "cooldownPeriod": { + "description": "CooldownPeriod in seconds. From radixconfig.yaml", + "type": "integer", + "format": "int32", + "x-go-name": "CooldownPeriod", + "example": 300 + }, "currentCPUUtilizationPercentage": { "description": "Component current average CPU utilization over all pods, represented as a percentage of requested CPU", "type": "integer", @@ -6329,6 +6336,13 @@ "x-go-name": "MinReplicas", "example": 2 }, + "pollingInterval": { + "description": "PollingInterval in seconds. From radixconfig.yaml", + "type": "integer", + "format": "int32", + "x-go-name": "PollingInterval", + "example": 30 + }, "targetCPUUtilizationPercentage": { "description": "Component target average CPU utilization over all pods", "type": "integer", @@ -6342,6 +6356,46 @@ "format": "int32", "x-go-name": "TargetMemoryUtilizationPercentage", "example": 80 + }, + "triggers": { + "description": "Triggers lists status of all triggers found in radixconfig.yaml", + "type": "array", + "items": { + "$ref": "#/definitions/HorizontalScalingSummaryTriggerStatus" + }, + "x-go-name": "Triggers", + "example": "30" + } + }, + "x-go-package": "github.com/equinor/radix-api/api/deployments/models" + }, + "HorizontalScalingSummaryTriggerStatus": { + "type": "object", + "properties": { + "current_utilization": { + "description": "CurrentUtilization is the last measured utilization", + "type": "string", + "x-go-name": "CurrentUtilization" + }, + "error": { + "description": "Error contains short description if trigger have problems", + "type": "string", + "x-go-name": "Error" + }, + "name": { + "description": "Name of trigger", + "type": "string", + "x-go-name": "Name" + }, + "target_utilization": { + "description": "TargetUtilization is the average target across replicas", + "type": "string", + "x-go-name": "TargetUtilization" + }, + "type": { + "description": "Type of trigger", + "type": "string", + "x-go-name": "Type" } }, "x-go-package": "github.com/equinor/radix-api/api/deployments/models" From b1004456fc7b940649a41cab62b006da95d0c5c6 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Thu, 13 Jun 2024 12:51:57 +0200 Subject: [PATCH 15/24] remove unused function --- api/deployments/component_controller_test.go | 41 -------------------- 1 file changed, 41 deletions(-) diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index 1b90af78..8df1e8c7 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -822,47 +822,6 @@ func createHorizontalScalingObjects(name string, minReplicas *int32, maxReplicas return scaler, hpa } -func createAutoscaler(name string, minReplicas *int32, maxReplicas int32, targetCpu *int32, targetMemory *int32) v2.HorizontalPodAutoscaler { - var metrics []v2.MetricSpec - - if targetCpu != nil { - metrics = append(metrics, v2.MetricSpec{ - Resource: &v2.ResourceMetricSource{ - Name: "cpu", - Target: v2.MetricTarget{ - Type: "cpu", - AverageUtilization: targetCpu, - }, - }, - }) - } - - if targetMemory != nil { - metrics = append(metrics, v2.MetricSpec{ - Resource: &v2.ResourceMetricSource{ - Name: "memory", - Target: v2.MetricTarget{ - Type: "memory", - AverageUtilization: targetMemory, - }, - }, - }) - } - - autoscaler := v2.HorizontalPodAutoscaler{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Labels: labelselector.ForComponent(anyAppName, "frontend"), - }, - Spec: v2.HorizontalPodAutoscalerSpec{ - MinReplicas: minReplicas, - MaxReplicas: maxReplicas, - Metrics: metrics, - }, - } - return autoscaler -} - func TestGetComponents_WithIdentity(t *testing.T) { // Setup commonTestUtils, controllerTestUtils, client, radixclient, kedaClient, promclient, secretProviderClient, certClient := setupTest(t) From b2db3489c2f3f7a350bf946ba8c5312a6573b8dc Mon Sep 17 00:00:00 2001 From: Richard Hagen Date: Thu, 13 Jun 2024 15:31:03 +0200 Subject: [PATCH 16/24] Update api/utils/logs/roundtrip_logger.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nils Gustav Stråbø <65334626+nilsgstrabo@users.noreply.github.com> --- api/utils/logs/roundtrip_logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go index 5097b839..c615193b 100644 --- a/api/utils/logs/roundtrip_logger.go +++ b/api/utils/logs/roundtrip_logger.go @@ -47,7 +47,7 @@ func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { ev. Str("method", r.Method). Stringer("path", r.URL). - Int64("ellapsed_ms", time.Since(start).Milliseconds()). + Int64("elapsed_ms", time.Since(start).Milliseconds()). Msg(http.StatusText(resp.StatusCode)) return resp, err }) From 9f43d5df6c742ae2c5a0645c628a6886cc144242 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 09:32:02 +0200 Subject: [PATCH 17/24] debugging --- .vscode/launch.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d39f06fd..63fdd4e0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,10 +14,10 @@ "RADIX_CONTAINER_REGISTRY":"radixdev.azurecr.io", "PIPELINE_IMG_TAG": "master-latest", "TEKTON_IMG_TAG": "main-latest", - "K8S_API_HOST": "https://weekly-14-clusters-16ede4-97pzjkre.hcp.northeurope.azmk8s.io", + "K8S_API_HOST": "https://weekly-24-clusters-dev-16ede4-uk527vqt.hcp.northeurope.azmk8s.io:443", "RADIX_CLUSTER_TYPE": "development", "RADIX_DNS_ZONE": "dev.radix.equinor.com", - "RADIX_CLUSTERNAME": "weekly-14", + "RADIX_CLUSTERNAME": "weekly-24", "RADIX_ACTIVE_CLUSTER_EGRESS_IPS": "104.45.84.1", "REQUIRE_APP_CONFIGURATION_ITEM": "true", "REQUIRE_APP_AD_GROUPS": "true", From 1e97f25b6b2f32f8e49cd9265b0e8770051f2ba2 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 09:50:45 +0200 Subject: [PATCH 18/24] handle client err seperatley from request error --- api/utils/logs/roundtrip_logger.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go index c615193b..b1865eb1 100644 --- a/api/utils/logs/roundtrip_logger.go +++ b/api/utils/logs/roundtrip_logger.go @@ -24,15 +24,29 @@ type WithFunc func(e *zerolog.Event) func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { return func(t http.RoundTripper) http.RoundTripper { return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { - start := time.Now() - logger := log.Ctx(r.Context()) + logger := log.Ctx(r.Context()).With(). + Str("method", r.Method). + Stringer("path", r.URL). + Logger() + start := time.Now() resp, err := t.RoundTrip(r) + elapsedMs := time.Since(start).Milliseconds() + + if err != nil { + errEvent := logger.Error().Err(err) + for _, fn := range fns { + errEvent.Func(fn) + } + errEvent. + Int64("elapsed_ms", elapsedMs). + Msg("Failed to send request") + + return resp, err + } var ev *zerolog.Event switch { - case err != nil: - logger.Error().Err(err) case resp.StatusCode >= 400 && resp.StatusCode <= 499: ev = logger.Warn() case resp.StatusCode >= 500: @@ -44,11 +58,7 @@ func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { for _, fn := range fns { ev.Func(fn) } - ev. - Str("method", r.Method). - Stringer("path", r.URL). - Int64("elapsed_ms", time.Since(start).Milliseconds()). - Msg(http.StatusText(resp.StatusCode)) + ev.Int64("elapsed_ms", elapsedMs).Int("status_code", resp.StatusCode).Msg(http.StatusText(resp.StatusCode)) return resp, err }) } From 3ee06de73ef1c5cedc025a296b97401c37131656 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 10:06:19 +0200 Subject: [PATCH 19/24] move getComponentStateFromSpec to environments package --- api/deployments/component_handler.go | 310 ----------------- api/environments/component_spec.go | 323 ++++++++++++++++++ .../component_spec_test.go} | 4 +- api/environments/environment_handler.go | 2 +- 4 files changed, 325 insertions(+), 314 deletions(-) create mode 100644 api/environments/component_spec.go rename api/{deployments/component_handler_test.go => environments/component_spec_test.go} (99%) diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index bd9ddf83..599e29e9 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -7,22 +7,9 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" "github.com/equinor/radix-api/api/kubequery" "github.com/equinor/radix-api/api/models" - "github.com/equinor/radix-api/api/utils/event" - "github.com/equinor/radix-api/api/utils/labelselector" - radixutils "github.com/equinor/radix-common/utils" - "github.com/equinor/radix-common/utils/slice" - "github.com/equinor/radix-operator/pkg/apis/defaults" - "github.com/equinor/radix-operator/pkg/apis/deployment" "github.com/equinor/radix-operator/pkg/apis/kube" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" - crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" - "github.com/kedacore/keda/v2/apis/keda/v1alpha1" - autoscalingv2 "k8s.io/api/autoscaling/v2" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - "k8s.io/client-go/kubernetes" ) // GetComponentsForDeployment Gets a list of components for a given deployment @@ -90,300 +77,3 @@ func (deploy *deployHandler) GetComponentsForDeploymentName(ctx context.Context, return nil, deploymentModels.NonExistingDeployment(nil, deploymentName) } - -// GetComponentStateFromSpec Returns a component with the current state -func GetComponentStateFromSpec( - ctx context.Context, - kubeClient kubernetes.Interface, - appName string, - deployment *deploymentModels.DeploymentSummary, - deploymentStatus v1.RadixDeployStatus, - environmentConfig v1.RadixCommonEnvironmentConfig, - component v1.RadixCommonDeployComponent, - hpas []autoscalingv2.HorizontalPodAutoscaler, - scaledObjects []v1alpha1.ScaledObject, -) (*deploymentModels.Component, error) { - - var componentPodNames []string - var environmentVariables map[string]string - var replicaSummaryList []deploymentModels.ReplicaSummary - var auxResource deploymentModels.AuxiliaryResource - var horizontalScalingSummary *deploymentModels.HorizontalScalingSummary - - envNs := crdUtils.GetEnvironmentNamespace(appName, deployment.Environment) - status := deploymentModels.ConsistentComponent - - if deployment.ActiveTo == "" { - // current active deployment - we get existing pods - componentPods, err := getComponentPodsByNamespace(ctx, kubeClient, envNs, component.GetName()) - if err != nil { - return nil, err - } - componentPodNames = getPodNames(componentPods) - environmentVariables = getRadixEnvironmentVariables(componentPods) - eventList, err := kubequery.GetEventsForEnvironment(ctx, kubeClient, appName, deployment.Environment) - if err != nil { - return nil, err - } - lastEventWarnings := event.ConvertToEventWarnings(eventList) - replicaSummaryList = getReplicaSummaryList(componentPods, lastEventWarnings) - auxResource, err = getAuxiliaryResources(ctx, kubeClient, appName, component, envNs) - if err != nil { - return nil, err - } - - status, err = getStatusOfActiveDeployment(component, - deploymentStatus, environmentConfig, componentPods) - if err != nil { - return nil, err - } - } - - componentBuilder := deploymentModels.NewComponentBuilder() - if jobComponent, ok := component.(*v1.RadixDeployJobComponent); ok { - componentBuilder.WithSchedulerPort(jobComponent.SchedulerPort) - if jobComponent.Payload != nil { - componentBuilder.WithScheduledJobPayloadPath(jobComponent.Payload.Path) - } - componentBuilder.WithNotifications(jobComponent.Notifications) - } - - if component.GetType() == v1.RadixComponentTypeComponent { - horizontalScalingSummary = models.GetHpaSummary(appName, component.GetName(), hpas, scaledObjects) - } - - return componentBuilder. - WithComponent(component). - WithStatus(status). - WithPodNames(componentPodNames). - WithReplicaSummaryList(replicaSummaryList). - WithRadixEnvironmentVariables(environmentVariables). - WithAuxiliaryResource(auxResource). - WithHorizontalScalingSummary(horizontalScalingSummary). - BuildComponent() -} - -func getPodNames(pods []corev1.Pod) []string { - var names []string - for _, pod := range pods { - names = append(names, pod.GetName()) - } - return names -} - -func getComponentPodsByNamespace(ctx context.Context, client kubernetes.Interface, envNs, componentName string) ([]corev1.Pod, error) { - var componentPods []corev1.Pod - pods, err := client.CoreV1().Pods(envNs).List(ctx, metav1.ListOptions{ - LabelSelector: getLabelSelectorForComponentPods(componentName).String(), - }) - if err != nil { - return nil, err - } - - for _, pod := range pods.Items { - pod := pod - - // A previous version of the job-scheduler added the "radix-job-type" label to job pods. - // For backward compatibility, we need to ignore these pods in the list of pods returned for a component - if _, isScheduledJobPod := pod.GetLabels()[kube.RadixJobTypeLabel]; isScheduledJobPod { - continue - } - - // Ignore pods related to jobs created from RadixBatch - if _, isRadixBatchJobPod := pod.GetLabels()[kube.RadixBatchNameLabel]; isRadixBatchJobPod { - continue - } - - componentPods = append(componentPods, pod) - } - - return componentPods, nil -} - -func getLabelSelectorForComponentPods(componentName string) labels.Selector { - componentNameRequirement, _ := labels.NewRequirement(kube.RadixComponentLabel, selection.Equals, []string{componentName}) - notJobAuxRequirement, _ := labels.NewRequirement(kube.RadixPodIsJobAuxObjectLabel, selection.DoesNotExist, []string{}) - return labels.NewSelector().Add(*componentNameRequirement, *notJobAuxRequirement) -} - -func runningReplicaDiffersFromConfig(environmentConfig v1.RadixCommonEnvironmentConfig, actualPods []corev1.Pod) bool { - actualPodsLength := len(actualPods) - if radixutils.IsNil(environmentConfig) { - return actualPodsLength != deployment.DefaultReplicas - } - // No HPA config - if environmentConfig.GetHorizontalScaling() == nil { - if environmentConfig.GetReplicas() != nil { - return actualPodsLength != *environmentConfig.GetReplicas() - } - return actualPodsLength != deployment.DefaultReplicas - } - // With HPA config - if environmentConfig.GetReplicas() != nil && *environmentConfig.GetReplicas() == 0 { - return actualPodsLength != *environmentConfig.GetReplicas() - } - if environmentConfig.GetHorizontalScaling().MinReplicas != nil { - return actualPodsLength < int(*environmentConfig.GetHorizontalScaling().MinReplicas) || - actualPodsLength > int(environmentConfig.GetHorizontalScaling().MaxReplicas) - } - return actualPodsLength < deployment.DefaultReplicas || - actualPodsLength > int(environmentConfig.GetHorizontalScaling().MaxReplicas) -} - -func runningReplicaDiffersFromSpec(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { - actualPodsLength := len(actualPods) - // No HPA config - if component.GetHorizontalScaling() == nil { - if component.GetReplicas() != nil { - return actualPodsLength != *component.GetReplicas() - } - return actualPodsLength != deployment.DefaultReplicas - } - // With HPA config - if component.GetReplicas() != nil && *component.GetReplicas() == 0 { - return actualPodsLength != *component.GetReplicas() - } - if component.GetHorizontalScaling().MinReplicas != nil { - return actualPodsLength < int(*component.GetHorizontalScaling().MinReplicas) || - actualPodsLength > int(component.GetHorizontalScaling().MaxReplicas) - } - return actualPodsLength < deployment.DefaultReplicas || - actualPodsLength > int(component.GetHorizontalScaling().MaxReplicas) -} - -func getRadixEnvironmentVariables(pods []corev1.Pod) map[string]string { - radixEnvironmentVariables := make(map[string]string) - - for _, pod := range pods { - for _, container := range pod.Spec.Containers { - for _, envVariable := range container.Env { - if crdUtils.IsRadixEnvVar(envVariable.Name) { - radixEnvironmentVariables[envVariable.Name] = envVariable.Value - } - } - } - } - - return radixEnvironmentVariables -} - -func getReplicaSummaryList(pods []corev1.Pod, lastEventWarnings event.LastEventWarnings) []deploymentModels.ReplicaSummary { - return slice.Map(pods, func(pod corev1.Pod) deploymentModels.ReplicaSummary { - return deploymentModels.GetReplicaSummary(pod, lastEventWarnings[pod.GetName()]) - }) -} - -func getAuxiliaryResources(ctx context.Context, kubeClient kubernetes.Interface, appName string, component v1.RadixCommonDeployComponent, envNamespace string) (auxResource deploymentModels.AuxiliaryResource, err error) { - if auth := component.GetAuthentication(); component.IsPublic() && auth != nil && auth.OAuth2 != nil { - auxResource.OAuth2, err = getOAuth2AuxiliaryResource(ctx, kubeClient, appName, component.GetName(), envNamespace) - if err != nil { - return - } - } - - return -} - -func getOAuth2AuxiliaryResource(ctx context.Context, kubeClient kubernetes.Interface, appName, componentName, envNamespace string) (*deploymentModels.OAuth2AuxiliaryResource, error) { - var oauth2Resource deploymentModels.OAuth2AuxiliaryResource - oauthDeployment, err := getAuxiliaryResourceDeployment(ctx, kubeClient, appName, componentName, envNamespace, defaults.OAuthProxyAuxiliaryComponentType) - if err != nil { - return nil, err - } - if oauthDeployment != nil { - oauth2Resource.Deployment = *oauthDeployment - } - - return &oauth2Resource, nil -} - -func getAuxiliaryResourceDeployment(ctx context.Context, kubeClient kubernetes.Interface, appName, componentName, envNamespace, auxType string) (*deploymentModels.AuxiliaryResourceDeployment, error) { - var auxResourceDeployment deploymentModels.AuxiliaryResourceDeployment - - selector := labelselector.ForAuxiliaryResource(appName, componentName, auxType).String() - deployments, err := kubeClient.AppsV1().Deployments(envNamespace).List(ctx, metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return nil, err - } - if len(deployments.Items) == 0 { - auxResourceDeployment.Status = deploymentModels.ComponentReconciling.String() - return &auxResourceDeployment, nil - } - deployment := deployments.Items[0] - - pods, err := kubeClient.CoreV1().Pods(envNamespace).List(ctx, metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return nil, err - } - auxResourceDeployment.ReplicaList = getReplicaSummaryList(pods.Items, nil) - auxResourceDeployment.Status = deploymentModels.ComponentStatusFromDeployment(&deployment).String() - return &auxResourceDeployment, nil -} - -func runningReplicaIsOutdated(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { - switch component.GetType() { - case v1.RadixComponentTypeComponent: - return runningComponentReplicaIsOutdated(component, actualPods) - case v1.RadixComponentTypeJob: - return false - default: - return false - } -} - -func runningComponentReplicaIsOutdated(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { - // Check if running component's image is not the same as active deployment image tag and that active rd image is equal to 'starting' component image tag - componentIsInconsistent := false - for _, pod := range actualPods { - if pod.DeletionTimestamp != nil { - // Pod is in termination phase - continue - } - for _, container := range pod.Spec.Containers { - if container.Image != component.GetImage() { - // Container is running an outdated image - componentIsInconsistent = true - } - } - } - - return componentIsInconsistent -} - -func getStatusOfActiveDeployment( - component v1.RadixCommonDeployComponent, - deploymentStatus v1.RadixDeployStatus, - environmentConfig v1.RadixCommonEnvironmentConfig, - pods []corev1.Pod) (deploymentModels.ComponentStatus, error) { - - if component.GetType() == v1.RadixComponentTypeComponent { - if runningReplicaDiffersFromConfig(environmentConfig, pods) && - !runningReplicaDiffersFromSpec(component, pods) && - len(pods) == 0 { - return deploymentModels.StoppedComponent, nil - } - if runningReplicaDiffersFromSpec(component, pods) { - return deploymentModels.ComponentReconciling, nil - } - } else if component.GetType() == v1.RadixComponentTypeJob { - if len(pods) == 0 { - return deploymentModels.StoppedComponent, nil - } - } - if runningReplicaIsOutdated(component, pods) { - return deploymentModels.ComponentOutdated, nil - } - restarted := component.GetEnvironmentVariables()[defaults.RadixRestartEnvironmentVariable] - if strings.EqualFold(restarted, "") { - return deploymentModels.ConsistentComponent, nil - } - restartedTime, err := radixutils.ParseTimestamp(restarted) - if err != nil { - return deploymentModels.ConsistentComponent, err - } - reconciledTime := deploymentStatus.Reconciled - if reconciledTime.IsZero() || restartedTime.After(reconciledTime.Time) { - return deploymentModels.ComponentRestarting, nil - } - return deploymentModels.ConsistentComponent, nil -} diff --git a/api/environments/component_spec.go b/api/environments/component_spec.go new file mode 100644 index 00000000..f10488e5 --- /dev/null +++ b/api/environments/component_spec.go @@ -0,0 +1,323 @@ +package environments + +import ( + "context" + "strings" + + deploymentModels "github.com/equinor/radix-api/api/deployments/models" + "github.com/equinor/radix-api/api/kubequery" + "github.com/equinor/radix-api/api/models" + "github.com/equinor/radix-api/api/utils/event" + "github.com/equinor/radix-api/api/utils/labelselector" + radixutils "github.com/equinor/radix-common/utils" + "github.com/equinor/radix-common/utils/slice" + "github.com/equinor/radix-operator/pkg/apis/defaults" + "github.com/equinor/radix-operator/pkg/apis/deployment" + "github.com/equinor/radix-operator/pkg/apis/kube" + v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/kedacore/keda/v2/apis/keda/v1alpha1" + autoscalingv2 "k8s.io/api/autoscaling/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/client-go/kubernetes" +) + +// getComponentStateFromSpec Returns a component with the current state +func getComponentStateFromSpec( + ctx context.Context, + kubeClient kubernetes.Interface, + appName string, + deployment *deploymentModels.DeploymentSummary, + deploymentStatus v1.RadixDeployStatus, + environmentConfig v1.RadixCommonEnvironmentConfig, + component v1.RadixCommonDeployComponent, + hpas []autoscalingv2.HorizontalPodAutoscaler, + scaledObjects []v1alpha1.ScaledObject, +) (*deploymentModels.Component, error) { + + var componentPodNames []string + var environmentVariables map[string]string + var replicaSummaryList []deploymentModels.ReplicaSummary + var auxResource deploymentModels.AuxiliaryResource + var horizontalScalingSummary *deploymentModels.HorizontalScalingSummary + + envNs := crdUtils.GetEnvironmentNamespace(appName, deployment.Environment) + status := deploymentModels.ConsistentComponent + + if deployment.ActiveTo == "" { + // current active deployment - we get existing pods + componentPods, err := getComponentPodsByNamespace(ctx, kubeClient, envNs, component.GetName()) + if err != nil { + return nil, err + } + componentPodNames = getPodNames(componentPods) + environmentVariables = getRadixEnvironmentVariables(componentPods) + eventList, err := kubequery.GetEventsForEnvironment(ctx, kubeClient, appName, deployment.Environment) + if err != nil { + return nil, err + } + lastEventWarnings := event.ConvertToEventWarnings(eventList) + replicaSummaryList = getReplicaSummaryList(componentPods, lastEventWarnings) + auxResource, err = getAuxiliaryResources(ctx, kubeClient, appName, component, envNs) + if err != nil { + return nil, err + } + + status, err = getStatusOfActiveDeployment(component, + deploymentStatus, environmentConfig, componentPods) + if err != nil { + return nil, err + } + } + + componentBuilder := deploymentModels.NewComponentBuilder() + if jobComponent, ok := component.(*v1.RadixDeployJobComponent); ok { + componentBuilder.WithSchedulerPort(jobComponent.SchedulerPort) + if jobComponent.Payload != nil { + componentBuilder.WithScheduledJobPayloadPath(jobComponent.Payload.Path) + } + componentBuilder.WithNotifications(jobComponent.Notifications) + } + + if component.GetType() == v1.RadixComponentTypeComponent { + horizontalScalingSummary = models.GetHpaSummary(appName, component.GetName(), hpas, scaledObjects) + } + + return componentBuilder. + WithComponent(component). + WithStatus(status). + WithPodNames(componentPodNames). + WithReplicaSummaryList(replicaSummaryList). + WithRadixEnvironmentVariables(environmentVariables). + WithAuxiliaryResource(auxResource). + WithHorizontalScalingSummary(horizontalScalingSummary). + BuildComponent() +} + +func getPodNames(pods []corev1.Pod) []string { + var names []string + for _, pod := range pods { + names = append(names, pod.GetName()) + } + return names +} + +func getComponentPodsByNamespace(ctx context.Context, client kubernetes.Interface, envNs, componentName string) ([]corev1.Pod, error) { + var componentPods []corev1.Pod + pods, err := client.CoreV1().Pods(envNs).List(ctx, metav1.ListOptions{ + LabelSelector: getLabelSelectorForComponentPods(componentName).String(), + }) + if err != nil { + return nil, err + } + + for _, pod := range pods.Items { + pod := pod + + // A previous version of the job-scheduler added the "radix-job-type" label to job pods. + // For backward compatibility, we need to ignore these pods in the list of pods returned for a component + if _, isScheduledJobPod := pod.GetLabels()[kube.RadixJobTypeLabel]; isScheduledJobPod { + continue + } + + // Ignore pods related to jobs created from RadixBatch + if _, isRadixBatchJobPod := pod.GetLabels()[kube.RadixBatchNameLabel]; isRadixBatchJobPod { + continue + } + + componentPods = append(componentPods, pod) + } + + return componentPods, nil +} + +func getLabelSelectorForComponentPods(componentName string) labels.Selector { + componentNameRequirement, _ := labels.NewRequirement(kube.RadixComponentLabel, selection.Equals, []string{componentName}) + notJobAuxRequirement, _ := labels.NewRequirement(kube.RadixPodIsJobAuxObjectLabel, selection.DoesNotExist, []string{}) + return labels.NewSelector().Add(*componentNameRequirement, *notJobAuxRequirement) +} + +func runningReplicaDiffersFromConfig(environmentConfig v1.RadixCommonEnvironmentConfig, actualPods []corev1.Pod) bool { + actualPodsLength := len(actualPods) + if radixutils.IsNil(environmentConfig) { + return actualPodsLength != deployment.DefaultReplicas + } + // No HPA config + if environmentConfig.GetHorizontalScaling() == nil { + if environmentConfig.GetReplicas() != nil { + return actualPodsLength != *environmentConfig.GetReplicas() + } + return actualPodsLength != deployment.DefaultReplicas + } + // With HPA config + if environmentConfig.GetReplicas() != nil && *environmentConfig.GetReplicas() == 0 { + return actualPodsLength != *environmentConfig.GetReplicas() + } + if environmentConfig.GetHorizontalScaling().MinReplicas != nil { + return actualPodsLength < int(*environmentConfig.GetHorizontalScaling().MinReplicas) || + actualPodsLength > int(environmentConfig.GetHorizontalScaling().MaxReplicas) + } + return actualPodsLength < deployment.DefaultReplicas || + actualPodsLength > int(environmentConfig.GetHorizontalScaling().MaxReplicas) +} + +func runningReplicaDiffersFromSpec(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { + actualPodsLength := len(actualPods) + // No HPA config + if component.GetHorizontalScaling() == nil { + if component.GetReplicas() != nil { + return actualPodsLength != *component.GetReplicas() + } + return actualPodsLength != deployment.DefaultReplicas + } + // With HPA config + if component.GetReplicas() != nil && *component.GetReplicas() == 0 { + return actualPodsLength != *component.GetReplicas() + } + if component.GetHorizontalScaling().MinReplicas != nil { + return actualPodsLength < int(*component.GetHorizontalScaling().MinReplicas) || + actualPodsLength > int(component.GetHorizontalScaling().MaxReplicas) + } + return actualPodsLength < deployment.DefaultReplicas || + actualPodsLength > int(component.GetHorizontalScaling().MaxReplicas) +} + +func getRadixEnvironmentVariables(pods []corev1.Pod) map[string]string { + radixEnvironmentVariables := make(map[string]string) + + for _, pod := range pods { + for _, container := range pod.Spec.Containers { + for _, envVariable := range container.Env { + if crdUtils.IsRadixEnvVar(envVariable.Name) { + radixEnvironmentVariables[envVariable.Name] = envVariable.Value + } + } + } + } + + return radixEnvironmentVariables +} + +func getReplicaSummaryList(pods []corev1.Pod, lastEventWarnings event.LastEventWarnings) []deploymentModels.ReplicaSummary { + return slice.Map(pods, func(pod corev1.Pod) deploymentModels.ReplicaSummary { + return deploymentModels.GetReplicaSummary(pod, lastEventWarnings[pod.GetName()]) + }) +} + +func getAuxiliaryResources(ctx context.Context, kubeClient kubernetes.Interface, appName string, component v1.RadixCommonDeployComponent, envNamespace string) (auxResource deploymentModels.AuxiliaryResource, err error) { + if auth := component.GetAuthentication(); component.IsPublic() && auth != nil && auth.OAuth2 != nil { + auxResource.OAuth2, err = getOAuth2AuxiliaryResource(ctx, kubeClient, appName, component.GetName(), envNamespace) + if err != nil { + return + } + } + + return +} + +func getOAuth2AuxiliaryResource(ctx context.Context, kubeClient kubernetes.Interface, appName, componentName, envNamespace string) (*deploymentModels.OAuth2AuxiliaryResource, error) { + var oauth2Resource deploymentModels.OAuth2AuxiliaryResource + oauthDeployment, err := getAuxiliaryResourceDeployment(ctx, kubeClient, appName, componentName, envNamespace, defaults.OAuthProxyAuxiliaryComponentType) + if err != nil { + return nil, err + } + if oauthDeployment != nil { + oauth2Resource.Deployment = *oauthDeployment + } + + return &oauth2Resource, nil +} + +func getAuxiliaryResourceDeployment(ctx context.Context, kubeClient kubernetes.Interface, appName, componentName, envNamespace, auxType string) (*deploymentModels.AuxiliaryResourceDeployment, error) { + var auxResourceDeployment deploymentModels.AuxiliaryResourceDeployment + + selector := labelselector.ForAuxiliaryResource(appName, componentName, auxType).String() + deployments, err := kubeClient.AppsV1().Deployments(envNamespace).List(ctx, metav1.ListOptions{LabelSelector: selector}) + if err != nil { + return nil, err + } + if len(deployments.Items) == 0 { + auxResourceDeployment.Status = deploymentModels.ComponentReconciling.String() + return &auxResourceDeployment, nil + } + deployment := deployments.Items[0] + + pods, err := kubeClient.CoreV1().Pods(envNamespace).List(ctx, metav1.ListOptions{LabelSelector: selector}) + if err != nil { + return nil, err + } + auxResourceDeployment.ReplicaList = getReplicaSummaryList(pods.Items, nil) + auxResourceDeployment.Status = deploymentModels.ComponentStatusFromDeployment(&deployment).String() + return &auxResourceDeployment, nil +} + +func runningReplicaIsOutdated(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { + switch component.GetType() { + case v1.RadixComponentTypeComponent: + return runningComponentReplicaIsOutdated(component, actualPods) + case v1.RadixComponentTypeJob: + return false + default: + return false + } +} + +func runningComponentReplicaIsOutdated(component v1.RadixCommonDeployComponent, actualPods []corev1.Pod) bool { + // Check if running component's image is not the same as active deployment image tag and that active rd image is equal to 'starting' component image tag + componentIsInconsistent := false + for _, pod := range actualPods { + if pod.DeletionTimestamp != nil { + // Pod is in termination phase + continue + } + for _, container := range pod.Spec.Containers { + if container.Image != component.GetImage() { + // Container is running an outdated image + componentIsInconsistent = true + } + } + } + + return componentIsInconsistent +} + +func getStatusOfActiveDeployment( + component v1.RadixCommonDeployComponent, + deploymentStatus v1.RadixDeployStatus, + environmentConfig v1.RadixCommonEnvironmentConfig, + pods []corev1.Pod) (deploymentModels.ComponentStatus, error) { + + if component.GetType() == v1.RadixComponentTypeComponent { + if runningReplicaDiffersFromConfig(environmentConfig, pods) && + !runningReplicaDiffersFromSpec(component, pods) && + len(pods) == 0 { + return deploymentModels.StoppedComponent, nil + } + if runningReplicaDiffersFromSpec(component, pods) { + return deploymentModels.ComponentReconciling, nil + } + } else if component.GetType() == v1.RadixComponentTypeJob { + if len(pods) == 0 { + return deploymentModels.StoppedComponent, nil + } + } + if runningReplicaIsOutdated(component, pods) { + return deploymentModels.ComponentOutdated, nil + } + restarted := component.GetEnvironmentVariables()[defaults.RadixRestartEnvironmentVariable] + if strings.EqualFold(restarted, "") { + return deploymentModels.ConsistentComponent, nil + } + restartedTime, err := radixutils.ParseTimestamp(restarted) + if err != nil { + return deploymentModels.ConsistentComponent, err + } + reconciledTime := deploymentStatus.Reconciled + if reconciledTime.IsZero() || restartedTime.After(reconciledTime.Time) { + return deploymentModels.ComponentRestarting, nil + } + return deploymentModels.ConsistentComponent, nil +} diff --git a/api/deployments/component_handler_test.go b/api/environments/component_spec_test.go similarity index 99% rename from api/deployments/component_handler_test.go rename to api/environments/component_spec_test.go index 08815675..5d8374c6 100644 --- a/api/deployments/component_handler_test.go +++ b/api/environments/component_spec_test.go @@ -1,4 +1,4 @@ -package deployments +package environments import ( "testing" @@ -40,7 +40,6 @@ func TestRunningReplicaDiffersFromConfig_NoHPA(t *testing.T) { isDifferent = runningReplicaDiffersFromConfig(raEnvironmentConfig, actualPods) assert.True(t, isDifferent) } - func TestRunningReplicaDiffersFromConfig_WithHPA(t *testing.T) { // Test replicas 0, pods 3, minReplicas 2, maxReplicas 6 replicas := 0 @@ -184,7 +183,6 @@ func TestRunningReplicaNotOutdatedImage_(t *testing.T) { isOutdated := runningReplicaIsOutdated(&rdComponent, actualPods) assert.False(t, isOutdated) } - func TestRunningReplicaNotOutdatedImage_TerminatingPod(t *testing.T) { // Test replicas 0, pods 1, minReplicas 2, maxReplicas 6 replicas := 0 diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 50e9d617..4c6e4fec 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -466,7 +466,7 @@ func (eh EnvironmentHandler) getRadixCommonComponentUpdater(ctx context.Context, ra, _ := eh.getRadixApplicationInAppNamespace(ctx, appName) baseUpdater.environmentConfig = utils.GetComponentEnvironmentConfig(ra, envName, componentName) - baseUpdater.componentState, err = deployments.GetComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas, scalers) + baseUpdater.componentState, err = getComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas, scalers) if err != nil { return nil, err } From 8ef08971f071914a548715282290e0bbba8b4891 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 10:28:19 +0200 Subject: [PATCH 20/24] use kubequery where possible, remove unsuded fields --- api/environments/environment_handler.go | 18 +++++---------- api/environments/utils.go | 30 ------------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 4c6e4fec..21c5004a 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -46,9 +46,6 @@ func WithAccounts(accounts models.Accounts) EnvironmentHandlerOptions { eh.eventHandler = events.Init(accounts.UserAccount.Client) eh.accounts = accounts kubeUtil, _ := kube.New(accounts.UserAccount.Client, accounts.UserAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.UserAccount.SecretProviderClient) - eh.kubeUtil = kubeUtil - kubeUtilsForServiceAccount, _ := kube.New(accounts.ServiceAccount.Client, accounts.ServiceAccount.RadixClient, accounts.UserAccount.KedaClient, accounts.ServiceAccount.SecretProviderClient) - eh.kubeUtilForServiceAccount = kubeUtilsForServiceAccount eh.jobSchedulerHandlerFactory = jobscheduler.NewFactory(kubeUtil) } } @@ -97,8 +94,6 @@ type EnvironmentHandler struct { deployHandler deployments.DeployHandler eventHandler events.EventHandler accounts models.Accounts - kubeUtil *kube.Kube - kubeUtilForServiceAccount *kube.Kube tlsValidator tlsvalidation.Validator jobSchedulerHandlerFactory jobscheduler.HandlerFactoryInterface } @@ -250,8 +245,7 @@ func (eh EnvironmentHandler) CreateEnvironment(ctx context.Context, appName, env // DeleteEnvironment Handler for DeleteEnvironment. Deletes an environment if it is considered orphaned func (eh EnvironmentHandler) DeleteEnvironment(ctx context.Context, appName, envName string) error { - uniqueName := k8sObjectUtils.GetEnvironmentNamespace(appName, envName) - re, err := eh.getRadixEnvironment(ctx, uniqueName) + re, err := kubequery.GetRadixEnvironment(ctx, eh.accounts.ServiceAccount.RadixClient, appName, envName) if err != nil { return err } @@ -262,7 +256,7 @@ func (eh EnvironmentHandler) DeleteEnvironment(ctx context.Context, appName, env } // idempotent removal of RadixEnvironment - err = eh.getServiceAccount().RadixClient.RadixV1().RadixEnvironments().Delete(ctx, uniqueName, metav1.DeleteOptions{}) + err = eh.getServiceAccount().RadixClient.RadixV1().RadixEnvironments().Delete(ctx, re.Name, metav1.DeleteOptions{}) // if an error is anything other than not-found, return it if err != nil && !errors.IsNotFound(err) { return err @@ -273,7 +267,7 @@ func (eh EnvironmentHandler) DeleteEnvironment(ctx context.Context, appName, env // GetEnvironmentEvents Handler for GetEnvironmentEvents func (eh EnvironmentHandler) GetEnvironmentEvents(ctx context.Context, appName, envName string) ([]*eventModels.Event, error) { - radixApplication, err := eh.getRadixApplicationInAppNamespace(ctx, appName) + radixApplication, err := kubequery.GetRadixApplication(ctx, eh.accounts.UserAccount.RadixClient, appName) if err != nil { return nil, err } @@ -452,11 +446,11 @@ func (eh EnvironmentHandler) getRadixCommonComponentUpdater(ctx context.Context, updater = &radixDeployJobComponentUpdater{base: baseUpdater} } - hpas, err := eh.getHPAsInEnvironment(ctx, appName, envName) + hpas, err := kubequery.GetHorizontalPodAutoscalersForEnvironment(ctx, eh.accounts.UserAccount.Client, appName, envName) if err != nil { return nil, err } - scalers, err := eh.getScaledObjectsInEnvironment(ctx, appName, envName) + scalers, err := kubequery.GetScaledObjectsForEnvironment(ctx, eh.accounts.UserAccount.KedaClient, appName, envName) if err != nil { return nil, err } @@ -464,7 +458,7 @@ func (eh EnvironmentHandler) getRadixCommonComponentUpdater(ctx context.Context, baseUpdater.componentIndex = componentIndex baseUpdater.componentToPatch = componentToPatch - ra, _ := eh.getRadixApplicationInAppNamespace(ctx, appName) + ra, _ := kubequery.GetRadixApplication(ctx, eh.accounts.UserAccount.RadixClient, appName) baseUpdater.environmentConfig = utils.GetComponentEnvironmentConfig(ra, envName, componentName) baseUpdater.componentState, err = getComponentStateFromSpec(ctx, eh.client, appName, deploymentSummary, rd.Status, baseUpdater.environmentConfig, componentToPatch, hpas, scalers) if err != nil { diff --git a/api/environments/utils.go b/api/environments/utils.go index 3b813168..9ba0d2bd 100644 --- a/api/environments/utils.go +++ b/api/environments/utils.go @@ -6,8 +6,6 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" - "github.com/kedacore/keda/v2/apis/keda/v1alpha1" - v2 "k8s.io/api/autoscaling/v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -24,31 +22,3 @@ func (eh EnvironmentHandler) getRadixDeployment(ctx context.Context, appName, en } return deploymentSummary, radixDeployment, nil } - -func (eh EnvironmentHandler) getRadixApplicationInAppNamespace(ctx context.Context, appName string) (*v1.RadixApplication, error) { - return eh.radixclient.RadixV1().RadixApplications(operatorutils.GetAppNamespace(appName)).Get(ctx, appName, metav1.GetOptions{}) -} - -func (eh EnvironmentHandler) getRadixEnvironment(ctx context.Context, name string) (*v1.RadixEnvironment, error) { - return eh.getServiceAccount().RadixClient.RadixV1().RadixEnvironments().Get(ctx, name, metav1.GetOptions{}) -} - -func (eh EnvironmentHandler) getHPAsInEnvironment(ctx context.Context, appName, envName string) ([]v2.HorizontalPodAutoscaler, error) { - envNs := operatorutils.GetEnvironmentNamespace(appName, envName) - hpas, err := eh.accounts.UserAccount.Client.AutoscalingV2().HorizontalPodAutoscalers(envNs).List(ctx, metav1.ListOptions{}) - if err != nil { - return nil, err - } - - return hpas.Items, nil -} - -func (eh EnvironmentHandler) getScaledObjectsInEnvironment(ctx context.Context, appName, envName string) ([]v1alpha1.ScaledObject, error) { - envNs := operatorutils.GetEnvironmentNamespace(appName, envName) - scaledObjects, err := eh.accounts.UserAccount.KedaClient.KedaV1alpha1().ScaledObjects(envNs).List(ctx, metav1.ListOptions{}) - if err != nil { - return nil, err - } - - return scaledObjects.Items, nil -} From 53d1e3cebd4138ba5f9232f640d0384a80698f1c Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 10:41:21 +0200 Subject: [PATCH 21/24] cleanup deprecated fields, add lint ignore --- api/deployments/component_controller_test.go | 16 ++++++++-------- api/deployments/models/component_deployment.go | 16 +++++----------- swaggerui/html/swagger.json | 10 +++++----- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/api/deployments/component_controller_test.go b/api/deployments/component_controller_test.go index 8df1e8c7..2b5845e1 100644 --- a/api/deployments/component_controller_test.go +++ b/api/deployments/component_controller_test.go @@ -102,9 +102,9 @@ func TestGetComponents_active_deployment(t *testing.T) { assert.Equal(t, 2, len(components)) app := getComponentByName("app", components) - assert.Equal(t, 2, len(app.Replicas)) + assert.Equal(t, 2, len(app.Replicas)) // nolint:staticcheck // SA1019: Ignore linting deprecated fields job := getComponentByName("job", components) - assert.Equal(t, 1, len(job.Replicas)) + assert.Equal(t, 1, len(job.Replicas)) // nolint:staticcheck // SA1019: Ignore linting deprecated fields } func TestGetComponents_WithVolumeMount_ContainsVolumeMountSecrets(t *testing.T) { @@ -322,9 +322,9 @@ func TestGetComponents_inactive_deployment(t *testing.T) { assert.Equal(t, 2, len(components)) app := getComponentByName("app", components) - assert.Equal(t, 0, len(app.Replicas)) + assert.Equal(t, 0, len(app.Replicas)) // nolint:staticcheck // SA1019: Ignore linting deprecated fields job := getComponentByName("job", components) - assert.Equal(t, 0, len(job.Replicas)) + assert.Equal(t, 0, len(job.Replicas)) // nolint:staticcheck // SA1019: Ignore linting deprecated fields } func createComponentPod(kubeclient kubernetes.Interface, podName, namespace, radixAppLabel, radixComponentLabel string) error { @@ -618,10 +618,10 @@ func TestGetComponents_WithHorizontalScaling(t *testing.T) { assert.Equal(t, scenario.minReplicas, components[0].HorizontalScalingSummary.MinReplicas) assert.Equal(t, scenario.maxReplicas, components[0].HorizontalScalingSummary.MaxReplicas) - assert.Nil(t, components[0].HorizontalScalingSummary.CurrentCPUUtilizationPercentage) - assert.Equal(t, scenario.targetCpu, components[0].HorizontalScalingSummary.TargetCPUUtilizationPercentage) - assert.Nil(t, components[0].HorizontalScalingSummary.CurrentMemoryUtilizationPercentage) - assert.Equal(t, scenario.targetMemory, components[0].HorizontalScalingSummary.TargetMemoryUtilizationPercentage) + assert.Nil(t, components[0].HorizontalScalingSummary.CurrentCPUUtilizationPercentage) // nolint:staticcheck // SA1019: Ignore linting deprecated fields + assert.Equal(t, scenario.targetCpu, components[0].HorizontalScalingSummary.TargetCPUUtilizationPercentage) // nolint:staticcheck // SA1019: Ignore linting deprecated fields + assert.Nil(t, components[0].HorizontalScalingSummary.CurrentMemoryUtilizationPercentage) // nolint:staticcheck // SA1019: Ignore linting deprecated fields + assert.Equal(t, scenario.targetMemory, components[0].HorizontalScalingSummary.TargetMemoryUtilizationPercentage) // nolint:staticcheck // SA1019: Ignore linting deprecated fields memoryTrigger, ok := slice.FindFirst(components[0].HorizontalScalingSummary.Triggers, func(s deploymentModels.HorizontalScalingSummaryTriggerStatus) bool { return s.Name == "memory" diff --git a/api/deployments/models/component_deployment.go b/api/deployments/models/component_deployment.go index 9b0b5559..4d71db52 100644 --- a/api/deployments/models/component_deployment.go +++ b/api/deployments/models/component_deployment.go @@ -74,12 +74,10 @@ type Component struct { // required: false Variables map[string]string `json:"variables"` - // Array of pod names + // Deprecated: Array of pod names. Use ReplicaList instead // // required: false - // deprecated: true // example: ["server-78fc8857c4-hm76l", "server-78fc8857c4-asfa2"] - // Deprecated: Use ReplicaList instead. Replicas []string `json:"replicas"` // Array of ReplicaSummary @@ -440,32 +438,28 @@ type HorizontalScalingSummary struct { // example: 30 Triggers []HorizontalScalingSummaryTriggerStatus `json:"triggers"` - // Component current average CPU utilization over all pods, represented as a percentage of requested CPU + // Deprecated: Component current average CPU utilization over all pods, represented as a percentage of requested CPU. Use Triggers instead. Will be removed from Radix API 2025-01-01. // // required: false // example: 70 - // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. CurrentCPUUtilizationPercentage *int32 `json:"currentCPUUtilizationPercentage"` - // Component target average CPU utilization over all pods + // Deprecated: Component target average CPU utilization over all pods. Use Triggers instead. Will be removed from Radix API 2025-01-01. // // required: false // example: 80 - // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage"` - // Component current average memory utilization over all pods, represented as a percentage of requested memory + // Deprecated: Component current average memory utilization over all pods, represented as a percentage of requested memory. Use Triggers instead. Will be removed from Radix API 2025-01-01. // // required: false // example: 80 - // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. CurrentMemoryUtilizationPercentage *int32 `json:"currentMemoryUtilizationPercentage"` - // Component target average memory utilization over all pods + // Deprecated: Component target average memory utilization over all pods. use Triggers instead. Will be removed from Radix API 2025-01-01. // // required: false // example: 80 - // deprecated: use Triggers instead. Will be removed from Radix API 2025-01-01. TargetMemoryUtilizationPercentage *int32 `json:"targetMemoryUtilizationPercentage"` } diff --git a/swaggerui/html/swagger.json b/swaggerui/html/swagger.json index 6a0f26e0..5b84cb8c 100644 --- a/swaggerui/html/swagger.json +++ b/swaggerui/html/swagger.json @@ -5623,7 +5623,7 @@ "x-go-name": "ReplicaList" }, "replicas": { - "description": "Array of pod names", + "description": "Deprecated: Array of pod names. Use ReplicaList instead", "type": "array", "items": { "type": "string" @@ -6309,14 +6309,14 @@ "example": 300 }, "currentCPUUtilizationPercentage": { - "description": "Component current average CPU utilization over all pods, represented as a percentage of requested CPU", + "description": "Deprecated: Component current average CPU utilization over all pods, represented as a percentage of requested CPU. Use Triggers instead. Will be removed from Radix API 2025-01-01.", "type": "integer", "format": "int32", "x-go-name": "CurrentCPUUtilizationPercentage", "example": 70 }, "currentMemoryUtilizationPercentage": { - "description": "Component current average memory utilization over all pods, represented as a percentage of requested memory", + "description": "Deprecated: Component current average memory utilization over all pods, represented as a percentage of requested memory. Use Triggers instead. Will be removed from Radix API 2025-01-01.", "type": "integer", "format": "int32", "x-go-name": "CurrentMemoryUtilizationPercentage", @@ -6344,14 +6344,14 @@ "example": 30 }, "targetCPUUtilizationPercentage": { - "description": "Component target average CPU utilization over all pods", + "description": "Deprecated: Component target average CPU utilization over all pods. Use Triggers instead. Will be removed from Radix API 2025-01-01.", "type": "integer", "format": "int32", "x-go-name": "TargetCPUUtilizationPercentage", "example": 80 }, "targetMemoryUtilizationPercentage": { - "description": "Component target average memory utilization over all pods", + "description": "Deprecated: Component target average memory utilization over all pods. use Triggers instead. Will be removed from Radix API 2025-01-01.", "type": "integer", "format": "int32", "x-go-name": "TargetMemoryUtilizationPercentage", From f48554fbf17670915b01a41b40b9142a25b80ec1 Mon Sep 17 00:00:00 2001 From: Richard87 Date: Fri, 14 Jun 2024 10:58:32 +0200 Subject: [PATCH 22/24] use same status code field as gin middleware --- api/utils/logs/roundtrip_logger.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/utils/logs/roundtrip_logger.go b/api/utils/logs/roundtrip_logger.go index b1865eb1..ae1bcd17 100644 --- a/api/utils/logs/roundtrip_logger.go +++ b/api/utils/logs/roundtrip_logger.go @@ -20,7 +20,7 @@ type WithFunc func(e *zerolog.Event) // Logger returns a http.RoundTripper that logs failed requests, and add traces for successfull requests // -// nolint Zerolog complains about potential unsent event, but we send the event on line 50 +// nolint Zerolog complains about potential unsent event, but we send the event on the end of the function func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { return func(t http.RoundTripper) http.RoundTripper { return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { @@ -58,7 +58,7 @@ func Logger(fns ...WithFunc) func(t http.RoundTripper) http.RoundTripper { for _, fn := range fns { ev.Func(fn) } - ev.Int64("elapsed_ms", elapsedMs).Int("status_code", resp.StatusCode).Msg(http.StatusText(resp.StatusCode)) + ev.Int64("elapsed_ms", elapsedMs).Int("status", resp.StatusCode).Msg(http.StatusText(resp.StatusCode)) return resp, err }) } From e1f44e562bf2405be2e73cd0c0c8b9a2a3267c21 Mon Sep 17 00:00:00 2001 From: Richard Hagen Date: Fri, 14 Jun 2024 11:16:09 +0200 Subject: [PATCH 23/24] Update api/deployments/component_handler.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nils Gustav Stråbø <65334626+nilsgstrabo@users.noreply.github.com> --- api/deployments/component_handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index 599e29e9..b36fe973 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -50,7 +50,7 @@ func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, app if err != nil { return nil, err } - certs, err := kubequery.GetCertificatesForEnvironment(ctx, deploy.accounts.UserAccount.CertManagerClient, appName, envName) + certs, err := kubequery.GetCertificatesForEnvironment(ctx, deploy.accounts.ServiceAccount.CertManagerClient, appName, envName) if err != nil { return nil, err } From b6507f344e9e5d36dc4656e8e4fe5ff2b75ca200 Mon Sep 17 00:00:00 2001 From: Richard Hagen Date: Fri, 14 Jun 2024 11:16:18 +0200 Subject: [PATCH 24/24] Update api/deployments/component_handler.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nils Gustav Stråbø <65334626+nilsgstrabo@users.noreply.github.com> --- api/deployments/component_handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/deployments/component_handler.go b/api/deployments/component_handler.go index b36fe973..0e1d36c3 100644 --- a/api/deployments/component_handler.go +++ b/api/deployments/component_handler.go @@ -54,7 +54,7 @@ func (deploy *deployHandler) GetComponentsForDeployment(ctx context.Context, app if err != nil { return nil, err } - certRequests, err := kubequery.GetCertificateRequestsForEnvironment(ctx, deploy.accounts.UserAccount.CertManagerClient, appName, envName) + certRequests, err := kubequery.GetCertificateRequestsForEnvironment(ctx, deploy.accounts.ServiceAccount.CertManagerClient, appName, envName) if err != nil { return nil, err }