Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 69 additions & 4 deletions internal/pkg/services/argus/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -56,14 +61,74 @@ 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 {
return "", fmt.Errorf("get Argus instance: %w", err)
}
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
}
276 changes: 274 additions & 2 deletions internal/pkg/services/argus/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
})
}
}