diff --git a/Makefile b/Makefile index 8dadddda..c647602f 100644 --- a/Makefile +++ b/Makefile @@ -110,9 +110,9 @@ check/format: $(call _print_check_step,Checking if files are formatted) ./scripts/check-formatting.sh -.PHONY: generate generate/code generate/examples generate/plantuml +.PHONY: generate generate/code generate/examples ## Auto generate files. -generate: generate/code generate/examples generate/plantuml +generate: generate/code generate/examples ## Generate Golang code. generate/code: @@ -127,22 +127,6 @@ generate/examples: echo "Generating examples..." go run internal/cmd/examplegen/main.go -PLANTUML_JAR_URL := https://sourceforge.net/projects/plantuml/files/plantuml.jar/download -PLANTUML_JAR := $(BIN_DIR)/plantuml.jar -DIAGRAMS_PATH ?= . - -## Generate PNG diagrams from PlantUML files. -generate/plantuml: $(PLANTUML_JAR) - for path in $$(find $(DIAGRAMS_PATH) -name "*.puml" -type f); do \ - echo "Generating PNG file(s) for $$path"; \ - java -jar $(PLANTUML_JAR) -tpng $$path; \ - done - -# If the plantuml.jar file isn't already present, download it. -$(PLANTUML_JAR): - echo "Downloading PlantUML JAR..." - curl -sSfL $(PLANTUML_JAR_URL) -o $(PLANTUML_JAR) - .PHONY: format format/go format/cspell ## Format files. format: format/go format/cspell @@ -151,7 +135,7 @@ format: format/go format/cspell format/go: echo "Formatting Go files..." $(call _ensure_installed,binary,goimports) - go fmt ./... + gofmt -w -l -s . $(BIN_DIR)/goimports -local=github.com/nobl9/nobl9-go -w . ## Format cspell config file. diff --git a/README.md b/README.md index 967b2a1c..12806d2d 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,9 @@ Legend: 1. [Installation](#installation) 2. [Examples](#examples) -3. [Repository structure](#repository-structure) -4. [Contributing](#contributing) +3. [Usage](#usage) +4. [Repository structure](#repository-structure) +5. [Contributing](#contributing) # Installation @@ -54,105 +55,155 @@ go get github.com/nobl9/nobl9-go ## Basic usage + ```go package main import ( - "context" - "encoding/json" - "fmt" - "log" - - "github.com/nobl9/nobl9-go/manifest" - "github.com/nobl9/nobl9-go/manifest/v1alpha" - "github.com/nobl9/nobl9-go/manifest/v1alpha/project" - "github.com/nobl9/nobl9-go/manifest/v1alpha/service" - "github.com/nobl9/nobl9-go/sdk" - objectsV1 "github.com/nobl9/nobl9-go/sdk/endpoints/objects/v1" + "context" + "encoding/json" + "fmt" + "log" + + "github.com/nobl9/nobl9-go/manifest" + "github.com/nobl9/nobl9-go/manifest/v1alpha" + "github.com/nobl9/nobl9-go/manifest/v1alpha/project" + "github.com/nobl9/nobl9-go/manifest/v1alpha/service" + "github.com/nobl9/nobl9-go/sdk" + objectsV1 "github.com/nobl9/nobl9-go/sdk/endpoints/objects/v1" ) func main() { - ctx := context.Background() - - // Create client. - client, err := sdk.DefaultClient() - if err != nil { - log.Fatalf("failed to create sdk client, err: %v", err) - } - - // Read from file, url or glob pattern. - objects, err := sdk.ReadObjects(ctx, "./project.yaml") - if err != nil { - log.Fatalf("failed to read project.yaml file, err: %v", err) - } - // Use manifest.FilterByKind to extract specific objects from the manifest.Object slice. - myProject := manifest.FilterByKind[project.Project](objects)[0] - // Define objects in code. - myService := service.New( - service.Metadata{ - Name: "my-service", - DisplayName: "My Service", - Project: myProject.GetName(), - Labels: v1alpha.Labels{ - "team": []string{"green", "orange"}, - "region": []string{"eu-central-1"}, - }, - }, - service.Spec{ - Description: "Example service", - }, - ) - objects = append(objects, myService) - - // Verify the objects. - if errs := manifest.Validate(objects); len(errs) > 0 { - log.Fatalf("service validation failed, errors: %v", errs) - } - - // Apply the objects. - if err = client.Objects().V1().Apply(ctx, objects); err != nil { - log.Fatalf("failed to apply objects, err: %v", err) - } - - // Get the applied resources. - services, err := client.Objects().V1().GetV1alphaServices(ctx, objectsV1.GetServicesRequest{ - Project: myProject.GetName(), - Names: []string{myService.GetName()}, - }) - if err != nil { - log.Fatalf("failed to get services, err: %v", err) - } - projects, err := client.Objects().V1().GetV1alphaProjects(ctx, objectsV1.GetProjectsRequest{ - Names: []string{myProject.GetName()}, - }) - if err != nil { - log.Fatalf("failed to get projects, err: %v", err) - } - - // Aggregate objects back into manifest.Objects slice. - appliedObjects := make([]manifest.Object, 0, len(services)+len(projects)) - for _, service := range services { - appliedObjects = append(appliedObjects, service) - } - for _, project := range projects { - appliedObjects = append(appliedObjects, project) - } - - // Print JSON representation of these objects. - data, err := json.MarshalIndent(appliedObjects, "", " ") - if err != nil { - log.Fatalf("failed to marshal objects, err: %v", err) - } - fmt.Println(string(data)) - - // Delete resources. - if err = client.Objects().V1().Delete(ctx, objects); err != nil { - log.Fatalf("failed to delete objects, err: %v", err) - } + ctx := context.Background() + + // Create client. + client, err := sdk.DefaultClient() + if err != nil { + log.Fatalf("failed to create sdk client, err: %v", err) + } + + // Read from file, url or glob pattern. + objects, err := sdk.ReadObjects(ctx, "./project.yaml") + if err != nil { + log.Fatalf("failed to read project.yaml file, err: %v", err) + } + // Use manifest.FilterByKind to extract specific objects from the manifest.Object slice. + myProject := manifest.FilterByKind[project.Project](objects)[0] + // Define objects in code. + myService := service.New( + service.Metadata{ + Name: "my-service", + DisplayName: "My Service", + Project: myProject.GetName(), + Labels: v1alpha.Labels{ + "team": []string{"green", "orange"}, + "region": []string{"eu-central-1"}, + }, + }, + service.Spec{ + Description: "Example service", + }, + ) + objects = append(objects, myService) + + // Verify the objects. + if errs := manifest.Validate(objects); len(errs) > 0 { + log.Fatalf("service validation failed, errors: %v", errs) + } + + // Apply the objects. + if err = client.Objects().V1().Apply(ctx, objects); err != nil { + log.Fatalf("failed to apply objects, err: %v", err) + } + + // Get the applied resources. + services, err := client.Objects().V1().GetV1alphaServices(ctx, objectsV1.GetServicesRequest{ + Project: myProject.GetName(), + Names: []string{myService.GetName()}, + }) + if err != nil { + log.Fatalf("failed to get services, err: %v", err) + } + projects, err := client.Objects().V1().GetV1alphaProjects(ctx, objectsV1.GetProjectsRequest{ + Names: []string{myProject.GetName()}, + }) + if err != nil { + log.Fatalf("failed to get projects, err: %v", err) + } + + // Aggregate objects back into manifest.Objects slice. + appliedObjects := make([]manifest.Object, 0, len(services)+len(projects)) + for _, service := range services { + appliedObjects = append(appliedObjects, service) + } + for _, project := range projects { + appliedObjects = append(appliedObjects, project) + } + + // Print JSON representation of these objects. + data, err := json.MarshalIndent(appliedObjects, "", " ") + if err != nil { + log.Fatalf("failed to marshal objects, err: %v", err) + } + fmt.Println(string(data)) + + // Delete resources. + if err = client.Objects().V1().Delete(ctx, objects); err != nil { + log.Fatalf("failed to delete objects, err: %v", err) + } } ``` + +# Usage + +## Reading configuration + +In order for `sdk.Client` to work, it needs to be configured. +The configuration can be read from a file, environment variables, +code options or a combination of these. + +The precedence of the configuration sources is as follows +(starting from the highest): + +- Code options +- Environment variables +- Configuration file +- Default values + +The following flowchart illustrates the process of reading the configuration: + +```mermaid +flowchart TD + subgraph s1[Read config file] + direction LR + As1{{Config file exists}} -- true --> Bs1(Read config file) + As1 -- false --> Cs1(Create default config file) + Cs1 --> Bs1 + end + subgraph s2[Build config struct] + direction LR + As2{{Has ConfigOption}} -- not set --> Bs2{{Has env variable}} + As2 -- set --> Fs2(Use value) + Bs2 -- not set --> Cs2{{Has config file option}} + Bs2 -- set --> Fs2 + Cs2 -- not set --> Ds2{{Has default value}} + Cs2 -- set --> Fs2 + Ds2 -- not set --> Es2(No value) + Ds2 -- set --> Fs2 + end + A(Read config) --> B(Read config options defined in code) + B --> C(Read env variables) + C --> s1 + s1 --> s2 --> I(Return Config) +``` + +## Testing code relying on nobl9-go + +Checkout [these instructions](./docs/mock_example/README.md) +along with a working example for recommendations on mocking `sdk.Client`. + # Repository structure ## Public packages @@ -184,6 +235,14 @@ func main() { - Object-specific packages, like [slo](./manifest/v1alpha/slo), provide object definition for specific object versions. +## Internal packages + +1. [tests](./tests) contains the end-to-end tests code. + These tests are run directly against a Nobl9 platform. +2. [internal](./internal) holds internal packages that are not meant to be + exposed as part of the library's API. + # Contributing -TBA +Checkout both [contributing guidelines](./docs/CONTRIBUTING.md) and +[development instructions](./docs/DEVELOPMENT.md). diff --git a/cspell.yaml b/cspell.yaml index 63f20bfc..fbd0db71 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -81,6 +81,7 @@ words: - generify - gobin - gofile + - gofmt - goimports - golangci - gomnd diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000..0b465c1b --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing to nobl9-go + +If you're here, chances are you want to contribute ;) +Thanks a lot for that! + +Your pull request will be reviewed by one of the maintainers. +We encourage and welcome any and all feedback. + +## Before you contribute + +The goal of this project is to provide a feature-rich and easy-to-use +Golang SDK for Nobl9 platform. + +Make sure you're familiarized with +[development instructions](./DEVELOPMENT.md). + +## Making a pull request + +Please make a fork of this repo and submit a PR from there. +More information can be found +[here](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request). + +## Merge Request title + +Try to be as descriptive as you can in your PR title. +Note that the title must adhere to the rules defined in +[this workflow](./.github/workflows/pr-title.yml). + +## License + +Nobl9-go is licensed under Mozilla Public License Version 2.0, see [LICENSE](../LICENSE). diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 44ba3a7f..5a5e3702 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -124,8 +124,9 @@ We use the following tools to do that: ## Validation -We're using our own validation library to write validation for all objects. -Refer to this [README.md](../internal/validation/README.md) for more information. +We're using [govy](https://github.com/nobl9/govy) library for validation. +If you encounter any bugs or shortcomings feel free to open an issue or PR +at govy's GitHub page. ## Dependencies diff --git a/internal/sdk/response_errors.go b/internal/sdk/response_errors.go deleted file mode 100644 index 205d02a6..00000000 --- a/internal/sdk/response_errors.go +++ /dev/null @@ -1,40 +0,0 @@ -package sdk - -import ( - "bytes" - "fmt" - "io" - "net/http" - - "github.com/pkg/errors" -) - -func ProcessResponseErrors(resp *http.Response) error { - switch { - case resp.StatusCode >= 300 && resp.StatusCode < 400: - rawErr, _ := io.ReadAll(resp.Body) - return fmt.Errorf("unexpected status code response: %d, body: %s", resp.StatusCode, string(rawErr)) - case resp.StatusCode >= 400 && resp.StatusCode < 500: - body, _ := io.ReadAll(resp.Body) - return fmt.Errorf("%s", bytes.TrimSpace(body)) - case resp.StatusCode >= 500: - return getResponseServerError(resp) - } - return nil -} - -var ErrConcurrencyIssue = errors.New("operation failed due to concurrency issue but can be retried") - -func getResponseServerError(resp *http.Response) error { - rawBody, _ := io.ReadAll(resp.Body) - body := string(bytes.TrimSpace(rawBody)) - if body == ErrConcurrencyIssue.Error() { - return ErrConcurrencyIssue - } - msg := fmt.Sprintf("%s error message: %s", http.StatusText(resp.StatusCode), rawBody) - traceID := resp.Header.Get(HeaderTraceID) - if traceID != "" { - msg = fmt.Sprintf("%s error id: %s", msg, traceID) - } - return errors.New(msg) -} diff --git a/internal/sdk/response_errors_test.go b/internal/sdk/response_errors_test.go deleted file mode 100644 index 74ebbec5..00000000 --- a/internal/sdk/response_errors_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package sdk - -import ( - "bytes" - "fmt" - "io" - "net/http" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestProcessResponseErrors(t *testing.T) { - t.Parallel() - - t.Run("status code smaller than 300, no error", func(t *testing.T) { - t.Parallel() - for code := 200; code < 300; code++ { - require.NoError(t, ProcessResponseErrors(&http.Response{StatusCode: code})) - } - }) - - t.Run("status code between 300 and 399", func(t *testing.T) { - t.Parallel() - for code := 300; code < 400; code++ { - err := ProcessResponseErrors(&http.Response{ - StatusCode: code, - Body: io.NopCloser(bytes.NewBufferString("error!"))}) - require.Error(t, err) - require.EqualError(t, err, fmt.Sprintf("unexpected status code response: %d, body: error!", code)) - } - }) - - t.Run("user errors", func(t *testing.T) { - t.Parallel() - for code := 400; code < 500; code++ { - err := ProcessResponseErrors(&http.Response{ - StatusCode: code, - Body: io.NopCloser(bytes.NewBufferString("error!"))}) - require.Error(t, err) - require.EqualError(t, err, "error!") - } - }) - - t.Run("server errors", func(t *testing.T) { - t.Parallel() - for code := 500; code < 600; code++ { - err := ProcessResponseErrors(&http.Response{ - StatusCode: code, - Header: http.Header{HeaderTraceID: []string{"123"}}, - Body: io.NopCloser(bytes.NewBufferString("error!"))}) - require.Error(t, err) - require.EqualError(t, - err, - fmt.Sprintf("%s error message: error! error id: 123", http.StatusText(code))) - } - }) - - t.Run("concurrency issue", func(t *testing.T) { - t.Parallel() - err := ProcessResponseErrors(&http.Response{ - StatusCode: 500, - Body: io.NopCloser(bytes.NewBufferString( - "operation failed due to concurrency issue but can be retried"))}) - require.Error(t, err) - require.Equal(t, ErrConcurrencyIssue, err) - }) -} diff --git a/sdk/api_error.tmpl b/sdk/api_error.tmpl new file mode 100644 index 00000000..187b041e --- /dev/null +++ b/sdk/api_error.tmpl @@ -0,0 +1 @@ +{{- if .CodeText }}{{ .CodeText }}: {{ end -}}{{ .Message }} (code: {{ .Code }}{{- if .URL }}, endpoint: {{ .Method }} {{ .URL }}{{- end }}{{- if .TraceID }}, traceId: {{ .TraceID }}{{- end }}) \ No newline at end of file diff --git a/sdk/client.go b/sdk/client.go index 5e25e928..8e8c96e3 100644 --- a/sdk/client.go +++ b/sdk/client.go @@ -132,6 +132,10 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) { if err != nil { return nil, errors.Wrap(err, "failed to execute request") } + if err = processHTTPResponse(resp); err != nil { + _ = resp.Body.Close() + return nil, err + } return resp, nil } diff --git a/sdk/client_errors.go b/sdk/client_errors.go new file mode 100644 index 00000000..e849e61d --- /dev/null +++ b/sdk/client_errors.go @@ -0,0 +1,80 @@ +package sdk + +import ( + "bytes" + _ "embed" + "fmt" + "io" + "net/http" + "os" + "text/template" +) + +// APIError represents an HTTP error response from the API. +type APIError struct { + Message string `json:"message"` + StatusCode int `json:"statusCode"` + Method string `json:"method"` + URL string `json:"url"` + TraceID string `json:"traceId,omitempty"` +} + +// IsRetryable returns true if the underlying API error can be retried. +func (r APIError) IsRetryable() bool { + return r.StatusCode >= 500 +} + +// Error returns a string representation of the error. +func (r APIError) Error() string { + buf := bytes.Buffer{} + buf.Grow(len(apiErrorTemplateData)) + if err := apiErrorTemplate.Execute(&buf, apiErrorTemplateFields{ + Message: r.Message, + Method: r.Method, + URL: r.URL, + TraceID: r.TraceID, + CodeText: http.StatusText(r.StatusCode), + Code: r.StatusCode, + }); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "failed to execute APIError template: %v\n", err) + } + return buf.String() +} + +// processHTTPResponse processes an HTTP response and returns an error if the response is erroneous. +func processHTTPResponse(resp *http.Response) error { + if resp.StatusCode < 300 { + return nil + } + var body string + if resp.Body != nil { + rawBody, _ := io.ReadAll(resp.Body) + body = string(bytes.TrimSpace(rawBody)) + } + respErr := APIError{ + StatusCode: resp.StatusCode, + TraceID: resp.Header.Get(HeaderTraceID), + Message: body, + } + if resp.Request != nil { + if resp.Request.URL != nil { + respErr.URL = resp.Request.URL.String() + } + respErr.Method = resp.Request.Method + } + return &respErr +} + +//go:embed api_error.tmpl +var apiErrorTemplateData string + +var apiErrorTemplate = template.Must(template.New("api_error").Parse(apiErrorTemplateData)) + +type apiErrorTemplateFields struct { + Message string + Method string + URL string + TraceID string + CodeText string + Code int +} diff --git a/sdk/client_errors_test.go b/sdk/client_errors_test.go new file mode 100644 index 00000000..baad6898 --- /dev/null +++ b/sdk/client_errors_test.go @@ -0,0 +1,127 @@ +package sdk + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAPIError(t *testing.T) { + t.Parallel() + t.Run("status code smaller than 300, no error", func(t *testing.T) { + t.Parallel() + for code := 200; code < 300; code++ { + require.NoError(t, processHTTPResponse(&http.Response{StatusCode: code})) + } + }) + t.Run("errors", func(t *testing.T) { + t.Parallel() + for code := 300; code < 600; code++ { + err := processHTTPResponse(&http.Response{ + StatusCode: code, + Body: io.NopCloser(bytes.NewBufferString("error!")), + Header: http.Header{HeaderTraceID: []string{"123"}}, + Request: &http.Request{ + Method: http.MethodGet, + URL: &url.URL{ + Scheme: "https", + Host: "app.nobl9.com", + Path: "/api/slos", + }, + }, + }) + require.Error(t, err) + expectedMessage := fmt.Sprintf("error! (code: %d, endpoint: GET https://app.nobl9.com/api/slos, traceId: 123)", code) + if textCode := http.StatusText(code); textCode != "" { + expectedMessage = textCode + ": " + expectedMessage + } + require.EqualError(t, err, expectedMessage) + } + }) + t.Run("missing trace id", func(t *testing.T) { + t.Parallel() + err := processHTTPResponse(&http.Response{ + StatusCode: http.StatusBadRequest, + Body: io.NopCloser(bytes.NewBufferString("error!")), + Request: &http.Request{ + Method: http.MethodGet, + URL: &url.URL{ + Scheme: "https", + Host: "app.nobl9.com", + Path: "/api/slos", + }, + }, + }) + require.Error(t, err) + expectedMessage := "Bad Request: error! (code: 400, endpoint: GET https://app.nobl9.com/api/slos)" + require.EqualError(t, err, expectedMessage) + }) + t.Run("missing status text", func(t *testing.T) { + t.Parallel() + err := processHTTPResponse(&http.Response{ + StatusCode: 555, + Body: io.NopCloser(bytes.NewBufferString("error!")), + Request: &http.Request{ + Method: http.MethodGet, + URL: &url.URL{ + Scheme: "https", + Host: "app.nobl9.com", + Path: "/api/slos", + }, + }, + }) + require.Error(t, err) + expectedMessage := "error! (code: 555, endpoint: GET https://app.nobl9.com/api/slos)" + require.EqualError(t, err, expectedMessage) + }) + t.Run("missing url", func(t *testing.T) { + t.Parallel() + err := processHTTPResponse(&http.Response{ + StatusCode: 555, + Body: io.NopCloser(bytes.NewBufferString("error!")), + }) + require.Error(t, err) + expectedMessage := "error! (code: 555)" + require.EqualError(t, err, expectedMessage) + }) +} + +func TestAPIError_IsRetryable(t *testing.T) { + t.Parallel() + tests := []*http.Response{ + { + StatusCode: http.StatusInternalServerError, + Body: io.NopCloser(bytes.NewBufferString("operation failed due to concurrency issue but can be retried")), + Request: &http.Request{ + Method: http.MethodPut, + URL: &url.URL{ + Scheme: "https", + Host: "app.nobl9.com", + Path: "/api/apply", + }, + }, + }, + { + StatusCode: http.StatusInternalServerError, + Request: &http.Request{ + Method: http.MethodPut, + URL: &url.URL{ + Scheme: "https", + Host: "app.nobl9.com", + Path: "/api/apply", + }, + }, + }, + } + for _, test := range tests { + err := processHTTPResponse(test) + require.Error(t, err) + assert.True(t, err.(*APIError).IsRetryable()) + } +} diff --git a/sdk/client_test.go b/sdk/client_test.go index f97e4fc8..e2ace0e8 100644 --- a/sdk/client_test.go +++ b/sdk/client_test.go @@ -145,8 +145,8 @@ func prepareTestClient(t *testing.T, endpoint endpointConfig) (client *Client, s KID: kid, }, }) - jwks := jwkset.JWKSMarshal{Keys: []jwkset.JWKMarshal{jwk.Marshal()}} require.NoError(t, err) + jwks := jwkset.JWKSMarshal{Keys: []jwkset.JWKMarshal{jwk.Marshal()}} // Prepare the token. claims := jwt.MapClaims{ diff --git a/sdk/config.go b/sdk/config.go index 33540446..4de09ce5 100644 --- a/sdk/config.go +++ b/sdk/config.go @@ -44,7 +44,7 @@ func GetDefaultConfigPath() (string, error) { // - config file // - default values where applicable // -// Detailed flow can be found in config_activity.png (generated from config_activity.puml). +// Detailed flow can be found in config_activity.mmd. func ReadConfig(options ...ConfigOption) (*Config, error) { conf, err := newConfig(options) if err != nil { @@ -243,7 +243,7 @@ func newConfig(options []ConfigOption) (*Config, error) { for _, applyOption := range options { applyOption(conf) } - if err := conf.processEnvVariables(&conf.options, false); err != nil { + if err = conf.processEnvVariables(&conf.options, false); err != nil { return nil, err } return conf, nil diff --git a/sdk/config_activity.png b/sdk/config_activity.png deleted file mode 100644 index b64ec382..00000000 Binary files a/sdk/config_activity.png and /dev/null differ diff --git a/sdk/config_activity.puml b/sdk/config_activity.puml deleted file mode 100644 index 614d52b8..00000000 --- a/sdk/config_activity.puml +++ /dev/null @@ -1,34 +0,0 @@ -@startuml -'https://plantuml.com/activity-diagram-beta - -start -:ReadConfig; -:Read ConfigOption; -:Read env variables; -if (NO_CONFIG_FILE) then (true) - label sp_lab0 -else (false) - if (Config file exists) then (true) - label sp_lab0 - else (false) - :create default config file; - label sp_lab0 - endif - label read_conf_file - :Read config file; -endif - -repeat - if (ConfigOption) then (use) - (not set) elseif (Env variable) then (use) - (not set) elseif (Config file option) then (use) - (not set) elseif (Has default value) then (use) - else (not set) - :no value; - endif -repeat while (More config options?) is (yes) - -:Return Config; -stop - -@enduml diff --git a/sdk/endpoints/authdata/v1/endpoints.go b/sdk/endpoints/authdata/v1/endpoints.go index d73fcfa7..aebf9d67 100644 --- a/sdk/endpoints/authdata/v1/endpoints.go +++ b/sdk/endpoints/authdata/v1/endpoints.go @@ -56,9 +56,6 @@ func (e endpoints) GetAgentCredentials( return creds, errors.Wrap(err, "failed to execute request") } defer func() { _ = resp.Body.Close() }() - if err = sdk.ProcessResponseErrors(resp); err != nil { - return creds, err - } if err = json.NewDecoder(resp.Body).Decode(&creds); err != nil { return creds, errors.Wrap(err, "failed to decode response body") } @@ -82,9 +79,6 @@ func (e endpoints) getIAMRoleIDs(ctx context.Context, endpoint, project string) return nil, errors.Wrap(err, "failed to execute request") } defer func() { _ = resp.Body.Close() }() - if err = sdk.ProcessResponseErrors(resp); err != nil { - return nil, err - } var response IAMRoleIDs if err = json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, errors.Wrap(err, "failed to decode response body") diff --git a/sdk/endpoints/objects/v1/endpoints.go b/sdk/endpoints/objects/v1/endpoints.go index 34376efe..f5989ca4 100644 --- a/sdk/endpoints/objects/v1/endpoints.go +++ b/sdk/endpoints/objects/v1/endpoints.go @@ -78,8 +78,8 @@ func (e endpoints) DeleteByName( if err != nil { return err } - defer func() { _ = resp.Body.Close() }() - return sdk.ProcessResponseErrors(resp) + _ = resp.Body.Close() + return nil } func (e endpoints) Get( @@ -104,9 +104,6 @@ func (e endpoints) Get( return nil, err } defer func() { _ = resp.Body.Close() }() - if err = sdk.ProcessResponseErrors(resp); err != nil { - return nil, err - } return e.readObjects(ctx, resp.Body) } @@ -147,8 +144,8 @@ func (e endpoints) applyOrDeleteObjects( if err != nil { return err } - defer func() { _ = resp.Body.Close() }() - return sdk.ProcessResponseErrors(resp) + _ = resp.Body.Close() + return nil } func (e endpoints) setOrganizationForObjects( diff --git a/sdk/endpoints/objects/v1/endpoints_v1alpha.go b/sdk/endpoints/objects/v1/endpoints_v1alpha.go index 81400e21..7ecb8f8c 100644 --- a/sdk/endpoints/objects/v1/endpoints_v1alpha.go +++ b/sdk/endpoints/objects/v1/endpoints_v1alpha.go @@ -251,9 +251,6 @@ func (e endpoints) GetAlerts( return nil, 0, err } defer func() { _ = resp.Body.Close() }() - if err = sdk.ProcessResponseErrors(resp); err != nil { - return nil, 0, err - } objects, err := e.readObjects(ctx, resp.Body) if err != nil {