From a3e24971e309e1ecc8a17daa394efff804c6a225 Mon Sep 17 00:00:00 2001 From: Bernd Warmuth <72415058+warber@users.noreply.github.com> Date: Wed, 21 Dec 2022 14:29:13 +0100 Subject: [PATCH] feat: Download settings (#19) * refactor: Rename downloader to classic * feat: Implement outline for settings 2.0 download * feat: Implement ListSchemas * feat: Implement ListSettings * feat: Write downloaded settings * feat: added unit test for settings::Download * feat: Add option to skip settings download * ci: Make mocks before vet * ci: Set up go for static-code-analysis workflow * ci: Integration tests target requires mocks Co-authored-by: David Laubreiter --- .github/workflows/pr-static-code-analysis.yml | 9 ++ Makefile | 10 +- cmd/monaco/download/download.go | 15 ++- .../download/download_integration_test.go | 1 + pkg/download/{downloader => classic}/doc.go | 2 +- .../download_filter.go | 2 +- .../download_filter_test.go | 2 +- .../download_sanitize.go | 2 +- .../download_sanitize_test.go | 2 +- .../{downloader => classic}/downloader.go | 10 +- .../downloader_test.go | 2 +- .../{downloader => classic}/test_utils.go | 2 +- pkg/download/settings/settings.go | 91 +++++++++++++ pkg/download/settings/settings_test.go | 126 ++++++++++++++++++ pkg/rest/client.go | 104 ++++++++++++++- pkg/rest/limiting_client.go | 16 +++ pkg/rest/settings_client.go | 1 + pkg/util/client/dummy_client.go | 12 +- 18 files changed, 386 insertions(+), 23 deletions(-) rename pkg/download/{downloader => classic}/doc.go (98%) rename pkg/download/{downloader => classic}/download_filter.go (99%) rename pkg/download/{downloader => classic}/download_filter_test.go (99%) rename pkg/download/{downloader => classic}/download_sanitize.go (99%) rename pkg/download/{downloader => classic}/download_sanitize_test.go (99%) rename pkg/download/{downloader => classic}/downloader.go (96%) rename pkg/download/{downloader => classic}/downloader_test.go (99%) rename pkg/download/{downloader => classic}/test_utils.go (97%) create mode 100644 pkg/download/settings/settings.go create mode 100644 pkg/download/settings/settings_test.go diff --git a/.github/workflows/pr-static-code-analysis.yml b/.github/workflows/pr-static-code-analysis.yml index 3813dc9f4..b613de07e 100644 --- a/.github/workflows/pr-static-code-analysis.yml +++ b/.github/workflows/pr-static-code-analysis.yml @@ -14,9 +14,18 @@ jobs: name: lint runs-on: ubuntu-latest steps: + + - name: Set up Go 1.x + uses: actions/setup-go@v3 + with: + go-version: '~1.19' + id: go + - uses: actions/checkout@v3 + - name: 🕵️ Go vet run: make vet + - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 with: diff --git a/Makefile b/Makefile index 54e4a7539..440ab0b15 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ mocks: setup @echo "Generating mocks" @go generate ./... -vet: +vet: mocks @echo "Vetting files" @go vet ./... @@ -79,19 +79,19 @@ test: setup mocks lint @echo "Testing ${BINARY}..." @gotestsum ${testopts} -- -tags=unit -v ./... -integration-test: setup +integration-test: mocks @gotestsum ${testopts} --format standard-verbose -- -tags=integration -timeout=30m -v ./... -integration-test-v1:setup +integration-test-v1:mocks @gotestsum ${testopts} --format standard-verbose -- -tags=integration_v1 -timeout=30m -v ./... -download-restore-test: setup +download-restore-test: mocks @gotestsum ${testopts} --format standard-verbose -- -tags=download_restore -timeout=30m -v ./... clean-environments: @gotestsum ${testopts} --format standard-verbose -- -tags=cleanup -v ./... -nightly-test:setup +nightly-test:mocks @gotestsum ${testopts} --format standard-verbose -- -tags=nightly -timeout=60m -v ./... # Build and Test a single package supplied via pgk variable, without using test cache diff --git a/cmd/monaco/download/download.go b/cmd/monaco/download/download.go index 7fcbe475b..ffdc7a568 100644 --- a/cmd/monaco/download/download.go +++ b/cmd/monaco/download/download.go @@ -18,7 +18,8 @@ import ( "fmt" "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api" "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/download" - "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/download/downloader" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/download/classic" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/download/settings" "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/manifest" project "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/project/v2" "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/project/v2/topologysort" @@ -172,6 +173,7 @@ type downloadOptions struct { apis api.ApiMap forceOverwriteManifest bool clientFactory dynatraceClientFactory + skipSettings bool } func (c downloadOptions) getDynatraceClient() (rest.DynatraceClient, error) { @@ -243,8 +245,15 @@ func downloadConfigs(context downloadOptions) (project.ConfigsPerType, error) { return nil, fmt.Errorf("failed to create Dynatrace client: %w", err) } - downloadedConfigs := downloader.DownloadAllConfigs(context.apis, client, context.projectName) - return downloadedConfigs, nil + configObjects := classic.DownloadAllConfigs(context.apis, client, context.projectName) + + if !context.skipSettings { + settingsObjects := settings.Download(client) + + maps.Copy(configObjects, settingsObjects) + } + + return configObjects, nil } func sumConfigs(configs project.ConfigsPerType) int { diff --git a/cmd/monaco/download/download_integration_test.go b/cmd/monaco/download/download_integration_test.go index 7ae27d48a..b6698acec 100644 --- a/cmd/monaco/download/download_integration_test.go +++ b/cmd/monaco/download/download_integration_test.go @@ -857,6 +857,7 @@ func getTestingDownloadOptions(server *httptest.Server, projectName string, apiM outputFolder: "out", projectName: projectName, apis: apiMap, + skipSettings: true, clientFactory: func(environmentUrl, token string) (rest.DynatraceClient, error) { return rest.NewDynatraceClientForTesting(environmentUrl, token, server.Client()) }, diff --git a/pkg/download/downloader/doc.go b/pkg/download/classic/doc.go similarity index 98% rename from pkg/download/downloader/doc.go rename to pkg/download/classic/doc.go index a0e4b31aa..9cb2efabc 100644 --- a/pkg/download/downloader/doc.go +++ b/pkg/download/classic/doc.go @@ -48,4 +48,4 @@ The process looks like this: ``` */ -package downloader +package classic diff --git a/pkg/download/downloader/download_filter.go b/pkg/download/classic/download_filter.go similarity index 99% rename from pkg/download/downloader/download_filter.go rename to pkg/download/classic/download_filter.go index 8552e5dfe..aae301d5a 100644 --- a/pkg/download/downloader/download_filter.go +++ b/pkg/download/classic/download_filter.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package downloader +package classic import ( "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api" diff --git a/pkg/download/downloader/download_filter_test.go b/pkg/download/classic/download_filter_test.go similarity index 99% rename from pkg/download/downloader/download_filter_test.go rename to pkg/download/classic/download_filter_test.go index e16fe3c33..c6e61e3ec 100644 --- a/pkg/download/downloader/download_filter_test.go +++ b/pkg/download/classic/download_filter_test.go @@ -16,7 +16,7 @@ * limitations under the License. */ -package downloader +package classic import ( "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api" diff --git a/pkg/download/downloader/download_sanitize.go b/pkg/download/classic/download_sanitize.go similarity index 99% rename from pkg/download/downloader/download_sanitize.go rename to pkg/download/classic/download_sanitize.go index b615c6ac7..3412154cd 100644 --- a/pkg/download/downloader/download_sanitize.go +++ b/pkg/download/classic/download_sanitize.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package downloader +package classic var apiSanitizeFunctions = map[string]func(properties map[string]interface{}) map[string]interface{}{ "service-detection-full-web-service": removeOrderProperty, diff --git a/pkg/download/downloader/download_sanitize_test.go b/pkg/download/classic/download_sanitize_test.go similarity index 99% rename from pkg/download/downloader/download_sanitize_test.go rename to pkg/download/classic/download_sanitize_test.go index 310ee2655..a63012fff 100644 --- a/pkg/download/downloader/download_sanitize_test.go +++ b/pkg/download/classic/download_sanitize_test.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package downloader +package classic import ( "gotest.tools/assert" diff --git a/pkg/download/downloader/downloader.go b/pkg/download/classic/downloader.go similarity index 96% rename from pkg/download/downloader/downloader.go rename to pkg/download/classic/downloader.go index cdf70b888..54a2c79ab 100644 --- a/pkg/download/downloader/downloader.go +++ b/pkg/download/classic/downloader.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package downloader +package classic import ( "encoding/json" @@ -154,7 +154,7 @@ func findConfigsToDownload(currentApi api.Api, client rest.DynatraceClient) ([]a return client.List(currentApi) } -func downloadConfigsOfApi(theApi api.Api, values []api.Value, client rest.DynatraceClient, projectId string) []config.Config { +func downloadConfigsOfApi(theApi api.Api, values []api.Value, client rest.DynatraceClient, projectName string) []config.Config { configs := make([]config.Config, 0, len(values)) configsMutex := sync.Mutex{} @@ -166,7 +166,7 @@ func downloadConfigsOfApi(theApi api.Api, values []api.Value, client rest.Dynatr value := value go func() { - conf, skipConfig := downloadConfig(theApi, value, client, projectId) + conf, skipConfig := downloadConfig(theApi, value, client, projectName) if !skipConfig { configsMutex.Lock() @@ -183,8 +183,8 @@ func downloadConfigsOfApi(theApi api.Api, values []api.Value, client rest.Dynatr return configs } -func downloadConfig(theApi api.Api, value api.Value, client rest.DynatraceClient, projectId string) (conf config.Config, skipConfig bool) { - return downloadConfigForTesting(theApi, value, client, projectId, shouldConfigBePersisted) +func downloadConfig(theApi api.Api, value api.Value, client rest.DynatraceClient, projectName string) (conf config.Config, skipConfig bool) { + return downloadConfigForTesting(theApi, value, client, projectName, shouldConfigBePersisted) } type shouldConfigBePersistedFunc func(a api.Api, json map[string]interface{}) bool diff --git a/pkg/download/downloader/downloader_test.go b/pkg/download/classic/downloader_test.go similarity index 99% rename from pkg/download/downloader/downloader_test.go rename to pkg/download/classic/downloader_test.go index 66d7b6a38..51517cf1d 100644 --- a/pkg/download/downloader/downloader_test.go +++ b/pkg/download/classic/downloader_test.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package downloader +package classic import ( "errors" diff --git a/pkg/download/downloader/test_utils.go b/pkg/download/classic/test_utils.go similarity index 97% rename from pkg/download/downloader/test_utils.go rename to pkg/download/classic/test_utils.go index a408cb43a..2bb2f39d1 100644 --- a/pkg/download/downloader/test_utils.go +++ b/pkg/download/classic/test_utils.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package downloader +package classic import ( "encoding/json" diff --git a/pkg/download/settings/settings.go b/pkg/download/settings/settings.go new file mode 100644 index 000000000..f118755e6 --- /dev/null +++ b/pkg/download/settings/settings.go @@ -0,0 +1,91 @@ +/** + * @license + * Copyright 2020 Dynatrace LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package settings + +import ( + config "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/coordinate" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/parameter" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/parameter/value" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/template" + v2 "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/project/v2" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/rest" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/util/log" +) + +func Download(client rest.SettingsClient) v2.ConfigsPerType { + + log.Debug("Fetching schemas to download") + schemas, err := client.ListSchemas() + if err != nil { + log.Error("Failed to fetch all known schemas. Skipping settings download. Reason: %s", err) + return nil + } + + results := make(v2.ConfigsPerType) + + for _, schema := range schemas { + log.Debug("Downloading all settings for schema %s", schema) + objects, err := client.ListSettings(schema.SchemaId) + if err != nil { + log.Error("Failed to fetch all settings for schema %s", schema) + continue + } + + configs := convertAllObjects(objects) + results[schema.SchemaId] = configs + } + + return results +} + +func convertAllObjects(objects []rest.DownloadSettingsObject) []config.Config { + result := make([]config.Config, 0, len(objects)) + + for _, o := range objects { + result = append(result, convertObject(o)) + } + + return result +} + +func convertObject(o rest.DownloadSettingsObject) config.Config { + + content := string(*o.Value) + + templ := template.NewDownloadTemplate(o.ObjectId, o.ObjectId, content) + + return config.Config{ + Template: templ, + Coordinate: coordinate.Coordinate{ + Project: "project", + Type: o.SchemaId, + ConfigId: o.ObjectId, // we need a unique id -> use the objectId as it is unique + }, + Type: config.Type{ + SchemaId: o.SchemaId, + SchemaVersion: o.SchemaVersion, + }, + Parameters: map[string]parameter.Parameter{ + config.NameParameter: &value.ValueParameter{Value: o.ObjectId}, + config.ScopeParameter: &value.ValueParameter{Value: o.Scope}, + }, + References: nil, + Skip: false, + } + +} diff --git a/pkg/download/settings/settings_test.go b/pkg/download/settings/settings_test.go new file mode 100644 index 000000000..02ff0f39b --- /dev/null +++ b/pkg/download/settings/settings_test.go @@ -0,0 +1,126 @@ +/** + * @license + * Copyright 2020 Dynatrace LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package settings + +import ( + "encoding/json" + "fmt" + config "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/coordinate" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/parameter" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/parameter/value" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/config/v2/template" + v2 "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/project/v2" + "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/rest" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestDownload(t *testing.T) { + type mockValues struct { + Schemas func() (rest.SchemaList, error) + ListSchamasCalls int + Settings func() ([]rest.DownloadSettingsObject, error) + ListSettingsCalls int + } + tests := []struct { + name string + mockValues mockValues + want v2.ConfigsPerType + }{ + { + name: "DownloadSettings - List Schemas fails", + mockValues: mockValues{ + ListSchamasCalls: 1, + Schemas: func() (rest.SchemaList, error) { + return nil, fmt.Errorf("oh no") + }, + Settings: func() ([]rest.DownloadSettingsObject, error) { + return nil, nil + }, + ListSettingsCalls: 0, + }, + want: nil, + }, + { + name: "DownloadSettings - List Settings fails", + mockValues: mockValues{ + ListSchamasCalls: 1, + Schemas: func() (rest.SchemaList, error) { + return rest.SchemaList{{SchemaId: "id1"}, {SchemaId: "id2"}}, nil + }, + Settings: func() ([]rest.DownloadSettingsObject, error) { + return nil, fmt.Errorf("oh no") + }, + ListSettingsCalls: 2, + }, + want: v2.ConfigsPerType{}, + }, + { + name: "DownloadSettings", + mockValues: mockValues{ + ListSchamasCalls: 1, + Schemas: func() (rest.SchemaList, error) { + return rest.SchemaList{{SchemaId: "id1"}}, nil + }, + Settings: func() ([]rest.DownloadSettingsObject, error) { + return []rest.DownloadSettingsObject{{ + ExternalId: "ex1", + SchemaVersion: "sv1", + SchemaId: "sid1", + ObjectId: "oid1", + Scope: "tenant", + Value: &json.RawMessage{}, + }}, nil + }, + ListSettingsCalls: 1, + }, + want: v2.ConfigsPerType{"id1": { + { + Template: template.NewDownloadTemplate("oid1", "oid1", string(json.RawMessage{})), + Coordinate: coordinate.Coordinate{ + Project: "project", + Type: "sid1", + ConfigId: "oid1", + }, + Type: config.Type{ + SchemaId: "sid1", + SchemaVersion: "sv1", + }, + Parameters: map[string]parameter.Parameter{ + config.NameParameter: &value.ValueParameter{Value: "oid1"}, + config.ScopeParameter: &value.ValueParameter{Value: "tenant"}, + }, + References: nil, + Skip: false, + }, + }}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := rest.NewMockDynatraceClient(gomock.NewController(t)) + schemas, err := tt.mockValues.Schemas() + c.EXPECT().ListSchemas().Times(tt.mockValues.ListSchamasCalls).Return(schemas, err) + settings, err := tt.mockValues.Settings() + c.EXPECT().ListSettings(gomock.Any()).Times(tt.mockValues.ListSettingsCalls).Return(settings, err) + res := Download(c) + assert.Equal(t, tt.want, res) + }) + } +} diff --git a/pkg/rest/client.go b/pkg/rest/client.go index b8cbeb98e..dc8ab9e84 100644 --- a/pkg/rest/client.go +++ b/pkg/rest/client.go @@ -69,6 +69,15 @@ type ConfigClient interface { // KnownSettings contains externalId -> objectId type KnownSettings map[string]string +type DownloadSettingsObject struct { + ExternalId string `json:"externalId"` + SchemaVersion string `json:"schemaVersion"` + SchemaId string `json:"schemaId"` + ObjectId string `json:"objectId"` + Scope string `json:"scope"` + Value *json.RawMessage `json:"value"` +} + // SettingsClient is the abstraction layer for CRUD operations on the Dynatrace Settings API. // Its design is intentionally not dependent on Monaco objects. // @@ -89,6 +98,12 @@ type SettingsClient interface { // ListKnownSettings queries all settings for the given schema ID. // All queried objects that have an external ID will be returned. ListKnownSettings(schemaId string) (KnownSettings, error) + + // ListSchemas returns all schemas that the Dynatrace environment reports + ListSchemas() (SchemaList, error) + + // ListSettings returns all settings objects for a given schema. + ListSettings(schema string) ([]DownloadSettingsObject, error) } //go:generate mockgen -source=client.go -destination=client_mock.go -package=rest -imports .=github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api DynatraceClient @@ -295,7 +310,7 @@ func (d *dynatraceClient) ListKnownSettings(schemaId string) (KnownSettings, err } u.RawQuery = params.Encode() - resp, err := get(d.client, u.String(), d.token) + resp, err := getWithRetry(d.client, u.String(), d.token, d.retrySettings.normal) if err != nil { return nil, fmt.Errorf("failed to build request: %w", err) } @@ -337,3 +352,90 @@ func (d *dynatraceClient) ListKnownSettings(schemaId string) (KnownSettings, err return result, nil } + +type SchemaListResponse struct { + Items SchemaList `json:"items"` +} +type SchemaList []struct { + SchemaId string `json:"schemaId"` +} + +func (d *dynatraceClient) ListSchemas() (SchemaList, error) { + u, err := url.Parse(d.environmentUrl + pathSchemas) + if err != nil { + return nil, fmt.Errorf("failed to parse url: %w", err) + } + + // getting all schemas does not have pagination + resp, err := get(d.client, u.String(), d.token) + if err != nil { + return nil, fmt.Errorf("failed to GET schemas: %w", err) + } + + if !success(resp) { + return nil, fmt.Errorf("request failed with HTTP (%d).\n\tResponse content: %s", resp.StatusCode, string(resp.Body)) + } + + var result SchemaListResponse + err = json.Unmarshal(resp.Body, &result) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal response: %w", err) + } + + return result.Items, nil +} + +func (d *dynatraceClient) ListSettings(schema string) ([]DownloadSettingsObject, error) { + + u, err := url.Parse(d.environmentUrl + pathSettingsObjects) + if err != nil { + return nil, fmt.Errorf("Failed to parse url '%s': %w", d.environmentUrl+pathSettingsObjects, err) + } + + params := url.Values{ + "schemaIds": []string{schema}, + "pageSize": []string{"500"}, + "fields": []string{"objectId,value,externalId,schemaVersion,schemaId,scope"}, + } + u.RawQuery = params.Encode() + + resp, err := getWithRetry(d.client, u.String(), d.token, d.retrySettings.normal) + if err != nil { + return nil, fmt.Errorf("failed to build request: %w", err) + } + + if !success(resp) { + return nil, fmt.Errorf("request failed with HTTP (%d).\n\tResponse content: %s", resp.StatusCode, string(resp.Body)) + } + + result := make([]DownloadSettingsObject, 0) + for { + var parsed struct { + Items []DownloadSettingsObject `json:"items"` + } + if err := json.Unmarshal(resp.Body, &parsed); err != nil { + return nil, fmt.Errorf("failed to unmarshal response: %w", err) + } + + result = append(result, parsed.Items...) + + if resp.NextPageKey != "" { + u = addNextPageQueryParams(u, resp.NextPageKey) + + resp, err = getWithRetry(d.client, u.String(), d.token, d.retrySettings.normal) + + if err != nil { + return nil, err + } + + if !success(resp) { + return nil, fmt.Errorf("Failed to get further configs from Settings API (HTTP %d)!\n Response was: %s", resp.StatusCode, string(resp.Body)) + } + + } else { + break + } + } + + return result, nil +} diff --git a/pkg/rest/limiting_client.go b/pkg/rest/limiting_client.go index b13a9a61d..4d837f3ca 100644 --- a/pkg/rest/limiting_client.go +++ b/pkg/rest/limiting_client.go @@ -97,3 +97,19 @@ func (l limitingClient) ListKnownSettings(schemaId string) (k KnownSettings, err return } + +func (l limitingClient) ListSchemas() (s SchemaList, err error) { + l.limiter.ExecuteBlocking(func() { + s, err = l.client.ListSchemas() + }) + + return +} + +func (l limitingClient) ListSettings(schema string) (o []DownloadSettingsObject, err error) { + l.limiter.ExecuteBlocking(func() { + o, err = l.client.ListSettings(schema) + }) + + return +} diff --git a/pkg/rest/settings_client.go b/pkg/rest/settings_client.go index 36920bb8d..1a05b5b4d 100644 --- a/pkg/rest/settings_client.go +++ b/pkg/rest/settings_client.go @@ -23,6 +23,7 @@ import ( ) const pathSettingsObjects = "/api/v2/settings/objects" +const pathSchemas = "/api/v2/settings/schemas" // SettingsObject contains all the information necessary to create/update a settings object type SettingsObject struct { diff --git a/pkg/util/client/dummy_client.go b/pkg/util/client/dummy_client.go index c2af6cb49..2b4eab9bc 100644 --- a/pkg/util/client/dummy_client.go +++ b/pkg/util/client/dummy_client.go @@ -238,13 +238,21 @@ func (c *DummyClient) ExistsByName(a api.Api, name string) (exists bool, id stri return false, "", nil } -func (c *DummyClient) UpsertSettings(k rest.KnownSettings, obj rest.SettingsObject) (api.DynatraceEntity, error) { +func (c *DummyClient) UpsertSettings(_ rest.KnownSettings, obj rest.SettingsObject) (api.DynatraceEntity, error) { return api.DynatraceEntity{ Id: obj.Id, Name: obj.Id, }, nil } -func (c *DummyClient) ListKnownSettings(schemaId string) (rest.KnownSettings, error) { +func (c *DummyClient) ListKnownSettings(_ string) (rest.KnownSettings, error) { return make(rest.KnownSettings), nil } + +func (c *DummyClient) ListSchemas() (rest.SchemaList, error) { + return make(rest.SchemaList, 0), nil +} + +func (c *DummyClient) ListSettings(_ string) ([]rest.DownloadSettingsObject, error) { + return make([]rest.DownloadSettingsObject, 0), nil +}