Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure environment is not accessed during a dry run #1616

Merged
merged 16 commits into from
Nov 7, 2024
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
24 changes: 4 additions & 20 deletions cmd/monaco/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ package delete
import (
"context"
"fmt"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/cmd/monaco/support"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/client"
"strings"

"github.com/dynatrace/dynatrace-configuration-as-code/v2/cmd/monaco/support"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/api"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/client"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/delete"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/manifest"
Expand All @@ -45,29 +44,14 @@ func Delete(environments manifest.Environments, entriesToDelete delete.DeleteEnt
log.WithCtxFields(ctx).Warn("Delete file contains Dynatrace Platform specific types, but no oAuth credentials are defined for environment %q - Dynatrace Platform configurations won't be deleted.", env.Name)
}

clientSet, err := client.CreateClientSet(env.URL.Value, env.Auth, client.ClientOptions{SupportArchive: support.SupportArchive})
clientSet, err := client.CreateClientSet(ctx, env.URL.Value, env.Auth, client.ClientOptions{SupportArchive: support.SupportArchive})
if err != nil {
return fmt.Errorf("failed to create API client for environment %q due to the following error: %w", env.Name, err)
}

log.WithCtxFields(ctx).Info("Deleting configs for environment %q...", env.Name)

classicAPIs := api.NewAPIs()
automationAPIs := map[string]config.AutomationResource{
string(config.Workflow): config.Workflow,
string(config.BusinessCalendar): config.BusinessCalendar,
string(config.SchedulingRule): config.SchedulingRule,
}

deleteClients := delete.ClientSet{
Classic: clientSet.Classic(),
Settings: clientSet.Settings(),
Automation: clientSet.Automation(),
Buckets: clientSet.Bucket(),
Documents: clientSet.Document(),
}

if err := delete.Configs(ctx, deleteClients, classicAPIs, automationAPIs, entriesToDelete); err != nil {
if err := delete.Configs(ctx, *clientSet, entriesToDelete); err != nil {
log.Error("Failed to delete all configurations from environment %q - check log for details", env.Name)
envsWithDeleteErrs = append(envsWithDeleteErrs, env.Name)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/monaco/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func deployConfigsWithContext(ctx context.Context, fs afero.Fs, manifestPath str
return fmt.Errorf("manifest auth field misconfigured: %w", err)
}

clientSets, err := dynatrace.CreateEnvironmentClients(loadedManifest.Environments)
clientSets, err := dynatrace.CreateEnvironmentClients(ctx, loadedManifest.Environments, dryRun)
if err != nil {
return fmt.Errorf("failed to create API clients: %w", err)
}
Expand Down Expand Up @@ -228,7 +228,7 @@ func configRequiresPlatform(c config.Config) bool {

func collectUndefinedEnvironmentErrors(undefinedEnvironments map[string]struct{}) []error {
errs := []error{}
for envName, _ := range undefinedEnvironments {
for envName := range undefinedEnvironments {
errs = append(errs, fmt.Errorf("undefined environment %q", envName))
}
return errs
Expand Down
12 changes: 7 additions & 5 deletions cmd/monaco/download/download_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
package download

import (
"context"
"errors"
"fmt"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/cmd/monaco/support"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/openpipeline"
"os"

"github.com/spf13/afero"

"github.com/dynatrace/dynatrace-configuration-as-code/v2/cmd/monaco/dynatrace"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/cmd/monaco/support"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/featureflags"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/secret"
Expand All @@ -34,12 +36,12 @@ import (
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/dependency_resolution"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/document"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/id_extraction"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/openpipeline"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/settings"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/manifest"
manifestloader "github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/manifest/loader"
project "github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/project/v2"
projectv2 "github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/project/v2"
"github.com/spf13/afero"
)

type downloadCmdOptions struct {
Expand Down Expand Up @@ -148,7 +150,7 @@ func (d DefaultCommand) DownloadConfigsBasedOnManifest(fs afero.Fs, cmdOptions d
return err
}

clientSet, err := client.CreateClientSet(options.environmentURL, options.auth, client.ClientOptions{SupportArchive: support.SupportArchive})
clientSet, err := client.CreateClientSet(context.TODO(), options.environmentURL, options.auth, client.ClientOptions{SupportArchive: support.SupportArchive})
if err != nil {
return err
}
Expand Down Expand Up @@ -186,7 +188,7 @@ func (d DefaultCommand) DownloadConfigs(fs afero.Fs, cmdOptions downloadCmdOptio
return err
}

clientSet, err := client.CreateClientSet(options.environmentURL, options.auth, client.ClientOptions{SupportArchive: support.SupportArchive})
clientSet, err := client.CreateClientSet(context.TODO(), options.environmentURL, options.auth, client.ClientOptions{SupportArchive: support.SupportArchive})
if err != nil {
return err
}
Expand Down
60 changes: 39 additions & 21 deletions cmd/monaco/download/download_configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ package download

import (
"errors"
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"

"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/testutils"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/api"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/client"
Expand All @@ -30,17 +36,14 @@ import (
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/download/settings"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/manifest"
projectv2 "github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/project/v2"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"testing"
)

func TestDownloadConfigsBehaviour(t *testing.T) {
tests := []struct {
name string
givenOpts downloadConfigsOptions
expectedBehaviour func(client *client.MockDynatraceClient)
name string
givenOpts downloadConfigsOptions
expectedConfigBehaviour func(client *client.MockConfigClient)
expectedSettingsBehaviour func(client *client.MockSettingsClient)
}{
{
name: "Default opts: downloads Configs and Settings",
Expand All @@ -50,9 +53,11 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: false,
onlySettings: false,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), gomock.Any()).AnyTimes().Return([]dtclient.Value{}, nil)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]byte("{}"), nil) // singleton configs are always attempted
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).Return(dtclient.SchemaList{}, nil)
c.EXPECT().ListSettings(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]dtclient.DownloadSettingsObject{}, nil)
},
Expand All @@ -65,9 +70,11 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: false,
onlySettings: false,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), gomock.Any()).Times(0)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), gomock.Any()).Times(0)
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).AnyTimes().Return(dtclient.SchemaList{{SchemaId: "builtin:magic.secret"}}, nil)
c.EXPECT().GetSchemaById(gomock.Any(), gomock.Any()).AnyTimes().Return(dtclient.Schema{SchemaId: "builtin:magic.secret"}, nil)
c.EXPECT().ListSettings(gomock.Any(), "builtin:magic.secret", gomock.Any()).AnyTimes().Return([]dtclient.DownloadSettingsObject{}, nil)
Expand All @@ -81,9 +88,11 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: false,
onlySettings: false,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), api.NewAPIs()["alerting-profile"]).Return([]dtclient.Value{{Id: "42", Name: "profile"}}, nil)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), "42").AnyTimes().Return([]byte("{}"), nil)
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).Times(0)
c.EXPECT().ListSettings(gomock.Any(), gomock.Any(), gomock.Any()).Times(0)
},
Expand All @@ -96,13 +105,14 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: false,
onlySettings: false,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), api.NewAPIs()["alerting-profile"]).Return([]dtclient.Value{{Id: "42", Name: "profile"}}, nil)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), "42").AnyTimes().Return([]byte("{}"), nil)
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).AnyTimes().Return(dtclient.SchemaList{{SchemaId: "builtin:magic.secret"}}, nil)
c.EXPECT().GetSchemaById(gomock.Any(), gomock.Any()).AnyTimes().Return(dtclient.Schema{SchemaId: "builtin:magic.secret"}, nil)
c.EXPECT().ListSettings(gomock.Any(), "builtin:magic.secret", gomock.Any()).AnyTimes().Return([]dtclient.DownloadSettingsObject{}, nil)

},
},
{
Expand All @@ -113,9 +123,11 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: true,
onlySettings: false,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), gomock.Any()).AnyTimes().Return([]dtclient.Value{}, nil)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]byte("{}"), nil) // singleton configs are always attempted
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).Times(0)
c.EXPECT().ListSettings(gomock.Any(), gomock.Any(), gomock.Any()).Times(0)
},
Expand All @@ -128,17 +140,18 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
onlyAPIs: false,
onlySettings: true,
},
expectedBehaviour: func(c *client.MockDynatraceClient) {
expectedConfigBehaviour: func(c *client.MockConfigClient) {
c.EXPECT().ListConfigs(gomock.Any(), gomock.Any()).Times(0)
c.EXPECT().ReadConfigById(gomock.Any(), gomock.Any(), gomock.Any()).Times(0)
},
expectedSettingsBehaviour: func(c *client.MockSettingsClient) {
c.EXPECT().ListSchemas(gomock.Any()).Return(dtclient.SchemaList{}, nil)
c.EXPECT().ListSettings(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]dtclient.DownloadSettingsObject{}, nil)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := client.NewMockDynatraceClient(gomock.NewController(t))

tt.givenOpts.downloadOptionsShared = downloadOptionsShared{
environmentURL: "testurl.com",
Expand All @@ -153,9 +166,13 @@ func TestDownloadConfigsBehaviour(t *testing.T) {
forceOverwriteManifest: false,
}

tt.expectedBehaviour(c)
configClient := client.NewMockConfigClient(gomock.NewController(t))
tt.expectedConfigBehaviour(configClient)

settingsClient := client.NewMockSettingsClient(gomock.NewController(t))
tt.expectedSettingsBehaviour(settingsClient)

_, err := downloadConfigs(&client.ClientSet{DTClient: c}, api.NewAPIs(), tt.givenOpts, defaultDownloadFn)
_, err := downloadConfigs(&client.ClientSet{ClassicClient: configClient, SettingsClient: settingsClient}, api.NewAPIs(), tt.givenOpts, defaultDownloadFn)
assert.NoError(t, err)
})
}
Expand Down Expand Up @@ -303,7 +320,8 @@ func TestDownload_Options(t *testing.T) {
},
}

_, err := downloadConfigs(&client.ClientSet{DTClient: client.NewMockDynatraceClient(gomock.NewController(t))}, api.NewAPIs(), tt.given, fn)
c := client.NewMockConfigClient(gomock.NewController(t))
_, err := downloadConfigs(&client.ClientSet{ClassicClient: c}, api.NewAPIs(), tt.given, fn)
assert.NoError(t, err)
})
}
Expand Down Expand Up @@ -390,10 +408,9 @@ func Test_shouldDownloadSettings(t *testing.T) {
}

func TestDownloadConfigsExitsEarlyForUnknownSettingsSchema(t *testing.T) {
c := client.NewMockDynatraceClient(gomock.NewController(t))

givenOpts := downloadConfigsOptions{
specificSchemas: []string{"UNKOWN SCHEMA"},
specificSchemas: []string{"UNKNOWN SCHEMA"},
onlySettings: false,
downloadOptionsShared: downloadOptionsShared{
environmentURL: "testurl.com",
Expand All @@ -409,9 +426,10 @@ func TestDownloadConfigsExitsEarlyForUnknownSettingsSchema(t *testing.T) {
},
}

c := client.NewMockSettingsClient(gomock.NewController(t))
c.EXPECT().ListSchemas(gomock.Any()).Return(dtclient.SchemaList{{SchemaId: "builtin:some.schema"}}, nil)

err := doDownloadConfigs(afero.NewMemMapFs(), &client.ClientSet{DTClient: c}, nil, givenOpts)
err := doDownloadConfigs(afero.NewMemMapFs(), &client.ClientSet{SettingsClient: c}, nil, givenOpts)
assert.ErrorContains(t, err, "not known", "expected download to fail for unkown Settings Schema")
c.EXPECT().ListSettings(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) // no downloads should even be attempted for unknown schema
}
Expand Down
Loading
Loading