From 7a5632faae512bdc39419c7e3e9657ab7061076d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Palet?= Date: Tue, 16 Apr 2024 18:58:11 +0100 Subject: [PATCH] Implemnt util for Argus grafana configuration commands --- internal/pkg/services/argus/utils/utils.go | 73 ++++- .../pkg/services/argus/utils/utils_test.go | 276 +++++++++++++++++- 2 files changed, 343 insertions(+), 6 deletions(-) diff --git a/internal/pkg/services/argus/utils/utils.go b/internal/pkg/services/argus/utils/utils.go index e530c187b..396aa84fb 100644 --- a/internal/pkg/services/argus/utils/utils.go +++ b/internal/pkg/services/argus/utils/utils.go @@ -14,6 +14,11 @@ const ( service = "argus" ) +type ArgusClient interface { + GetInstanceExecute(ctx context.Context, instanceId, projectId string) (*argus.GetInstanceResponse, error) + GetGrafanaConfigsExecute(ctx context.Context, instanceId, projectId string) (*argus.GrafanaConfigs, error) +} + func ValidatePlanId(planId string, resp *argus.PlansResponse) error { if resp == nil { return fmt.Errorf("no Argus plans provided") @@ -56,10 +61,6 @@ func LoadPlanId(planName string, resp *argus.PlansResponse) (*string, error) { } } -type ArgusClient interface { - GetInstanceExecute(ctx context.Context, instanceId, projectId string) (*argus.GetInstanceResponse, error) -} - func GetInstanceName(ctx context.Context, apiClient ArgusClient, instanceId, projectId string) (string, error) { resp, err := apiClient.GetInstanceExecute(ctx, instanceId, projectId) if err != nil { @@ -67,3 +68,67 @@ func GetInstanceName(ctx context.Context, apiClient ArgusClient, instanceId, pro } return *resp.Name, nil } + +func toPayloadGenericOAuth(response *argus.GrafanaOauth) *argus.UpdateGrafanaConfigsPayloadGenericOauth { + if response == nil { + return nil + } + return &argus.UpdateGrafanaConfigsPayloadGenericOauth{ + ApiUrl: response.ApiUrl, + AuthUrl: response.AuthUrl, + Enabled: response.Enabled, + Name: response.Name, + OauthClientId: response.OauthClientId, + OauthClientSecret: response.OauthClientSecret, + RoleAttributePath: response.RoleAttributePath, + RoleAttributeStrict: response.RoleAttributeStrict, + Scopes: response.Scopes, + TokenUrl: response.TokenUrl, + UsePkce: response.UsePkce, + } +} + +func toRespGenericOAuth(payloadModel *argus.UpdateGrafanaConfigsPayloadGenericOauth) *argus.GrafanaOauth { + if payloadModel == nil { + return nil + } + return &argus.GrafanaOauth{ + ApiUrl: payloadModel.ApiUrl, + AuthUrl: payloadModel.AuthUrl, + Enabled: payloadModel.Enabled, + Name: payloadModel.Name, + OauthClientId: payloadModel.OauthClientId, + OauthClientSecret: payloadModel.OauthClientSecret, + RoleAttributePath: payloadModel.RoleAttributePath, + RoleAttributeStrict: payloadModel.RoleAttributeStrict, + Scopes: payloadModel.Scopes, + TokenUrl: payloadModel.TokenUrl, + UsePkce: payloadModel.UsePkce, + } +} + +func GetPartialUpdateGrafanaConfigsPayload(ctx context.Context, apiClient ArgusClient, instanceId, projectId string, singleSignOn, publicReadAccess *bool) (*argus.UpdateGrafanaConfigsPayload, error) { + currentConfigs, err := apiClient.GetGrafanaConfigsExecute(ctx, instanceId, projectId) + if err != nil { + return nil, fmt.Errorf("get current Grafana configs: %w", err) + } + + if currentConfigs == nil || currentConfigs.GenericOauth == nil { + return nil, fmt.Errorf("no Grafana configs found for instance %q", instanceId) + } + + payload := &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(currentConfigs.GenericOauth), + PublicReadAccess: currentConfigs.PublicReadAccess, + UseStackitSso: currentConfigs.UseStackitSso, + } + + if singleSignOn != nil { + payload.UseStackitSso = singleSignOn + } + if publicReadAccess != nil { + payload.PublicReadAccess = publicReadAccess + } + + return payload, nil +} diff --git a/internal/pkg/services/argus/utils/utils_test.go b/internal/pkg/services/argus/utils/utils_test.go index 8adf5de1b..911eb061c 100644 --- a/internal/pkg/services/argus/utils/utils_test.go +++ b/internal/pkg/services/argus/utils/utils_test.go @@ -8,6 +8,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/stackitcloud/stackit-sdk-go/services/argus" ) @@ -33,8 +34,10 @@ var testPlansResponse = argus.PlansResponse{ } type argusClientMocked struct { - getInstanceFails bool - getInstanceResp *argus.GetInstanceResponse + getInstanceFails bool + getInstanceResp *argus.GetInstanceResponse + getGrafanaConfigsFails bool + getGrafanaConfigsResp *argus.GrafanaConfigs } func (m *argusClientMocked) GetInstanceExecute(_ context.Context, _, _ string) (*argus.GetInstanceResponse, error) { @@ -43,6 +46,38 @@ func (m *argusClientMocked) GetInstanceExecute(_ context.Context, _, _ string) ( } return m.getInstanceResp, nil } + +func (m *argusClientMocked) GetGrafanaConfigsExecute(_ context.Context, _, _ string) (*argus.GrafanaConfigs, error) { + if m.getGrafanaConfigsFails { + return nil, fmt.Errorf("could not get grafana configs") + } + return m.getGrafanaConfigsResp, nil +} + +func fixtureGrafanaConfigs(mods ...func(gc *argus.GrafanaConfigs)) *argus.GrafanaConfigs { + gc := argus.GrafanaConfigs{ + GenericOauth: &argus.GrafanaOauth{ + ApiUrl: utils.Ptr("apiUrl"), + AuthUrl: utils.Ptr("authUrl"), + Enabled: utils.Ptr(true), + Name: utils.Ptr("name"), + OauthClientId: utils.Ptr("oauthClientId"), + OauthClientSecret: utils.Ptr("oauthClientSecret"), + RoleAttributePath: utils.Ptr("roleAttributePath"), + RoleAttributeStrict: utils.Ptr(true), + Scopes: utils.Ptr("scopes"), + TokenUrl: utils.Ptr("tokenUrl"), + UsePkce: utils.Ptr(true), + }, + PublicReadAccess: utils.Ptr(false), + UseStackitSso: utils.Ptr(false), + } + for _, mod := range mods { + mod(&gc) + } + return &gc +} + func TestGetInstanceName(t *testing.T) { tests := []struct { description string @@ -220,3 +255,240 @@ func TestValidatePlanId(t *testing.T) { }) } } + +func TestToPayloadGenericOAuth(t *testing.T) { + tests := []struct { + description string + response *argus.GrafanaOauth + expected *argus.UpdateGrafanaConfigsPayloadGenericOauth + }{ + { + description: "base", + response: &argus.GrafanaOauth{ + ApiUrl: utils.Ptr("apiUrl"), + AuthUrl: utils.Ptr("authUrl"), + Enabled: utils.Ptr(true), + Name: utils.Ptr("name"), + OauthClientId: utils.Ptr("oauthClientId"), + OauthClientSecret: utils.Ptr("oauthClientSecret"), + RoleAttributePath: utils.Ptr("roleAttributePath"), + RoleAttributeStrict: utils.Ptr(true), + Scopes: utils.Ptr("scopes"), + TokenUrl: utils.Ptr("tokenUrl"), + UsePkce: utils.Ptr(true), + }, + expected: &argus.UpdateGrafanaConfigsPayloadGenericOauth{ + ApiUrl: utils.Ptr("apiUrl"), + AuthUrl: utils.Ptr("authUrl"), + Enabled: utils.Ptr(true), + Name: utils.Ptr("name"), + OauthClientId: utils.Ptr("oauthClientId"), + OauthClientSecret: utils.Ptr("oauthClientSecret"), + RoleAttributePath: utils.Ptr("roleAttributePath"), + RoleAttributeStrict: utils.Ptr(true), + Scopes: utils.Ptr("scopes"), + TokenUrl: utils.Ptr("tokenUrl"), + UsePkce: utils.Ptr(true), + }, + }, + { + description: "nil response", + response: nil, + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + output := toPayloadGenericOAuth(tt.response) + + diff := cmp.Diff(output, tt.expected) + if diff != "" { + t.Errorf("expected output to be %+v, got %+v", tt.expected, output) + } + }) + } +} + +func TestToRespGenericOAuth(t *testing.T) { + tests := []struct { + description string + payload *argus.UpdateGrafanaConfigsPayloadGenericOauth + expected *argus.GrafanaOauth + }{ + { + description: "base", + payload: &argus.UpdateGrafanaConfigsPayloadGenericOauth{ + ApiUrl: utils.Ptr("apiUrl"), + AuthUrl: utils.Ptr("authUrl"), + Enabled: utils.Ptr(true), + Name: utils.Ptr("name"), + OauthClientId: utils.Ptr("oauthClientId"), + OauthClientSecret: utils.Ptr("oauthClientSecret"), + RoleAttributePath: utils.Ptr("roleAttributePath"), + RoleAttributeStrict: utils.Ptr(true), + Scopes: utils.Ptr("scopes"), + TokenUrl: utils.Ptr("tokenUrl"), + UsePkce: utils.Ptr(true), + }, + expected: &argus.GrafanaOauth{ + ApiUrl: utils.Ptr("apiUrl"), + AuthUrl: utils.Ptr("authUrl"), + Enabled: utils.Ptr(true), + Name: utils.Ptr("name"), + OauthClientId: utils.Ptr("oauthClientId"), + OauthClientSecret: utils.Ptr("oauthClientSecret"), + RoleAttributePath: utils.Ptr("roleAttributePath"), + RoleAttributeStrict: utils.Ptr(true), + Scopes: utils.Ptr("scopes"), + TokenUrl: utils.Ptr("tokenUrl"), + UsePkce: utils.Ptr(true), + }, + }, + { + description: "nil payload", + payload: nil, + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + output := toRespGenericOAuth(tt.payload) + + diff := cmp.Diff(output, tt.expected) + if diff != "" { + t.Errorf("expected output to be %+v, got %+v", tt.expected, output) + } + }) + } +} + +func TestGetPartialUpdateGrafanaConfigsPayload(t *testing.T) { + tests := []struct { + description string + singleSignOn *bool + publicReadAccess *bool + getGrafanaConfigsFails bool + getGrafanaConfigsResp *argus.GrafanaConfigs + isValid bool + expectedPayload *argus.UpdateGrafanaConfigsPayload + }{ + { + description: "enable both", + singleSignOn: utils.Ptr(true), + publicReadAccess: utils.Ptr(true), + getGrafanaConfigsResp: fixtureGrafanaConfigs(), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: utils.Ptr(true), + PublicReadAccess: utils.Ptr(true), + }, + }, + { + description: "disable both", + singleSignOn: utils.Ptr(false), + publicReadAccess: utils.Ptr(false), + getGrafanaConfigsResp: fixtureGrafanaConfigs(), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: utils.Ptr(false), + PublicReadAccess: utils.Ptr(false), + }, + }, + { + description: "enable single sign on", + singleSignOn: utils.Ptr(true), + publicReadAccess: nil, + getGrafanaConfigsResp: fixtureGrafanaConfigs(), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: utils.Ptr(true), + PublicReadAccess: fixtureGrafanaConfigs().PublicReadAccess, + }, + }, + { + description: "enable public read access", + singleSignOn: nil, + publicReadAccess: utils.Ptr(true), + getGrafanaConfigsResp: fixtureGrafanaConfigs(), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: fixtureGrafanaConfigs().UseStackitSso, + PublicReadAccess: utils.Ptr(true), + }, + }, + { + description: "disable single sign on", + singleSignOn: utils.Ptr(false), + publicReadAccess: nil, + getGrafanaConfigsResp: fixtureGrafanaConfigs(func(gc *argus.GrafanaConfigs) { + gc.UseStackitSso = utils.Ptr(true) + }), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: utils.Ptr(false), + PublicReadAccess: fixtureGrafanaConfigs().PublicReadAccess, + }, + }, + { + description: "disable public read access", + singleSignOn: nil, + publicReadAccess: utils.Ptr(false), + getGrafanaConfigsResp: fixtureGrafanaConfigs(func(gc *argus.GrafanaConfigs) { + gc.PublicReadAccess = utils.Ptr(true) + }), + isValid: true, + expectedPayload: &argus.UpdateGrafanaConfigsPayload{ + GenericOauth: toPayloadGenericOAuth(fixtureGrafanaConfigs().GenericOauth), + UseStackitSso: fixtureGrafanaConfigs().UseStackitSso, + PublicReadAccess: utils.Ptr(false), + }, + }, + { + description: "get grafana configs fails", + singleSignOn: utils.Ptr(true), + publicReadAccess: utils.Ptr(true), + getGrafanaConfigsFails: true, + isValid: false, + }, + { + description: "no grafana configs", + singleSignOn: utils.Ptr(true), + publicReadAccess: utils.Ptr(true), + getGrafanaConfigsResp: &argus.GrafanaConfigs{}, + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + client := &argusClientMocked{ + getGrafanaConfigsFails: tt.getGrafanaConfigsFails, + getGrafanaConfigsResp: tt.getGrafanaConfigsResp, + } + + payload, err := GetPartialUpdateGrafanaConfigsPayload(context.Background(), client, testInstanceId, testProjectId, tt.singleSignOn, tt.publicReadAccess) + + if tt.isValid && err != nil { + t.Errorf("failed on valid input") + } + if !tt.isValid && err == nil { + t.Errorf("did not fail on invalid input") + } + if !tt.isValid { + return + } + + diff := cmp.Diff(payload, tt.expectedPayload) + if diff != "" { + t.Errorf("expected output payload to be %+v, got %+v", tt.expectedPayload, payload) + } + }) + } +}