From c5af0073cbd1a1e5ed205073b10aaf41a0fe7d9c Mon Sep 17 00:00:00 2001 From: Shristi Singh Date: Thu, 22 Aug 2024 13:52:37 +0000 Subject: [PATCH 01/34] DXE-4081 Changelog boilerplate Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/DXE-4081-changelog-boilerplate to develop --- CHANGELOG.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09dc3e0f..04098f0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,97 @@ # EDGEGRID GOLANG RELEASE NOTES + +## X.X.X (X X, X) + +#### BREAKING CHANGES: + + + + + + + + + + + + + + + + + + + + + + + + + + +#### FEATURES/ENHANCEMENTS: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#### BUG FIXES: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## 8.4.0 (Aug 22, 2024) From ea1dbf609af2a07bcbcd8188d4076cb44d98600e Mon Sep 17 00:00:00 2001 From: Rahul Bhatvedekar Date: Tue, 17 Sep 2024 12:37:58 +0000 Subject: [PATCH 02/34] DXE-3001 Retry CreateProperty on Property Validation Failure - Error Handling Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/DXE-3001 to develop --- Makefile | 10 +++++++--- pkg/gtm/errors.go | 8 ++++++++ pkg/gtm/errors_test.go | 22 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9911609a..b24fff07 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,13 @@ M = $(shell echo ">") clean-tools: @rm -rf $(BIN)/go* +# Until v0.25.0 is not fixed, we have to use previous version. To install it, we must enable module aware mode. +GOIMPORTS = $(BIN)/goimports +GOIMPORTS_VERSION = v0.24.0 +# Rule to install goimports with version pinning +$(GOIMPORTS): | $(BIN) ; $(info $(M) Installing goimports $(GOIMPORTS_VERSION)...) + $Q env GO111MODULE=on GOBIN=$(BIN) $(GO) install golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) + $(BIN): @mkdir -p $@ $(BIN)/%: | $(BIN) ; $(info $(M) Building $(PACKAGE)...) @@ -34,9 +41,6 @@ $(BIN)/gocov-xml: PACKAGE=github.com/AlekSi/gocov-xml GOJUNITREPORT = $(BIN)/go-junit-report $(BIN)/go-junit-report: PACKAGE=github.com/jstemmer/go-junit-report -GOIMPORTS = $(BIN)/goimports -$(BIN)/goimports: PACKAGE=golang.org/x/tools/cmd/goimports - GOLANGCILINT = $(BIN)/golangci-lint $(BIN)/golangci-lint: ; $(info $(M) Installing golangci-lint...) @ $Q curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(BIN) $(GOLANGCI_LINT_VERSION) diff --git a/pkg/gtm/errors.go b/pkg/gtm/errors.go index 0f956b6d..130a943e 100644 --- a/pkg/gtm/errors.go +++ b/pkg/gtm/errors.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" ) @@ -13,6 +14,9 @@ import ( var ( // ErrNotFound used when status code is 404 Not Found ErrNotFound = errors.New("404 Not Found") + + // ErrNoDatacenterAssignedToMap occurs when no datacenter is assigned to the map target during the creation of a geographic property. + ErrNoDatacenterAssignedToMap = errors.New("no datacenter is assigned to map target (all others)") ) type ( @@ -70,6 +74,10 @@ func (e *Error) Is(target error) bool { return true } + if errors.Is(target, ErrNoDatacenterAssignedToMap) && strings.Contains(e.Detail, "no datacenter is assigned to map target (all others)") { + return true + } + var t *Error if !errors.As(target, &t) { return false diff --git a/pkg/gtm/errors_test.go b/pkg/gtm/errors_test.go index 354b2f97..9b3d79a9 100644 --- a/pkg/gtm/errors_test.go +++ b/pkg/gtm/errors_test.go @@ -107,3 +107,25 @@ func TestJSONErrorUnmarshalling(t *testing.T) { }) } } + +func TestIs(t *testing.T) { + tests := map[string]struct { + err Error + target Error + expected bool + }{ + "no datacenter is assigned to map target (all others)": { + err: Error{StatusCode: 400, Type: "https://problems.luna.akamaiapis.net/config-gtm/v1/propertyValidationError", Title: "Property Validation Error", Detail: "Invalid configuration for property \"publishprod\": no datacenter is assigned to map target (all others)", + Errors: nil}, + target: Error{StatusCode: 400, Type: "https://problems.luna.akamaiapis.net/config-gtm/v1/propertyValidationError", Title: "Property Validation Error", Detail: "Invalid configuration for property \"publishprod\": no datacenter is assigned to map target (all others)", + Errors: nil}, + expected: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.err.Is(&test.target), test.expected) + }) + } +} From 99792574b255c8db7001ef758cef6e93d6e5bda5 Mon Sep 17 00:00:00 2001 From: Shristi Singh Date: Fri, 5 Apr 2024 09:50:46 +0000 Subject: [PATCH 03/34] DXE-3526 Adjust property struct to API real behaviour Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/DXE-3526 to feature/sp-breaking-changes --- CHANGELOG.md | 2 ++ pkg/papi/property.go | 2 -- pkg/papi/property_test.go | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04098f0d..4dc9d613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ #### FEATURES/ENHANCEMENTS: +* PAPI + * Removed `rule_format` and `product_id` from `Property` struct as this information is populated from `GetPropertyVersion` diff --git a/pkg/papi/property.go b/pkg/papi/property.go index 90fe520c..05e80a64 100644 --- a/pkg/papi/property.go +++ b/pkg/papi/property.go @@ -56,11 +56,9 @@ type ( GroupID string `json:"groupId"` LatestVersion int `json:"latestVersion"` Note string `json:"note"` - ProductID string `json:"productId"` ProductionVersion *int `json:"productionVersion,omitempty"` PropertyID string `json:"propertyId"` PropertyName string `json:"propertyName"` - RuleFormat string `json:"ruleFormat"` StagingVersion *int `json:"stagingVersion,omitempty"` } diff --git a/pkg/papi/property_test.go b/pkg/papi/property_test.go index 844eec0f..5fe154da 100644 --- a/pkg/papi/property_test.go +++ b/pkg/papi/property_test.go @@ -56,7 +56,6 @@ func TestPapiGetProperties(t *testing.T) { ContractID: "ctr_1-1TJZH5", GroupID: "grp_15166", PropertyID: "prp_175780", - ProductID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, StagingVersion: tools.IntPtr(1), @@ -146,7 +145,6 @@ func TestPapiGetProperty(t *testing.T) { "propertyName": "example.com", "latestVersion": 2, "stagingVersion": 1, - "productId": "prp_175780", "productionVersion": null, "assetId": "aid_101", "note": "Notes about example.com" @@ -162,7 +160,6 @@ func TestPapiGetProperty(t *testing.T) { ContractID: "ctr_1-1TJZH5", GroupID: "grp_15166", PropertyID: "prp_175780", - ProductID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, StagingVersion: tools.IntPtr(1), @@ -177,7 +174,6 @@ func TestPapiGetProperty(t *testing.T) { ContractID: "ctr_1-1TJZH5", GroupID: "grp_15166", PropertyID: "prp_175780", - ProductID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, StagingVersion: tools.IntPtr(1), From 8f4d021e4ccc2fc4e567424e9b18385ef89947d4 Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Thu, 25 Apr 2024 10:03:54 +0000 Subject: [PATCH 04/34] DXE-3640 Refactor response/request/objects struct names in GTM and DNS (Edgegrid) --- CHANGELOG.md | 44 ++ pkg/dns/authorities.go | 70 ++- pkg/dns/authorities_test.go | 51 +- pkg/dns/data.go | 8 - pkg/dns/data_test.go | 17 +- pkg/dns/dns.go | 167 +++++- pkg/dns/errors_test.go | 1 - pkg/dns/mocks.go | 226 +++----- pkg/dns/record.go | 150 +++-- pkg/dns/record_lookup.go | 115 +++- pkg/dns/record_lookup_test.go | 77 +-- pkg/dns/record_test.go | 88 +-- pkg/dns/recordsets.go | 198 ++++--- pkg/dns/recordsets_test.go | 141 ++--- pkg/dns/tsig.go | 225 ++++++-- pkg/dns/tsig_test.go | 151 +++-- pkg/dns/zone.go | 392 ++++++++----- pkg/dns/zone_test.go | 232 ++++---- pkg/dns/zonebulk.go | 266 +++++++-- pkg/dns/zonebulk_test.go | 161 +++--- pkg/gtm/asmap.go | 224 +++++-- pkg/gtm/asmap_test.go | 104 ++-- pkg/gtm/cidrmap.go | 241 +++++--- pkg/gtm/cidrmap_test.go | 173 ++++-- pkg/gtm/common.go | 52 +- pkg/gtm/datacenter.go | 249 +++++--- pkg/gtm/datacenter_test.go | 102 ++-- pkg/gtm/domain.go | 379 +++++++----- pkg/gtm/domain_test.go | 95 +-- pkg/gtm/errors_test.go | 1 - pkg/gtm/geomap.go | 245 +++++--- pkg/gtm/geomap_test.go | 104 ++-- pkg/gtm/gtm.go | 205 ++++++- pkg/gtm/mocks.go | 213 ++++--- pkg/gtm/property.go | 381 +++++++----- pkg/gtm/property_test.go | 545 ++++++++++-------- pkg/gtm/resource.go | 266 ++++++--- pkg/gtm/resource_test.go | 119 ++-- .../testdata/TestGTM_CreateResource.req.json | 2 +- 39 files changed, 4184 insertions(+), 2296 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc9d613..52e68bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/dns/authorities.go b/pkg/dns/authorities.go index 58c2de17..f15663f3 100644 --- a/pkg/dns/authorities.go +++ b/pkg/dns/authorities.go @@ -2,51 +2,77 @@ package dns import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // Authorities contains operations available on Authorities data sources. - Authorities interface { - // GetAuthorities provides a list of structured read-only list of name servers. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-data-authorities - GetAuthorities(context.Context, string) (*AuthorityResponse, error) - // GetNameServerRecordList provides a list of name server records. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-data-authorities - GetNameServerRecordList(context.Context, string) ([]string, error) - } - // Contract contains contractID and a list of currently assigned Akamai authoritative nameservers Contract struct { ContractID string `json:"contractId"` Authorities []string `json:"authorities"` } - // AuthorityResponse contains response with a list of one or more Contracts AuthorityResponse struct { Contracts []Contract `json:"contracts"` } + // GetAuthoritiesRequest contains request parameters for GetAuthorities + GetAuthoritiesRequest struct { + ContractIDs string + } + + // GetAuthoritiesResponse contains the response data from GetAuthorities operation + GetAuthoritiesResponse struct { + Contracts []Contract `json:"contracts"` + } + + // GetNameServerRecordListRequest contains request parameters for GetNameServerRecordList + GetNameServerRecordListRequest struct { + ContractIDs string + } +) + +var ( + // ErrGetAuthorities is returned when GetAuthorities fails + ErrGetAuthorities = errors.New("get authorities") + // ErrGetNameServerRecordList is returned when GetNameServerRecordList fails + ErrGetNameServerRecordList = errors.New("get name server record list") ) -func (d *dns) GetAuthorities(ctx context.Context, contractID string) (*AuthorityResponse, error) { +// Validate validates GetAuthoritiesRequest +func (r GetAuthoritiesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ContractIDs": validation.Validate(r.ContractIDs, validation.Required), + }) +} + +// Validate validates GetNameServerRecordListRequest +func (r GetNameServerRecordListRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ContractIDs": validation.Validate(r.ContractIDs, validation.Required), + }) +} + +func (d *dns) GetAuthorities(ctx context.Context, params GetAuthoritiesRequest) (*GetAuthoritiesResponse, error) { logger := d.Log(ctx) logger.Debug("GetAuthorities") - if contractID == "" { - return nil, fmt.Errorf("%w: GetAuthorities reqs valid contractId", ErrBadRequest) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetAuthorities, ErrStructValidation, err) } - getURL := fmt.Sprintf("/config-dns/v2/data/authorities?contractIds=%s", contractID) + getURL := fmt.Sprintf("/config-dns/v2/data/authorities?contractIds=%s", params.ContractIDs) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create getauthorities request: %w", err) } - var result AuthorityResponse + var result GetAuthoritiesResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetAuthorities request failed: %w", err) @@ -59,15 +85,15 @@ func (d *dns) GetAuthorities(ctx context.Context, contractID string) (*Authority return &result, nil } -func (d *dns) GetNameServerRecordList(ctx context.Context, contractID string) ([]string, error) { +func (d *dns) GetNameServerRecordList(ctx context.Context, params GetNameServerRecordListRequest) ([]string, error) { logger := d.Log(ctx) logger.Debug("GetNameServerRecordList") - if contractID == "" { - return nil, fmt.Errorf("%w: GetAuthorities requires valid contractId", ErrBadRequest) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetNameServerRecordList, ErrStructValidation, err) } - NSrecords, err := d.GetAuthorities(ctx, contractID) + NSrecords, err := d.GetAuthorities(ctx, GetAuthoritiesRequest{ContractIDs: params.ContractIDs}) if err != nil { return nil, err } diff --git a/pkg/dns/authorities_test.go b/pkg/dns/authorities_test.go index d6ef7596..b06de3a1 100644 --- a/pkg/dns/authorities_test.go +++ b/pkg/dns/authorities_test.go @@ -13,15 +13,15 @@ import ( func TestDNS_GetAuthorities(t *testing.T) { tests := map[string]struct { - contractID string + params GetAuthoritiesRequest responseStatus int responseBody string expectedPath string - expectedResponse *AuthorityResponse - withError error + expectedResponse *GetAuthoritiesResponse + withError func(*testing.T, error) }{ "200 OK": { - contractID: "9-9XXXXX", + params: GetAuthoritiesRequest{ContractIDs: "9-9XXXXX"}, responseStatus: http.StatusOK, responseBody: ` { @@ -40,7 +40,7 @@ func TestDNS_GetAuthorities(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/data/authorities?contractIds=9-9XXXXX", - expectedResponse: &AuthorityResponse{ + expectedResponse: &GetAuthoritiesResponse{ Contracts: []Contract{ { ContractID: "9-9XXXXX", @@ -57,14 +57,13 @@ func TestDNS_GetAuthorities(t *testing.T) { }, }, "Missing arguments": { - contractID: "", responseStatus: http.StatusOK, - responseBody: "", - expectedPath: "/config-dns/v2/data/authorities?contractIds=9-9XXXXX", - withError: ErrBadRequest, + withError: func(t *testing.T, err error) { + assert.Equal(t, "get authorities: struct validation: ContractIDs: cannot be blank", err.Error()) + }, }, "500 internal server error": { - contractID: "9-9XXXXX", + params: GetAuthoritiesRequest{ContractIDs: "9-9XXXXX"}, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -74,11 +73,14 @@ func TestDNS_GetAuthorities(t *testing.T) { "status": 500 }`, expectedPath: "/config-dns/v2/data/authorities?contractIds=9-9XXXXX", - withError: &Error{ - Type: "internal_error", - Title: "Internal Server Error", - Detail: "Error fetching authorities", - StatusCode: http.StatusInternalServerError, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error fetching authorities", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) }, }, } @@ -93,9 +95,9 @@ func TestDNS_GetAuthorities(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetAuthorities(context.Background(), test.contractID) + result, err := client.GetAuthorities(context.Background(), test.params) if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + test.withError(t, err) return } require.NoError(t, err) @@ -106,15 +108,15 @@ func TestDNS_GetAuthorities(t *testing.T) { func TestDNS_GetNameServerRecordList(t *testing.T) { tests := map[string]struct { - contractID string + params GetNameServerRecordListRequest responseStatus int responseBody string expectedPath string expectedResponse []string - withError error + withError func(*testing.T, error) }{ "test with valid arguments": { - contractID: "9-9XXXXX", + params: GetNameServerRecordListRequest{ContractIDs: "9-9XXXXX"}, responseStatus: http.StatusOK, responseBody: ` { @@ -136,9 +138,10 @@ func TestDNS_GetNameServerRecordList(t *testing.T) { expectedPath: "/config-dns/v2/data/authorities?contractIds=9-9XXXXX", }, "test with missing arguments": { - contractID: "", expectedPath: "/config-dns/v2/data/authorities?contractIds=9-9XXXXX", - withError: ErrBadRequest, + withError: func(t *testing.T, err error) { + assert.Equal(t, "get name server record list: struct validation: ContractIDs: cannot be blank", err.Error()) + }, }, } @@ -152,9 +155,9 @@ func TestDNS_GetNameServerRecordList(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetNameServerRecordList(context.Background(), test.contractID) + result, err := client.GetNameServerRecordList(context.Background(), test.params) if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + test.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/dns/data.go b/pkg/dns/data.go index 61744f85..87b573cb 100644 --- a/pkg/dns/data.go +++ b/pkg/dns/data.go @@ -9,14 +9,6 @@ import ( ) type ( - // Data contains operations available on Data resources. - Data interface { - // ListGroups returns group list associated with particular user - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-data-groups - ListGroups(context.Context, ListGroupRequest) (*ListGroupResponse, error) - } - // ListGroupResponse lists the groups accessible to the current user ListGroupResponse struct { Groups []Group `json:"groups"` diff --git a/pkg/dns/data_test.go b/pkg/dns/data_test.go index f233e8bf..757aa0e3 100644 --- a/pkg/dns/data_test.go +++ b/pkg/dns/data_test.go @@ -18,7 +18,7 @@ func TestDNS_ListGroups(t *testing.T) { responseBody string expectedPath string expectedResponse *ListGroupResponse - withError error + withError func(*testing.T, error) }{ "200 OK, when optional query parameter provided": { request: ListGroupRequest{ @@ -137,11 +137,14 @@ func TestDNS_ListGroups(t *testing.T) { "status": 500 }`, expectedPath: "/config-dns/v2/data/groups/", - withError: &Error{ - Type: "internal_error", - Title: "Internal Server Error", - Detail: "Error fetching authorities", - StatusCode: http.StatusInternalServerError, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error fetching authorities", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) }, }, } @@ -158,7 +161,7 @@ func TestDNS_ListGroups(t *testing.T) { client := mockAPIClient(t, mockServer) result, err := client.ListGroups(context.Background(), test.request) if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + test.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go index bbb72ac5..15f29237 100644 --- a/pkg/dns/dns.go +++ b/pkg/dns/dns.go @@ -4,6 +4,7 @@ package dns import ( + "context" "errors" "net/http" @@ -11,19 +12,171 @@ import ( ) var ( - // ErrStructValidation is returned when given struct validation failed + // ErrStructValidation is returned when given struct validation failed. ErrStructValidation = errors.New("struct validation") ) type ( // DNS is the dns api interface DNS interface { - Authorities - Data - Recordsets - Records - TSIGKeys - Zones + // GetAuthorities provides a list of structured read-only list of name servers. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-data-authorities + GetAuthorities(context.Context, GetAuthoritiesRequest) (*GetAuthoritiesResponse, error) + + // GetNameServerRecordList provides a list of name server records. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-data-authorities + GetNameServerRecordList(context.Context, GetNameServerRecordListRequest) ([]string, error) + + // ListGroups returns group list associated with particular user + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-data-groups + ListGroups(context.Context, ListGroupRequest) (*ListGroupResponse, error) + + // GetRecordSets retrieves record sets with Query Args. No formatting of arg values. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets + GetRecordSets(context.Context, GetRecordSetsRequest) (*GetRecordSetsResponse, error) + // CreateRecordSets creates multiple record sets. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-recordsets + CreateRecordSets(context.Context, CreateRecordSetsRequest) error + // UpdateRecordSets replaces list of record sets. + // + // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-recordsets + UpdateRecordSets(context.Context, UpdateRecordSetsRequest) error + + // GetRecordList retrieves recordset list based on type. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets + GetRecordList(context.Context, GetRecordListRequest) (*GetRecordListResponse, error) + // GetRdata retrieves record rdata, e.g. target. + GetRdata(context.Context, GetRdataRequest) ([]string, error) + // ProcessRdata process rdata. + ProcessRdata(context.Context, []string, string) []string + // ParseRData parses rdata. returning map. + ParseRData(context.Context, string, []string) map[string]interface{} + // GetRecord retrieves a recordset and returns as RecordBody. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-type + GetRecord(context.Context, GetRecordRequest) (*GetRecordResponse, error) + // CreateRecord creates recordset. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-names-name-types-type + CreateRecord(context.Context, CreateRecordRequest) error + // DeleteRecord removes recordset. + // + // See: https://techdocs.akamai.com/edge-dns/reference/delete-zone-name-type + DeleteRecord(context.Context, DeleteRecordRequest) error + // UpdateRecord replaces the recordset. + // + // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-names-name-types-type + UpdateRecord(context.Context, UpdateRecordRequest) error + + // ListTSIGKeys lists the TSIG keys used by zones that you are allowed to manage. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-keys + ListTSIGKeys(context.Context, ListTSIGKeysRequest) (*ListTSIGKeysResponse, error) + // GetTSIGKeyZones retrieves DNS Zones using TSIG key. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-used-by + GetTSIGKeyZones(context.Context, GetTSIGKeyZonesRequest) (*GetTSIGKeyZonesResponse, error) + // GetTSIGKeyAliases retrieves a DNS Zone's aliases. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key-used-by + GetTSIGKeyAliases(context.Context, GetTSIGKeyAliasesRequest) (*GetTSIGKeyAliasesResponse, error) + // UpdateTSIGKeyBulk updates Bulk Zones TSIG key. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-bulk-update + UpdateTSIGKeyBulk(context.Context, UpdateTSIGKeyBulkRequest) error + // GetTSIGKey retrieves a TSIG key for zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key + GetTSIGKey(context.Context, GetTSIGKeyRequest) (*GetTSIGKeyResponse, error) + // DeleteTSIGKey deletes TSIG key for zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/delete-zones-zone-key + DeleteTSIGKey(context.Context, DeleteTSIGKeyRequest) error + // UpdateTSIGKey updates TSIG key for zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-key + UpdateTSIGKey(context.Context, UpdateTSIGKeyRequest) error + + // ListZones retrieves a list of all zones user can access. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones + ListZones(context.Context, ListZonesRequest) (*ZoneListResponse, error) + + // GetZone retrieves Zone metadata. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zone + GetZone(context.Context, GetZoneRequest) (*GetZoneResponse, error) + //GetChangeList retrieves Zone changelist. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-changelists-zone + GetChangeList(context.Context, GetChangeListRequest) (*GetChangeListResponse, error) + // GetMasterZoneFile retrieves master zone file. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-zone-file + GetMasterZoneFile(context.Context, GetMasterZoneFileRequest) (string, error) + // PostMasterZoneFile updates master zone file. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-zone-file + PostMasterZoneFile(context.Context, PostMasterZoneFileRequest) error + // CreateZone creates new zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zone + CreateZone(context.Context, CreateZoneRequest) error + // SaveChangeList creates a new Change List based on the most recent version of a zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists + SaveChangeList(context.Context, SaveChangeListRequest) error + // SubmitChangeList submits changelist for the Zone to create default NS SOA records. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists-zone-submit + SubmitChangeList(context.Context, SubmitChangeListRequest) error + // UpdateZone updates zone. + // + // See: https://techdocs.akamai.com/edge-dns/reference/put-zone + UpdateZone(context.Context, UpdateZoneRequest) error + + // GetZoneNames retrieves a list of a zone's record names. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-names + GetZoneNames(context.Context, GetZoneNamesRequest) (*GetZoneNamesResponse, error) + // GetZoneNameTypes retrieves a zone name's record types. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-types + GetZoneNameTypes(context.Context, GetZoneNameTypesRequest) (*GetZoneNameTypesResponse, error) + // CreateBulkZones submits create bulk zone request. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-create-requests + CreateBulkZones(context.Context, CreateBulkZonesRequest) (*CreateBulkZonesResponse, error) + // DeleteBulkZones submits delete bulk zone request. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-delete-requests + DeleteBulkZones(context.Context, DeleteBulkZonesRequest) (*DeleteBulkZonesResponse, error) + // GetBulkZoneCreateStatus retrieves submit request status. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid + GetBulkZoneCreateStatus(context.Context, GetBulkZoneCreateStatusRequest) (*GetBulkZoneCreateStatusResponse, error) + //GetBulkZoneDeleteStatus retrieves submit request status. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid + GetBulkZoneDeleteStatus(context.Context, GetBulkZoneDeleteStatusRequest) (*GetBulkZoneDeleteStatusResponse, error) + // GetBulkZoneCreateResult retrieves create request result. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid-result + GetBulkZoneCreateResult(ctx context.Context, request GetBulkZoneCreateResultRequest) (*GetBulkZoneCreateResultResponse, error) + // GetBulkZoneDeleteResult retrieves delete request result. + // + // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid-result + GetBulkZoneDeleteResult(context.Context, GetBulkZoneDeleteResultRequest) (*GetBulkZoneDeleteResultResponse, error) + // GetZonesDNSSecStatus returns the current DNSSEC status for one or more zones. + // + // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-dns-sec-status + GetZonesDNSSecStatus(context.Context, GetZonesDNSSecStatusRequest) (*GetZonesDNSSecStatusResponse, error) } dns struct { diff --git a/pkg/dns/errors_test.go b/pkg/dns/errors_test.go index d3c41c8d..e87d671d 100644 --- a/pkg/dns/errors_test.go +++ b/pkg/dns/errors_test.go @@ -9,7 +9,6 @@ import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" "github.com/stretchr/testify/require" - "github.com/tj/assert" ) diff --git a/pkg/dns/mocks.go b/pkg/dns/mocks.go index e9998be0..161b82a2 100644 --- a/pkg/dns/mocks.go +++ b/pkg/dns/mocks.go @@ -14,14 +14,8 @@ type Mock struct { var _ DNS = &Mock{} -func (d *Mock) ListZones(ctx context.Context, query ...ZoneListQueryArgs) (*ZoneListResponse, error) { - var args mock.Arguments - - if len(query) > 0 { - args = d.Called(ctx, query[0]) - } else { - args = d.Called(ctx) - } +func (d *Mock) ListZones(ctx context.Context, req ListZonesRequest) (*ZoneListResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) @@ -40,156 +34,151 @@ func (d *Mock) GetZonesDNSSecStatus(ctx context.Context, params GetZonesDNSSecSt return args.Get(0).(*GetZonesDNSSecStatusResponse), args.Error(1) } -func (d *Mock) GetZone(ctx context.Context, name string) (*ZoneResponse, error) { - args := d.Called(ctx, name) +func (d *Mock) GetZone(ctx context.Context, req GetZoneRequest) (*GetZoneResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ZoneResponse), args.Error(1) + return args.Get(0).(*GetZoneResponse), args.Error(1) } -func (d *Mock) GetChangeList(ctx context.Context, param string) (*ChangeListResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetChangeList(ctx context.Context, req GetChangeListRequest) (*GetChangeListResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ChangeListResponse), args.Error(1) + return args.Get(0).(*GetChangeListResponse), args.Error(1) } -func (d *Mock) GetMasterZoneFile(ctx context.Context, param string) (string, error) { - args := d.Called(ctx, param) +func (d *Mock) GetMasterZoneFile(ctx context.Context, req GetMasterZoneFileRequest) (string, error) { + args := d.Called(ctx, req) return args.String(0), args.Error(1) } -func (d *Mock) CreateZone(ctx context.Context, param1 *ZoneCreate, param2 ZoneQueryString, param3 ...bool) error { +func (d *Mock) CreateZone(ctx context.Context, req CreateZoneRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param1, param2, param3[0]) - } else { - args = d.Called(ctx, param1, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) SaveChangelist(ctx context.Context, param *ZoneCreate) error { - args := d.Called(ctx, param) +func (d *Mock) SaveChangeList(ctx context.Context, req SaveChangeListRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) SubmitChangelist(ctx context.Context, param *ZoneCreate) error { - args := d.Called(ctx, param) +func (d *Mock) SubmitChangeList(ctx context.Context, req SubmitChangeListRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) UpdateZone(ctx context.Context, param1 *ZoneCreate, param2 ZoneQueryString) error { - args := d.Called(ctx, param1, param2) +func (d *Mock) UpdateZone(ctx context.Context, req UpdateZoneRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) DeleteZone(ctx context.Context, param1 *ZoneCreate, param2 ZoneQueryString) error { - args := d.Called(ctx, param1, param2) +func (d *Mock) DeleteZone(ctx context.Context, req DeleteRecordRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) GetZoneNames(ctx context.Context, param string) (*ZoneNamesResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetZoneNames(ctx context.Context, req GetZoneNamesRequest) (*GetZoneNamesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ZoneNamesResponse), args.Error(1) + return args.Get(0).(*GetZoneNamesResponse), args.Error(1) } -func (d *Mock) GetZoneNameTypes(ctx context.Context, param1 string, param2 string) (*ZoneNameTypesResponse, error) { - args := d.Called(ctx, param1, param2) +func (d *Mock) GetZoneNameTypes(ctx context.Context, req GetZoneNameTypesRequest) (*GetZoneNameTypesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ZoneNameTypesResponse), args.Error(1) + return args.Get(0).(*GetZoneNameTypesResponse), args.Error(1) } -func (d *Mock) ListTSIGKeys(ctx context.Context, param *TSIGQueryString) (*TSIGReportResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) ListTSIGKeys(ctx context.Context, req ListTSIGKeysRequest) (*ListTSIGKeysResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*TSIGReportResponse), args.Error(1) + return args.Get(0).(*ListTSIGKeysResponse), args.Error(1) } -func (d *Mock) GetTSIGKeyZones(ctx context.Context, param *TSIGKey) (*ZoneNameListResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetTSIGKeyZones(ctx context.Context, req GetTSIGKeyZonesRequest) (*GetTSIGKeyZonesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ZoneNameListResponse), args.Error(1) + return args.Get(0).(*GetTSIGKeyZonesResponse), args.Error(1) } -func (d *Mock) GetTSIGKeyAliases(ctx context.Context, param string) (*ZoneNameListResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetTSIGKeyAliases(ctx context.Context, req GetTSIGKeyAliasesRequest) (*GetTSIGKeyAliasesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ZoneNameListResponse), args.Error(1) + return args.Get(0).(*GetTSIGKeyAliasesResponse), args.Error(1) } -func (d *Mock) TSIGKeyBulkUpdate(ctx context.Context, param1 *TSIGKeyBulkPost) error { - args := d.Called(ctx, param1) +func (d *Mock) UpdateTSIGKeyBulk(ctx context.Context, req UpdateTSIGKeyBulkRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) GetTSIGKey(ctx context.Context, param string) (*TSIGKeyResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetTSIGKey(ctx context.Context, req GetTSIGKeyRequest) (*GetTSIGKeyResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*TSIGKeyResponse), args.Error(1) + return args.Get(0).(*GetTSIGKeyResponse), args.Error(1) } -func (d *Mock) DeleteTSIGKey(ctx context.Context, param1 string) error { - args := d.Called(ctx, param1) +func (d *Mock) DeleteTSIGKey(ctx context.Context, req DeleteTSIGKeyRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) UpdateTSIGKey(ctx context.Context, param1 *TSIGKey, param2 string) error { - args := d.Called(ctx, param1, param2) +func (d *Mock) UpdateTSIGKey(ctx context.Context, req UpdateTSIGKeyRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) GetAuthorities(ctx context.Context, param string) (*AuthorityResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetAuthorities(ctx context.Context, req GetAuthoritiesRequest) (*GetAuthoritiesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*AuthorityResponse), args.Error(1) + return args.Get(0).(*GetAuthoritiesResponse), args.Error(1) } -func (d *Mock) GetNameServerRecordList(ctx context.Context, param string) ([]string, error) { - args := d.Called(ctx, param) +func (d *Mock) GetNameServerRecordList(ctx context.Context, req GetNameServerRecordListRequest) ([]string, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) @@ -198,18 +187,18 @@ func (d *Mock) GetNameServerRecordList(ctx context.Context, param string) ([]str return args.Get(0).([]string), args.Error(1) } -func (d *Mock) GetRecordList(ctx context.Context, param string, param2 string, param3 string) (*RecordSetResponse, error) { - args := d.Called(ctx, param, param2, param3) +func (d *Mock) GetRecordList(ctx context.Context, req GetRecordListRequest) (*GetRecordListResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*RecordSetResponse), args.Error(1) + return args.Get(0).(*GetRecordListResponse), args.Error(1) } -func (d *Mock) GetRdata(ctx context.Context, param string, param2 string, param3 string) ([]string, error) { - args := d.Called(ctx, param, param2, param3) +func (d *Mock) GetRdata(ctx context.Context, req GetRdataRequest) ([]string, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) @@ -234,154 +223,119 @@ func (d *Mock) ParseRData(ctx context.Context, param string, param2 []string) ma return args.Get(0).(map[string]interface{}) } -func (d *Mock) GetRecord(ctx context.Context, param string, param2 string, param3 string) (*RecordBody, error) { - args := d.Called(ctx, param, param2, param3) +func (d *Mock) GetRecord(ctx context.Context, req GetRecordRequest) (*GetRecordResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*RecordBody), args.Error(1) + return args.Get(0).(*GetRecordResponse), args.Error(1) } -func (d *Mock) CreateRecord(ctx context.Context, param *RecordBody, param2 string, param3 ...bool) error { +func (d *Mock) CreateRecord(ctx context.Context, req CreateRecordRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param, param2, param3) - } else { - args = d.Called(ctx, param, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) DeleteRecord(ctx context.Context, param *RecordBody, param2 string, param3 ...bool) error { +func (d *Mock) DeleteRecord(ctx context.Context, req DeleteRecordRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param, param2, param3) - } else { - args = d.Called(ctx, param, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) UpdateRecord(ctx context.Context, param *RecordBody, param2 string, param3 ...bool) error { +func (d *Mock) UpdateRecord(ctx context.Context, req UpdateRecordRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param, param2, param3) - } else { - args = d.Called(ctx, param, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) GetRecordSets(ctx context.Context, param string, param2 ...RecordSetQueryArgs) (*RecordSetResponse, error) { +func (d *Mock) GetRecordSets(ctx context.Context, req GetRecordSetsRequest) (*GetRecordSetsResponse, error) { var args mock.Arguments - - if len(param2) > 0 { - args = d.Called(ctx, param, param2) - } else { - args = d.Called(ctx, param) - } + args = d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*RecordSetResponse), args.Error(1) + return args.Get(0).(*GetRecordSetsResponse), args.Error(1) } -func (d *Mock) CreateRecordSets(ctx context.Context, param *RecordSets, param2 string, param3 ...bool) error { +func (d *Mock) CreateRecordSets(ctx context.Context, req CreateRecordSetsRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param, param2, param3) - } else { - args = d.Called(ctx, param, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) UpdateRecordSets(ctx context.Context, param *RecordSets, param2 string, param3 ...bool) error { +func (d *Mock) UpdateRecordSets(ctx context.Context, req UpdateRecordSetsRequest) error { var args mock.Arguments - - if len(param3) > 0 { - args = d.Called(ctx, param, param2, param3) - } else { - args = d.Called(ctx, param, param2) - } + args = d.Called(ctx, req) return args.Error(0) } -func (d *Mock) PostMasterZoneFile(ctx context.Context, param string, param2 string) error { - args := d.Called(ctx, param, param2) +func (d *Mock) PostMasterZoneFile(ctx context.Context, req PostMasterZoneFileRequest) error { + args := d.Called(ctx, req) return args.Error(0) } -func (d *Mock) CreateBulkZones(ctx context.Context, param *BulkZonesCreate, param2 ZoneQueryString) (*BulkZonesResponse, error) { - args := d.Called(ctx, param, param2) +func (d *Mock) CreateBulkZones(ctx context.Context, req CreateBulkZonesRequest) (*CreateBulkZonesResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkZonesResponse), args.Error(1) + return args.Get(0).(*CreateBulkZonesResponse), args.Error(1) } -func (d *Mock) DeleteBulkZones(ctx context.Context, param *ZoneNameListResponse, param2 ...bool) (*BulkZonesResponse, error) { +func (d *Mock) DeleteBulkZones(ctx context.Context, req DeleteBulkZonesRequest) (*DeleteBulkZonesResponse, error) { var args mock.Arguments - - if len(param2) > 0 { - args = d.Called(ctx, param, param2[0]) - } else { - args = d.Called(ctx, param) - } + args = d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkZonesResponse), args.Error(1) + return args.Get(0).(*DeleteBulkZonesResponse), args.Error(1) } -func (d *Mock) GetBulkZoneCreateStatus(ctx context.Context, param string) (*BulkStatusResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetBulkZoneCreateStatus(ctx context.Context, req GetBulkZoneCreateStatusRequest) (*GetBulkZoneCreateStatusResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkStatusResponse), args.Error(1) + return args.Get(0).(*GetBulkZoneCreateStatusResponse), args.Error(1) } -func (d *Mock) GetBulkZoneDeleteStatus(ctx context.Context, param string) (*BulkStatusResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetBulkZoneDeleteStatus(ctx context.Context, req GetBulkZoneDeleteStatusRequest) (*GetBulkZoneDeleteStatusResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkStatusResponse), args.Error(1) + return args.Get(0).(*GetBulkZoneDeleteStatusResponse), args.Error(1) } -func (d *Mock) GetBulkZoneCreateResult(ctx context.Context, param string) (*BulkCreateResultResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetBulkZoneCreateResult(ctx context.Context, req GetBulkZoneCreateResultRequest) (*GetBulkZoneCreateResultResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkCreateResultResponse), args.Error(1) + return args.Get(0).(*GetBulkZoneCreateResultResponse), args.Error(1) } -func (d *Mock) GetBulkZoneDeleteResult(ctx context.Context, param string) (*BulkDeleteResultResponse, error) { - args := d.Called(ctx, param) +func (d *Mock) GetBulkZoneDeleteResult(ctx context.Context, req GetBulkZoneDeleteResultRequest) (*GetBulkZoneDeleteResultResponse, error) { + args := d.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*BulkDeleteResultResponse), args.Error(1) + return args.Get(0).(*GetBulkZoneDeleteResultResponse), args.Error(1) } func (d *Mock) ListGroups(ctx context.Context, request ListGroupRequest) (*ListGroupResponse, error) { diff --git a/pkg/dns/record.go b/pkg/dns/record.go index cb72441f..f5368593 100644 --- a/pkg/dns/record.go +++ b/pkg/dns/record.go @@ -2,55 +2,84 @@ package dns import ( "context" + "errors" "fmt" "net/http" - "sync" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) -// Records contains operations available on a Record resource. -type Records interface { - // GetRecordList retrieves recordset list based on type. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets - GetRecordList(context.Context, string, string, string) (*RecordSetResponse, error) - // GetRdata retrieves record rdata, e.g. target. - GetRdata(context.Context, string, string, string) ([]string, error) - // ProcessRdata process rdata. - ProcessRdata(context.Context, []string, string) []string - // ParseRData parses rdata. returning map. - ParseRData(context.Context, string, []string) map[string]interface{} - // GetRecord retrieves a recordset and returns as RecordBody. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-type - GetRecord(context.Context, string, string, string) (*RecordBody, error) - // CreateRecord creates recordset. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-names-name-types-type - CreateRecord(context.Context, *RecordBody, string, ...bool) error - // DeleteRecord removes recordset. - // - // See: https://techdocs.akamai.com/edge-dns/reference/delete-zone-name-type - DeleteRecord(context.Context, *RecordBody, string, ...bool) error - // UpdateRecord replaces the recordset. - // - // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-names-name-types-type - UpdateRecord(context.Context, *RecordBody, string, ...bool) error -} +type ( + // RecordBody contains request body for dns record + RecordBody struct { + Name string `json:"name,omitempty"` + RecordType string `json:"type,omitempty"` + TTL int `json:"ttl,omitempty"` + Active bool `json:"active,omitempty"` + Target []string `json:"rdata,omitempty"` + } -// RecordBody contains request body for dns record -type RecordBody struct { - Name string `json:"name,omitempty"` - RecordType string `json:"type,omitempty"` - TTL int `json:"ttl,omitempty"` - Active bool `json:"active,omitempty"` - Target []string `json:"rdata,omitempty"` -} + // RecordRequest contains request parameters + RecordRequest struct { + Record *RecordBody + Zone string + RecLock []bool + } + // CreateRecordRequest contains request parameters for CreateRecord + CreateRecordRequest RecordRequest + + // UpdateRecordRequest contains request parameters for UpdateRecord + UpdateRecordRequest RecordRequest + + // DeleteRecordRequest contains request parameters for DeleteRecord + DeleteRecordRequest struct { + Zone string + Name string + RecordType string + RecLock []bool + } +) var ( zoneRecordWriteLock sync.Mutex ) +var ( + // ErrCreateRecord is returned when CreateRecord fails + ErrCreateRecord = errors.New("create record") + // ErrUpdateRecord is returned when UpdateRecord fails + ErrUpdateRecord = errors.New("update record") + // ErrDeleteRecord is returned when UpdateRecord fails + ErrDeleteRecord = errors.New("delete record") +) + +// Validate validates CreateRecordRequest +func (r CreateRecordRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "Record": validation.Validate(r.Record, validation.Required), + }) +} + +// Validate validates UpdateRecordRequest +func (r UpdateRecordRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "Record": validation.Validate(r.Record, validation.Required), + }) +} + +// Validate validates DeleteRecordRequest +func (r DeleteRecordRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "Name": validation.Validate(r.Name, validation.Required), + "RecordType": validation.Validate(r.RecordType, validation.Required), + }) +} + // Validate validates RecordBody func (rec *RecordBody) Validate() error { if len(rec.Name) < 1 { @@ -79,32 +108,32 @@ func localLock(lockArg []bool) bool { return true } -func (d *dns) CreateRecord(ctx context.Context, record *RecordBody, zone string, recLock ...bool) error { +func (d *dns) CreateRecord(ctx context.Context, params CreateRecordRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone, // so we have to save just one request at a time to ensure this is always // incremented properly - if localLock(recLock) { + if localLock(params.RecLock) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } logger := d.Log(ctx) logger.Debug("CreateRecord") - logger.Debugf("DNS Lib Create Record: [%v]", record) - if err := record.Validate(); err != nil { - logger.Errorf("Record content not valid: %w", err) - return fmt.Errorf("CreateRecord content not valid. [%w]", err) + logger.Debugf("DNS Lib Create Record: [%v]", params.Record) + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrCreateRecord, ErrStructValidation, err) } - reqBody, err := convertStructToReqBody(record) + reqBody, err := convertStructToReqBody(params.Record) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - postURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, record.Name, record.RecordType) + postURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", params.Zone, + params.Record.Name, params.Record.RecordType) req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) if err != nil { return fmt.Errorf("failed to create CreateRecord request: %w", err) @@ -122,32 +151,33 @@ func (d *dns) CreateRecord(ctx context.Context, record *RecordBody, zone string, return nil } -func (d *dns) UpdateRecord(ctx context.Context, record *RecordBody, zone string, recLock ...bool) error { +func (d *dns) UpdateRecord(ctx context.Context, params UpdateRecordRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone // so we have to save just one request at a time to ensure this is always // incremented properly - if localLock(recLock) { + if localLock(params.RecLock) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } logger := d.Log(ctx) logger.Debug("UpdateRecord") - logger.Debugf("DNS Lib Update Record: [%v]", record) - if err := record.Validate(); err != nil { - logger.Errorf("Record content not valid: %s", err.Error()) - return fmt.Errorf("UpdateRecord content not valid. [%w]", err) + logger.Debugf("DNS Lib Update Record: [%v]", params.Record) + + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrUpdateRecord, ErrStructValidation, err) } - reqBody, err := convertStructToReqBody(record) + reqBody, err := convertStructToReqBody(params.Record) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - putURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, record.Name, record.RecordType) + putURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", params.Zone, + params.Record.Name, params.Record.RecordType) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) if err != nil { return fmt.Errorf("failed to create UpdateRecord request: %w", err) @@ -165,14 +195,14 @@ func (d *dns) UpdateRecord(ctx context.Context, record *RecordBody, zone string, return nil } -func (d *dns) DeleteRecord(ctx context.Context, record *RecordBody, zone string, recLock ...bool) error { +func (d *dns) DeleteRecord(ctx context.Context, params DeleteRecordRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone // so we have to save just one request at a time to ensure this is always // incremented properly - if localLock(recLock) { + if localLock(params.RecLock) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } @@ -180,12 +210,12 @@ func (d *dns) DeleteRecord(ctx context.Context, record *RecordBody, zone string, logger := d.Log(ctx) logger.Debug("DeleteRecord") - if err := record.Validate(); err != nil { - logger.Errorf("Record content not valid: %w", err) - return fmt.Errorf("DeleteRecord content not valid. [%w]", err) + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrDeleteRecord, ErrStructValidation, err) } - deleteURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, record.Name, record.RecordType) + deleteURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", params.Zone, + params.Name, params.RecordType) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, deleteURL, nil) if err != nil { return fmt.Errorf("failed to create DeleteRecord request: %w", err) diff --git a/pkg/dns/record_lookup.go b/pkg/dns/record_lookup.go index 2d52288a..84538487 100644 --- a/pkg/dns/record_lookup.go +++ b/pkg/dns/record_lookup.go @@ -2,15 +2,87 @@ package dns import ( "context" - "fmt" - "net/http" - "encoding/hex" + "errors" + "fmt" "net" + "net/http" "strconv" "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) +type ( + // RdataRequest contains request parameters + RdataRequest struct { + Zone string + Name string + RecordType string + } + + // GetRecordRequest contains request parameters for GetRecord + GetRecordRequest RdataRequest + + // GetRecordResponse contains the response data from GetRecord operation + GetRecordResponse struct { + Name string `json:"name"` + RecordType string `json:"type"` + TTL int `json:"ttl"` + Active bool `json:"active"` + Target []string `json:"rdata"` + } + + // GetRecordListRequest contains request parameters for GetRecordList + GetRecordListRequest struct { + Zone string + RecordType string + } + + // GetRecordListResponse contains the response data from GetRecordList operation + GetRecordListResponse struct { + Metadata Metadata `json:"metadata"` + RecordSets []RecordSet `json:"recordsets"` + } + + // GetRdataRequest contains request parameters for GetRdata + GetRdataRequest RdataRequest +) + +var ( + // ErrGetRecord is returned when GetRecord fails + ErrGetRecord = errors.New("get record") + // ErrGetRecordList is returned when GetRecordList fails + ErrGetRecordList = errors.New("get record list") +) + +// Validate validates GetRecordRequest +func (r GetRecordRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "Name": validation.Validate(r.Name, validation.Required), + "RecordType": validation.Validate(r.RecordType, validation.Required), + }) +} + +// Validate validates GetRdataRequest +func (r GetRdataRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "Name": validation.Validate(r.Name, validation.Required), + "RecordType": validation.Validate(r.RecordType, validation.Required), + }) +} + +// Validate validates GetRecordListRequest +func (r GetRecordListRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "RecordType": validation.Validate(r.RecordType, validation.Required), + }) +} + func fullIPv6(ip net.IP) string { dst := make([]byte, hex.EncodedLen(len(ip))) @@ -46,17 +118,21 @@ func padCoordinates(str string) string { return latd + " " + latm + " " + lats + " " + latDir + " " + longd + " " + longm + " " + longs + " " + longDir + " " + padValue(altitude) + "m " + padValue(size) + "m " + padValue(horizPrecision) + "m " + padValue(vertPrecision) + "m" } -func (d *dns) GetRecord(ctx context.Context, zone, name, recordType string) (*RecordBody, error) { +func (d *dns) GetRecord(ctx context.Context, params GetRecordRequest) (*GetRecordResponse, error) { logger := d.Log(ctx) logger.Debug("GetRecord") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, name, recordType) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetRecord, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", params.Zone, params.Name, params.RecordType) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetRecord request: %w", err) } - var result RecordBody + var result GetRecordResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetRecord request failed: %w", err) @@ -69,17 +145,21 @@ func (d *dns) GetRecord(ctx context.Context, zone, name, recordType string) (*Re return &result, nil } -func (d *dns) GetRecordList(ctx context.Context, zone, _, recordType string) (*RecordSetResponse, error) { +func (d *dns) GetRecordList(ctx context.Context, params GetRecordListRequest) (*GetRecordListResponse, error) { logger := d.Log(ctx) logger.Debug("GetRecordList") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets?types=%s&showAll=true", zone, recordType) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetRecordList, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets?types=%s&showAll=true", params.Zone, params.RecordType) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetRecordList request: %w", err) } - var result RecordSetResponse + var result GetRecordListResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetRecordList request failed: %w", err) @@ -92,26 +172,33 @@ func (d *dns) GetRecordList(ctx context.Context, zone, _, recordType string) (*R return &result, nil } -func (d *dns) GetRdata(ctx context.Context, zone, name, recordType string) ([]string, error) { +func (d *dns) GetRdata(ctx context.Context, params GetRdataRequest) ([]string, error) { logger := d.Log(ctx) logger.Debug("GetrData") - records, err := d.GetRecordList(ctx, zone, name, recordType) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetRecordList, ErrStructValidation, err) + } + + records, err := d.GetRecordList(ctx, GetRecordListRequest{ + Zone: params.Zone, + RecordType: params.RecordType, + }) if err != nil { return nil, err } var rData []string for _, r := range records.RecordSets { - if r.Name == name { + if r.Name == params.Name { for _, i := range r.Rdata { str := i - if recordType == "AAAA" { + if params.RecordType == "AAAA" { addr := net.ParseIP(str) result := fullIPv6(addr) str = result - } else if recordType == "LOC" { + } else if params.RecordType == "LOC" { str = padCoordinates(str) } rData = append(rData, str) diff --git a/pkg/dns/record_lookup_test.go b/pkg/dns/record_lookup_test.go index ac81c8a3..903aa498 100644 --- a/pkg/dns/record_lookup_test.go +++ b/pkg/dns/record_lookup_test.go @@ -14,19 +14,19 @@ import ( func TestDNS_GetRecord(t *testing.T) { tests := map[string]struct { - zone string - name string - recordType string + params GetRecordRequest responseStatus int responseBody string expectedPath string - expectedResponse *RecordBody + expectedResponse *GetRecordResponse withError error }{ "200 OK": { - zone: "example.com", - name: "www.example.com", - recordType: "A", + params: GetRecordRequest{ + Zone: "example.com", + Name: "www.example.com", + RecordType: "A", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -39,7 +39,7 @@ func TestDNS_GetRecord(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", - expectedResponse: &RecordBody{ + expectedResponse: &GetRecordResponse{ Name: "www.example.com", RecordType: "A", TTL: 300, @@ -48,9 +48,11 @@ func TestDNS_GetRecord(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", - name: "www.example.com", - recordType: "A", + params: GetRecordRequest{ + Zone: "example.com", + Name: "www.example.com", + RecordType: "A", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -79,7 +81,7 @@ func TestDNS_GetRecord(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetRecord(context.Background(), test.zone, test.name, test.recordType) + result, err := client.GetRecord(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -92,18 +94,18 @@ func TestDNS_GetRecord(t *testing.T) { func TestDNS_GetRecordList(t *testing.T) { tests := map[string]struct { - zone string - name string - recordType string + params GetRecordListRequest responseStatus int responseBody string expectedPath string - expectedResponse *RecordSetResponse + expectedResponse *GetRecordListResponse withError error }{ "200 OK": { - zone: "example.com", - recordType: "A", + params: GetRecordListRequest{ + Zone: "example.com", + RecordType: "A", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -129,7 +131,7 @@ func TestDNS_GetRecordList(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/example.com/recordsets?showAll=true&types=A", - expectedResponse: &RecordSetResponse{ + expectedResponse: &GetRecordListResponse{ Metadata: Metadata{ LastPage: 0, Page: 1, @@ -148,8 +150,10 @@ func TestDNS_GetRecordList(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", - recordType: "A", + params: GetRecordListRequest{ + Zone: "example.com", + RecordType: "A", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -178,7 +182,7 @@ func TestDNS_GetRecordList(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetRecordList(context.Background(), test.zone, test.name, test.recordType) + result, err := client.GetRecordList(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -191,9 +195,7 @@ func TestDNS_GetRecordList(t *testing.T) { func TestDNS_GetRdata(t *testing.T) { tests := map[string]struct { - zone string - name string - recordType string + params GetRdataRequest responseStatus int responseBody string expectedPath string @@ -201,9 +203,11 @@ func TestDNS_GetRdata(t *testing.T) { withError error }{ "ipv6 test": { - zone: "example.com", - name: "www.example.com", - recordType: "AAAA", + params: GetRdataRequest{ + Zone: "example.com", + RecordType: "AAAA", + Name: "www.example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -231,9 +235,11 @@ func TestDNS_GetRdata(t *testing.T) { expectedResponse: []string{"2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, }, "loc test": { - zone: "example.com", - name: "www.example.com", - recordType: "LOC", + params: GetRdataRequest{ + Zone: "example.com", + RecordType: "LOC", + Name: "www.example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -261,8 +267,11 @@ func TestDNS_GetRdata(t *testing.T) { expectedResponse: []string{"52 22 23.000 N 4 53 32.000 E -2.00m 0.00m 10000.00m 10.00m"}, }, "500 internal server error": { - zone: "example.com", - recordType: "A", + params: GetRdataRequest{ + Zone: "example.com", + RecordType: "A", + Name: "www.example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -291,7 +300,7 @@ func TestDNS_GetRdata(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetRdata(context.Background(), test.zone, test.name, test.recordType) + result, err := client.GetRdata(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/dns/record_test.go b/pkg/dns/record_test.go index e3d9a4a9..a983a9de 100644 --- a/pkg/dns/record_test.go +++ b/pkg/dns/record_test.go @@ -13,21 +13,24 @@ import ( func TestDNS_CreateRecord(t *testing.T) { tests := map[string]struct { - body RecordBody + params CreateRecordRequest responseStatus int responseBody string expectedPath string withError error }{ "200 OK": { - responseStatus: http.StatusCreated, - body: RecordBody{ - Name: "www.example.com", - RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + params: CreateRecordRequest{ + Record: &RecordBody{ + Name: "www.example.com", + RecordType: "A", + TTL: 300, + Target: []string{"10.0.0.2", "10.0.0.3"}, + }, + Zone: "example.com", }, - expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", + responseStatus: http.StatusCreated, + expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", responseBody: ` { "name": "www.example.com", @@ -40,11 +43,14 @@ func TestDNS_CreateRecord(t *testing.T) { }`, }, "500 internal server error": { - body: RecordBody{ - Name: "www.example.com", - RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + params: CreateRecordRequest{ + Record: &RecordBody{ + Name: "www.example.com", + RecordType: "A", + TTL: 300, + Target: []string{"10.0.0.2", "10.0.0.3"}, + }, + Zone: "example.com", }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -74,7 +80,7 @@ func TestDNS_CreateRecord(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.CreateRecord(context.Background(), &test.body, "example.com") + err := client.CreateRecord(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -87,21 +93,24 @@ func TestDNS_CreateRecord(t *testing.T) { func TestDNS_UpdateRecord(t *testing.T) { tests := map[string]struct { - body RecordBody + params UpdateRecordRequest responseStatus int responseBody string expectedPath string withError error }{ "204 No Content": { - responseStatus: http.StatusOK, - body: RecordBody{ - Name: "www.example.com", - RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + params: UpdateRecordRequest{ + Record: &RecordBody{ + Name: "www.example.com", + RecordType: "A", + TTL: 300, + Target: []string{"10.0.0.2", "10.0.0.3"}, + }, + Zone: "example.com", }, - expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", + responseStatus: http.StatusOK, + expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", responseBody: ` { "name": "www.example.com", @@ -114,11 +123,14 @@ func TestDNS_UpdateRecord(t *testing.T) { }`, }, "500 internal server error": { - body: RecordBody{ - Name: "www.example.com", - RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + params: UpdateRecordRequest{ + Record: &RecordBody{ + Name: "www.example.com", + RecordType: "A", + TTL: 300, + Target: []string{"10.0.0.2", "10.0.0.3"}, + }, + Zone: "example.com", }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -148,7 +160,7 @@ func TestDNS_UpdateRecord(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.UpdateRecord(context.Background(), &test.body, "example.com") + err := client.UpdateRecord(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -161,29 +173,27 @@ func TestDNS_UpdateRecord(t *testing.T) { func TestDNS_DeleteRecord(t *testing.T) { tests := map[string]struct { - body RecordBody + params DeleteRecordRequest responseStatus int responseBody string expectedPath string withError error }{ "204 No Content": { - responseStatus: http.StatusNoContent, - body: RecordBody{ + params: DeleteRecordRequest{ Name: "www.example.com", RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + Zone: "example.com", }, - expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", - responseBody: ``, + responseStatus: http.StatusNoContent, + expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types/A", + responseBody: ``, }, "500 internal server error": { - body: RecordBody{ + params: DeleteRecordRequest{ Name: "www.example.com", RecordType: "A", - TTL: 300, - Target: []string{"10.0.0.2", "10.0.0.3"}, + Zone: "example.com", }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -213,7 +223,7 @@ func TestDNS_DeleteRecord(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeleteRecord(context.Background(), &test.body, "example.com") + err := client.DeleteRecord(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/dns/recordsets.go b/pkg/dns/recordsets.go index 3004e035..f08d4b73 100644 --- a/pkg/dns/recordsets.go +++ b/pkg/dns/recordsets.go @@ -2,71 +2,109 @@ package dns import ( "context" + "errors" "fmt" "net/http" - - validation "github.com/go-ozzo/ozzo-validation/v4" - "strconv" "sync" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) var ( zoneRecordSetsWriteLock sync.Mutex ) -// Recordsets contains operations available on a record sets. -type Recordsets interface { - // GetRecordSets retrieves record sets with Query Args. No formatting of arg values. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets - GetRecordSets(context.Context, string, ...RecordSetQueryArgs) (*RecordSetResponse, error) - // CreateRecordSets creates multiple record sets. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-recordsets - CreateRecordSets(context.Context, *RecordSets, string, ...bool) error - // UpdateRecordSets replaces list of record sets. - // - // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-recordsets - UpdateRecordSets(context.Context, *RecordSets, string, ...bool) error -} +type ( + // RecordSetQueryArgs contains query parameters for recordset request + RecordSetQueryArgs struct { + Page int + PageSize int + Search string + ShowAll bool + SortBy string + Types string + } -// RecordSetQueryArgs contains query parameters for recordset request -type RecordSetQueryArgs struct { - Page int - PageSize int - Search string - ShowAll bool - SortBy string - Types string -} + // RecordSets Struct. Used for Create and Update record sets. Contains a list of RecordSet objects + RecordSets struct { + RecordSets []RecordSet `json:"recordsets"` + } -// RecordSets Struct. Used for Create and Update record sets. Contains a list of RecordSet objects -type RecordSets struct { - RecordSets []RecordSet `json:"recordsets"` -} + // RecordSet contains record set metadata + RecordSet struct { + Name string `json:"name"` + Type string `json:"type"` + TTL int `json:"ttl"` + Rdata []string `json:"rdata"` + } + + // Metadata contains metadata of RecordSet response + Metadata struct { + LastPage int `json:"lastPage"` + Page int `json:"page"` + PageSize int `json:"pageSize"` + ShowAll bool `json:"showAll"` + TotalElements int `json:"totalElements"` + } + + // GetRecordSetsRequest contains request parameters for GetRecordSets + GetRecordSetsRequest struct { + Zone string + QueryArgs *RecordSetQueryArgs + } -// RecordSet contains record set metadata -type RecordSet struct { - Name string `json:"name"` - Type string `json:"type"` - TTL int `json:"ttl"` - Rdata []string `json:"rdata"` + // GetRecordSetsResponse contains the response data from GetRecordSets operation + GetRecordSetsResponse struct { + Metadata Metadata `json:"metadata"` + RecordSets []RecordSet `json:"recordsets"` + } + + // RecordSetsRequest contains request parameters + RecordSetsRequest struct { + RecordSets *RecordSets + Zone string + RecLock []bool + } + + // CreateRecordSetsRequest contains request parameters for CreateRecordSets + CreateRecordSetsRequest RecordSetsRequest + + // UpdateRecordSetsRequest contains request parameters for UpdateRecordSets + UpdateRecordSetsRequest RecordSetsRequest +) + +var ( + // ErrCreateRecordSets is returned when CreateRecordSets fails + ErrCreateRecordSets = errors.New("create record sets") + // ErrGetRecordSets is returned when GetRecordSets fails + ErrGetRecordSets = errors.New("get record sets") + // ErrUpdateRecordSets is returned when UpdateRecordSets fails + ErrUpdateRecordSets = errors.New("update record sets") +) + +// Validate validates GetRecordSetsRequest +func (r GetRecordSetsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) } -// Metadata contains metadata of RecordSet response -type Metadata struct { - LastPage int `json:"lastPage"` - Page int `json:"page"` - PageSize int `json:"pageSize"` - ShowAll bool `json:"showAll"` - TotalElements int `json:"totalElements"` +// Validate validates CreateRecordSetsRequest +func (r CreateRecordSetsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "RecordSets": validation.Validate(r.RecordSets, validation.Required), + }) } -// RecordSetResponse contains a response with a list of record sets -type RecordSetResponse struct { - Metadata Metadata `json:"metadata"` - RecordSets []RecordSet `json:"recordsets"` +// Validate validates UpdateRecordSetsRequest +func (r UpdateRecordSetsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "RecordSets": validation.Validate(r.RecordSets, validation.Required), + }) } // Validate validates RecordSets @@ -88,43 +126,43 @@ func (rs *RecordSets) Validate() error { return nil } -func (d *dns) GetRecordSets(ctx context.Context, zone string, queryArgs ...RecordSetQueryArgs) (*RecordSetResponse, error) { +func (d *dns) GetRecordSets(ctx context.Context, params GetRecordSetsRequest) (*GetRecordSetsResponse, error) { logger := d.Log(ctx) logger.Debug("GetRecordSets") - if len(queryArgs) > 1 { - return nil, fmt.Errorf("invalid arguments GetRecordSets QueryArgs") + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetRecordSets, ErrStructValidation, err) } - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetRecordsets request: %w", err) } - q := req.URL.Query() - if len(queryArgs) > 0 { - if queryArgs[0].Page > 0 { - q.Add("page", strconv.Itoa(queryArgs[0].Page)) + if params.QueryArgs != nil { + q := req.URL.Query() + if params.QueryArgs.Page > 0 { + q.Add("page", strconv.Itoa(params.QueryArgs.Page)) } - if queryArgs[0].PageSize > 0 { - q.Add("pageSize", strconv.Itoa(queryArgs[0].PageSize)) + if params.QueryArgs.PageSize > 0 { + q.Add("pageSize", strconv.Itoa(params.QueryArgs.PageSize)) } - if queryArgs[0].Search != "" { - q.Add("search", queryArgs[0].Search) + if params.QueryArgs.Search != "" { + q.Add("search", params.QueryArgs.Search) } - q.Add("showAll", strconv.FormatBool(queryArgs[0].ShowAll)) - if queryArgs[0].SortBy != "" { - q.Add("sortBy", queryArgs[0].SortBy) + q.Add("showAll", strconv.FormatBool(params.QueryArgs.ShowAll)) + if params.QueryArgs.SortBy != "" { + q.Add("sortBy", params.QueryArgs.SortBy) } - if queryArgs[0].Types != "" { - q.Add("types", queryArgs[0].Types) + if params.QueryArgs.Types != "" { + q.Add("types", params.QueryArgs.Types) } req.URL.RawQuery = q.Encode() } - var result RecordSetResponse + var result GetRecordSetsResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetRecordsets request failed: %w", err) @@ -137,14 +175,14 @@ func (d *dns) GetRecordSets(ctx context.Context, zone string, queryArgs ...Recor return &result, nil } -func (d *dns) CreateRecordSets(ctx context.Context, recordSets *RecordSets, zone string, recLock ...bool) error { +func (d *dns) CreateRecordSets(ctx context.Context, params CreateRecordSetsRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone // so we have to save just one request at a time to ensure this is always // incremented properly - if localLock(recLock) { + if localLock(params.RecLock) { zoneRecordSetsWriteLock.Lock() defer zoneRecordSetsWriteLock.Unlock() } @@ -152,16 +190,20 @@ func (d *dns) CreateRecordSets(ctx context.Context, recordSets *RecordSets, zone logger := d.Log(ctx) logger.Debug("CreateRecordSets") - if err := recordSets.Validate(); err != nil { + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrCreateRecordSets, ErrStructValidation, err) + } + + if err := params.RecordSets.Validate(); err != nil { return err } - reqBody, err := convertStructToReqBody(recordSets) + reqBody, err := convertStructToReqBody(params.RecordSets) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - postURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) + postURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) if err != nil { return fmt.Errorf("failed to create CreateRecordsets request: %w", err) @@ -179,14 +221,14 @@ func (d *dns) CreateRecordSets(ctx context.Context, recordSets *RecordSets, zone return nil } -func (d *dns) UpdateRecordSets(ctx context.Context, recordSets *RecordSets, zone string, recLock ...bool) error { +func (d *dns) UpdateRecordSets(ctx context.Context, params UpdateRecordSetsRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone // so we have to save just one request at a time to ensure this is always // incremented properly - if localLock(recLock) { + if localLock(params.RecLock) { zoneRecordSetsWriteLock.Lock() defer zoneRecordSetsWriteLock.Unlock() } @@ -194,16 +236,20 @@ func (d *dns) UpdateRecordSets(ctx context.Context, recordSets *RecordSets, zone logger := d.Log(ctx) logger.Debug("UpdateRecordsets") - if err := recordSets.Validate(); err != nil { + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrUpdateRecordSets, ErrStructValidation, err) + } + + if err := params.RecordSets.Validate(); err != nil { return err } - reqBody, err := convertStructToReqBody(recordSets) + reqBody, err := convertStructToReqBody(params.RecordSets) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - putURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) + putURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) if err != nil { return fmt.Errorf("failed to create UpdateRecordsets request: %w", err) diff --git a/pkg/dns/recordsets_test.go b/pkg/dns/recordsets_test.go index 9d082db1..01be675a 100644 --- a/pkg/dns/recordsets_test.go +++ b/pkg/dns/recordsets_test.go @@ -13,17 +13,18 @@ import ( func TestDNS_GetRecordSets(t *testing.T) { tests := map[string]struct { - zone string - args []RecordSetQueryArgs + params GetRecordSetsRequest responseStatus int responseBody string expectedPath string - expectedResponse *RecordSetResponse + expectedResponse *GetRecordSetsResponse withError error }{ "200 OK": { - zone: "example.com", - args: []RecordSetQueryArgs{}, + params: GetRecordSetsRequest{ + Zone: "example.com", + QueryArgs: &RecordSetQueryArgs{}, + }, responseStatus: http.StatusOK, responseBody: ` { @@ -48,8 +49,8 @@ func TestDNS_GetRecordSets(t *testing.T) { } ] }`, - expectedPath: "/config-dns/v2/zones/example.com/recordsets", - expectedResponse: &RecordSetResponse{ + expectedPath: "/config-dns/v2/zones/example.com/recordsets?showAll=false", + expectedResponse: &GetRecordSetsResponse{ Metadata: Metadata{ LastPage: 0, Page: 1, @@ -68,8 +69,10 @@ func TestDNS_GetRecordSets(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", - args: []RecordSetQueryArgs{}, + params: GetRecordSetsRequest{ + Zone: "example.com", + QueryArgs: &RecordSetQueryArgs{}, + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -78,7 +81,7 @@ func TestDNS_GetRecordSets(t *testing.T) { "detail": "Error fetching authorities", "status": 500 }`, - expectedPath: "/config-dns/v2/zones/example.com/recordsets", + expectedPath: "/config-dns/v2/zones/example.com/recordsets?showAll=false", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -98,7 +101,7 @@ func TestDNS_GetRecordSets(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetRecordSets(context.Background(), test.zone, test.args...) + result, err := client.GetRecordSets(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -111,25 +114,25 @@ func TestDNS_GetRecordSets(t *testing.T) { func TestDNS_CreateRecordSets(t *testing.T) { tests := map[string]struct { - zone string - sets *RecordSets - responseStatus int - responseBody string - expectedPath string - expectedResponse *RecordSetResponse - withError error + params CreateRecordSetsRequest + responseStatus int + responseBody string + expectedPath string + withError error }{ "200 OK": { - zone: "example.com", - sets: &RecordSets{ - []RecordSet{ - { - Name: "www.example.com", - Type: "A", - TTL: 300, - Rdata: []string{ - "10.0.0.2", - "10.0.0.3", + params: CreateRecordSetsRequest{ + Zone: "example.com", + RecordSets: &RecordSets{ + []RecordSet{ + { + Name: "www.example.com", + Type: "A", + TTL: 300, + Rdata: []string{ + "10.0.0.2", + "10.0.0.3", + }, }, }, }, @@ -138,16 +141,18 @@ func TestDNS_CreateRecordSets(t *testing.T) { expectedPath: "/config-dns/v2/zones/example.com/recordsets", }, "500 internal server error": { - zone: "example.com", - sets: &RecordSets{ - []RecordSet{ - { - Name: "www.example.com", - Type: "A", - TTL: 300, - Rdata: []string{ - "10.0.0.2", - "10.0.0.3", + params: CreateRecordSetsRequest{ + Zone: "example.com", + RecordSets: &RecordSets{ + []RecordSet{ + { + Name: "www.example.com", + Type: "A", + TTL: 300, + Rdata: []string{ + "10.0.0.2", + "10.0.0.3", + }, }, }, }, @@ -182,7 +187,7 @@ func TestDNS_CreateRecordSets(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.CreateRecordSets(context.Background(), test.sets, test.zone) + err := client.CreateRecordSets(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -194,25 +199,25 @@ func TestDNS_CreateRecordSets(t *testing.T) { func TestDNS_UpdateRecordSets(t *testing.T) { tests := map[string]struct { - zone string - sets *RecordSets - responseStatus int - responseBody string - expectedPath string - expectedResponse *RecordSetResponse - withError error + params UpdateRecordSetsRequest + responseStatus int + responseBody string + expectedPath string + withError error }{ "200 OK": { - zone: "example.com", - sets: &RecordSets{ - []RecordSet{ - { - Name: "www.example.com", - Type: "A", - TTL: 300, - Rdata: []string{ - "10.0.0.2", - "10.0.0.3", + params: UpdateRecordSetsRequest{ + Zone: "example.com", + RecordSets: &RecordSets{ + []RecordSet{ + { + Name: "www.example.com", + Type: "A", + TTL: 300, + Rdata: []string{ + "10.0.0.2", + "10.0.0.3", + }, }, }, }, @@ -221,16 +226,18 @@ func TestDNS_UpdateRecordSets(t *testing.T) { expectedPath: "/config-dns/v2/zones/example.com/recordsets", }, "500 internal server error": { - zone: "example.com", - sets: &RecordSets{ - []RecordSet{ - { - Name: "www.example.com", - Type: "A", - TTL: 300, - Rdata: []string{ - "10.0.0.2", - "10.0.0.3", + params: UpdateRecordSetsRequest{ + Zone: "example.com", + RecordSets: &RecordSets{ + []RecordSet{ + { + Name: "www.example.com", + Type: "A", + TTL: 300, + Rdata: []string{ + "10.0.0.2", + "10.0.0.3", + }, }, }, }, @@ -265,7 +272,7 @@ func TestDNS_UpdateRecordSets(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.UpdateRecordSets(context.Background(), test.sets, test.zone) + err := client.UpdateRecordSets(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/dns/tsig.go b/pkg/dns/tsig.go index 19525f33..5b6a08e3 100644 --- a/pkg/dns/tsig.go +++ b/pkg/dns/tsig.go @@ -2,48 +2,17 @@ package dns import ( "context" + "errors" "fmt" "net/http" - - validation "github.com/go-ozzo/ozzo-validation/v4" - "reflect" "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // TSIGKeys contains operations available on TSIKeyG resource. - TSIGKeys interface { - // ListTSIGKeys lists the TSIG keys used by zones that you are allowed to manage. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-keys - ListTSIGKeys(context.Context, *TSIGQueryString) (*TSIGReportResponse, error) - // GetTSIGKeyZones retrieves DNS Zones using TSIG key. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-used-by - GetTSIGKeyZones(context.Context, *TSIGKey) (*ZoneNameListResponse, error) - // GetTSIGKeyAliases retrieves a DNS Zone's aliases. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key-used-by - GetTSIGKeyAliases(context.Context, string) (*ZoneNameListResponse, error) - // TSIGKeyBulkUpdate updates Bulk Zones TSIG key. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-bulk-update - TSIGKeyBulkUpdate(context.Context, *TSIGKeyBulkPost) error - // GetTSIGKey retrieves a TSIG key for zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key - GetTSIGKey(context.Context, string) (*TSIGKeyResponse, error) - // DeleteTSIGKey deletes TSIG key for zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/delete-zones-zone-key - DeleteTSIGKey(context.Context, string) error - // UpdateTSIGKey updates TSIG key for zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-key - UpdateTSIGKey(context.Context, *TSIGKey, string) error - } - // TSIGQueryString contains TSIG query parameters TSIGQueryString struct { ContractIDs []string `json:"contractIds,omitempty"` @@ -58,6 +27,33 @@ type ( Algorithm string `json:"algorithm,omitempty"` Secret string `json:"secret,omitempty"` } + + // TSIGKeyRequest contains request parameter + TSIGKeyRequest struct { + Zone string + } + + // GetTSIGKeyRequest contains request parameters for GetTSIGKey + GetTSIGKeyRequest TSIGKeyRequest + + // GetTSIGKeyResponse contains the response data from GetTSIGKey operation + GetTSIGKeyResponse struct { + TSIGKey + ZoneCount int64 `json:"zonesCount,omitempty"` + } + + // DeleteTSIGKeyRequest contains request parameters for DeleteTSIGKey + DeleteTSIGKeyRequest TSIGKeyRequest + + // GetTSIGKeyAliasesRequest contains request parameters for GetTSIGKeyAliases + GetTSIGKeyAliasesRequest TSIGKeyRequest + + // GetTSIGKeyAliasesResponse contains the response data from GetTSIGKeyAliases operation + GetTSIGKeyAliasesResponse struct { + Zones []string `json:"zones"` + Aliases []string `json:"aliases"` + } + // TSIGKeyResponse contains TSIG key GET response TSIGKeyResponse struct { TSIGKey @@ -86,11 +82,104 @@ type ( // TSIGReportResponse contains response with a list of the TSIG keys used by zones. TSIGReportResponse struct { - Metadata *TSIGReportMeta `json:"metadata"` - Keys []*TSIGKeyResponse `json:"keys,omitempty"` + Metadata *TSIGReportMeta `json:"metadata"` + Keys []TSIGKeyResponse `json:"keys,omitempty"` + } + + // UpdateTSIGKeyRequest contains request parameters for UpdateTSIGKey + UpdateTSIGKeyRequest struct { + TsigKey *TSIGKey + Zone string + } + + // UpdateTSIGKeyBulkRequest contains request parameters for UpdateTSIGKeyBulk + UpdateTSIGKeyBulkRequest struct { + TSIGKeyBulk *TSIGKeyBulkPost + } + + // GetTSIGKeyZonesRequest contains request parameters for GetTSIGKeyZones + GetTSIGKeyZonesRequest struct { + TsigKey *TSIGKey + } + + // GetTSIGKeyZonesResponse contains the response data from GetTSIGKeyZones operation + GetTSIGKeyZonesResponse struct { + Zones []string `json:"zones"` + Aliases []string `json:"aliases"` + } + + // ListTSIGKeysRequest contains request parameters for ListTSIGKeys + ListTSIGKeysRequest struct { + TsigQuery *TSIGQueryString + } + + // ListTSIGKeysResponse contains the response data from ListTSIGKeys operation + ListTSIGKeysResponse struct { + Metadata *TSIGReportMeta `json:"metadata"` + Keys []TSIGKeyResponse `json:"keys,omitempty"` } ) +var ( + // ErrGetTSIGKey is returned when GetTSIGKey fails + ErrGetTSIGKey = errors.New("get tsig key") + // ErrDeleteTSIGKey is returned when DeleteTSIGKey fails + ErrDeleteTSIGKey = errors.New("delete tsig key") + // ErrGetTSIGKeyAliases is returned when GetTSIGKeyAliases fails + ErrGetTSIGKeyAliases = errors.New("get tsig key aliases") + // ErrUpdateTSIGKey is returned when UpdateTSIGKey fails + ErrUpdateTSIGKey = errors.New("updated tsig key") + // ErrUpdateTSIGKeyBulk is returned when UpdateTSIGKeyBulk fails + ErrUpdateTSIGKeyBulk = errors.New("update tsig key for multiple zones") + // ErrGetTSIGKeyZones is returned when GetTSIGKeyZones fails + ErrGetTSIGKeyZones = errors.New("list zones using tsig key") + // ErrListTSIGKeys is returned when ListTSIGKeys fails + ErrListTSIGKeys = errors.New("get a list of the tsig keys") +) + +// Validate validates GetTSIGKeyRequest +func (r GetTSIGKeyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates DeleteTSIGKeyRequest +func (r DeleteTSIGKeyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates GetTSIGKeyAliasesRequest +func (r GetTSIGKeyAliasesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates UpdateTSIGKeyRequest +func (r UpdateTSIGKeyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "TsigKey": validation.Validate(r.TsigKey), + }) +} + +// Validate validates UpdateTSIGKeyBulkRequest +func (r UpdateTSIGKeyBulkRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "TSIGKeyBulk": validation.Validate(r.TSIGKeyBulk, validation.Required), + }) +} + +// Validate validates GetTSIGKeyZonesRequest +func (r GetTSIGKeyZonesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "TsigKey": validation.Validate(r.TsigKey, validation.Required), + }) +} + // Validate validates TSIGKey func (key *TSIGKey) Validate() error { return validation.Errors{ @@ -158,17 +247,17 @@ func constructTSIGQueryString(tsigQueryString *TSIGQueryString) string { return "" } -func (d *dns) ListTSIGKeys(ctx context.Context, tsigQueryString *TSIGQueryString) (*TSIGReportResponse, error) { +func (d *dns) ListTSIGKeys(ctx context.Context, params ListTSIGKeysRequest) (*ListTSIGKeysResponse, error) { logger := d.Log(ctx) logger.Debug("ListTSIGKeys") - getURL := fmt.Sprintf("/config-dns/v2/keys%s", constructTSIGQueryString(tsigQueryString)) + getURL := fmt.Sprintf("/config-dns/v2/keys%s", constructTSIGQueryString(params.TsigQuery)) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListTsigKeyss request: %w", err) } - var result TSIGReportResponse + var result ListTSIGKeysResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf(" ListTsigKeys request failed: %w", err) @@ -181,15 +270,15 @@ func (d *dns) ListTSIGKeys(ctx context.Context, tsigQueryString *TSIGQueryString return &result, nil } -func (d *dns) GetTSIGKeyZones(ctx context.Context, tsigKey *TSIGKey) (*ZoneNameListResponse, error) { +func (d *dns) GetTSIGKeyZones(ctx context.Context, params GetTSIGKeyZonesRequest) (*GetTSIGKeyZonesResponse, error) { logger := d.Log(ctx) logger.Debug("GetTSIGKeyZones") - if err := tsigKey.Validate(); err != nil { - return nil, err + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetTSIGKeyZones, ErrStructValidation, err) } - reqBody, err := convertStructToReqBody(tsigKey) + reqBody, err := convertStructToReqBody(params.TsigKey) if err != nil { return nil, fmt.Errorf("failed to generate request body: %w", err) } @@ -200,7 +289,7 @@ func (d *dns) GetTSIGKeyZones(ctx context.Context, tsigKey *TSIGKey) (*ZoneNameL return nil, fmt.Errorf("failed to create GetTsigKeyZones request: %w", err) } - var result ZoneNameListResponse + var result GetTSIGKeyZonesResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetTsigKeyZones request failed: %w", err) @@ -213,17 +302,21 @@ func (d *dns) GetTSIGKeyZones(ctx context.Context, tsigKey *TSIGKey) (*ZoneNameL return &result, nil } -func (d *dns) GetTSIGKeyAliases(ctx context.Context, zone string) (*ZoneNameListResponse, error) { +func (d *dns) GetTSIGKeyAliases(ctx context.Context, params GetTSIGKeyAliasesRequest) (*GetTSIGKeyAliasesResponse, error) { logger := d.Log(ctx) logger.Debug("GetTSIGKeyAliases") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key/used-by", zone) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetTSIGKeyAliases, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key/used-by", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetTsigKeyAliases request: %w", err) } - var result ZoneNameListResponse + var result GetTSIGKeyAliasesResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetTsigKeyAliases request failed: %w", err) @@ -236,15 +329,15 @@ func (d *dns) GetTSIGKeyAliases(ctx context.Context, zone string) (*ZoneNameList return &result, nil } -func (d *dns) TSIGKeyBulkUpdate(ctx context.Context, tsigBulk *TSIGKeyBulkPost) error { +func (d *dns) UpdateTSIGKeyBulk(ctx context.Context, params UpdateTSIGKeyBulkRequest) error { logger := d.Log(ctx) logger.Debug("TSIGKeyBulkUpdate") - if err := tsigBulk.Validate(); err != nil { - return err + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrUpdateTSIGKeyBulk, ErrStructValidation, err) } - reqBody, err := convertStructToReqBody(tsigBulk) + reqBody, err := convertStructToReqBody(params.TSIGKeyBulk) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } @@ -267,17 +360,21 @@ func (d *dns) TSIGKeyBulkUpdate(ctx context.Context, tsigBulk *TSIGKeyBulkPost) return nil } -func (d *dns) GetTSIGKey(ctx context.Context, zone string) (*TSIGKeyResponse, error) { +func (d *dns) GetTSIGKey(ctx context.Context, params GetTSIGKeyRequest) (*GetTSIGKeyResponse, error) { logger := d.Log(ctx) logger.Debug("GetTSIGKey") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetTSIGKey, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetTsigKey request: %w", err) } - var result TSIGKeyResponse + var result GetTSIGKeyResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetTsigKey request failed: %w", err) @@ -290,11 +387,15 @@ func (d *dns) GetTSIGKey(ctx context.Context, zone string) (*TSIGKeyResponse, er return &result, nil } -func (d *dns) DeleteTSIGKey(ctx context.Context, zone string) error { +func (d *dns) DeleteTSIGKey(ctx context.Context, params DeleteTSIGKeyRequest) error { logger := d.Log(ctx) logger.Debug("DeleteTSIGKey") - delURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrDeleteTSIGKey, ErrStructValidation, err) + } + + delURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return fmt.Errorf("failed to create DeleteTsigKey request: %w", err) @@ -312,20 +413,20 @@ func (d *dns) DeleteTSIGKey(ctx context.Context, zone string) error { return nil } -func (d *dns) UpdateTSIGKey(ctx context.Context, tsigKey *TSIGKey, zone string) error { +func (d *dns) UpdateTSIGKey(ctx context.Context, params UpdateTSIGKeyRequest) error { logger := d.Log(ctx) logger.Debug("UpdateTSIGKey") - if err := tsigKey.Validate(); err != nil { - return err + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrUpdateTSIGKey, ErrStructValidation, err) } - reqBody, err := convertStructToReqBody(tsigKey) + reqBody, err := convertStructToReqBody(params.TsigKey) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - putURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) + putURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) if err != nil { return fmt.Errorf("failed to create UpdateTsigKey request: %w", err) diff --git a/pkg/dns/tsig_test.go b/pkg/dns/tsig_test.go index b9fa0ef5..e5c491f4 100644 --- a/pkg/dns/tsig_test.go +++ b/pkg/dns/tsig_test.go @@ -13,16 +13,16 @@ import ( func TestDNS_ListTSIGKeys(t *testing.T) { tests := map[string]struct { - query TSIGQueryString + params ListTSIGKeysRequest responseStatus int responseBody string expectedPath string - expectedResponse *TSIGReportResponse + expectedResponse *ListTSIGKeysResponse withError error }{ "200 OK": { - query: TSIGQueryString{ - ContractIDs: []string{"1-1ABCD"}, + params: ListTSIGKeysRequest{ + TsigQuery: &TSIGQueryString{ContractIDs: []string{"1-1ABCD"}}, }, responseStatus: http.StatusOK, responseBody: ` @@ -40,11 +40,11 @@ func TestDNS_ListTSIGKeys(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/keys?contractIds=1-1ABCD", - expectedResponse: &TSIGReportResponse{ + expectedResponse: &ListTSIGKeysResponse{ Metadata: &TSIGReportMeta{ TotalElements: 1, }, - Keys: []*TSIGKeyResponse{ + Keys: []TSIGKeyResponse{ { TSIGKey: TSIGKey{ Name: "a.test.key.", @@ -57,8 +57,8 @@ func TestDNS_ListTSIGKeys(t *testing.T) { }, }, "500 internal server error": { - query: TSIGQueryString{ - ContractIDs: []string{"1-1ABCD"}, + params: ListTSIGKeysRequest{ + TsigQuery: &TSIGQueryString{ContractIDs: []string{"1-1ABCD"}}, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -88,7 +88,7 @@ func TestDNS_ListTSIGKeys(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListTSIGKeys(context.Background(), &test.query) + result, err := client.ListTSIGKeys(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -101,18 +101,20 @@ func TestDNS_ListTSIGKeys(t *testing.T) { func TestDNS_GetTSIGKeyZones(t *testing.T) { tests := map[string]struct { - key TSIGKey + params GetTSIGKeyZonesRequest responseStatus int responseBody string expectedPath string - expectedResponse *ZoneNameListResponse + expectedResponse *GetTSIGKeyZonesResponse withError error }{ "200 OK": { - key: TSIGKey{ - Name: "example.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: GetTSIGKeyZonesRequest{ + TsigKey: &TSIGKey{ + Name: "example.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, }, responseStatus: http.StatusOK, responseBody: ` @@ -123,15 +125,17 @@ func TestDNS_GetTSIGKeyZones(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/keys/used-by", - expectedResponse: &ZoneNameListResponse{ + expectedResponse: &GetTSIGKeyZonesResponse{ Zones: []string{"river.com", "stream.com"}, }, }, "500 internal server error": { - key: TSIGKey{ - Name: "example.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: GetTSIGKeyZonesRequest{ + TsigKey: &TSIGKey{ + Name: "example.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -161,7 +165,7 @@ func TestDNS_GetTSIGKeyZones(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetTSIGKeyZones(context.Background(), &test.key) + result, err := client.GetTSIGKeyZones(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -174,15 +178,17 @@ func TestDNS_GetTSIGKeyZones(t *testing.T) { func TestDNS_GetTSIGKeyAliases(t *testing.T) { tests := map[string]struct { - zone string + params GetTSIGKeyAliasesRequest responseStatus int responseBody string expectedPath string - expectedResponse *ZoneNameListResponse + expectedResponse *GetTSIGKeyAliasesResponse withError error }{ "200 OK": { - zone: "example.com", + params: GetTSIGKeyAliasesRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -194,12 +200,14 @@ func TestDNS_GetTSIGKeyAliases(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/example.com/key/used-by", - expectedResponse: &ZoneNameListResponse{ + expectedResponse: &GetTSIGKeyAliasesResponse{ Aliases: []string{"exmaple.com", "river.com", "brook.com", "ocean.com"}, }, }, "500 internal server error": { - zone: "example.com", + params: GetTSIGKeyAliasesRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -228,7 +236,7 @@ func TestDNS_GetTSIGKeyAliases(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetTSIGKeyAliases(context.Background(), test.zone) + result, err := client.GetTSIGKeyAliases(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -241,7 +249,7 @@ func TestDNS_GetTSIGKeyAliases(t *testing.T) { func TestDNS_TSIGKeyBulkUpdate(t *testing.T) { tests := map[string]struct { - bulk TSIGKeyBulkPost + params UpdateTSIGKeyBulkRequest responseStatus int responseBody string expectedPath string @@ -249,13 +257,15 @@ func TestDNS_TSIGKeyBulkUpdate(t *testing.T) { withError error }{ "200 OK": { - bulk: TSIGKeyBulkPost{ - Key: &TSIGKey{ - Name: "brook.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: UpdateTSIGKeyBulkRequest{ + TSIGKeyBulk: &TSIGKeyBulkPost{ + Key: &TSIGKey{ + Name: "brook.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, + Zones: []string{"brook.com", "river.com"}, }, - Zones: []string{"brook.com", "river.com"}, }, responseStatus: http.StatusNoContent, expectedPath: "/config-dns/v2/keys/bulk-update", @@ -264,13 +274,15 @@ func TestDNS_TSIGKeyBulkUpdate(t *testing.T) { }, }, "500 internal server error": { - bulk: TSIGKeyBulkPost{ - Key: &TSIGKey{ - Name: "brook.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: UpdateTSIGKeyBulkRequest{ + TSIGKeyBulk: &TSIGKeyBulkPost{ + Key: &TSIGKey{ + Name: "brook.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, + Zones: []string{"brook.com", "river.com"}, }, - Zones: []string{"brook.com", "river.com"}, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -302,7 +314,7 @@ func TestDNS_TSIGKeyBulkUpdate(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.TSIGKeyBulkUpdate(context.Background(), &test.bulk) + err := client.UpdateTSIGKeyBulk(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -314,15 +326,17 @@ func TestDNS_TSIGKeyBulkUpdate(t *testing.T) { func TestDNS_GetTSIGKey(t *testing.T) { tests := map[string]struct { - zone string + params GetTSIGKeyRequest responseStatus int responseBody string expectedPath string - expectedResponse *TSIGKeyResponse + expectedResponse *GetTSIGKeyResponse withError error }{ "200 OK": { - zone: "example.com", + params: GetTSIGKeyRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -332,7 +346,7 @@ func TestDNS_GetTSIGKey(t *testing.T) { "zonesCount": 7 }`, expectedPath: "/config-dns/v2/zones/example.com/key", - expectedResponse: &TSIGKeyResponse{ + expectedResponse: &GetTSIGKeyResponse{ TSIGKey: TSIGKey{ Name: "example.com.akamai.com.", Algorithm: "hmac-sha512", @@ -342,7 +356,9 @@ func TestDNS_GetTSIGKey(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", + params: GetTSIGKeyRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -371,7 +387,7 @@ func TestDNS_GetTSIGKey(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetTSIGKey(context.Background(), test.zone) + result, err := client.GetTSIGKey(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -384,7 +400,7 @@ func TestDNS_GetTSIGKey(t *testing.T) { func TestDNS_DeleteTSIGKey(t *testing.T) { tests := map[string]struct { - zone string + params DeleteTSIGKeyRequest responseStatus int responseBody string expectedPath string @@ -392,12 +408,16 @@ func TestDNS_DeleteTSIGKey(t *testing.T) { withError error }{ "204 No Content": { - zone: "example.com", + params: DeleteTSIGKeyRequest{ + Zone: "example.com", + }, responseStatus: http.StatusNoContent, expectedPath: "/config-dns/v2/zones/example.com/key", }, "500 internal server error": { - zone: "example.com", + params: DeleteTSIGKeyRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -428,7 +448,7 @@ func TestDNS_DeleteTSIGKey(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.DeleteTSIGKey(context.Background(), test.zone) + err := client.DeleteTSIGKey(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -440,8 +460,7 @@ func TestDNS_DeleteTSIGKey(t *testing.T) { func TestDNS_UpdateTSIGKey(t *testing.T) { tests := map[string]struct { - key TSIGKey - zone string + params UpdateTSIGKeyRequest responseStatus int responseBody string expectedPath string @@ -449,22 +468,26 @@ func TestDNS_UpdateTSIGKey(t *testing.T) { withError error }{ "200 OK": { - key: TSIGKey{ - Name: "example.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: UpdateTSIGKeyRequest{ + TsigKey: &TSIGKey{ + Name: "example.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, + Zone: "example.com", }, - zone: "example.com", responseStatus: http.StatusNoContent, expectedPath: "/config-dns/v2/zones/example.com/key", }, "500 internal server error": { - key: TSIGKey{ - Name: "example.com.akamai.com.", - Algorithm: "hmac-sha512", - Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + params: UpdateTSIGKeyRequest{ + TsigKey: &TSIGKey{ + Name: "example.com.akamai.com.", + Algorithm: "hmac-sha512", + Secret: "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw==", + }, + Zone: "example.com", }, - zone: "example.com", responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -495,7 +518,7 @@ func TestDNS_UpdateTSIGKey(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.UpdateTSIGKey(context.Background(), &test.key, test.zone) + err := client.UpdateTSIGKey(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/dns/zone.go b/pkg/dns/zone.go index 79ab0538..c671c778 100644 --- a/pkg/dns/zone.go +++ b/pkg/dns/zone.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -23,82 +24,6 @@ var ( ) type ( - // Zones contains operations available on Zone resources. - Zones interface { - // ListZones retrieves a list of all zones user can access. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones - ListZones(context.Context, ...ZoneListQueryArgs) (*ZoneListResponse, error) - // GetZone retrieves Zone metadata. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zone - GetZone(context.Context, string) (*ZoneResponse, error) - //GetChangeList retrieves Zone changelist. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-changelists-zone - GetChangeList(context.Context, string) (*ChangeListResponse, error) - // GetMasterZoneFile retrieves master zone file. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-zone-file - GetMasterZoneFile(context.Context, string) (string, error) - // PostMasterZoneFile updates master zone file. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-zone-file - PostMasterZoneFile(context.Context, string, string) error - // CreateZone creates new zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zone - CreateZone(context.Context, *ZoneCreate, ZoneQueryString, ...bool) error - // SaveChangelist creates a new Change List based on the most recent version of a zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists - SaveChangelist(context.Context, *ZoneCreate) error - // SubmitChangelist submits changelist for the Zone to create default NS SOA records. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists-zone-submit - SubmitChangelist(context.Context, *ZoneCreate) error - // UpdateZone updates zone. - // - // See: https://techdocs.akamai.com/edge-dns/reference/put-zone - UpdateZone(context.Context, *ZoneCreate, ZoneQueryString) error - // GetZoneNames retrieves a list of a zone's record names. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-names - GetZoneNames(context.Context, string) (*ZoneNamesResponse, error) - // GetZoneNameTypes retrieves a zone name's record types. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-types - GetZoneNameTypes(context.Context, string, string) (*ZoneNameTypesResponse, error) - // CreateBulkZones submits create bulk zone request. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-create-requests - CreateBulkZones(context.Context, *BulkZonesCreate, ZoneQueryString) (*BulkZonesResponse, error) - // DeleteBulkZones submits delete bulk zone request. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-delete-requests - DeleteBulkZones(context.Context, *ZoneNameListResponse, ...bool) (*BulkZonesResponse, error) - // GetBulkZoneCreateStatus retrieves submit request status. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid - GetBulkZoneCreateStatus(context.Context, string) (*BulkStatusResponse, error) - //GetBulkZoneDeleteStatus retrieves submit request status. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid - GetBulkZoneDeleteStatus(context.Context, string) (*BulkStatusResponse, error) - // GetBulkZoneCreateResult retrieves create request result. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid-result - GetBulkZoneCreateResult(ctx context.Context, requestid string) (*BulkCreateResultResponse, error) - // GetBulkZoneDeleteResult retrieves delete request result. - // - // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid-result - GetBulkZoneDeleteResult(context.Context, string) (*BulkDeleteResultResponse, error) - // GetZonesDNSSecStatus returns the current DNSSEC status for one or more zones. - // - // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-dns-sec-status - GetZonesDNSSecStatus(context.Context, GetZonesDNSSecStatusRequest) (*GetZonesDNSSecStatusResponse, error) - } - // ZoneQueryString contains zone query parameters ZoneQueryString struct { Contract string @@ -139,17 +64,6 @@ type ( VersionID string `json:"versionId,omitempty"` } - // ZoneListQueryArgs contains parameters for List Zones query - ZoneListQueryArgs struct { - ContractIDs string - Page int - PageSize int - Search string - ShowAll bool - SortBy string - Types string - } - // ListMetadata contains metadata for List Zones request ListMetadata struct { ContractIDs []string `json:"contractIds"` @@ -161,12 +75,20 @@ type ( // ZoneListResponse contains response for List Zones request ZoneListResponse struct { - Metadata *ListMetadata `json:"metadata,omitempty"` - Zones []*ZoneResponse `json:"zones,omitempty"` + Metadata *ListMetadata `json:"metadata,omitempty"` + Zones []ZoneResponse `json:"zones,omitempty"` } - // ChangeListResponse contains metadata about a change list - ChangeListResponse struct { + // ZoneRequest contains request parameters + ZoneRequest struct { + Zone string + } + + // GetZoneResponse contains the response data from GetZone operation + GetZoneResponse ZoneResponse + + // GetChangeListResponse contains metadata about a change list + GetChangeListResponse struct { Zone string `json:"zone,omitempty"` ChangeTag string `json:"changeTag,omitempty"` ZoneVersionID string `json:"zoneVersionId,omitempty"` @@ -180,15 +102,63 @@ type ( Aliases []string `json:"aliases,omitempty"` } - // ZoneNamesResponse contains record set names for zone - ZoneNamesResponse struct { + // GetZoneNamesResponse contains record set names for zone + GetZoneNamesResponse struct { Names []string `json:"names"` } - // ZoneNameTypesResponse contains record set types for zone - ZoneNameTypesResponse struct { + // GetZoneNameTypesResponse contains record set types for zone + GetZoneNameTypesResponse struct { Types []string `json:"types"` } + // GetZoneRequest contains request parameters for GetZone + GetZoneRequest ZoneRequest + + // GetChangeListRequest contains request parameters for GetChangeList + GetChangeListRequest ZoneRequest + + // ListZonesRequest contains request parameters for ListZones + ListZonesRequest struct { + ContractIDs string + Page int + PageSize int + Search string + ShowAll bool + SortBy string + Types string + } + // GetMasterZoneFileRequest contains request parameters for GetMasterZoneFile + GetMasterZoneFileRequest ZoneRequest + + // PostMasterZoneFileRequest contains request parameters for PostMasterZoneFile + PostMasterZoneFileRequest struct { + Zone string + FileData string + } + // CreateZoneRequest contains request parameters for CreateZone + CreateZoneRequest struct { + CreateZone *ZoneCreate + ZoneQueryString ZoneQueryString + ClearConn []bool + } + // SaveChangeListRequest contains request parameters for SaveChangelist + SaveChangeListRequest ZoneCreate + + // SubmitChangeListRequest contains request parameters for SubmitChangeList + SubmitChangeListRequest ZoneCreate + + // UpdateZoneRequest contains request parameters for UpdateZone + UpdateZoneRequest struct { + CreateZone *ZoneCreate + } + // GetZoneNamesRequest contains request parameters for GetZoneNames + GetZoneNamesRequest ZoneRequest + + // GetZoneNameTypesRequest contains request parameters for GetZoneNameTypes + GetZoneNameTypesRequest struct { + Zone string + ZoneName string + } // GetZonesDNSSecStatusRequest is used to get the DNSSEC status for one or more zones GetZonesDNSSecStatusRequest struct { @@ -218,6 +188,91 @@ type ( } ) +var ( + // ErrGetZone is returned when GetZone fails + ErrGetZone = errors.New("get zone") + // ErrGetChangeList is returned when GetChangeList fails + ErrGetChangeList = errors.New("get change list") + // ErrGetMasterZoneFile is returned when GetMasterZoneFile fails + ErrGetMasterZoneFile = errors.New("get master zone file") + // ErrPostMasterZoneFile is returned when PostMasterZoneFile fails + ErrPostMasterZoneFile = errors.New("post master zone file") + // ErrCreateZone is returned when CreateZone fails + ErrCreateZone = errors.New("create zone") + // ErrSaveChangeList is returned when SaveChangeList fails + ErrSaveChangeList = errors.New("save change list") + // ErrSubmitChangeList is returned when SubmitChangeList fails + ErrSubmitChangeList = errors.New("submit change list") + // ErrGetZoneNames is returned when GetZoneNames fails + ErrGetZoneNames = errors.New("get zone names") + // ErrGetZoneNameTypes is returned when GetZoneNameTypes fails + ErrGetZoneNameTypes = errors.New("get zone name types") +) + +// Validate validates GetZoneNameTypesRequest +func (r GetZoneNameTypesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + "ZoneName": validation.Validate(r.ZoneName, validation.Required), + }) +} + +// Validate validates GetZoneNamesRequest +func (r GetZoneNamesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates SubmitChangeListRequest +func (r SubmitChangeListRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates SaveChangelistRequest +func (r SaveChangeListRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates PostMasterZoneFileRequest +func (r PostMasterZoneFileRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates CreateZoneRequest +func (r CreateZoneRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ZoneQueryString": validation.Validate(r.ZoneQueryString, validation.Required), + }) +} + +// Validate validates GetZoneRequest +func (r GetZoneRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates GetMasterZoneFileRequest +func (r GetMasterZoneFileRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + +// Validate validates GetChangeListRequest +func (r GetChangeListRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Zone": validation.Validate(r.Zone, validation.Required), + }) +} + // Validate validates GetZonesDNSSecStatusRequest func (r GetZonesDNSSecStatusRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ @@ -246,14 +301,11 @@ func convertStructToReqBody(srcStruct interface{}) (io.Reader, error) { return bytes.NewBuffer(reqBody), nil } -func (d *dns) ListZones(ctx context.Context, queryArgs ...ZoneListQueryArgs) (*ZoneListResponse, error) { +func (d *dns) ListZones(ctx context.Context, params ListZonesRequest) (*ZoneListResponse, error) { logger := d.Log(ctx) logger.Debug("ListZones") getURL := fmt.Sprintf("/config-dns/v2/zones") - if len(queryArgs) > 1 { - return nil, fmt.Errorf("ListZones QueryArgs invalid") - } req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -261,28 +313,26 @@ func (d *dns) ListZones(ctx context.Context, queryArgs ...ZoneListQueryArgs) (*Z } q := req.URL.Query() - if len(queryArgs) > 0 { - if queryArgs[0].Page > 0 { - q.Add("page", strconv.Itoa(queryArgs[0].Page)) - } - if queryArgs[0].PageSize > 0 { - q.Add("pageSize", strconv.Itoa(queryArgs[0].PageSize)) - } - if queryArgs[0].Search != "" { - q.Add("search", queryArgs[0].Search) - } - q.Add("showAll", strconv.FormatBool(queryArgs[0].ShowAll)) - if queryArgs[0].SortBy != "" { - q.Add("sortBy", queryArgs[0].SortBy) - } - if queryArgs[0].Types != "" { - q.Add("types", queryArgs[0].Types) - } - if queryArgs[0].ContractIDs != "" { - q.Add("contractIds", queryArgs[0].ContractIDs) - } - req.URL.RawQuery = q.Encode() + if params.Page > 0 { + q.Add("page", strconv.Itoa(params.Page)) + } + if params.PageSize > 0 { + q.Add("pageSize", strconv.Itoa(params.PageSize)) + } + if params.Search != "" { + q.Add("search", params.Search) + } + q.Add("showAll", strconv.FormatBool(params.ShowAll)) + if params.SortBy != "" { + q.Add("sortBy", params.SortBy) } + if params.Types != "" { + q.Add("types", params.Types) + } + if params.ContractIDs != "" { + q.Add("contractIds", params.ContractIDs) + } + req.URL.RawQuery = q.Encode() var result ZoneListResponse resp, err := d.Exec(req, &result) @@ -297,17 +347,21 @@ func (d *dns) ListZones(ctx context.Context, queryArgs ...ZoneListQueryArgs) (*Z return &result, nil } -func (d *dns) GetZone(ctx context.Context, zoneName string) (*ZoneResponse, error) { +func (d *dns) GetZone(ctx context.Context, params GetZoneRequest) (*GetZoneResponse, error) { logger := d.Log(ctx) logger.Debug("GetZone") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s", zoneName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetZone, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetZone request: %w", err) } - var result ZoneResponse + var result GetZoneResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetZone request failed: %w", err) @@ -320,17 +374,21 @@ func (d *dns) GetZone(ctx context.Context, zoneName string) (*ZoneResponse, erro return &result, nil } -func (d *dns) GetChangeList(ctx context.Context, zone string) (*ChangeListResponse, error) { +func (d *dns) GetChangeList(ctx context.Context, params GetChangeListRequest) (*GetChangeListResponse, error) { logger := d.Log(ctx) logger.Debug("GetChangeList") - getURL := fmt.Sprintf("/config-dns/v2/changelists/%s", zone) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetChangeList, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/changelists/%s", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetChangeList request: %w", err) } - var result ChangeListResponse + var result GetChangeListResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetChangeList request failed: %w", err) @@ -343,11 +401,15 @@ func (d *dns) GetChangeList(ctx context.Context, zone string) (*ChangeListRespon return &result, nil } -func (d *dns) GetMasterZoneFile(ctx context.Context, zone string) (string, error) { +func (d *dns) GetMasterZoneFile(ctx context.Context, params GetMasterZoneFileRequest) (string, error) { logger := d.Log(ctx) logger.Debug("GetMasterZoneFile") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", zone) + if err := params.Validate(); err != nil { + return "", fmt.Errorf("%s: %w: %s", ErrGetMasterZoneFile, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return "", fmt.Errorf("failed to create GetMasterZoneFile request: %w", err) @@ -371,13 +433,17 @@ func (d *dns) GetMasterZoneFile(ctx context.Context, zone string) (string, error return string(masterFile), nil } -func (d *dns) PostMasterZoneFile(ctx context.Context, zone string, fileData string) error { +func (d *dns) PostMasterZoneFile(ctx context.Context, params PostMasterZoneFileRequest) error { logger := d.Log(ctx) logger.Debug("PostMasterZoneFile") + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrPostMasterZoneFile, ErrStructValidation, err) + } + mtResp := "" - pmzfURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", zone) - buf := bytes.NewReader([]byte(fileData)) + pmzfURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", params.Zone) + buf := bytes.NewReader([]byte(params.FileData)) req, err := http.NewRequestWithContext(ctx, http.MethodPost, pmzfURL, buf) if err != nil { return fmt.Errorf("failed to create PostMasterZoneFile request: %w", err) @@ -397,7 +463,7 @@ func (d *dns) PostMasterZoneFile(ctx context.Context, zone string, fileData stri return nil } -func (d *dns) CreateZone(ctx context.Context, zone *ZoneCreate, zoneQueryString ZoneQueryString, clearConn ...bool) error { +func (d *dns) CreateZone(ctx context.Context, params CreateZoneRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone, @@ -410,16 +476,20 @@ func (d *dns) CreateZone(ctx context.Context, zone *ZoneCreate, zoneQueryString logger := d.Log(ctx) logger.Debug("Zone Create") - if err := ValidateZone(zone); err != nil { + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrCreateZone, ErrStructValidation, err) + } + + if err := ValidateZone(params.CreateZone); err != nil { return err } - zoneMap := filterZoneCreate(zone) + zoneMap := filterZoneCreate(params.CreateZone) var zoneResponse ZoneResponse - zoneURL := "/config-dns/v2/zones/?contractId=" + zoneQueryString.Contract - if len(zoneQueryString.Group) > 0 { - zoneURL += "&gid=" + zoneQueryString.Group + zoneURL := "/config-dns/v2/zones/?contractId=" + params.ZoneQueryString.Contract + if len(params.ZoneQueryString.Group) > 0 { + zoneURL += "&gid=" + params.ZoneQueryString.Group } reqBody, err := convertStructToReqBody(zoneMap) @@ -441,9 +511,9 @@ func (d *dns) CreateZone(ctx context.Context, zone *ZoneCreate, zoneQueryString return d.Error(resp) } - if strings.ToUpper(zone.Type) == "PRIMARY" { + if strings.ToUpper(params.CreateZone.Type) == "PRIMARY" { // Timing issue with Create immediately followed by SaveChangelist - for _, clear := range clearConn { + for _, clear := range params.ClearConn { // should only be one entry if clear { logger.Info("Clearing Idle Connections") @@ -455,7 +525,7 @@ func (d *dns) CreateZone(ctx context.Context, zone *ZoneCreate, zoneQueryString return nil } -func (d *dns) SaveChangelist(ctx context.Context, zone *ZoneCreate) error { +func (d *dns) SaveChangeList(ctx context.Context, params SaveChangeListRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone @@ -468,12 +538,16 @@ func (d *dns) SaveChangelist(ctx context.Context, zone *ZoneCreate) error { logger := d.Log(ctx) logger.Debug("SaveChangeList") + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrSaveChangeList, ErrStructValidation, err) + } + reqBody, err := convertStructToReqBody("") if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - postURL := fmt.Sprintf("/config-dns/v2/changelists/?zone=%s", zone.Zone) + postURL := fmt.Sprintf("/config-dns/v2/changelists/?zone=%s", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) if err != nil { return fmt.Errorf("failed to create SaveChangeList request: %w", err) @@ -491,7 +565,7 @@ func (d *dns) SaveChangelist(ctx context.Context, zone *ZoneCreate) error { return nil } -func (d *dns) SubmitChangelist(ctx context.Context, zone *ZoneCreate) error { +func (d *dns) SubmitChangeList(ctx context.Context, params SubmitChangeListRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone @@ -504,12 +578,16 @@ func (d *dns) SubmitChangelist(ctx context.Context, zone *ZoneCreate) error { logger := d.Log(ctx) logger.Debug("SubmitChangeList") + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrSubmitChangeList, ErrStructValidation, err) + } + reqBody, err := convertStructToReqBody("") if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - postURL := fmt.Sprintf("/config-dns/v2/changelists/%s/submit", zone.Zone) + postURL := fmt.Sprintf("/config-dns/v2/changelists/%s/submit", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) if err != nil { return fmt.Errorf("failed to create SubmitChangeList request: %w", err) @@ -527,7 +605,7 @@ func (d *dns) SubmitChangelist(ctx context.Context, zone *ZoneCreate) error { return nil } -func (d *dns) UpdateZone(ctx context.Context, zone *ZoneCreate, _ ZoneQueryString) error { +func (d *dns) UpdateZone(ctx context.Context, params UpdateZoneRequest) error { // This lock will restrict the concurrency of API calls // to 1 save request at a time. This is needed for the Soa.Serial value which // is required to be incremented for every subsequent update to a zone @@ -540,17 +618,17 @@ func (d *dns) UpdateZone(ctx context.Context, zone *ZoneCreate, _ ZoneQueryStrin logger := d.Log(ctx) logger.Debug("Zone Update") - if err := ValidateZone(zone); err != nil { + if err := ValidateZone(params.CreateZone); err != nil { return err } - zoneMap := filterZoneCreate(zone) + zoneMap := filterZoneCreate(params.CreateZone) reqBody, err := convertStructToReqBody(zoneMap) if err != nil { return fmt.Errorf("failed to generate request body: %w", err) } - putURL := fmt.Sprintf("/config-dns/v2/zones/%s", zone.Zone) + putURL := fmt.Sprintf("/config-dns/v2/zones/%s", params.CreateZone.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) if err != nil { return fmt.Errorf("failed to create Get Update request: %w", err) @@ -644,17 +722,21 @@ func ValidateZone(zone *ZoneCreate) error { return nil } -func (d *dns) GetZoneNames(ctx context.Context, zone string) (*ZoneNamesResponse, error) { +func (d *dns) GetZoneNames(ctx context.Context, params GetZoneNamesRequest) (*GetZoneNamesResponse, error) { logger := d.Log(ctx) logger.Debug("GetZoneNames") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names", zone) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetZoneNames, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names", params.Zone) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetZoneNames request: %w", err) } - var result ZoneNamesResponse + var result GetZoneNamesResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetZoneNames request failed: %w", err) @@ -667,17 +749,21 @@ func (d *dns) GetZoneNames(ctx context.Context, zone string) (*ZoneNamesResponse return &result, nil } -func (d *dns) GetZoneNameTypes(ctx context.Context, zName, zone string) (*ZoneNameTypesResponse, error) { +func (d *dns) GetZoneNameTypes(ctx context.Context, params GetZoneNameTypesRequest) (*GetZoneNameTypesResponse, error) { logger := d.Log(ctx) logger.Debug(" GetZoneNameTypes") - getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types", zone, zName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetZoneNameTypes, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types", params.Zone, params.ZoneName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetZoneNameTypes request: %w", err) } - var result ZoneNameTypesResponse + var result GetZoneNameTypesResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetZoneNameTypes request failed: %w", err) diff --git a/pkg/dns/zone_test.go b/pkg/dns/zone_test.go index 8a66ca9f..4a67aa3b 100644 --- a/pkg/dns/zone_test.go +++ b/pkg/dns/zone_test.go @@ -17,7 +17,7 @@ import ( func TestDNS_ListZones(t *testing.T) { tests := map[string]struct { - args []ZoneListQueryArgs + params ListZonesRequest responseStatus int responseBody string expectedPath string @@ -26,15 +26,13 @@ func TestDNS_ListZones(t *testing.T) { headers http.Header }{ "200 OK": { - args: []ZoneListQueryArgs{ - { - ContractIDs: "1-1ACYUM", - Search: "org", - SortBy: "-contractId,zone", - Types: "primary,alias", - Page: 1, - PageSize: 25, - }, + params: ListZonesRequest{ + ContractIDs: "1-1ACYUM", + Search: "org", + SortBy: "-contractId,zone", + Types: "primary,alias", + Page: 1, + PageSize: 25, }, headers: http.Header{ "Accept": []string{"application/json"}, @@ -75,7 +73,7 @@ func TestDNS_ListZones(t *testing.T) { TotalElements: 17, ContractIDs: []string{"1-2ABCDE"}, }, - Zones: []*ZoneResponse{ + Zones: []ZoneResponse{ { ContractID: "1-2ABCDE", Zone: "example.com", @@ -92,15 +90,13 @@ func TestDNS_ListZones(t *testing.T) { }, }, "500 internal server error": { - args: []ZoneListQueryArgs{ - { - ContractIDs: "1-1ACYUM", - Search: "org", - SortBy: "-contractId,zone", - Types: "primary,alias", - Page: 1, - PageSize: 25, - }, + params: ListZonesRequest{ + ContractIDs: "1-1ACYUM", + Search: "org", + SortBy: "-contractId,zone", + Types: "primary,alias", + Page: 1, + PageSize: 25, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -132,7 +128,7 @@ func TestDNS_ListZones(t *testing.T) { result, err := client.ListZones( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.args...) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -303,15 +299,17 @@ func TestDNS_GetZonesDNSSecStatus(t *testing.T) { func TestDNS_GetZone(t *testing.T) { tests := map[string]struct { - zone string + params GetZoneRequest responseStatus int responseBody string expectedPath string - expectedResponse *ZoneResponse + expectedResponse *GetZoneResponse withError error }{ "200 OK": { - zone: "example.com", + params: GetZoneRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -328,7 +326,7 @@ func TestDNS_GetZone(t *testing.T) { "activationState": "ACTIVE" }`, expectedPath: "/config-dns/v2/zones/example.com", - expectedResponse: &ZoneResponse{ + expectedResponse: &GetZoneResponse{ ContractID: "1-2ABCDE", Zone: "example.com", Type: "primary", @@ -343,7 +341,9 @@ func TestDNS_GetZone(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", + params: GetZoneRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -372,7 +372,7 @@ func TestDNS_GetZone(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetZone(context.Background(), test.zone) + result, err := client.GetZone(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -385,7 +385,7 @@ func TestDNS_GetZone(t *testing.T) { func TestDNS_GetZoneMasterFile(t *testing.T) { tests := map[string]struct { - zone string + params GetMasterZoneFileRequest responseStatus int responseBody string expectedPath string @@ -393,7 +393,9 @@ func TestDNS_GetZoneMasterFile(t *testing.T) { withError error }{ "200 OK": { - zone: "example.com", + params: GetMasterZoneFileRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: `"example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 example.com. 10000 IN NS ns1.akamaidns.com. @@ -412,7 +414,9 @@ www.example.com. 300 IN A 10.0.0.1 www.example.com. 300 IN A 10.0.0.2"`, }, "500 internal server error": { - zone: "example.com", + params: GetMasterZoneFileRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -441,7 +445,7 @@ www.example.com. 300 IN A 10.0.0.2"`, assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetMasterZoneFile(context.Background(), test.zone) + result, err := client.GetMasterZoneFile(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -454,35 +458,38 @@ www.example.com. 300 IN A 10.0.0.2"`, func TestDNS_UpdateZoneMasterFile(t *testing.T) { tests := map[string]struct { - zone string - masterfile string + params PostMasterZoneFileRequest responseStatus int expectedPath string responseBody string withError error }{ "204 Updated": { - zone: "example.com", - masterfile: `"example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 + params: PostMasterZoneFileRequest{ + Zone: "example.com", + FileData: `"example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 example.com. 10000 IN NS ns1.akamaidns.com. example.com. 10000 IN NS ns2.akamaidns.com. example.com. 300 IN A 10.0.0.1 example.com. 300 IN A 10.0.0.2 www.example.com. 300 IN A 10.0.0.1 www.example.com. 300 IN A 10.0.0.2"`, + }, responseStatus: http.StatusNoContent, responseBody: "", expectedPath: "/config-dns/v2/zones/example.com/zone-file", }, "500 internal server error": { - zone: "example.com", - masterfile: `"example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 + params: PostMasterZoneFileRequest{ + Zone: "example.com", + FileData: `"example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 example.com. 10000 IN NS ns1.akamaidns.com. example.com. 10000 IN NS ns2.akamaidns.com. example.com. 300 IN A 10.0.0.1 example.com. 300 IN A 10.0.0.2 www.example.com. 300 IN A 10.0.0.1 www.example.com. 300 IN A 10.0.0.2"`, + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -512,7 +519,7 @@ www.example.com. 300 IN A 10.0.0.2"`, } })) client := mockAPIClient(t, mockServer) - err := client.PostMasterZoneFile(context.Background(), test.zone, test.masterfile) + err := client.PostMasterZoneFile(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -524,15 +531,17 @@ www.example.com. 300 IN A 10.0.0.2"`, func TestDNS_GetChangeList(t *testing.T) { tests := map[string]struct { - zone string + params GetChangeListRequest responseStatus int responseBody string expectedPath string - expectedResponse *ChangeListResponse + expectedResponse *GetChangeListResponse withError error }{ "200 OK": { - zone: "example.com", + params: GetChangeListRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -543,7 +552,7 @@ func TestDNS_GetChangeList(t *testing.T) { "stale": false }`, expectedPath: "/config-dns/v2/zones/example.com", - expectedResponse: &ChangeListResponse{ + expectedResponse: &GetChangeListResponse{ Zone: "example.com", ChangeTag: "476754f4-d605-479f-853b-db854d7254fa", ZoneVersionID: "1d9c887c-49bb-4382-87a6-d1bf690aa58f", @@ -552,7 +561,9 @@ func TestDNS_GetChangeList(t *testing.T) { }, }, "500 internal server error": { - zone: "example.com", + params: GetChangeListRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -581,7 +592,7 @@ func TestDNS_GetChangeList(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetChangeList(context.Background(), test.zone) + result, err := client.GetChangeList(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -594,7 +605,7 @@ func TestDNS_GetChangeList(t *testing.T) { func TestDNS_GetMasterZoneFile(t *testing.T) { tests := map[string]struct { - zone string + params GetMasterZoneFileRequest responseStatus int responseBody string expectedPath string @@ -602,7 +613,9 @@ func TestDNS_GetMasterZoneFile(t *testing.T) { withError error }{ "200 OK": { - zone: "example.com", + params: GetMasterZoneFileRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` example.com. 10000 IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400 @@ -623,7 +636,9 @@ func TestDNS_GetMasterZoneFile(t *testing.T) { www.example.com. 300 IN A 10.0.0.2`, }, "500 internal server error": { - zone: "example.com", + params: GetMasterZoneFileRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -654,7 +669,7 @@ func TestDNS_GetMasterZoneFile(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - result, err := client.GetMasterZoneFile(context.Background(), test.zone) + result, err := client.GetMasterZoneFile(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -667,18 +682,19 @@ func TestDNS_GetMasterZoneFile(t *testing.T) { func TestDNS_CreateZone(t *testing.T) { tests := map[string]struct { - zone ZoneCreate - query ZoneQueryString + params CreateZoneRequest responseStatus int responseBody string expectedPath string withError error }{ "201 Created": { - zone: ZoneCreate{ - Zone: "example.com", - ContractID: "1-2ABCDE", - Type: "primary", + params: CreateZoneRequest{ + CreateZone: &ZoneCreate{ + Zone: "example.com", + ContractID: "1-2ABCDE", + Type: "primary", + }, }, responseStatus: http.StatusCreated, responseBody: ` @@ -707,10 +723,12 @@ func TestDNS_CreateZone(t *testing.T) { expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE", }, "500 internal server error": { - zone: ZoneCreate{ - Zone: "example.com", - ContractID: "1-2ABCDE", - Type: "secondary", + params: CreateZoneRequest{ + CreateZone: &ZoneCreate{ + Zone: "example.com", + ContractID: "1-2ABCDE", + Type: "primary", + }, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -741,7 +759,7 @@ func TestDNS_CreateZone(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.CreateZone(context.Background(), &test.zone, test.query, true) + err := client.CreateZone(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -753,14 +771,15 @@ func TestDNS_CreateZone(t *testing.T) { func TestDNS_SaveChangelist(t *testing.T) { tests := map[string]struct { + params SaveChangeListRequest zone ZoneCreate responseStatus int responseBody string expectedPath string - withError error + withError func(*testing.T, error) }{ "201 Created": { - zone: ZoneCreate{ + params: SaveChangeListRequest{ Zone: "example.com", ContractID: "1-2ABCDE", Type: "primary", @@ -769,10 +788,10 @@ func TestDNS_SaveChangelist(t *testing.T) { expectedPath: "/config-dns/v2/changelists?zone=example.com", }, "500 internal server error": { - zone: ZoneCreate{ + params: SaveChangeListRequest{ Zone: "example.com", ContractID: "1-2ABCDE", - Type: "secondary", + Type: "primary", }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -783,11 +802,14 @@ func TestDNS_SaveChangelist(t *testing.T) { "status": 500 }`, expectedPath: "/config-dns/v2/changelists?zone=example.com", - withError: &Error{ - Type: "internal_error", - Title: "Internal Server Error", - Detail: "Error creating zone", - StatusCode: http.StatusInternalServerError, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error creating zone", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) }, }, } @@ -803,9 +825,9 @@ func TestDNS_SaveChangelist(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.SaveChangelist(context.Background(), &test.zone) + err := client.SaveChangeList(context.Background(), test.params) if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + test.withError(t, err) return } require.NoError(t, err) @@ -815,14 +837,14 @@ func TestDNS_SaveChangelist(t *testing.T) { func TestDNS_SubmitChangelist(t *testing.T) { tests := map[string]struct { - zone ZoneCreate + params SubmitChangeListRequest responseStatus int responseBody string expectedPath string withError error }{ "204 No Content": { - zone: ZoneCreate{ + params: SubmitChangeListRequest{ Zone: "example.com", ContractID: "1-2ABCDE", Type: "primary", @@ -831,7 +853,7 @@ func TestDNS_SubmitChangelist(t *testing.T) { expectedPath: "/config-dns/v2/changelists?zone=example.com", }, "500 internal server error": { - zone: ZoneCreate{ + params: SubmitChangeListRequest{ Zone: "example.com", ContractID: "1-2ABCDE", Type: "secondary", @@ -865,7 +887,7 @@ func TestDNS_SubmitChangelist(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.SubmitChangelist(context.Background(), &test.zone) + err := client.SubmitChangeList(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -877,18 +899,19 @@ func TestDNS_SubmitChangelist(t *testing.T) { func TestDNS_UpdateZone(t *testing.T) { tests := map[string]struct { - zone ZoneCreate - query ZoneQueryString + params UpdateZoneRequest responseStatus int responseBody string expectedPath string withError error }{ "200 OK": { - zone: ZoneCreate{ - Zone: "example.com", - ContractID: "1-2ABCDE", - Type: "primary", + params: UpdateZoneRequest{ + CreateZone: &ZoneCreate{ + Zone: "example.com", + ContractID: "1-2ABCDE", + Type: "primary", + }, }, responseStatus: http.StatusOK, responseBody: ` @@ -917,10 +940,12 @@ func TestDNS_UpdateZone(t *testing.T) { expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE", }, "500 internal server error": { - zone: ZoneCreate{ - Zone: "example.com", - ContractID: "1-2ABCDE", - Type: "secondary", + params: UpdateZoneRequest{ + CreateZone: &ZoneCreate{ + Zone: "example.com", + ContractID: "1-2ABCDE", + Type: "secondary", + }, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -951,7 +976,7 @@ func TestDNS_UpdateZone(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - err := client.UpdateZone(context.Background(), &test.zone, test.query) + err := client.UpdateZone(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -963,15 +988,17 @@ func TestDNS_UpdateZone(t *testing.T) { func TestDNS_GetZoneNames(t *testing.T) { tests := map[string]struct { - zone string + params GetZoneNamesRequest responseStatus int responseBody string expectedPath string - expectedResponse *ZoneNamesResponse + expectedResponse *GetZoneNamesResponse withError error }{ "200 OK": { - zone: "example.com", + params: GetZoneNamesRequest{ + Zone: "example.com", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -984,12 +1011,14 @@ func TestDNS_GetZoneNames(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/example.com/names", - expectedResponse: &ZoneNamesResponse{ + expectedResponse: &GetZoneNamesResponse{ Names: []string{"example.com", "www.example.com", "ftp.example.com", "space.example.com", "bar.example.com"}, }, }, "500 internal server error": { - zone: "example.com", + params: GetZoneNamesRequest{ + Zone: "example.com", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -1018,7 +1047,7 @@ func TestDNS_GetZoneNames(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetZoneNames(context.Background(), test.zone) + result, err := client.GetZoneNames(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -1031,17 +1060,18 @@ func TestDNS_GetZoneNames(t *testing.T) { func TestDNS_GetZoneNameTypes(t *testing.T) { tests := map[string]struct { - zone string - zname string + params GetZoneNameTypesRequest responseStatus int responseBody string expectedPath string - expectedResponse *ZoneNameTypesResponse + expectedResponse *GetZoneNameTypesResponse withError error }{ "200 OK": { - zone: "example.com", - zname: "names", + params: GetZoneNameTypesRequest{ + Zone: "example.com", + ZoneName: "names", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -1052,13 +1082,15 @@ func TestDNS_GetZoneNameTypes(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types", - expectedResponse: &ZoneNameTypesResponse{ + expectedResponse: &GetZoneNameTypesResponse{ Types: []string{"A", "AAAA", "MX"}, }, }, "500 internal server error": { - zone: "example.com", - zname: "names", + params: GetZoneNameTypesRequest{ + Zone: "example.com", + ZoneName: "names", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -1087,7 +1119,7 @@ func TestDNS_GetZoneNameTypes(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetZoneNameTypes(context.Background(), test.zname, test.zone) + result, err := client.GetZoneNameTypes(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/dns/zonebulk.go b/pkg/dns/zonebulk.go index 0751112e..f70e58c9 100644 --- a/pkg/dns/zonebulk.go +++ b/pkg/dns/zonebulk.go @@ -2,63 +2,205 @@ package dns import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // BulkZonesCreate contains a list of one or more new Zones to create + BulkZonesCreate struct { + Zones []ZoneCreate `json:"zones"` + } + + // BulkZonesResponse contains response from bulk-create request + BulkZonesResponse struct { + RequestID string `json:"requestId"` + ExpirationDate string `json:"expirationDate"` + } + + // BulkRequest contains request parameter + BulkRequest struct { + RequestID string + } + + // BulkStatusResponse contains current status of a running or completed bulk-create request + BulkStatusResponse struct { + RequestID string `json:"requestId"` + ZonesSubmitted int `json:"zonesSubmitted"` + SuccessCount int `json:"successCount"` + FailureCount int `json:"failureCount"` + IsComplete bool `json:"isComplete"` + ExpirationDate string `json:"expirationDate"` + } + + // BulkFailedZone contains information about failed zone + BulkFailedZone struct { + Zone string `json:"zone"` + FailureReason string `json:"failureReason"` + } + + // BulkCreateResultResponse contains the response from a completed bulk-create request + BulkCreateResultResponse struct { + RequestID string `json:"requestId"` + SuccessfullyCreatedZones []string `json:"successfullyCreatedZones"` + FailedZones []BulkFailedZone `json:"failedZones"` + } + + // BulkDeleteResultResponse contains the response from a completed bulk-delete request + BulkDeleteResultResponse struct { + RequestID string `json:"requestId"` + SuccessfullyDeletedZones []string `json:"successfullyDeletedZones"` + FailedZones []BulkFailedZone `json:"failedZones"` + } + + // GetBulkZoneCreateStatusRequest contains request parameters for GetBulkZoneCreateStatus + GetBulkZoneCreateStatusRequest BulkRequest + + // GetBulkZoneCreateStatusResponse contains the response data from GetBulkZoneCreateStatus operation + GetBulkZoneCreateStatusResponse struct { + RequestID string `json:"requestId"` + ZonesSubmitted int `json:"zonesSubmitted"` + SuccessCount int `json:"successCount"` + FailureCount int `json:"failureCount"` + IsComplete bool `json:"isComplete"` + ExpirationDate string `json:"expirationDate"` + } + + // GetBulkZoneDeleteStatusRequest contains request parameters for GetBulkZoneDeleteStatus + GetBulkZoneDeleteStatusRequest BulkRequest + + // GetBulkZoneDeleteStatusResponse contains the response data from GetBulkZoneDeleteStatus operation + GetBulkZoneDeleteStatusResponse struct { + RequestID string `json:"requestId"` + ZonesSubmitted int `json:"zonesSubmitted"` + SuccessCount int `json:"successCount"` + FailureCount int `json:"failureCount"` + IsComplete bool `json:"isComplete"` + ExpirationDate string `json:"expirationDate"` + } + + // GetBulkZoneCreateResultRequest contains request parameters for GetBulkZoneCreateResult + GetBulkZoneCreateResultRequest BulkRequest + + // GetBulkZoneCreateResultResponse contains the response data from GetBulkZoneCreateResult operation + GetBulkZoneCreateResultResponse struct { + RequestID string `json:"requestId"` + SuccessfullyCreatedZones []string `json:"successfullyCreatedZones"` + FailedZones []BulkFailedZone `json:"failedZones"` + } + + // GetBulkZoneDeleteResultRequest contains request parameters for GetBulkZoneDeleteResult + GetBulkZoneDeleteResultRequest BulkRequest + + // GetBulkZoneDeleteResultResponse contains the response data from GetBulkZoneDeleteResult operation + GetBulkZoneDeleteResultResponse struct { + RequestID string `json:"requestId"` + SuccessfullyDeletedZones []string `json:"successfullyDeletedZones"` + FailedZones []BulkFailedZone `json:"failedZones"` + } + + // CreateBulkZonesRequest contains request parameters for CreateBulkZones + CreateBulkZonesRequest struct { + BulkZones *BulkZonesCreate + ZoneQueryString ZoneQueryString + } + + // CreateBulkZonesResponse contains the response data from CreateBulkZones operation + CreateBulkZonesResponse struct { + RequestID string `json:"requestId"` + ExpirationDate string `json:"expirationDate"` + } + + // DeleteBulkZonesRequest contains request parameters for DeleteBulkZones + DeleteBulkZonesRequest struct { + ZonesList *ZoneNameListResponse + BypassSafetyChecks *bool + } + + // DeleteBulkZonesResponse contains the response data from DeleteBulkZones operation + DeleteBulkZonesResponse struct { + RequestID string `json:"requestId"` + ExpirationDate string `json:"expirationDate"` + } +) + +var ( + // ErrGetBulkZoneCreateStatus is returned when GetBulkZoneCreateStatus fails + ErrGetBulkZoneCreateStatus = errors.New("get bulk zone create status") + // ErrGetBulkZoneDeleteStatus is returned when GetBulkZoneDeleteStatus fails + ErrGetBulkZoneDeleteStatus = errors.New("get bulk zone delete status") + // ErrGetBulkZoneCreateResult is returned when GetBulkZoneCreateResult fails + ErrGetBulkZoneCreateResult = errors.New("get bulk zone create result") + // ErrGetBulkZoneDeleteResult is returned when GetBulkZoneDeleteResult fails + ErrGetBulkZoneDeleteResult = errors.New("get bulk zone delete result") + // ErrCreateBulkZones is returned when CreateBulkZones fails + ErrCreateBulkZones = errors.New("create bulk zones") + // ErrDeleteBulkZones is returned when DeleteBulkZones fails + ErrDeleteBulkZones = errors.New("delete bulk zones") ) -// BulkZonesCreate contains a list of one or more new Zones to create -type BulkZonesCreate struct { - Zones []*ZoneCreate `json:"zones"` +// Validate validates GetBulkZoneCreateStatusRequest +func (r GetBulkZoneCreateStatusRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "RequestID": validation.Validate(r.RequestID, validation.Required), + }) } -// BulkZonesResponse contains response from bulk-create request -type BulkZonesResponse struct { - RequestID string `json:"requestId"` - ExpirationDate string `json:"expirationDate"` +// Validate validates GetBulkZoneDeleteStatusRequest +func (r GetBulkZoneDeleteStatusRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "RequestID": validation.Validate(r.RequestID, validation.Required), + }) } -// BulkStatusResponse contains current status of a running or completed bulk-create request -type BulkStatusResponse struct { - RequestID string `json:"requestId"` - ZonesSubmitted int `json:"zonesSubmitted"` - SuccessCount int `json:"successCount"` - FailureCount int `json:"failureCount"` - IsComplete bool `json:"isComplete"` - ExpirationDate string `json:"expirationDate"` +// Validate validates GetBulkZoneCreateResultRequest +func (r GetBulkZoneCreateResultRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "RequestID": validation.Validate(r.RequestID, validation.Required), + }) } -// BulkFailedZone contains information about failed zone -type BulkFailedZone struct { - Zone string `json:"zone"` - FailureReason string `json:"failureReason"` +// Validate validates GetBulkZoneDeleteResultRequest +func (r GetBulkZoneDeleteResultRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "RequestID": validation.Validate(r.RequestID, validation.Required), + }) } -// BulkCreateResultResponse contains the response from a completed bulk-create request -type BulkCreateResultResponse struct { - RequestID string `json:"requestId"` - SuccessfullyCreatedZones []string `json:"successfullyCreatedZones"` - FailedZones []*BulkFailedZone `json:"failedZones"` +// Validate validates CreateBulkZonesRequest +func (r CreateBulkZonesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "BulkZones": validation.Validate(r.BulkZones, validation.Required), + }) } -// BulkDeleteResultResponse contains the response from a completed bulk-delete request -type BulkDeleteResultResponse struct { - RequestID string `json:"requestId"` - SuccessfullyDeletedZones []string `json:"successfullyDeletedZones"` - FailedZones []*BulkFailedZone `json:"failedZones"` +// Validate validates DeleteBulkZonesRequest +func (r DeleteBulkZonesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ZonesList": validation.Validate(r.ZonesList, validation.Required), + }) } -func (d *dns) GetBulkZoneCreateStatus(ctx context.Context, requestID string) (*BulkStatusResponse, error) { +func (d *dns) GetBulkZoneCreateStatus(ctx context.Context, params GetBulkZoneCreateStatusRequest) (*GetBulkZoneCreateStatusResponse, error) { logger := d.Log(ctx) logger.Debug("GetBulkZoneCreateStatus") - bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s", requestID) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetBulkZoneCreateStatus, ErrStructValidation, err) + } + + bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s", params.RequestID) req, err := http.NewRequestWithContext(ctx, http.MethodGet, bulkZonesURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetBulkZoneCreateStatus request: %w", err) } - var result BulkStatusResponse + var result GetBulkZoneCreateStatusResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetBulkZoneCreateStatus request failed: %w", err) @@ -71,18 +213,22 @@ func (d *dns) GetBulkZoneCreateStatus(ctx context.Context, requestID string) (*B return &result, nil } -func (d *dns) GetBulkZoneDeleteStatus(ctx context.Context, requestID string) (*BulkStatusResponse, error) { +func (d *dns) GetBulkZoneDeleteStatus(ctx context.Context, params GetBulkZoneDeleteStatusRequest) (*GetBulkZoneDeleteStatusResponse, error) { logger := d.Log(ctx) logger.Debug("GetBulkZoneDeleteStatus") - bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s", requestID) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetBulkZoneDeleteStatus, ErrStructValidation, err) + } + + bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s", params.RequestID) req, err := http.NewRequestWithContext(ctx, http.MethodGet, bulkZonesURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetBulkZoneDeleteStatus request: %w", err) } - var result BulkStatusResponse + var result GetBulkZoneDeleteStatusResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetBulkZoneDeleteStatus request failed: %w", err) @@ -95,12 +241,16 @@ func (d *dns) GetBulkZoneDeleteStatus(ctx context.Context, requestID string) (*B return &result, nil } -func (d *dns) GetBulkZoneCreateResult(ctx context.Context, requestID string) (*BulkCreateResultResponse, error) { +func (d *dns) GetBulkZoneCreateResult(ctx context.Context, params GetBulkZoneCreateResultRequest) (*GetBulkZoneCreateResultResponse, error) { logger := d.Log(ctx) logger.Debug("GetBulkZoneCreateResult") - bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s/result", requestID) - var status BulkCreateResultResponse + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetBulkZoneCreateResult, ErrStructValidation, err) + } + + bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s/result", params.RequestID) + var status GetBulkZoneCreateResultResponse req, err := http.NewRequestWithContext(ctx, http.MethodGet, bulkZonesURL, nil) if err != nil { @@ -119,18 +269,22 @@ func (d *dns) GetBulkZoneCreateResult(ctx context.Context, requestID string) (*B return &status, nil } -func (d *dns) GetBulkZoneDeleteResult(ctx context.Context, requestID string) (*BulkDeleteResultResponse, error) { +func (d *dns) GetBulkZoneDeleteResult(ctx context.Context, params GetBulkZoneDeleteResultRequest) (*GetBulkZoneDeleteResultResponse, error) { logger := d.Log(ctx) logger.Debug("GetBulkZoneDeleteResult") - bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s/result", requestID) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetBulkZoneDeleteResult, ErrStructValidation, err) + } + + bulkZonesURL := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s/result", params.RequestID) req, err := http.NewRequestWithContext(ctx, http.MethodGet, bulkZonesURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetBulkZoneDeleteResult request: %w", err) } - var result BulkDeleteResultResponse + var result GetBulkZoneDeleteResultResponse resp, err := d.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetBulkZoneDeleteResult request failed: %w", err) @@ -143,13 +297,17 @@ func (d *dns) GetBulkZoneDeleteResult(ctx context.Context, requestID string) (*B return &result, nil } -func (d *dns) CreateBulkZones(ctx context.Context, bulkZones *BulkZonesCreate, zoneQueryString ZoneQueryString) (*BulkZonesResponse, error) { +func (d *dns) CreateBulkZones(ctx context.Context, params CreateBulkZonesRequest) (*CreateBulkZonesResponse, error) { logger := d.Log(ctx) logger.Debug("CreateBulkZones") - bulkZonesURL := "/config-dns/v2/zones/create-requests?contractId=" + zoneQueryString.Contract - if len(zoneQueryString.Group) > 0 { - bulkZonesURL += "&gid=" + zoneQueryString.Group + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateBulkZones, ErrStructValidation, err) + } + + bulkZonesURL := "/config-dns/v2/zones/create-requests?contractId=" + params.ZoneQueryString.Contract + if len(params.ZoneQueryString.Group) > 0 { + bulkZonesURL += "&gid=" + params.ZoneQueryString.Group } req, err := http.NewRequestWithContext(ctx, http.MethodPost, bulkZonesURL, nil) @@ -157,8 +315,8 @@ func (d *dns) CreateBulkZones(ctx context.Context, bulkZones *BulkZonesCreate, z return nil, fmt.Errorf("failed to create CreateBulkZones request: %w", err) } - var result BulkZonesResponse - resp, err := d.Exec(req, &result, bulkZones) + var result CreateBulkZonesResponse + resp, err := d.Exec(req, &result, params.BulkZones) if err != nil { return nil, fmt.Errorf("CreateBulkZones request failed: %w", err) } @@ -170,13 +328,17 @@ func (d *dns) CreateBulkZones(ctx context.Context, bulkZones *BulkZonesCreate, z return &result, nil } -func (d *dns) DeleteBulkZones(ctx context.Context, zonesList *ZoneNameListResponse, bypassSafetyChecks ...bool) (*BulkZonesResponse, error) { +func (d *dns) DeleteBulkZones(ctx context.Context, params DeleteBulkZonesRequest) (*DeleteBulkZonesResponse, error) { logger := d.Log(ctx) logger.Debug("DeleteBulkZones") + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteBulkZones, ErrStructValidation, err) + } + bulkZonesURL := "/config-dns/v2/zones/delete-requests" - if len(bypassSafetyChecks) > 0 { - bulkZonesURL += fmt.Sprintf("?bypassSafetyChecks=%t", bypassSafetyChecks[0]) + if params.BypassSafetyChecks != nil { + bulkZonesURL += fmt.Sprintf("?bypassSafetyChecks=%t", *params.BypassSafetyChecks) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, bulkZonesURL, nil) @@ -184,8 +346,8 @@ func (d *dns) DeleteBulkZones(ctx context.Context, zonesList *ZoneNameListRespon return nil, fmt.Errorf("failed to create DeleteBulkZones request: %w", err) } - var result BulkZonesResponse - resp, err := d.Exec(req, &result, zonesList) + var result DeleteBulkZonesResponse + resp, err := d.Exec(req, &result, params.ZonesList) if err != nil { return nil, fmt.Errorf("DeleteBulkZones request failed: %w", err) } diff --git a/pkg/dns/zonebulk_test.go b/pkg/dns/zonebulk_test.go index 5c5d32d2..818d2c77 100644 --- a/pkg/dns/zonebulk_test.go +++ b/pkg/dns/zonebulk_test.go @@ -7,21 +7,24 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestDNS_GetBulkZoneCreateStatus(t *testing.T) { tests := map[string]struct { - requestID string + params GetBulkZoneCreateStatusRequest responseStatus int responseBody string expectedPath string - expectedResponse *BulkStatusResponse + expectedResponse *GetBulkZoneCreateStatusResponse withError error }{ "200 OK": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneCreateStatusRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -33,7 +36,7 @@ func TestDNS_GetBulkZoneCreateStatus(t *testing.T) { "expirationDate": "2020-10-28T17:10:04.515792Z" }`, expectedPath: "/config-dns/v2/zones/create-requests/15bc138f-8d82-451b-80b7-a56b88ffc474", - expectedResponse: &BulkStatusResponse{ + expectedResponse: &GetBulkZoneCreateStatusResponse{ RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", ZonesSubmitted: 2, SuccessCount: 0, @@ -43,7 +46,9 @@ func TestDNS_GetBulkZoneCreateStatus(t *testing.T) { }, }, "500 internal server error": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneCreateStatusRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -71,7 +76,7 @@ func TestDNS_GetBulkZoneCreateStatus(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetBulkZoneCreateStatus(context.Background(), test.requestID) + result, err := client.GetBulkZoneCreateStatus(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -84,15 +89,17 @@ func TestDNS_GetBulkZoneCreateStatus(t *testing.T) { func TestDNS_GetBulkZoneCreateResult(t *testing.T) { tests := map[string]struct { - requestID string + params GetBulkZoneCreateResultRequest responseStatus int responseBody string expectedPath string - expectedResponse *BulkCreateResultResponse + expectedResponse *GetBulkZoneCreateResultResponse withError error }{ "200 OK": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneCreateResultRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -106,10 +113,10 @@ func TestDNS_GetBulkZoneCreateResult(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/create-requests/15bc138f-8d82-451b-80b7-a56b88ffc474/result", - expectedResponse: &BulkCreateResultResponse{ + expectedResponse: &GetBulkZoneCreateResultResponse{ RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", SuccessfullyCreatedZones: make([]string, 0), - FailedZones: []*BulkFailedZone{ + FailedZones: []BulkFailedZone{ { Zone: "one.testbulk.net", FailureReason: "ZONE_ALREADY_EXISTS", @@ -118,7 +125,9 @@ func TestDNS_GetBulkZoneCreateResult(t *testing.T) { }, }, "500 internal server error": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneCreateResultRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -146,7 +155,7 @@ func TestDNS_GetBulkZoneCreateResult(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetBulkZoneCreateResult(context.Background(), test.requestID) + result, err := client.GetBulkZoneCreateResult(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -159,62 +168,67 @@ func TestDNS_GetBulkZoneCreateResult(t *testing.T) { func TestDNS_CreateBulkZones(t *testing.T) { tests := map[string]struct { + params CreateBulkZonesRequest zones BulkZonesCreate query ZoneQueryString responseStatus int responseBody string - expectedResponse *BulkZonesResponse + expectedResponse *CreateBulkZonesResponse expectedPath string withError error }{ "200 Created": { - zones: BulkZonesCreate{ - Zones: []*ZoneCreate{ - { - Zone: "one.testbulk.net", - Type: "secondary", - Comment: "testing bulk operations", - Masters: []string{"1.2.3.4", "1.2.3.10"}, - }, - { - Zone: "two.testbulk.net", - Type: "secondary", - Comment: "testing bulk operations", - Masters: []string{"1.2.3.6", "1.2.3.70"}, + params: CreateBulkZonesRequest{ + BulkZones: &BulkZonesCreate{ + Zones: []ZoneCreate{ + { + Zone: "one.testbulk.net", + Type: "secondary", + Comment: "testing bulk operations", + Masters: []string{"1.2.3.4", "1.2.3.10"}, + }, + { + Zone: "two.testbulk.net", + Type: "secondary", + Comment: "testing bulk operations", + Masters: []string{"1.2.3.6", "1.2.3.70"}, + }, }, }, + ZoneQueryString: ZoneQueryString{Contract: "1-2ABCDE", Group: "testgroup"}, }, - query: ZoneQueryString{Contract: "1-2ABCDE", Group: "testgroup"}, responseStatus: http.StatusCreated, responseBody: ` { "requestId": "93e97a28-4e05-45f4-8b9a-cebd71155949", "expirationDate": "2020-10-28T19:50:36.272668Z" }`, - expectedResponse: &BulkZonesResponse{ + expectedResponse: &CreateBulkZonesResponse{ RequestID: "93e97a28-4e05-45f4-8b9a-cebd71155949", ExpirationDate: "2020-10-28T19:50:36.272668Z", }, expectedPath: "/config-dns/v2/zones/create-requests?contractId=1-2ABCDE&gid=testgroup", }, "500 internal server error": { - zones: BulkZonesCreate{ - Zones: []*ZoneCreate{ - { - Zone: "one.testbulk.net", - Type: "secondary", - Comment: "testing bulk operations", - Masters: []string{"1.2.3.4", "1.2.3.10"}, - }, - { - Zone: "two.testbulk.net", - Type: "secondary", - Comment: "testing bulk operations", - Masters: []string{"1.2.3.6", "1.2.3.70"}, + params: CreateBulkZonesRequest{ + BulkZones: &BulkZonesCreate{ + Zones: []ZoneCreate{ + { + Zone: "one.testbulk.net", + Type: "secondary", + Comment: "testing bulk operations", + Masters: []string{"1.2.3.4", "1.2.3.10"}, + }, + { + Zone: "two.testbulk.net", + Type: "secondary", + Comment: "testing bulk operations", + Masters: []string{"1.2.3.6", "1.2.3.70"}, + }, }, }, + ZoneQueryString: ZoneQueryString{Contract: "1-2ABCDE", Group: "testgroup"}, }, - query: ZoneQueryString{Contract: "1-2ABCDE", Group: "testgroup"}, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -244,7 +258,7 @@ func TestDNS_CreateBulkZones(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - result, err := client.CreateBulkZones(context.Background(), &test.zones, test.query) + result, err := client.CreateBulkZones(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -258,15 +272,17 @@ func TestDNS_CreateBulkZones(t *testing.T) { // Bulk Delete tests func TestDNS_GetBulkZoneDeleteStatus(t *testing.T) { tests := map[string]struct { - requestID string + params GetBulkZoneDeleteStatusRequest responseStatus int responseBody string expectedPath string - expectedResponse *BulkStatusResponse + expectedResponse *GetBulkZoneDeleteStatusResponse withError error }{ "200 OK": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneDeleteStatusRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -278,7 +294,7 @@ func TestDNS_GetBulkZoneDeleteStatus(t *testing.T) { "expirationDate": "2020-10-28T17:10:04.515792Z" }`, expectedPath: "/config-dns/v2/zones/delete-requests/15bc138f-8d82-451b-80b7-a56b88ffc474", - expectedResponse: &BulkStatusResponse{ + expectedResponse: &GetBulkZoneDeleteStatusResponse{ RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", ZonesSubmitted: 2, SuccessCount: 0, @@ -288,7 +304,9 @@ func TestDNS_GetBulkZoneDeleteStatus(t *testing.T) { }, }, "500 internal server error": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneDeleteStatusRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -316,7 +334,7 @@ func TestDNS_GetBulkZoneDeleteStatus(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetBulkZoneDeleteStatus(context.Background(), test.requestID) + result, err := client.GetBulkZoneDeleteStatus(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -329,15 +347,17 @@ func TestDNS_GetBulkZoneDeleteStatus(t *testing.T) { func TestDNS_GetBulkZoneDeleteResult(t *testing.T) { tests := map[string]struct { - requestID string + params GetBulkZoneDeleteResultRequest responseStatus int responseBody string expectedPath string - expectedResponse *BulkDeleteResultResponse + expectedResponse *GetBulkZoneDeleteResultResponse withError error }{ "200 OK": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneDeleteResultRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusOK, responseBody: ` { @@ -351,10 +371,10 @@ func TestDNS_GetBulkZoneDeleteResult(t *testing.T) { ] }`, expectedPath: "/config-dns/v2/zones/delete-requests/15bc138f-8d82-451b-80b7-a56b88ffc474/result", - expectedResponse: &BulkDeleteResultResponse{ + expectedResponse: &GetBulkZoneDeleteResultResponse{ RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", SuccessfullyDeletedZones: make([]string, 0), - FailedZones: []*BulkFailedZone{ + FailedZones: []BulkFailedZone{ { Zone: "one.testbulk.net", FailureReason: "ZONE_ALREADY_EXISTS", @@ -363,7 +383,9 @@ func TestDNS_GetBulkZoneDeleteResult(t *testing.T) { }, }, "500 internal server error": { - requestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + params: GetBulkZoneDeleteResultRequest{ + RequestID: "15bc138f-8d82-451b-80b7-a56b88ffc474", + }, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -391,7 +413,7 @@ func TestDNS_GetBulkZoneDeleteResult(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetBulkZoneDeleteResult(context.Background(), test.requestID) + result, err := client.GetBulkZoneDeleteResult(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -404,36 +426,39 @@ func TestDNS_GetBulkZoneDeleteResult(t *testing.T) { func TestDNS_DeleteBulkZones(t *testing.T) { tests := map[string]struct { - zonesList ZoneNameListResponse - bypassSafety bool + params DeleteBulkZonesRequest responseStatus int responseBody string - expectedResponse *BulkZonesResponse + expectedResponse *DeleteBulkZonesResponse expectedPath string withError error }{ "200 Created": { - zonesList: ZoneNameListResponse{ - Zones: []string{"one.testbulk.net", "two.testbulk.net"}, + params: DeleteBulkZonesRequest{ + ZonesList: &ZoneNameListResponse{ + Zones: []string{"one.testbulk.net", "two.testbulk.net"}, + }, + BypassSafetyChecks: tools.BoolPtr(true), }, - bypassSafety: true, responseStatus: http.StatusCreated, responseBody: ` { "requestId": "93e97a28-4e05-45f4-8b9a-cebd71155949", "expirationDate": "2020-10-28T19:50:36.272668Z" }`, - expectedResponse: &BulkZonesResponse{ + expectedResponse: &DeleteBulkZonesResponse{ RequestID: "93e97a28-4e05-45f4-8b9a-cebd71155949", ExpirationDate: "2020-10-28T19:50:36.272668Z", }, expectedPath: "/config-dns/v2/zones/delete-requests?bypassSafetyChecks=true", }, "500 internal server error": { - zonesList: ZoneNameListResponse{ - Zones: []string{"one.testbulk.net", "two.testbulk.net"}, + params: DeleteBulkZonesRequest{ + ZonesList: &ZoneNameListResponse{ + Zones: []string{"one.testbulk.net", "two.testbulk.net"}, + }, + BypassSafetyChecks: tools.BoolPtr(true), }, - bypassSafety: true, responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -463,7 +488,7 @@ func TestDNS_DeleteBulkZones(t *testing.T) { } })) client := mockAPIClient(t, mockServer) - result, err := client.DeleteBulkZones(context.Background(), &test.zonesList, test.bypassSafety) + result, err := client.DeleteBulkZones(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/asmap.go b/pkg/gtm/asmap.go index 0a98c254..a7bf6f09 100644 --- a/pkg/gtm/asmap.go +++ b/pkg/gtm/asmap.go @@ -2,34 +2,15 @@ package gtm import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) -// ASMaps contains operations available on a ASmap resource. type ( - ASMaps interface { - // ListASMaps retrieves all AsMaps. - // - // See: https://techdocs.akamai.com/gtm/reference/get-as-maps - ListASMaps(context.Context, string) ([]*ASMap, error) - // GetASMap retrieves a AsMap with the given name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-as-map - GetASMap(context.Context, string, string) (*ASMap, error) - // CreateASMap creates the datacenter identified by the receiver argument in the specified domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-as-map - CreateASMap(context.Context, *ASMap, string) (*ASMapResponse, error) - // DeleteASMap deletes the datacenter identified by the receiver argument from the domain specified. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-as-map - DeleteASMap(context.Context, *ASMap, string) (*ResponseStatus, error) - // UpdateASMap updates the datacenter identified in the receiver argument in the provided domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-as-map - UpdateASMap(context.Context, *ASMap, string) (*ResponseStatus, error) - } // ASAssignment represents a GTM as map assignment structure ASAssignment struct { DatacenterBase @@ -39,34 +20,137 @@ type ( // ASMap represents a GTM ASMap ASMap struct { DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` - Assignments []*ASAssignment `json:"assignments,omitempty"` + Assignments []ASAssignment `json:"assignments,omitempty"` Name string `json:"name"` - Links []*Link `json:"links,omitempty"` + Links []Link `json:"links,omitempty"` } // ASMapList represents the returned GTM ASMap List body ASMapList struct { - ASMapItems []*ASMap `json:"items"` + ASMapItems []ASMap `json:"items"` } -) -// Validate validates ASMap -func (a *ASMap) Validate() error { - if len(a.Name) < 1 { - return fmt.Errorf("ASMap is missing Name") + // ListASMapsRequest contains request parameters for ListASMaps + ListASMapsRequest struct { + DomainName string + } + + // GetASMapRequest contains request parameters for GetASMap + GetASMapRequest struct { + ASMapName string + DomainName string + } + + // GetASMapResponse contains the response data from GetASMap operation + GetASMapResponse ASMap + + // ASMapRequest contains request parameters + ASMapRequest struct { + ASMap *ASMap + DomainName string + } + + // CreateASMapRequest contains request parameters for CreateASMap + CreateASMapRequest ASMapRequest + + // CreateASMapResponse contains the response data from CreateASMap operation + CreateASMapResponse struct { + Resource *ASMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdateASMapRequest contains request parameters for UpdateASMap + UpdateASMapRequest ASMapRequest + + // UpdateASMapResponse contains the response data from UpdateASMap operation + UpdateASMapResponse struct { + Resource *ASMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeleteASMapRequest contains request parameters for DeleteASMap + DeleteASMapRequest struct { + ASMapName string + DomainName string } - if a.DefaultDatacenter == nil { - return fmt.Errorf("ASMap is missing DefaultDatacenter") + + // DeleteASMapResponse contains the response data from DeleteASMap operation + DeleteASMapResponse struct { + Resource *ASMap `json:"resource"` + Status *ResponseStatus `json:"status"` } +) + +var ( + // ErrListASMaps is returned when ListASMaps fails + ErrListASMaps = errors.New("list asmaps") + // ErrGetASMap is returned when GetASMap fails + ErrGetASMap = errors.New("get asmap") + // ErrCreateASMap is returned when CreateASMap fails + ErrCreateASMap = errors.New("create asmap") + // ErrUpdateASMap is returned when UpdateASMap fails + ErrUpdateASMap = errors.New("update asmap") + // ErrDeleteASMap is returned when DeleteASMap fails + ErrDeleteASMap = errors.New("delete asmap") +) - return nil +// Validate validates ListASMapsRequest +func (r ListASMapsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) +} + +// Validate validates GetASMapRequest +func (r GetASMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ASMapName": validation.Validate(r.ASMapName, validation.Required), + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) +} + +// Validate validates CreateASMapRequest +func (r CreateASMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "ASMap": validation.Validate(r.ASMap, validation.Required), + }) +} + +// Validate validates ASMap +func (a ASMap) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Name": validation.Validate(a.Name, validation.Required), + "DefaultDatacenter": validation.Validate(a.DefaultDatacenter, validation.Required), + "Assignments": validation.Validate(a.Assignments, validation.Required), + }) } -func (g *gtm) ListASMaps(ctx context.Context, domainName string) ([]*ASMap, error) { +// Validate validates UpdateASMapRequest +func (r UpdateASMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "ASMap": validation.Validate(r.ASMap, validation.Required), + }) +} + +// Validate validates DeleteASMapRequest +func (r DeleteASMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "ASMapName": validation.Validate(r.ASMapName, validation.Required), + }) +} + +func (g *gtm) ListASMaps(ctx context.Context, params ListASMapsRequest) ([]ASMap, error) { logger := g.Log(ctx) logger.Debug("ListASMaps") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListASMaps, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListASMaps request: %w", err) @@ -86,18 +170,22 @@ func (g *gtm) ListASMaps(ctx context.Context, domainName string) ([]*ASMap, erro return result.ASMapItems, nil } -func (g *gtm) GetASMap(ctx context.Context, asMapName, domainName string) (*ASMap, error) { +func (g *gtm) GetASMap(ctx context.Context, params GetASMapRequest) (*GetASMapResponse, error) { logger := g.Log(ctx) logger.Debug("GetASMap") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, asMapName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetASMap, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", params.DomainName, params.ASMapName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetASMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result ASMap + var result GetASMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetASMap request failed: %w", err) @@ -110,66 +198,78 @@ func (g *gtm) GetASMap(ctx context.Context, asMapName, domainName string) (*ASMa return &result, nil } -func (g *gtm) CreateASMap(ctx context.Context, asMap *ASMap, domainName string) (*ASMapResponse, error) { +func (g *gtm) CreateASMap(ctx context.Context, params CreateASMapRequest) (*CreateASMapResponse, error) { logger := g.Log(ctx) logger.Debug("CreateASMap") - return asMap.save(ctx, g, domainName) -} + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateASMap, ErrStructValidation, err) + } -func (g *gtm) UpdateASMap(ctx context.Context, asMap *ASMap, domainName string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateASMap") + uri := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", params.DomainName, params.ASMap.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) + if err != nil { + return nil, fmt.Errorf("failed to create ASMap request: %w", err) + } + setVersionHeader(req, schemaVersion) - stat, err := asMap.save(ctx, g, domainName) + var result CreateASMapResponse + resp, err := g.Exec(req, &result, params.ASMap) if err != nil { - return nil, err + return nil, fmt.Errorf("ASMap request failed: %w", err) } - return stat.Status, err + + if resp.StatusCode != http.StatusCreated { + return nil, g.Error(resp) + } + + return &result, nil } -// save AsMap in given domain. Common path for Create and Update. -func (a *ASMap) save(ctx context.Context, g *gtm, domainName string) (*ASMapResponse, error) { - if err := a.Validate(); err != nil { - return nil, fmt.Errorf("ASMap validation failed. %w", err) +func (g *gtm) UpdateASMap(ctx context.Context, params UpdateASMapRequest) (*UpdateASMapResponse, error) { + logger := g.Log(ctx) + logger.Debug("UpdateASMap") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateASMap, ErrStructValidation, err) } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, a.Name) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", params.DomainName, params.ASMap.Name) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ASMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result ASMapResponse - resp, err := g.Exec(req, &result, a) + var result UpdateASMapResponse + resp, err := g.Exec(req, &result, params.ASMap) if err != nil { return nil, fmt.Errorf("ASMap request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusOK { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) DeleteASMap(ctx context.Context, asMap *ASMap, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteASMap(ctx context.Context, params DeleteASMapRequest) (*DeleteASMapResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteASMap") - if err := asMap.Validate(); err != nil { - return nil, fmt.Errorf("resource validation failed: %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteASMap, ErrStructValidation, err) } - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, asMap.Name) + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", params.DomainName, params.ASMapName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Delete request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeleteASMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("ASMap request failed: %w", err) @@ -179,5 +279,5 @@ func (g *gtm) DeleteASMap(ctx context.Context, asMap *ASMap, domainName string) return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/asmap_test.go b/pkg/gtm/asmap_test.go index 7a322f30..fe72e39a 100644 --- a/pkg/gtm/asmap_test.go +++ b/pkg/gtm/asmap_test.go @@ -27,16 +27,18 @@ func TestGTM_ListASMap(t *testing.T) { } tests := map[string]struct { - domainName string + params ListASMapsRequest responseStatus int responseBody string expectedPath string - expectedResponse []*ASMap + expectedResponse []ASMap withError error headers http.Header }{ "200 OK": { - domainName: "example.akadns.net", + params: ListASMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -46,7 +48,9 @@ func TestGTM_ListASMap(t *testing.T) { expectedResponse: result.ASMapItems, }, "500 internal server error": { - domainName: "example.akadns.net", + params: ListASMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -79,7 +83,7 @@ func TestGTM_ListASMap(t *testing.T) { result, err := client.ListASMaps( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -91,7 +95,7 @@ func TestGTM_ListASMap(t *testing.T) { } func TestGTM_GetASMap(t *testing.T) { - var result ASMap + var result GetASMapResponse respData, err := loadTestData("TestGTM_GetASMap.resp.json") if err != nil { @@ -103,18 +107,19 @@ func TestGTM_GetASMap(t *testing.T) { } tests := map[string]struct { - name string - domainName string + params GetASMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ASMap + expectedResponse *GetASMapResponse withError error headers http.Header }{ "200 OK": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetASMapRequest{ + DomainName: "example.akadns.net", + ASMapName: "Software-rollout", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -124,8 +129,10 @@ func TestGTM_GetASMap(t *testing.T) { expectedResponse: &result, }, "500 internal server error": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetASMapRequest{ + DomainName: "example.akadns.net", + ASMapName: "Software-rollout", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -158,7 +165,7 @@ func TestGTM_GetASMap(t *testing.T) { result, err := client.GetASMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.name, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -170,7 +177,7 @@ func TestGTM_GetASMap(t *testing.T) { } func TestGTM_CreateASMap(t *testing.T) { - var result ASMapResponse + var result CreateASMapResponse var req ASMap respData, err := loadTestData("TestGTM_CreateASMap.resp.json") @@ -192,29 +199,32 @@ func TestGTM_CreateASMap(t *testing.T) { } tests := map[string]struct { - asMap *ASMap - domainName string + params CreateASMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ASMapResponse + expectedResponse *CreateASMapResponse withError error headers http.Header }{ "200 OK": { - asMap: &req, - domainName: "example.akadns.net", + params: CreateASMapRequest{ + ASMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusOK, + responseStatus: http.StatusCreated, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", expectedResponse: &result, }, "500 internal server error": { - asMap: &req, - domainName: "example.akadns.net", + params: CreateASMapRequest{ + ASMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -246,7 +256,7 @@ func TestGTM_CreateASMap(t *testing.T) { result, err := client.CreateASMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.asMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -258,7 +268,7 @@ func TestGTM_CreateASMap(t *testing.T) { } func TestGTM_UpdateASMap(t *testing.T) { - var result ASMapResponse + var result UpdateASMapResponse var req ASMap respData, err := loadTestData("TestGTM_CreateASMap.resp.json") @@ -280,29 +290,32 @@ func TestGTM_UpdateASMap(t *testing.T) { } tests := map[string]struct { - asMap *ASMap - domainName string + params UpdateASMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateASMapResponse withError error headers http.Header }{ "200 OK": { - asMap: &req, - domainName: "example.akadns.net", + params: UpdateASMapRequest{ + ASMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - asMap: &req, - domainName: "example.akadns.net", + params: UpdateASMapRequest{ + ASMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -334,7 +347,7 @@ func TestGTM_UpdateASMap(t *testing.T) { result, err := client.UpdateASMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.asMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -346,7 +359,7 @@ func TestGTM_UpdateASMap(t *testing.T) { } func TestGTM_DeleteASMap(t *testing.T) { - var result ASMapResponse + var result DeleteASMapResponse var req ASMap respData, err := loadTestData("TestGTM_CreateASMap.resp.json") @@ -368,29 +381,32 @@ func TestGTM_DeleteASMap(t *testing.T) { } tests := map[string]struct { - asMap *ASMap - domainName string + params DeleteASMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeleteASMapResponse withError error headers http.Header }{ "200 OK": { - asMap: &req, - domainName: "example.akadns.net", + params: DeleteASMapRequest{ + ASMapName: "The%20North", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - asMap: &req, - domainName: "example.akadns.net", + params: DeleteASMapRequest{ + ASMapName: "The%20North", + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -422,7 +438,7 @@ func TestGTM_DeleteASMap(t *testing.T) { result, err := client.DeleteASMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.asMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/cidrmap.go b/pkg/gtm/cidrmap.go index 2f56e5c8..3ea263bd 100644 --- a/pkg/gtm/cidrmap.go +++ b/pkg/gtm/cidrmap.go @@ -2,70 +2,152 @@ package gtm import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) -// CIDRMaps contains operations available on a CIDR map resource. -type CIDRMaps interface { - // ListCIDRMaps retrieves all CIDRMaps. - // - // See: https://techdocs.akamai.com/gtm/reference/get-cidr-maps - ListCIDRMaps(context.Context, string) ([]*CIDRMap, error) - // GetCIDRMap retrieves a CIDRMap with the given name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-cidr-map - GetCIDRMap(context.Context, string, string) (*CIDRMap, error) - // CreateCIDRMap creates the datacenter identified by the receiver argument in the specified domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-cidr-map - CreateCIDRMap(context.Context, *CIDRMap, string) (*CIDRMapResponse, error) - // DeleteCIDRMap deletes the datacenter identified by the receiver argument from the domain specified. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-cidr-maps - DeleteCIDRMap(context.Context, *CIDRMap, string) (*ResponseStatus, error) - // UpdateCIDRMap updates the datacenter identified in the receiver argument in the provided domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-cidr-map - UpdateCIDRMap(context.Context, *CIDRMap, string) (*ResponseStatus, error) +type ( + // CIDRAssignment represents a GTM CIDR assignment element + CIDRAssignment struct { + DatacenterBase + Blocks []string `json:"blocks"` + } + + // CIDRMap represents a GTM CIDRMap element + CIDRMap struct { + DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` + Assignments []CIDRAssignment `json:"assignments,omitempty"` + Name string `json:"name"` + Links []Link `json:"links,omitempty"` + } + + // CIDRMapList represents a GTM returned CIDRMap list body + CIDRMapList struct { + CIDRMapItems []CIDRMap `json:"items"` + } + // ListCIDRMapsRequest contains request parameters for ListCIDRMaps + ListCIDRMapsRequest struct { + DomainName string + } + + // GetCIDRMapRequest contains request parameters for GetCIDRMap + GetCIDRMapRequest struct { + MapName string + DomainName string + } + + // GetCIDRMapResponse contains the response data from GetCIDRMap operation + GetCIDRMapResponse CIDRMap + + // CIDRMapRequest contains request parameters + CIDRMapRequest struct { + CIDR *CIDRMap + DomainName string + } + + // CreateCIDRMapRequest contains request parameters for CreateCIDRMap + CreateCIDRMapRequest CIDRMapRequest + + // CreateCIDRMapResponse contains the response data from CreateCIDRMap operation + CreateCIDRMapResponse struct { + Resource *CIDRMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdateCIDRMapRequest contains request parameters for UpdateCIDRMap + UpdateCIDRMapRequest CIDRMapRequest + + // UpdateCIDRMapResponse contains the response data from UpdateCIDRMap operation + UpdateCIDRMapResponse struct { + Resource *CIDRMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeleteCIDRMapRequest contains request parameters for DeleteCIDRMap + DeleteCIDRMapRequest struct { + MapName string + DomainName string + } + + // DeleteCIDRMapResponse contains the response data from DeleteCIDRMap operation + DeleteCIDRMapResponse struct { + Resource *CIDRMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } +) + +var ( + // ErrListCIDRMaps is returned when ListCIDRMaps fails + ErrListCIDRMaps = errors.New("list cidrmaps") + // ErrGetCIDRMap is returned when GetCIDRMap fails + ErrGetCIDRMap = errors.New("get cidrmap") + // ErrCreateCIDRMap is returned when CreateCIDRMap fails + ErrCreateCIDRMap = errors.New("create cidrmap") + // ErrUpdateCIDRMap is returned when UpdateCIDRMap fails + ErrUpdateCIDRMap = errors.New("update cidrmap") + // ErrDeleteCIDRMap is returned when DeleteCIDRMap fails + ErrDeleteCIDRMap = errors.New("delete cidrmap") +) + +// Validate validates ListCIDRMapsRequest +func (r ListCIDRMapsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// CIDRAssignment represents a GTM CIDR assignment element -type CIDRAssignment struct { - DatacenterBase - Blocks []string `json:"blocks"` +// Validate validates GetCIDRMapRequest +func (r GetCIDRMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "MapName": validation.Validate(r.MapName, validation.Required), + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// CIDRMap represents a GTM CIDRMap element -type CIDRMap struct { - DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` - Assignments []*CIDRAssignment `json:"assignments,omitempty"` - Name string `json:"name"` - Links []*Link `json:"links,omitempty"` +// Validate validates CreateCIDRMapRequest +func (r CreateCIDRMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "CIDRMap": validation.Validate(r.CIDR, validation.Required), + }) } -// CIDRMapList represents a GTM returned CIDRMap list body -type CIDRMapList struct { - CIDRMapItems []*CIDRMap `json:"items"` +// Validate validates UpdateCIDRMapRequest +func (r UpdateCIDRMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "CIDRMap": validation.Validate(r.CIDR, validation.Required), + }) } -// Validate validates CIDRMap -func (c *CIDRMap) Validate() error { - if len(c.Name) < 1 { - return fmt.Errorf("CIDRMap is missing Name") - } - if c.DefaultDatacenter == nil { - return fmt.Errorf("CIDRMap is missing DefaultDatacenter") - } +// Validate validates DeleteCIDRMapRequest +func (r DeleteCIDRMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "MapName": validation.Validate(r.MapName, validation.Required), + }) +} - return nil +// Validate validates CIDRMap +func (c CIDRMap) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Name": validation.Validate(c.Name, validation.Required), + }) } -func (g *gtm) ListCIDRMaps(ctx context.Context, domainName string) ([]*CIDRMap, error) { +func (g *gtm) ListCIDRMaps(ctx context.Context, params ListCIDRMapsRequest) ([]CIDRMap, error) { logger := g.Log(ctx) logger.Debug("ListCIDRMaps") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListCIDRMaps, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListCIDRMaps request: %w", err) @@ -85,18 +167,22 @@ func (g *gtm) ListCIDRMaps(ctx context.Context, domainName string) ([]*CIDRMap, return result.CIDRMapItems, nil } -func (g *gtm) GetCIDRMap(ctx context.Context, mapName, domainName string) (*CIDRMap, error) { +func (g *gtm) GetCIDRMap(ctx context.Context, params GetCIDRMapRequest) (*GetCIDRMapResponse, error) { logger := g.Log(ctx) logger.Debug("GetCIDRMap") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, mapName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetCIDRMap, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", params.DomainName, params.MapName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetCIDRMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result CIDRMap + var result GetCIDRMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetCIDRMap request failed: %w", err) @@ -109,67 +195,78 @@ func (g *gtm) GetCIDRMap(ctx context.Context, mapName, domainName string) (*CIDR return &result, nil } -func (g *gtm) CreateCIDRMap(ctx context.Context, cidr *CIDRMap, domainName string) (*CIDRMapResponse, error) { +func (g *gtm) CreateCIDRMap(ctx context.Context, params CreateCIDRMapRequest) (*CreateCIDRMapResponse, error) { logger := g.Log(ctx) logger.Debug("CreateCIDRMap") - return cidr.save(ctx, g, domainName) -} + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateCIDRMap, ErrStructValidation, err) + } -func (g *gtm) UpdateCIDRMap(ctx context.Context, cidr *CIDRMap, domainName string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateCIDRMap") + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", params.DomainName, params.CIDR.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create CIDRMap request: %w", err) + } + setVersionHeader(req, schemaVersion) - stat, err := cidr.save(ctx, g, domainName) + var result CreateCIDRMapResponse + resp, err := g.Exec(req, &result, params.CIDR) if err != nil { - return nil, err + return nil, fmt.Errorf("CIDRMap request failed: %w", err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, g.Error(resp) } - return stat.Status, err + + return &result, nil } -// Save CIDRMap in given domain. Common path for Create and Update. -func (c *CIDRMap) save(ctx context.Context, g *gtm, domainName string) (*CIDRMapResponse, error) { +func (g *gtm) UpdateCIDRMap(ctx context.Context, params UpdateCIDRMapRequest) (*UpdateCIDRMapResponse, error) { + logger := g.Log(ctx) + logger.Debug("UpdateCIDRMap") - if err := c.Validate(); err != nil { - return nil, fmt.Errorf("CIDRMap validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateCIDRMap, ErrStructValidation, err) } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, c.Name) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", params.DomainName, params.CIDR.Name) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create CIDRMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result CIDRMapResponse - resp, err := g.Exec(req, &result, c) + var result UpdateCIDRMapResponse + resp, err := g.Exec(req, &result, params.CIDR) if err != nil { return nil, fmt.Errorf("CIDRMap request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusOK { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) DeleteCIDRMap(ctx context.Context, cidr *CIDRMap, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteCIDRMap(ctx context.Context, params DeleteCIDRMapRequest) (*DeleteCIDRMapResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteCIDRMap") - if err := cidr.Validate(); err != nil { - return nil, fmt.Errorf("CIDRMap validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteCIDRMap, ErrStructValidation, err) } - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, cidr.Name) + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", params.DomainName, params.MapName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Delete request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeleteCIDRMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("CIDRMap request failed: %w", err) @@ -179,5 +276,5 @@ func (g *gtm) DeleteCIDRMap(ctx context.Context, cidr *CIDRMap, domainName strin return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/cidrmap_test.go b/pkg/gtm/cidrmap_test.go index 17fa558d..271ebac8 100644 --- a/pkg/gtm/cidrmap_test.go +++ b/pkg/gtm/cidrmap_test.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "errors" + "io" "net/http" "net/http/httptest" "testing" @@ -27,16 +28,18 @@ func TestGTM_ListCIDRMaps(t *testing.T) { } tests := map[string]struct { - domainName string + params ListCIDRMapsRequest responseStatus int responseBody string expectedPath string - expectedResponse []*CIDRMap + expectedResponse []CIDRMap withError error headers http.Header }{ "200 OK": { - domainName: "example.akadns.net", + params: ListCIDRMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -46,7 +49,9 @@ func TestGTM_ListCIDRMaps(t *testing.T) { expectedResponse: result.CIDRMapItems, }, "500 internal server error": { - domainName: "example.akadns.net", + params: ListCIDRMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -79,7 +84,7 @@ func TestGTM_ListCIDRMaps(t *testing.T) { result, err := client.ListCIDRMaps( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -91,7 +96,7 @@ func TestGTM_ListCIDRMaps(t *testing.T) { } func TestGTM_GetCIDRMap(t *testing.T) { - var result CIDRMap + var result GetCIDRMapResponse respData, err := loadTestData("TestGTM_GetCIDRMap.resp.json") if err != nil { @@ -103,18 +108,19 @@ func TestGTM_GetCIDRMap(t *testing.T) { } tests := map[string]struct { - name string - domainName string + params GetCIDRMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *CIDRMap + expectedResponse *GetCIDRMapResponse withError error headers http.Header }{ "200 OK": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetCIDRMapRequest{ + MapName: "Software-rollout", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -124,8 +130,10 @@ func TestGTM_GetCIDRMap(t *testing.T) { expectedResponse: &result, }, "500 internal server error": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetCIDRMapRequest{ + MapName: "Software-rollout", + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -158,7 +166,7 @@ func TestGTM_GetCIDRMap(t *testing.T) { result, err := client.GetCIDRMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.name, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -170,7 +178,7 @@ func TestGTM_GetCIDRMap(t *testing.T) { } func TestGTM_CreateCIDRMap(t *testing.T) { - var result CIDRMapResponse + var result CreateCIDRMapResponse var req CIDRMap respData, err := loadTestData("TestGTM_CreateCIDRMap.resp.json") @@ -192,29 +200,85 @@ func TestGTM_CreateCIDRMap(t *testing.T) { } tests := map[string]struct { - cmap *CIDRMap - domainName string - responseStatus int - responseBody string - expectedPath string - expectedResponse *CIDRMapResponse - withError error - headers http.Header + params CreateCIDRMapRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse *CreateCIDRMapResponse + expectedRequestBody string + withError error + headers http.Header }{ "200 OK": { - cmap: &req, - domainName: "example.akadns.net", + params: CreateCIDRMapRequest{ + CIDR: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusOK, + responseStatus: http.StatusCreated, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/cidr-maps/The%20North", expectedResponse: &result, + expectedRequestBody: `{ + "name": "The North", + "defaultDatacenter": { + "datacenterId": 5400, + "nickname": "All Other CIDR Blocks" + }, + "assignments": [ + { + "datacenterId": 3134, + "nickname": "Frostfangs and the Fist of First Men", + "blocks": [ + "1.3.5.9", + "1.2.3.0/24" + ] + }, + { + "datacenterId": 3133, + "nickname": "Winterfell", + "blocks": [ + "1.2.4.0/24" + ] + } + ] +}`, + }, + "200 test": { + params: CreateCIDRMapRequest{ + CIDR: &CIDRMap{ + DefaultDatacenter: &DatacenterBase{ + Nickname: "test_datacenter", + DatacenterID: 200, + }, + Assignments: nil, + Name: "test_name", + Links: nil, + }, + DomainName: "example.akadns.net", + }, + headers: http.Header{ + "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, + }, + responseStatus: http.StatusCreated, + responseBody: string(respData), + expectedPath: "/config-gtm/v1/domains/example.akadns.net/cidr-maps/test_name", + expectedResponse: &result, + expectedRequestBody: `{ + "name": "test_name", + "defaultDatacenter": { + "datacenterId": 200, + "nickname": "test_datacenter" + } +}`, }, "500 internal server error": { - cmap: &req, - domainName: "example.akadns.net", + params: CreateCIDRMapRequest{ + CIDR: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -241,12 +305,17 @@ func TestGTM_CreateCIDRMap(t *testing.T) { w.WriteHeader(test.responseStatus) _, err := w.Write([]byte(test.responseBody)) assert.NoError(t, err) + if test.expectedRequestBody != "" { + body, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.JSONEq(t, test.expectedRequestBody, string(body)) + } })) client := mockAPIClient(t, mockServer) result, err := client.CreateCIDRMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.cmap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -258,7 +327,7 @@ func TestGTM_CreateCIDRMap(t *testing.T) { } func TestGTM_UpdateCIDRMap(t *testing.T) { - var result CIDRMapResponse + var result UpdateCIDRMapResponse var req CIDRMap respData, err := loadTestData("TestGTM_CreateCIDRMap.resp.json") @@ -280,29 +349,32 @@ func TestGTM_UpdateCIDRMap(t *testing.T) { } tests := map[string]struct { - cmap *CIDRMap - domainName string + params UpdateCIDRMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateCIDRMapResponse withError error headers http.Header }{ "200 OK": { - cmap: &req, - domainName: "example.akadns.net", + params: UpdateCIDRMapRequest{ + CIDR: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/cidr-maps/The%20North", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - cmap: &req, - domainName: "example.akadns.net", + params: UpdateCIDRMapRequest{ + CIDR: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -334,7 +406,7 @@ func TestGTM_UpdateCIDRMap(t *testing.T) { result, err := client.UpdateCIDRMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.cmap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -346,7 +418,7 @@ func TestGTM_UpdateCIDRMap(t *testing.T) { } func TestGTM_DeleteCIDRMap(t *testing.T) { - var result CIDRMapResponse + var result DeleteCIDRMapResponse var req CIDRMap respData, err := loadTestData("TestGTM_CreateCIDRMap.resp.json") @@ -368,29 +440,32 @@ func TestGTM_DeleteCIDRMap(t *testing.T) { } tests := map[string]struct { - cmap *CIDRMap - domainName string + params DeleteCIDRMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeleteCIDRMapResponse withError error headers http.Header }{ "200 OK": { - cmap: &req, - domainName: "example.akadns.net", + params: DeleteCIDRMapRequest{ + MapName: "The%20North", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/cidr-maps/The%20North", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - cmap: &req, - domainName: "example.akadns.net", + params: DeleteCIDRMapRequest{ + MapName: "The%20North", + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -422,7 +497,7 @@ func TestGTM_DeleteCIDRMap(t *testing.T) { result, err := client.DeleteCIDRMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.cmap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/common.go b/pkg/gtm/common.go index c83c5858..dd172663 100644 --- a/pkg/gtm/common.go +++ b/pkg/gtm/common.go @@ -23,24 +23,12 @@ func setVersionHeader(req *http.Request, version string) { // ResponseStatus is returned on Create, Update or Delete operations for all entity types type ResponseStatus struct { - ChangeID string `json:"changeId,omitempty"` - Links *[]Link `json:"links,omitempty"` - Message string `json:"message,omitempty"` - PassingValidation bool `json:"passingValidation,omitempty"` - PropagationStatus string `json:"propagationStatus,omitempty"` - PropagationStatusDate string `json:"propagationStatusDate,omitempty"` -} - -// ResponseBody is a generic response struct -type ResponseBody struct { - Resource interface{} `json:"resource"` - Status *ResponseStatus `json:"status"` -} - -// DomainResponse contains a response after creating or updating Domain -type DomainResponse struct { - Resource *Domain `json:"resource"` - Status *ResponseStatus `json:"status"` + ChangeID string `json:"changeId,omitempty"` + Links []Link `json:"links,omitempty"` + Message string `json:"message,omitempty"` + PassingValidation bool `json:"passingValidation,omitempty"` + PropagationStatus string `json:"propagationStatus,omitempty"` + PropagationStatusDate string `json:"propagationStatusDate,omitempty"` } // DatacenterResponse contains a response after creating or updating Datacenter @@ -49,40 +37,16 @@ type DatacenterResponse struct { Resource *Datacenter `json:"resource"` } -// PropertyResponse contains a response after creating or updating Property -type PropertyResponse struct { - Resource *Property `json:"resource"` - Status *ResponseStatus `json:"status"` -} - // ResourceResponse contains a response after creating or updating Resource type ResourceResponse struct { Resource *Resource `json:"resource"` Status *ResponseStatus `json:"status"` } -// CIDRMapResponse contains a response after creating or updating CIDRMap -type CIDRMapResponse struct { - Resource *CIDRMap `json:"resource"` - Status *ResponseStatus `json:"status"` -} - -// GeoMapResponse contains a response after creating or updating GeoMap -type GeoMapResponse struct { - Resource *GeoMap `json:"resource"` - Status *ResponseStatus `json:"status"` -} - -// ASMapResponse contains a response after creating or updating ASMap -type ASMapResponse struct { - Resource *ASMap `json:"resource"` - Status *ResponseStatus `json:"status"` -} - // Link is Probably THE most common type type Link struct { - Rel string `json:"rel"` - Href string `json:"href"` + Rel string `json:"rel,omitempty"` + Href string `json:"href,omitempty"` } // LoadObject contains information about the load reporting interface diff --git a/pkg/gtm/datacenter.go b/pkg/gtm/datacenter.go index 39b52078..9066992a 100644 --- a/pkg/gtm/datacenter.go +++ b/pkg/gtm/datacenter.go @@ -2,76 +2,161 @@ package gtm import ( "context" + "errors" "fmt" "net/http" - "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // Datacenter represents a GTM datacenter + Datacenter struct { + City string `json:"city,omitempty"` + CloneOf int `json:"cloneOf,omitempty"` + CloudServerHostHeaderOverride bool `json:"cloudServerHostHeaderOverride"` + CloudServerTargeting bool `json:"cloudServerTargeting"` + Continent string `json:"continent,omitempty"` + Country string `json:"country,omitempty"` + DefaultLoadObject *LoadObject `json:"defaultLoadObject,omitempty"` + Latitude float64 `json:"latitude,omitempty"` + Links []Link `json:"links,omitempty"` + Longitude float64 `json:"longitude,omitempty"` + Nickname string `json:"nickname,omitempty"` + PingInterval int `json:"pingInterval,omitempty"` + PingPacketSize int `json:"pingPacketSize,omitempty"` + DatacenterID int `json:"datacenterId,omitempty"` + ScorePenalty int `json:"scorePenalty,omitempty"` + ServermonitorLivenessCount int `json:"servermonitorLivenessCount,omitempty"` + ServermonitorLoadCount int `json:"servermonitorLoadCount,omitempty"` + ServermonitorPool string `json:"servermonitorPool,omitempty"` + StateOrProvince string `json:"stateOrProvince,omitempty"` + Virtual bool `json:"virtual"` + } + + // DatacenterList contains a list of Datacenters + DatacenterList struct { + DatacenterItems []Datacenter `json:"items"` + } + + // ListDatacentersRequest contains request parameters for ListDatacenters + ListDatacentersRequest struct { + DomainName string + } + + // GetDatacenterRequest contains request parameters for GetDatacenter + GetDatacenterRequest struct { + DatacenterID int + DomainName string + } + + // DatacenterRequest contains request parameters + DatacenterRequest struct { + Datacenter *Datacenter + DomainName string + } + + // CreateDatacenterRequest contains request parameters for CreateDatacenter + CreateDatacenterRequest DatacenterRequest + + // CreateDatacenterResponse contains the response data from CreateDatacenter operation + CreateDatacenterResponse struct { + Status *ResponseStatus `json:"status"` + Resource *Datacenter `json:"resource"` + } + + // UpdateDatacenterRequest contains request parameters for UpdateDatacenter + UpdateDatacenterRequest DatacenterRequest + + // UpdateDatacenterResponse contains the response data from UpdateDatacenter operation + UpdateDatacenterResponse struct { + Status *ResponseStatus `json:"status"` + Resource *Datacenter `json:"resource"` + } + + // DeleteDatacenterRequest contains request parameters for DeleteDatacenter + DeleteDatacenterRequest struct { + DatacenterID int + DomainName string + } + + // DeleteDatacenterResponse contains the response data from DeleteDatacenter operation + DeleteDatacenterResponse struct { + Status *ResponseStatus `json:"status"` + Resource *Datacenter `json:"resource"` + } +) + +var ( + // ErrListDatacenters is returned when ListDatacenters fails + ErrListDatacenters = errors.New("list datacenters") + // ErrGetDatacenter is returned when GetDatacenter fails + ErrGetDatacenter = errors.New("get datacenter") + // ErrCreateDatacenter is returned when CreateDatacenter fails + ErrCreateDatacenter = errors.New("create datacenter") + // ErrUpdateDatacenter is returned when UpdateDatacenter fails + ErrUpdateDatacenter = errors.New("update datacenter") + // ErrDeleteDatacenter is returned when DeleteDatacenter fails + ErrDeleteDatacenter = errors.New("delete datacenter") ) -// Datacenters contains operations available on a Datacenter resource. -type Datacenters interface { - // ListDatacenters retrieves all Datacenters. - // - // See: https://techdocs.akamai.com/gtm/reference/get-datacenters - ListDatacenters(context.Context, string) ([]*Datacenter, error) - // GetDatacenter retrieves a Datacenter with the given name. NOTE: Id arg is int! - // - // See: https://techdocs.akamai.com/gtm/reference/get-datacenter - GetDatacenter(context.Context, int, string) (*Datacenter, error) - // CreateDatacenter creates the datacenter identified by the receiver argument in the specified domain. - // - // See: https://techdocs.akamai.com/gtm/reference/post-datacenter - CreateDatacenter(context.Context, *Datacenter, string) (*DatacenterResponse, error) - // DeleteDatacenter deletes the datacenter identified by the receiver argument from the domain specified. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-datacenter - DeleteDatacenter(context.Context, *Datacenter, string) (*ResponseStatus, error) - // UpdateDatacenter updates the datacenter identified in the receiver argument in the provided domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-datacenter - UpdateDatacenter(context.Context, *Datacenter, string) (*ResponseStatus, error) - // CreateMapsDefaultDatacenter creates Default Datacenter for Maps. - CreateMapsDefaultDatacenter(context.Context, string) (*Datacenter, error) - // CreateIPv4DefaultDatacenter creates Default Datacenter for IPv4 Selector. - CreateIPv4DefaultDatacenter(context.Context, string) (*Datacenter, error) - // CreateIPv6DefaultDatacenter creates Default Datacenter for IPv6 Selector. - CreateIPv6DefaultDatacenter(context.Context, string) (*Datacenter, error) +// Validate validates ListDatacentersRequest +func (r ListDatacentersRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) +} + +// Validate validates GetDatacenterRequest +func (r GetDatacenterRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DatacenterID": validation.Validate(r.DatacenterID, validation.Required), + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) +} + +// Validate validates CreateDatacenterRequest +func (r CreateDatacenterRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Datacenter": validation.Validate(r.Datacenter, validation.Required), + }) } -// Datacenter represents a GTM datacenter -type Datacenter struct { - City string `json:"city,omitempty"` - CloneOf int `json:"cloneOf,omitempty"` - CloudServerHostHeaderOverride bool `json:"cloudServerHostHeaderOverride"` - CloudServerTargeting bool `json:"cloudServerTargeting"` - Continent string `json:"continent,omitempty"` - Country string `json:"country,omitempty"` - DefaultLoadObject *LoadObject `json:"defaultLoadObject,omitempty"` - Latitude float64 `json:"latitude,omitempty"` - Links []*Link `json:"links,omitempty"` - Longitude float64 `json:"longitude,omitempty"` - Nickname string `json:"nickname,omitempty"` - PingInterval int `json:"pingInterval,omitempty"` - PingPacketSize int `json:"pingPacketSize,omitempty"` - DatacenterID int `json:"datacenterId,omitempty"` - ScorePenalty int `json:"scorePenalty,omitempty"` - ServermonitorLivenessCount int `json:"servermonitorLivenessCount,omitempty"` - ServermonitorLoadCount int `json:"servermonitorLoadCount,omitempty"` - ServermonitorPool string `json:"servermonitorPool,omitempty"` - StateOrProvince string `json:"stateOrProvince,omitempty"` - Virtual bool `json:"virtual"` +// Validate validates UpdateDatacenterRequest +func (r UpdateDatacenterRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Datacenter": validation.Validate(r.Datacenter, validation.Required), + }) } -// DatacenterList contains a list of Datacenters -type DatacenterList struct { - DatacenterItems []*Datacenter `json:"items"` +// Validate validates DeleteDatacenterRequest +func (r DeleteDatacenterRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "DatacenterID": validation.Validate(r.DatacenterID, validation.Required), + }) } -func (g *gtm) ListDatacenters(ctx context.Context, domainName string) ([]*Datacenter, error) { +// Validate validates Datacenter +func (d Datacenter) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DatacenterID": validation.Validate(d.DatacenterID), + }) +} + +func (g *gtm) ListDatacenters(ctx context.Context, params ListDatacentersRequest) ([]Datacenter, error) { logger := g.Log(ctx) logger.Debug("ListDatacenters") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListDatacenters, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListDatacenters request: %w", err) @@ -91,11 +176,15 @@ func (g *gtm) ListDatacenters(ctx context.Context, domainName string) ([]*Datace return result.DatacenterItems, nil } -func (g *gtm) GetDatacenter(ctx context.Context, dcID int, domainName string) (*Datacenter, error) { +func (g *gtm) GetDatacenter(ctx context.Context, params GetDatacenterRequest) (*Datacenter, error) { logger := g.Log(ctx) logger.Debug("GetDatacenter") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dcID)) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetDatacenter, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", params.DomainName, strconv.Itoa(params.DatacenterID)) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetDatacenter request: %w", err) @@ -115,19 +204,23 @@ func (g *gtm) GetDatacenter(ctx context.Context, dcID int, domainName string) (* return &result, nil } -func (g *gtm) CreateDatacenter(ctx context.Context, dc *Datacenter, domainName string) (*DatacenterResponse, error) { +func (g *gtm) CreateDatacenter(ctx context.Context, params CreateDatacenterRequest) (*CreateDatacenterResponse, error) { logger := g.Log(ctx) logger.Debug("CreateDatacenter") - postURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateDatacenter, ErrStructValidation, err) + } + + postURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Datacenter request: %w", err) } setVersionHeader(req, schemaVersion) - var result DatacenterResponse - resp, err := g.Exec(req, &result, dc) + var result CreateDatacenterResponse + resp, err := g.Exec(req, &result, params.Datacenter) if err != nil { return nil, fmt.Errorf("CreateDatacenter request failed: %w", err) } @@ -173,8 +266,12 @@ func createDefaultDC(ctx context.Context, g *gtm, defaultID int, domainName stri if defaultID != MapDefaultDC && defaultID != Ipv4DefaultDC && defaultID != Ipv6DefaultDC { return nil, fmt.Errorf("invalid default datacenter id provided for creation") } + // check if already exists - dc, err := g.GetDatacenter(ctx, defaultID, domainName) + dc, err := g.GetDatacenter(ctx, GetDatacenterRequest{ + DatacenterID: defaultID, + DomainName: domainName, + }) if err == nil { return dc, err } @@ -211,19 +308,23 @@ func createDefaultDC(ctx context.Context, g *gtm, defaultID int, domainName stri return result.Resource, nil } -func (g *gtm) UpdateDatacenter(ctx context.Context, dc *Datacenter, domainName string) (*ResponseStatus, error) { +func (g *gtm) UpdateDatacenter(ctx context.Context, params UpdateDatacenterRequest) (*UpdateDatacenterResponse, error) { logger := g.Log(ctx) logger.Debug("UpdateDatacenter") - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterID)) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateDatacenter, ErrStructValidation, err) + } + + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", params.DomainName, strconv.Itoa(params.Datacenter.DatacenterID)) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Update Datacenter request: %w", err) } setVersionHeader(req, schemaVersion) - var result DatacenterResponse - resp, err := g.Exec(req, &result, dc) + var result UpdateDatacenterResponse + resp, err := g.Exec(req, &result, params.Datacenter) if err != nil { return nil, fmt.Errorf("UpdateDatacenter request failed: %w", err) } @@ -231,21 +332,25 @@ func (g *gtm) UpdateDatacenter(ctx context.Context, dc *Datacenter, domainName s return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } -func (g *gtm) DeleteDatacenter(ctx context.Context, dc *Datacenter, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteDatacenter(ctx context.Context, params DeleteDatacenterRequest) (*DeleteDatacenterResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteDatacenter") - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterID)) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteDatacenter, ErrStructValidation, err) + } + + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", params.DomainName, strconv.Itoa(params.DatacenterID)) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Delete Datacenter request: %w", err) } setVersionHeader(req, schemaVersion) - var result DatacenterResponse + var result DeleteDatacenterResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("DeleteDatacenter request failed: %w", err) @@ -254,5 +359,5 @@ func (g *gtm) DeleteDatacenter(ctx context.Context, dc *Datacenter, domainName s return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/datacenter_test.go b/pkg/gtm/datacenter_test.go index b6f894c8..71e9b0ad 100644 --- a/pkg/gtm/datacenter_test.go +++ b/pkg/gtm/datacenter_test.go @@ -27,16 +27,18 @@ func TestGTM_ListDatacenters(t *testing.T) { } tests := map[string]struct { - domainName string + params ListDatacentersRequest responseStatus int responseBody string expectedPath string - expectedResponse []*Datacenter + expectedResponse []Datacenter withError error headers http.Header }{ "200 OK": { - domainName: "example.akadns.net", + params: ListDatacentersRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -46,7 +48,9 @@ func TestGTM_ListDatacenters(t *testing.T) { expectedResponse: result.DatacenterItems, }, "500 internal server error": { - domainName: "example.akadns.net", + params: ListDatacentersRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -78,7 +82,7 @@ func TestGTM_ListDatacenters(t *testing.T) { result, err := client.ListDatacenters( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -102,8 +106,7 @@ func TestGTM_GetDatacenter(t *testing.T) { } tests := map[string]struct { - id int - domainName string + params GetDatacenterRequest responseStatus int responseBody string expectedPath string @@ -112,8 +115,10 @@ func TestGTM_GetDatacenter(t *testing.T) { headers http.Header }{ "200 OK": { - id: 1, - domainName: "example.akadns.net", + params: GetDatacenterRequest{ + DatacenterID: 1, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -123,8 +128,10 @@ func TestGTM_GetDatacenter(t *testing.T) { expectedResponse: &result, }, "500 internal server error": { - id: 1, - domainName: "example.akadns.net", + params: GetDatacenterRequest{ + DatacenterID: 1, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -156,7 +163,7 @@ func TestGTM_GetDatacenter(t *testing.T) { result, err := client.GetDatacenter( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.id, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -168,7 +175,7 @@ func TestGTM_GetDatacenter(t *testing.T) { } func TestGTM_CreateDatacenter(t *testing.T) { - var result DatacenterResponse + var result CreateDatacenterResponse var req Datacenter respData, err := loadTestData("TestGTM_CreateDatacenter.resp.json") @@ -190,18 +197,19 @@ func TestGTM_CreateDatacenter(t *testing.T) { } tests := map[string]struct { - dc *Datacenter - domainName string + params CreateDatacenterRequest responseStatus int responseBody string expectedPath string - expectedResponse *DatacenterResponse + expectedResponse *CreateDatacenterResponse withError error headers http.Header }{ "200 OK": { - dc: &req, - domainName: "example.akadns.net", + params: CreateDatacenterRequest{ + Datacenter: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -211,8 +219,10 @@ func TestGTM_CreateDatacenter(t *testing.T) { expectedResponse: &result, }, "500 internal server error": { - dc: &req, - domainName: "example.akadns.net", + params: CreateDatacenterRequest{ + Datacenter: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -244,7 +254,7 @@ func TestGTM_CreateDatacenter(t *testing.T) { result, err := client.CreateDatacenter( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.dc, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -511,7 +521,7 @@ func TestGTM_CreateIPv6DefaultDatacenter(t *testing.T) { } func TestGTM_UpdateDatacenter(t *testing.T) { - var result DatacenterResponse + var result UpdateDatacenterResponse var req Datacenter respData, err := loadTestData("TestGTM_CreateDatacenter.resp.json") @@ -533,29 +543,32 @@ func TestGTM_UpdateDatacenter(t *testing.T) { } tests := map[string]struct { - dc *Datacenter - domainName string + params UpdateDatacenterRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateDatacenterResponse withError error headers http.Header }{ "200 OK": { - dc: &req, - domainName: "example.akadns.net", + params: UpdateDatacenterRequest{ + Datacenter: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/datacenters/0", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - dc: &req, - domainName: "example.akadns.net", + params: UpdateDatacenterRequest{ + Datacenter: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -587,7 +600,7 @@ func TestGTM_UpdateDatacenter(t *testing.T) { result, err := client.UpdateDatacenter( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.dc, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -599,7 +612,7 @@ func TestGTM_UpdateDatacenter(t *testing.T) { } func TestGTM_DeleteDatacenter(t *testing.T) { - var result DatacenterResponse + var result DeleteDatacenterResponse var req Datacenter respData, err := loadTestData("TestGTM_CreateDatacenter.resp.json") @@ -621,29 +634,32 @@ func TestGTM_DeleteDatacenter(t *testing.T) { } tests := map[string]struct { - dc *Datacenter - domainName string + params DeleteDatacenterRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeleteDatacenterResponse withError error headers http.Header }{ "200 OK": { - dc: &req, - domainName: "example.akadns.net", + params: DeleteDatacenterRequest{ + DatacenterID: 1, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), - expectedPath: "/config-gtm/v1/domains/example.akadns.net/datacenters/0", - expectedResponse: result.Status, + expectedPath: "/config-gtm/v1/domains/example.akadns.net/datacenters/1", + expectedResponse: &result, }, "500 internal server error": { - dc: &req, - domainName: "example.akadns.net", + params: DeleteDatacenterRequest{ + DatacenterID: 1, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -652,7 +668,7 @@ func TestGTM_DeleteDatacenter(t *testing.T) { "title": "Internal Server Error", "detail": "Error updating dc" }`, - expectedPath: "/config-gtm/v1/domains/example.akadns.net/datacenters/0", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/datacenters/1", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -675,7 +691,7 @@ func TestGTM_DeleteDatacenter(t *testing.T) { result, err := client.DeleteDatacenter( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.dc, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/domain.go b/pkg/gtm/domain.go index 2ea8af34..6d659d8f 100644 --- a/pkg/gtm/domain.go +++ b/pkg/gtm/domain.go @@ -2,110 +2,191 @@ package gtm import ( "context" + "errors" "fmt" "net/http" - "reflect" - "strings" "unicode" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) -// Domains contains operations available on a Domain resource. -type Domains interface { - // NullFieldMap retrieves map of null fields. - NullFieldMap(context.Context, *Domain) (*NullFieldMapStruct, error) - // GetDomainStatus retrieves current status for the given domain name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-status-current - GetDomainStatus(context.Context, string) (*ResponseStatus, error) - // ListDomains retrieves all Domains. - // - // See: https://techdocs.akamai.com/gtm/reference/get-domains - ListDomains(context.Context) ([]*DomainItem, error) - // GetDomain retrieves a Domain with the given domain name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-domain - GetDomain(context.Context, string) (*Domain, error) - // CreateDomain creates domain. - // - // See: https://techdocs.akamai.com/gtm/reference/post-domain - CreateDomain(context.Context, *Domain, map[string]string) (*DomainResponse, error) - // DeleteDomain is a method applied to a domain object resulting in removal. - // - // See: ** Not Supported by API ** - DeleteDomain(context.Context, *Domain) (*ResponseStatus, error) - // UpdateDomain is a method applied to a domain object resulting in an update. - // - // See: https://techdocs.akamai.com/gtm/reference/put-domain - UpdateDomain(context.Context, *Domain, map[string]string) (*ResponseStatus, error) +// The Domain data structure represents a GTM domain +type ( + Domain struct { + Name string `json:"name"` + Type string `json:"type"` + ASMaps []ASMap `json:"asMaps,omitempty"` + Resources []Resource `json:"resources,omitempty"` + DefaultUnreachableThreshold float32 `json:"defaultUnreachableThreshold,omitempty"` + EmailNotificationList []string `json:"emailNotificationList,omitempty"` + MinPingableRegionFraction float32 `json:"minPingableRegionFraction,omitempty"` + DefaultTimeoutPenalty int `json:"defaultTimeoutPenalty,omitempty"` + Datacenters []Datacenter `json:"datacenters,omitempty"` + ServermonitorLivenessCount int `json:"servermonitorLivenessCount,omitempty"` + RoundRobinPrefix string `json:"roundRobinPrefix,omitempty"` + ServermonitorLoadCount int `json:"servermonitorLoadCount,omitempty"` + PingInterval int `json:"pingInterval,omitempty"` + MaxTTL int64 `json:"maxTTL,omitempty"` + LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` + DefaultHealthMax float64 `json:"defaultHealthMax,omitempty"` + LastModified string `json:"lastModified,omitempty"` + Status *ResponseStatus `json:"status,omitempty"` + MapUpdateInterval int `json:"mapUpdateInterval,omitempty"` + MaxProperties int `json:"maxProperties,omitempty"` + MaxResources int `json:"maxResources,omitempty"` + DefaultSSLClientPrivateKey string `json:"defaultSslClientPrivateKey,omitempty"` + DefaultErrorPenalty int `json:"defaultErrorPenalty,omitempty"` + Links []Link `json:"links,omitempty"` + Properties []Property `json:"properties,omitempty"` + MaxTestTimeout float64 `json:"maxTestTimeout,omitempty"` + CNameCoalescingEnabled bool `json:"cnameCoalescingEnabled"` + DefaultHealthMultiplier float64 `json:"defaultHealthMultiplier,omitempty"` + ServermonitorPool string `json:"servermonitorPool,omitempty"` + LoadFeedback bool `json:"loadFeedback"` + MinTTL int64 `json:"minTTL,omitempty"` + GeographicMaps []GeoMap `json:"geographicMaps,omitempty"` + CIDRMaps []CIDRMap `json:"cidrMaps,omitempty"` + DefaultMaxUnreachablePenalty int `json:"defaultMaxUnreachablePenalty"` + DefaultHealthThreshold float64 `json:"defaultHealthThreshold,omitempty"` + LastModifiedBy string `json:"lastModifiedBy,omitempty"` + ModificationComments string `json:"modificationComments,omitempty"` + MinTestInterval int `json:"minTestInterval,omitempty"` + PingPacketSize int `json:"pingPacketSize,omitempty"` + DefaultSSLClientCertificate string `json:"defaultSslClientCertificate,omitempty"` + EndUserMappingEnabled bool `json:"endUserMappingEnabled"` + SignAndServe bool `json:"signAndServe"` + SignAndServeAlgorithm *string `json:"signAndServeAlgorithm"` + } + + // DomainQueryArgs contains query parameters for domain request + DomainQueryArgs struct { + ContractID string + GroupID string + } + + // DomainsList contains a list of domain items + DomainsList struct { + DomainItems []DomainItem `json:"items"` + } + + // DomainItem is a DomainsList item + DomainItem struct { + AcgID string `json:"acgId"` + LastModified string `json:"lastModified"` + Links []Link `json:"links"` + Name string `json:"name"` + Status string `json:"status"` + LastModifiedBy string `json:"lastModifiedBy"` + ChangeID string `json:"changeId"` + ActivationState string `json:"activationState"` + ModificationComments string `json:"modificationComments"` + SignAndServe bool `json:"signAndServe"` + SignAndServeAlgorithm string `json:"signAndServeAlgorithm"` + DeleteRequestID string `json:"deleteRequestId"` + } + // GetDomainStatusRequest contains request parameters for GetDomainStatus + GetDomainStatusRequest struct { + DomainName string + } + // GetDomainStatusResponse contains the response data from GetDomainStatus operation + GetDomainStatusResponse ResponseStatus + + // DomainRequest contains request parameters + DomainRequest struct { + Domain *Domain + QueryArgs *DomainQueryArgs + } + + // GetDomainRequest contains request parameters for GetDomain + GetDomainRequest struct { + DomainName string + } + + // GetDomainResponse contains the response data from GetDomain operation + GetDomainResponse Domain + + // CreateDomainRequest contains request parameters for CreateDomain + CreateDomainRequest DomainRequest + + // CreateDomainResponse contains the response data from CreateDomain operation + CreateDomainResponse struct { + Resource *Domain `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdateDomainRequest contains request parameters for UpdateDomain + UpdateDomainRequest DomainRequest + + // UpdateDomainResponse contains the response data from UpdateDomain operation + UpdateDomainResponse struct { + Resource *Domain `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeleteDomainRequest contains request parameters for DeleteDomain + DeleteDomainRequest struct { + DomainName string + } + + // DeleteDomainResponse contains request parameters for DeleteDomain + DeleteDomainResponse struct { + ChangeID string `json:"changeId,omitempty"` + Links []Link `json:"links,omitempty"` + Message string `json:"message,omitempty"` + PassingValidation bool `json:"passingValidation,omitempty"` + PropagationStatus string `json:"propagationStatus,omitempty"` + PropagationStatusDate string `json:"propagationStatusDate,omitempty"` + } +) + +var ( + // ErrGetDomainStatus is returned when GetDomainStatus fails + ErrGetDomainStatus = errors.New("get domain status") + // ErrGetDomain is returned when GetDomain fails + ErrGetDomain = errors.New("get domain") + // ErrCreateDomain is returned when CreateDomain fails + ErrCreateDomain = errors.New("create domain") + // ErrUpdateDomain is returned when UpdateDomain fails + ErrUpdateDomain = errors.New("update domain") + // ErrDeleteDomain is returned when DeleteDomain fails + ErrDeleteDomain = errors.New("delete domain") +) + +// Validate validates DeleteDomainRequest +func (r DeleteDomainRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// The Domain data structure represents a GTM domain -type Domain struct { - Name string `json:"name"` - Type string `json:"type"` - ASMaps []*ASMap `json:"asMaps,omitempty"` - Resources []*Resource `json:"resources,omitempty"` - DefaultUnreachableThreshold float32 `json:"defaultUnreachableThreshold,omitempty"` - EmailNotificationList []string `json:"emailNotificationList,omitempty"` - MinPingableRegionFraction float32 `json:"minPingableRegionFraction,omitempty"` - DefaultTimeoutPenalty int `json:"defaultTimeoutPenalty,omitempty"` - Datacenters []*Datacenter `json:"datacenters,omitempty"` - ServermonitorLivenessCount int `json:"servermonitorLivenessCount,omitempty"` - RoundRobinPrefix string `json:"roundRobinPrefix,omitempty"` - ServermonitorLoadCount int `json:"servermonitorLoadCount,omitempty"` - PingInterval int `json:"pingInterval,omitempty"` - MaxTTL int64 `json:"maxTTL,omitempty"` - LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` - DefaultHealthMax float64 `json:"defaultHealthMax,omitempty"` - LastModified string `json:"lastModified,omitempty"` - Status *ResponseStatus `json:"status,omitempty"` - MapUpdateInterval int `json:"mapUpdateInterval,omitempty"` - MaxProperties int `json:"maxProperties,omitempty"` - MaxResources int `json:"maxResources,omitempty"` - DefaultSSLClientPrivateKey string `json:"defaultSslClientPrivateKey,omitempty"` - DefaultErrorPenalty int `json:"defaultErrorPenalty,omitempty"` - Links []*Link `json:"links,omitempty"` - Properties []*Property `json:"properties,omitempty"` - MaxTestTimeout float64 `json:"maxTestTimeout,omitempty"` - CNameCoalescingEnabled bool `json:"cnameCoalescingEnabled"` - DefaultHealthMultiplier float64 `json:"defaultHealthMultiplier,omitempty"` - ServermonitorPool string `json:"servermonitorPool,omitempty"` - LoadFeedback bool `json:"loadFeedback"` - MinTTL int64 `json:"minTTL,omitempty"` - GeographicMaps []*GeoMap `json:"geographicMaps,omitempty"` - CIDRMaps []*CIDRMap `json:"cidrMaps,omitempty"` - DefaultMaxUnreachablePenalty int `json:"defaultMaxUnreachablePenalty"` - DefaultHealthThreshold float64 `json:"defaultHealthThreshold,omitempty"` - LastModifiedBy string `json:"lastModifiedBy,omitempty"` - ModificationComments string `json:"modificationComments,omitempty"` - MinTestInterval int `json:"minTestInterval,omitempty"` - PingPacketSize int `json:"pingPacketSize,omitempty"` - DefaultSSLClientCertificate string `json:"defaultSslClientCertificate,omitempty"` - EndUserMappingEnabled bool `json:"endUserMappingEnabled"` - SignAndServe bool `json:"signAndServe"` - SignAndServeAlgorithm *string `json:"signAndServeAlgorithm"` +// Validate validates UpdateDomainRequest +func (r UpdateDomainRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Domain": validation.Validate(r.Domain, validation.Required), + }) +} + +// Validate validates CreateDomainRequest +func (r CreateDomainRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Domain": validation.Validate(r.Domain, validation.Required), + }) } -// DomainsList contains a list of domain items -type DomainsList struct { - DomainItems []*DomainItem `json:"items"` +// Validate validates GetDomainStatusRequest +func (r GetDomainStatusRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// DomainItem is a DomainsList item -type DomainItem struct { - AcgID string `json:"acgId"` - LastModified string `json:"lastModified"` - Links []*Link `json:"links"` - Name string `json:"name"` - Status string `json:"status"` - LastModifiedBy string `json:"lastModifiedBy"` - ChangeID string `json:"changeId"` - ActivationState string `json:"activationState"` - ModificationComments string `json:"modificationComments"` - SignAndServe bool `json:"signAndServe"` - SignAndServeAlgorithm string `json:"signAndServeAlgorithm"` - DeleteRequestID string `json:"deleteRequestId"` +// Validate validates GetDomainRequest +func (r GetDomainRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } // Validate validates Domain @@ -120,18 +201,22 @@ func (d *Domain) Validate() error { return nil } -func (g *gtm) GetDomainStatus(ctx context.Context, domainName string) (*ResponseStatus, error) { +func (g *gtm) GetDomainStatus(ctx context.Context, params GetDomainStatusRequest) (*GetDomainStatusResponse, error) { logger := g.Log(ctx) logger.Debug("GetDomainStatus") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/status/current", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetDomainStatus, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/status/current", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetDomain request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseStatus + var result GetDomainStatusResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetDomain request failed: %w", err) @@ -144,7 +229,7 @@ func (g *gtm) GetDomainStatus(ctx context.Context, domainName string) (*Response return &result, nil } -func (g *gtm) ListDomains(ctx context.Context) ([]*DomainItem, error) { +func (g *gtm) ListDomains(ctx context.Context) ([]DomainItem, error) { logger := g.Log(ctx) logger.Debug("ListDomains") @@ -168,18 +253,22 @@ func (g *gtm) ListDomains(ctx context.Context) ([]*DomainItem, error) { return result.DomainItems, nil } -func (g *gtm) GetDomain(ctx context.Context, domainName string) (*Domain, error) { +func (g *gtm) GetDomain(ctx context.Context, params GetDomainRequest) (*GetDomainResponse, error) { logger := g.Log(ctx) logger.Debug("GetDomain") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetDomain, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetDomain request: %w", err) } setVersionHeader(req, schemaVersion) - var result Domain + var result GetDomainResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetDomain request failed: %w", err) @@ -192,86 +281,106 @@ func (g *gtm) GetDomain(ctx context.Context, domainName string) (*Domain, error) return &result, nil } -// save method; Create or Update -func (d *Domain) save(_ context.Context, g *gtm, queryArgs map[string]string, req *http.Request) (*DomainResponse, error) { +func (g *gtm) CreateDomain(ctx context.Context, params CreateDomainRequest) (*CreateDomainResponse, error) { + logger := g.Log(ctx) + logger.Debug("CreateDomain") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateDomain, ErrStructValidation, err) + } + + postURL := fmt.Sprintf("/config-gtm/v1/domains") + req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create CreateDomain request: %w", err) + } + // set schema version setVersionHeader(req, schemaVersion) // Look for optional args - if len(queryArgs) > 0 { + if params.QueryArgs != nil { q := req.URL.Query() - if val, ok := queryArgs["contractId"]; ok { - q.Add("contractId", strings.TrimPrefix(val, "ctr_")) + if params.QueryArgs.ContractID != "" { + q.Add("contractId", params.QueryArgs.ContractID) } - if val, ok := queryArgs["gid"]; ok { - q.Add("gid", strings.TrimPrefix(val, "grp_")) + if params.QueryArgs.GroupID != "" { + q.Add("gid", params.QueryArgs.GroupID) } req.URL.RawQuery = q.Encode() } - var result DomainResponse - resp, err := g.Exec(req, &result, d) + var result CreateDomainResponse + resp, err := g.Exec(req, &result, params.Domain) if err != nil { return nil, fmt.Errorf("domain request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusCreated { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) CreateDomain(ctx context.Context, domain *Domain, queryArgs map[string]string) (*DomainResponse, error) { +func (g *gtm) UpdateDomain(ctx context.Context, params UpdateDomainRequest) (*UpdateDomainResponse, error) { logger := g.Log(ctx) - logger.Debug("CreateDomain") + logger.Debug("UpdateDomain") - if err := domain.Validate(); err != nil { - return nil, fmt.Errorf("CreateDomain validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateDomain, ErrStructValidation, err) } - postURL := fmt.Sprintf("/config-gtm/v1/domains/") - req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, nil) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s", params.Domain.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { - return nil, fmt.Errorf("failed to create CreateDomain request: %w", err) + return nil, fmt.Errorf("failed to create UpdateDomain request: %w", err) } - return domain.save(ctx, g, queryArgs, req) -} - -func (g *gtm) UpdateDomain(ctx context.Context, domain *Domain, queryArgs map[string]string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateDomain") + // set schema version + setVersionHeader(req, schemaVersion) - if err := domain.Validate(); err != nil { - return nil, fmt.Errorf("UpdateDomain validation failed. %w", err) + // Look for optional args + if params.QueryArgs != nil { + q := req.URL.Query() + if params.QueryArgs.ContractID != "" { + q.Add("contractId", params.QueryArgs.ContractID) + } + if params.QueryArgs.GroupID != "" { + q.Add("gid", params.QueryArgs.GroupID) + } + req.URL.RawQuery = q.Encode() } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name) - req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) + var result UpdateDomainResponse + resp, err := g.Exec(req, &result, params.Domain) if err != nil { - return nil, fmt.Errorf("failed to create UpdateDomain request: %w", err) + return nil, fmt.Errorf("domain request failed: %w", err) } - stat, err := domain.save(ctx, g, queryArgs, req) - if err != nil { - return nil, err + if resp.StatusCode != http.StatusOK { + return nil, g.Error(resp) } - return stat.Status, err + + return &result, nil } -func (g *gtm) DeleteDomain(ctx context.Context, domain *Domain) (*ResponseStatus, error) { +func (g *gtm) DeleteDomain(ctx context.Context, params DeleteDomainRequest) (*DeleteDomainResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteDomain") - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteDomain, ErrStructValidation, err) + } + + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create DeleteDomain request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeleteDomainResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("DeleteDomain request failed: %w", err) @@ -281,7 +390,7 @@ func (g *gtm) DeleteDomain(ctx context.Context, domain *Domain) (*ResponseStatus return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } // NullPerObjectAttributeStruct represents core and child null object attributes diff --git a/pkg/gtm/domain_test.go b/pkg/gtm/domain_test.go index ec0f8ef6..4b6fec35 100644 --- a/pkg/gtm/domain_test.go +++ b/pkg/gtm/domain_test.go @@ -20,7 +20,7 @@ func TestGTM_ListDomains(t *testing.T) { responseStatus int responseBody string expectedPath string - expectedResponse []*DomainItem + expectedResponse []DomainItem withError error headers http.Header }{ @@ -65,7 +65,7 @@ func TestGTM_ListDomains(t *testing.T) { }] }]}`, expectedPath: "/config-gtm/v1/domains", - expectedResponse: []*DomainItem{{ + expectedResponse: []DomainItem{{ AcgID: "1-2345", LastModified: "2014-03-03T16:02:45.000+0000", Name: "example.akadns.net", @@ -77,7 +77,7 @@ func TestGTM_ListDomains(t *testing.T) { SignAndServe: false, SignAndServeAlgorithm: "", DeleteRequestID: "", - Links: []*Link{{ + Links: []Link{{ Rel: "self", Href: "/config-gtm/v1/domains/example.akadns.net", }}, @@ -94,7 +94,7 @@ func TestGTM_ListDomains(t *testing.T) { SignAndServe: false, SignAndServeAlgorithm: "", DeleteRequestID: "", - Links: []*Link{{ + Links: []Link{{ Rel: "self", Href: "/config-gtm/v1/domains/example.akadns.net", }}, @@ -261,7 +261,7 @@ func TestGTM_NullFieldMap(t *testing.T) { } func TestGTM_GetDomain(t *testing.T) { - var result Domain + var result GetDomainResponse respData, err := loadTestData("TestGTM_GetDomain.resp.json") if err != nil { @@ -273,22 +273,26 @@ func TestGTM_GetDomain(t *testing.T) { } tests := map[string]struct { - domain string + params GetDomainRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *Domain + expectedResponse *GetDomainResponse withError error }{ "200 OK": { - domain: "example.akadns.net", + params: GetDomainRequest{ + DomainName: "example.akadns.net", + }, responseStatus: http.StatusOK, responseBody: respData, expectedPath: "/config-gtm/v1/domains/example.akadns.net", expectedResponse: &result, }, "500 internal server error": { - domain: "example.akadns.net", + params: GetDomainRequest{ + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -316,7 +320,7 @@ func TestGTM_GetDomain(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetDomain(context.Background(), test.domain) + result, err := client.GetDomain(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -328,7 +332,7 @@ func TestGTM_GetDomain(t *testing.T) { } func TestGTM_CreateDomain(t *testing.T) { - var result DomainResponse + var result CreateDomainResponse respData, err := loadTestData("TestGTM_GetDomain.resp.json") if err != nil { @@ -340,21 +344,22 @@ func TestGTM_CreateDomain(t *testing.T) { } tests := map[string]struct { - domain Domain - query map[string]string + params CreateDomainRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *DomainResponse + expectedResponse *CreateDomainResponse withError error headers http.Header }{ "201 Created": { - domain: Domain{ - Name: "gtmdomtest.akadns.net", - Type: "basic", + params: CreateDomainRequest{ + Domain: &Domain{ + Name: "gtmdomtest.akadns.net", + Type: "basic", + }, + QueryArgs: &DomainQueryArgs{ContractID: "1-2ABCDE"}, }, - query: map[string]string{"contractId": "1-2ABCDE"}, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -364,11 +369,13 @@ func TestGTM_CreateDomain(t *testing.T) { expectedPath: "/config-gtm/v1/domains?contractId=1-2ABCDE", }, "500 internal server error": { - domain: Domain{ - Name: "gtmdomtest.akadns.net", - Type: "basic", + params: CreateDomainRequest{ + Domain: &Domain{ + Name: "gtmdomtest.akadns.net", + Type: "basic", + }, + QueryArgs: &DomainQueryArgs{ContractID: "1-2ABCDE"}, }, - query: map[string]string{"contractId": "1-2ABCDE"}, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -389,6 +396,7 @@ func TestGTM_CreateDomain(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -400,7 +408,7 @@ func TestGTM_CreateDomain(t *testing.T) { result, err := client.CreateDomain( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), &test.domain, test.query) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -412,7 +420,7 @@ func TestGTM_CreateDomain(t *testing.T) { } func TestGTM_UpdateDomain(t *testing.T) { - var result DomainResponse + var result UpdateDomainResponse respData, err := loadTestData("TestGTM_UpdateDomain.resp.json") if err != nil { @@ -424,36 +432,40 @@ func TestGTM_UpdateDomain(t *testing.T) { } tests := map[string]struct { - domain Domain - query map[string]string + params UpdateDomainRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateDomainResponse withError error headers http.Header }{ "200 Success": { - domain: Domain{ - EndUserMappingEnabled: false, - Name: "gtmdomtest.akadns.net", - Type: "basic", + params: UpdateDomainRequest{ + Domain: &Domain{ + EndUserMappingEnabled: false, + Name: "gtmdomtest.akadns.net", + Type: "basic", + }, + QueryArgs: &DomainQueryArgs{ContractID: "1-2ABCDE"}, }, - query: map[string]string{"contractId": "1-2ABCDE"}, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusCreated, + responseStatus: http.StatusOK, responseBody: respData, - expectedResponse: result.Status, - expectedPath: "/config-gtm/v1/domains?contractId=1-2ABCDE", + expectedResponse: &result, + expectedPath: "/config-gtm/v1/domains/gtmdomtest.akadns.net?contractId=1-2ABCDE", }, "500 internal server error": { - domain: Domain{ - Name: "gtmdomtest.akadns.net", - Type: "basic", + params: UpdateDomainRequest{ + Domain: &Domain{ + EndUserMappingEnabled: false, + Name: "gtmdomtest.akadns.net", + Type: "basic", + }, + QueryArgs: &DomainQueryArgs{ContractID: "1-2ABCDE"}, }, - query: map[string]string{"contractId": "1-2ABCDE"}, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -461,7 +473,7 @@ func TestGTM_UpdateDomain(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating zone" }`), - expectedPath: "/config-gtm/v1/domains?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/gtmdomtest.akadns.net?contractId=1-2ABCDE", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -474,6 +486,7 @@ func TestGTM_UpdateDomain(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -485,7 +498,7 @@ func TestGTM_UpdateDomain(t *testing.T) { result, err := client.UpdateDomain( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), &test.domain, test.query) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/errors_test.go b/pkg/gtm/errors_test.go index 9b3d79a9..23cd19d8 100644 --- a/pkg/gtm/errors_test.go +++ b/pkg/gtm/errors_test.go @@ -9,7 +9,6 @@ import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" "github.com/stretchr/testify/require" - "github.com/tj/assert" ) diff --git a/pkg/gtm/geomap.go b/pkg/gtm/geomap.go index 5a776efa..b755a204 100644 --- a/pkg/gtm/geomap.go +++ b/pkg/gtm/geomap.go @@ -2,70 +2,154 @@ package gtm import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // GeoAssignment represents a GTM Geo assignment element + GeoAssignment struct { + DatacenterBase + Countries []string `json:"countries"` + } + + // GeoMap represents a GTM GeoMap + GeoMap struct { + DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` + Assignments []GeoAssignment `json:"assignments,omitempty"` + Name string `json:"name"` + Links []Link `json:"links,omitempty"` + } + + // GeoMapList represents the returned GTM GeoMap List body + GeoMapList struct { + GeoMapItems []GeoMap `json:"items"` + } + + // ListGeoMapsRequest contains request parameters for ListGeoMaps + ListGeoMapsRequest struct { + DomainName string + } + + // GetGeoMapRequest contains request parameters for GetGeoMap + GetGeoMapRequest struct { + MapName string + DomainName string + } + + // GetGeoMapResponse contains the response data from GetGeoMap operation + GetGeoMapResponse GeoMap + + // GeoMapRequest contains request parameters + GeoMapRequest struct { + GeoMap *GeoMap + DomainName string + } + + // CreateGeoMapRequest contains request parameters for CreateGeoMap + CreateGeoMapRequest GeoMapRequest + + // CreateGeoMapResponse contains the response data from CreateGeoMap operation + CreateGeoMapResponse struct { + Resource *GeoMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdateGeoMapRequest contains request parameters for UpdateGeoMap + UpdateGeoMapRequest GeoMapRequest + + // UpdateGeoMapResponse contains the response data from UpdateGeoMap operation + UpdateGeoMapResponse struct { + Resource *GeoMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeleteGeoMapRequest contains request parameters for DeleteGeoMap + DeleteGeoMapRequest struct { + MapName string + DomainName string + } + + // DeleteGeoMapResponse contains the response data from DeleteGeoMap operation + DeleteGeoMapResponse struct { + Resource *GeoMap `json:"resource"` + Status *ResponseStatus `json:"status"` + } ) -// GeoMaps contains operations available on a GeoMap resource. -type GeoMaps interface { - // ListGeoMaps retrieves all GeoMaps. - // - // See: https://techdocs.akamai.com/gtm/reference/get-geographic-maps - ListGeoMaps(context.Context, string) ([]*GeoMap, error) - // GetGeoMap retrieves a GeoMap with the given name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-geographic-map - GetGeoMap(context.Context, string, string) (*GeoMap, error) - // CreateGeoMap creates the datacenter identified by the receiver argument in the specified domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-geographic-map - CreateGeoMap(context.Context, *GeoMap, string) (*GeoMapResponse, error) - // DeleteGeoMap deletes the datacenter identified by the receiver argument from the domain specified. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-geographic-map - DeleteGeoMap(context.Context, *GeoMap, string) (*ResponseStatus, error) - // UpdateGeoMap updates the datacenter identified in the receiver argument in the provided domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-geographic-map - UpdateGeoMap(context.Context, *GeoMap, string) (*ResponseStatus, error) +var ( + // ErrListGeoMaps is returned when ListGeoMaps fails + ErrListGeoMaps = errors.New("list geomaps") + // ErrGetGeoMap is returned when GetGeoMap fails + ErrGetGeoMap = errors.New("get geomap") + // ErrCreateGeoMap is returned when CreateGeoMap fails + ErrCreateGeoMap = errors.New("create geomap") + // ErrUpdateGeoMap is returned when UpdateGeoMap fails + ErrUpdateGeoMap = errors.New("update geomap") + // ErrDeleteGeoMap is returned when DeleteGeoMap fails + ErrDeleteGeoMap = errors.New("delete geomap") +) + +// Validate validates ListGeoMapsRequest +func (r ListGeoMapsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// GeoAssignment represents a GTM Geo assignment element -type GeoAssignment struct { - DatacenterBase - Countries []string `json:"countries"` +// Validate validates GetGeoMapRequest +func (r GetGeoMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "MapName": validation.Validate(r.MapName, validation.Required), + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// GeoMap represents a GTM GeoMap -type GeoMap struct { - DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` - Assignments []*GeoAssignment `json:"assignments,omitempty"` - Name string `json:"name"` - Links []*Link `json:"links,omitempty"` +// Validate validates CreateGeoMapRequest +func (r CreateGeoMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "GeoMap": validation.Validate(r.GeoMap, validation.Required), + }) } -// GeoMapList represents the returned GTM GeoMap List body -type GeoMapList struct { - GeoMapItems []*GeoMap `json:"items"` +// Validate validates UpdateGeoMapRequest +func (r UpdateGeoMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "GeoMap": validation.Validate(r.GeoMap, validation.Required), + }) } -// Validate validates GeoMap -func (m *GeoMap) Validate() error { - if len(m.Name) < 1 { - return fmt.Errorf("GeoMap is missing Name") - } - if m.DefaultDatacenter == nil { - return fmt.Errorf("GeoMap is missing DefaultDatacenter") - } +// Validate validates DeleteGeoMapRequest +func (r DeleteGeoMapRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "MapName": validation.Validate(r.MapName, validation.Required), + }) +} - return nil +// Validate validates GeoMap +func (g *GeoMap) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Name": validation.Validate(g.Name, validation.Required), + "DefaultDatacenter": validation.Validate(g.DefaultDatacenter, validation.Required), + }) } -func (g *gtm) ListGeoMaps(ctx context.Context, domainName string) ([]*GeoMap, error) { +func (g *gtm) ListGeoMaps(ctx context.Context, params ListGeoMapsRequest) ([]GeoMap, error) { logger := g.Log(ctx) logger.Debug("ListGeoMaps") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListGeoMaps, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListGeoMaps request: %w", err) @@ -85,18 +169,22 @@ func (g *gtm) ListGeoMaps(ctx context.Context, domainName string) ([]*GeoMap, er return result.GeoMapItems, nil } -func (g *gtm) GetGeoMap(ctx context.Context, mapName, domainName string) (*GeoMap, error) { +func (g *gtm) GetGeoMap(ctx context.Context, params GetGeoMapRequest) (*GetGeoMapResponse, error) { logger := g.Log(ctx) logger.Debug("GetGeoMap") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, mapName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetGeoMap, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", params.DomainName, params.MapName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetGeoMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result GeoMap + var result GetGeoMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetGeoMap request failed: %w", err) @@ -109,67 +197,78 @@ func (g *gtm) GetGeoMap(ctx context.Context, mapName, domainName string) (*GeoMa return &result, nil } -func (g *gtm) CreateGeoMap(ctx context.Context, geo *GeoMap, domainName string) (*GeoMapResponse, error) { +func (g *gtm) CreateGeoMap(ctx context.Context, params CreateGeoMapRequest) (*CreateGeoMapResponse, error) { logger := g.Log(ctx) logger.Debug("CreateGeoMap") - return geo.save(ctx, g, domainName) -} + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateGeoMap, ErrStructValidation, err) + } -func (g *gtm) UpdateGeoMap(ctx context.Context, geo *GeoMap, domainName string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateGeoMap") + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", params.DomainName, params.GeoMap.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create GeoMap request: %w", err) + } + setVersionHeader(req, schemaVersion) - stat, err := geo.save(ctx, g, domainName) + var result CreateGeoMapResponse + resp, err := g.Exec(req, &result, params.GeoMap) if err != nil { - return nil, err + return nil, fmt.Errorf("GeoMap request failed: %w", err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, g.Error(resp) } - return stat.Status, err + + return &result, nil } -// Save GeoMap in given domain. Common path for Create and Update. -func (m *GeoMap) save(ctx context.Context, g *gtm, domainName string) (*GeoMapResponse, error) { - if err := m.Validate(); err != nil { - return nil, fmt.Errorf("GeoMap validation failed. %w", err) +func (g *gtm) UpdateGeoMap(ctx context.Context, params UpdateGeoMapRequest) (*UpdateGeoMapResponse, error) { + logger := g.Log(ctx) + logger.Debug("UpdateGeoMap") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateGeoMap, ErrStructValidation, err) } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, m.Name) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", params.DomainName, params.GeoMap.Name) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GeoMap request: %w", err) } setVersionHeader(req, schemaVersion) - var result GeoMapResponse - resp, err := g.Exec(req, &result, m) + var result UpdateGeoMapResponse + resp, err := g.Exec(req, &result, params.GeoMap) if err != nil { return nil, fmt.Errorf("GeoMap request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusOK { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) DeleteGeoMap(ctx context.Context, geo *GeoMap, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteGeoMap(ctx context.Context, params DeleteGeoMapRequest) (*DeleteGeoMapResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteGeoMap") - if err := geo.Validate(); err != nil { - logger.Errorf("Resource validation failed. %w", err) - return nil, fmt.Errorf("GeoMap validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteGeoMap, ErrStructValidation, err) } - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, geo.Name) + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", params.DomainName, params.MapName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Delete request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeleteGeoMapResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GeoMap request failed: %w", err) @@ -179,5 +278,5 @@ func (g *gtm) DeleteGeoMap(ctx context.Context, geo *GeoMap, domainName string) return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/geomap_test.go b/pkg/gtm/geomap_test.go index 6c00645b..5c726e24 100644 --- a/pkg/gtm/geomap_test.go +++ b/pkg/gtm/geomap_test.go @@ -27,16 +27,18 @@ func TestGTM_ListGeoMap(t *testing.T) { } tests := map[string]struct { - domainName string + params ListGeoMapsRequest responseStatus int responseBody string expectedPath string - expectedResponse []*GeoMap + expectedResponse []GeoMap withError error headers http.Header }{ "200 OK": { - domainName: "example.akadns.net", + params: ListGeoMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -46,7 +48,9 @@ func TestGTM_ListGeoMap(t *testing.T) { expectedResponse: result.GeoMapItems, }, "500 internal server error": { - domainName: "example.akadns.net", + params: ListGeoMapsRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -79,7 +83,7 @@ func TestGTM_ListGeoMap(t *testing.T) { result, err := client.ListGeoMaps( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -91,7 +95,7 @@ func TestGTM_ListGeoMap(t *testing.T) { } func TestGTM_GetGeoMap(t *testing.T) { - var result GeoMap + var result GetGeoMapResponse respData, err := loadTestData("TestGTM_GetGeoMap.resp.json") if err != nil { @@ -103,18 +107,19 @@ func TestGTM_GetGeoMap(t *testing.T) { } tests := map[string]struct { - name string - domainName string + params GetGeoMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *GeoMap + expectedResponse *GetGeoMapResponse withError error headers http.Header }{ "200 OK": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetGeoMapRequest{ + MapName: "Software-rollout", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -124,8 +129,10 @@ func TestGTM_GetGeoMap(t *testing.T) { expectedResponse: &result, }, "500 internal server error": { - name: "Software-rollout", - domainName: "example.akadns.net", + params: GetGeoMapRequest{ + MapName: "Software-rollout", + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -158,7 +165,7 @@ func TestGTM_GetGeoMap(t *testing.T) { result, err := client.GetGeoMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.name, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -170,7 +177,7 @@ func TestGTM_GetGeoMap(t *testing.T) { } func TestGTM_CreateGeoMap(t *testing.T) { - var result GeoMapResponse + var result CreateGeoMapResponse var req GeoMap respData, err := loadTestData("TestGTM_CreateGeoMap.resp.json") @@ -192,29 +199,32 @@ func TestGTM_CreateGeoMap(t *testing.T) { } tests := map[string]struct { - GeoMap *GeoMap - domainName string + params CreateGeoMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *GeoMapResponse + expectedResponse *CreateGeoMapResponse withError error headers http.Header }{ "200 OK": { - GeoMap: &req, - domainName: "example.akadns.net", + params: CreateGeoMapRequest{ + GeoMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusOK, + responseStatus: http.StatusCreated, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", expectedResponse: &result, }, "500 internal server error": { - GeoMap: &req, - domainName: "example.akadns.net", + params: CreateGeoMapRequest{ + GeoMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -246,7 +256,7 @@ func TestGTM_CreateGeoMap(t *testing.T) { result, err := client.CreateGeoMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.GeoMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -258,7 +268,7 @@ func TestGTM_CreateGeoMap(t *testing.T) { } func TestGTM_UpdateGeoMap(t *testing.T) { - var result GeoMapResponse + var result UpdateGeoMapResponse var req GeoMap respData, err := loadTestData("TestGTM_CreateGeoMap.resp.json") @@ -280,29 +290,32 @@ func TestGTM_UpdateGeoMap(t *testing.T) { } tests := map[string]struct { - GeoMap *GeoMap - domainName string + params UpdateGeoMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateGeoMapResponse withError error headers http.Header }{ "200 OK": { - GeoMap: &req, - domainName: "example.akadns.net", + params: UpdateGeoMapRequest{ + GeoMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - GeoMap: &req, - domainName: "example.akadns.net", + params: UpdateGeoMapRequest{ + GeoMap: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -334,7 +347,7 @@ func TestGTM_UpdateGeoMap(t *testing.T) { result, err := client.UpdateGeoMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.GeoMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -346,7 +359,7 @@ func TestGTM_UpdateGeoMap(t *testing.T) { } func TestGTM_DeleteGeoMap(t *testing.T) { - var result GeoMapResponse + var result DeleteGeoMapResponse var req GeoMap respData, err := loadTestData("TestGTM_CreateGeoMap.resp.json") @@ -368,29 +381,32 @@ func TestGTM_DeleteGeoMap(t *testing.T) { } tests := map[string]struct { - GeoMap *GeoMap - domainName string + params DeleteGeoMapRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeleteGeoMapResponse withError error headers http.Header }{ "200 OK": { - GeoMap: &req, - domainName: "example.akadns.net", + params: DeleteGeoMapRequest{ + MapName: "UK%20Delivery", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: string(respData), expectedPath: "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", - expectedResponse: result.Status, + expectedResponse: &result, }, "500 internal server error": { - GeoMap: &req, - domainName: "example.akadns.net", + params: DeleteGeoMapRequest{ + MapName: "UK%20Delivery", + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -422,7 +438,7 @@ func TestGTM_DeleteGeoMap(t *testing.T) { result, err := client.DeleteGeoMap( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.GeoMap, test.domainName) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/gtm.go b/pkg/gtm/gtm.go index 5903788c..78f429da 100644 --- a/pkg/gtm/gtm.go +++ b/pkg/gtm/gtm.go @@ -4,21 +4,212 @@ package gtm import ( + "context" + "errors" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" ) +var ( + // ErrStructValidation is returned when given struct validation failed. + ErrStructValidation = errors.New("struct validation") +) + type ( // GTM is the gtm api interface GTM interface { - Domains - Properties - Datacenters - Resources - ASMaps - GeoMaps - CIDRMaps + // NullFieldMap retrieves map of null fields. + NullFieldMap(context.Context, *Domain) (*NullFieldMapStruct, error) + + // GetDomainStatus retrieves current status for the given domain name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-status-current + GetDomainStatus(context.Context, GetDomainStatusRequest) (*GetDomainStatusResponse, error) + + // ListDomains retrieves all Domains. + // + // See: https://techdocs.akamai.com/gtm/reference/get-domains + ListDomains(context.Context) ([]DomainItem, error) + + // GetDomain retrieves a Domain with the given domain name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-domain + GetDomain(context.Context, GetDomainRequest) (*GetDomainResponse, error) + + // CreateDomain creates domain. + // + // See: https://techdocs.akamai.com/gtm/reference/post-domain + CreateDomain(context.Context, CreateDomainRequest) (*CreateDomainResponse, error) + + // DeleteDomain is a method applied to a domain object resulting in removal. + // + // See: ** Not Supported by API ** + DeleteDomain(context.Context, DeleteDomainRequest) (*DeleteDomainResponse, error) + + // UpdateDomain is a method applied to a domain object resulting in an update. + // + // See: https://techdocs.akamai.com/gtm/reference/put-domain + UpdateDomain(context.Context, UpdateDomainRequest) (*UpdateDomainResponse, error) + + // ListProperties retrieves all Properties for the provided domainName. + // + // See: https://techdocs.akamai.com/gtm/reference/get-properties + ListProperties(context.Context, ListPropertiesRequest) ([]Property, error) + + // GetProperty retrieves a Property with the given domain and property names. + // + // See: https://techdocs.akamai.com/gtm/reference/get-property + GetProperty(context.Context, GetPropertyRequest) (*GetPropertyResponse, error) + + // CreateProperty creates property. + // + // See: https://techdocs.akamai.com/gtm/reference/put-property + CreateProperty(context.Context, CreatePropertyRequest) (*CreatePropertyResponse, error) + + // DeleteProperty is a method applied to a property object resulting in removal. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-property + DeleteProperty(context.Context, DeletePropertyRequest) (*DeletePropertyResponse, error) + + // UpdateProperty is a method applied to a property object resulting in an update. + // + // See: https://techdocs.akamai.com/gtm/reference/put-property + UpdateProperty(context.Context, UpdatePropertyRequest) (*UpdatePropertyResponse, error) + + // ListDatacenters retrieves all Datacenters. + // + // See: https://techdocs.akamai.com/gtm/reference/get-datacenters + ListDatacenters(context.Context, ListDatacentersRequest) ([]Datacenter, error) + + // GetDatacenter retrieves a Datacenter with the given name. NOTE: Id arg is int! + // + // See: https://techdocs.akamai.com/gtm/reference/get-datacenter + GetDatacenter(context.Context, GetDatacenterRequest) (*Datacenter, error) + + // CreateDatacenter creates the datacenter identified by the receiver argument in the specified domain. + // + // See: https://techdocs.akamai.com/gtm/reference/post-datacenter + CreateDatacenter(context.Context, CreateDatacenterRequest) (*CreateDatacenterResponse, error) + + // DeleteDatacenter deletes the datacenter identified by the receiver argument from the domain specified. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-datacenter + DeleteDatacenter(context.Context, DeleteDatacenterRequest) (*DeleteDatacenterResponse, error) + + // UpdateDatacenter updates the datacenter identified in the receiver argument in the provided domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-datacenter + UpdateDatacenter(context.Context, UpdateDatacenterRequest) (*UpdateDatacenterResponse, error) + + // CreateMapsDefaultDatacenter creates Default Datacenter for Maps. + CreateMapsDefaultDatacenter(context.Context, string) (*Datacenter, error) + + // CreateIPv4DefaultDatacenter creates Default Datacenter for IPv4 Selector. + CreateIPv4DefaultDatacenter(context.Context, string) (*Datacenter, error) + + // CreateIPv6DefaultDatacenter creates Default Datacenter for IPv6 Selector. + CreateIPv6DefaultDatacenter(context.Context, string) (*Datacenter, error) + + // ListResources retrieves all Resources + // + // See: https://techdocs.akamai.com/gtm/reference/get-resources + ListResources(context.Context, ListResourcesRequest) ([]Resource, error) + + // GetResource retrieves a Resource with the given name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-resource + GetResource(context.Context, GetResourceRequest) (*GetResourceResponse, error) + + // CreateResource creates the datacenter identified by the receiver argument in the specified domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-resource + CreateResource(context.Context, CreateResourceRequest) (*CreateResourceResponse, error) + + // DeleteResource deletes the datacenter identified by the receiver argument from the domain specified. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-resource + DeleteResource(context.Context, DeleteResourceRequest) (*DeleteResourceResponse, error) + + // UpdateResource updates the datacenter identified in the receiver argument in the provided domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-resource + UpdateResource(context.Context, UpdateResourceRequest) (*UpdateResourceResponse, error) + + // ListASMaps retrieves all AsMaps. + // + // See: https://techdocs.akamai.com/gtm/reference/get-as-maps + ListASMaps(context.Context, ListASMapsRequest) ([]ASMap, error) + + // GetASMap retrieves a AsMap with the given name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-as-map + GetASMap(context.Context, GetASMapRequest) (*GetASMapResponse, error) + + // CreateASMap creates the datacenter identified by the receiver argument in the specified domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-as-map + CreateASMap(context.Context, CreateASMapRequest) (*CreateASMapResponse, error) + + // DeleteASMap deletes the datacenter identified by the receiver argument from the domain specified. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-as-map + DeleteASMap(context.Context, DeleteASMapRequest) (*DeleteASMapResponse, error) + + // UpdateASMap updates the datacenter identified in the receiver argument in the provided domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-as-map + UpdateASMap(context.Context, UpdateASMapRequest) (*UpdateASMapResponse, error) + + // ListGeoMaps retrieves all GeoMaps. + // + // See: https://techdocs.akamai.com/gtm/reference/get-geographic-maps + ListGeoMaps(context.Context, ListGeoMapsRequest) ([]GeoMap, error) + + // GetGeoMap retrieves a GeoMap with the given name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-geographic-map + GetGeoMap(context.Context, GetGeoMapRequest) (*GetGeoMapResponse, error) + + // CreateGeoMap creates the datacenter identified by the receiver argument in the specified domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-geographic-map + CreateGeoMap(context.Context, CreateGeoMapRequest) (*CreateGeoMapResponse, error) + + // DeleteGeoMap deletes the datacenter identified by the receiver argument from the domain specified. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-geographic-map + DeleteGeoMap(context.Context, DeleteGeoMapRequest) (*DeleteGeoMapResponse, error) + + // UpdateGeoMap updates the datacenter identified in the receiver argument in the provided domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-geographic-map + UpdateGeoMap(context.Context, UpdateGeoMapRequest) (*UpdateGeoMapResponse, error) + + // ListCIDRMaps retrieves all CIDRMaps. + // + // See: https://techdocs.akamai.com/gtm/reference/get-cidr-maps + ListCIDRMaps(context.Context, ListCIDRMapsRequest) ([]CIDRMap, error) + + // GetCIDRMap retrieves a CIDRMap with the given name. + // + // See: https://techdocs.akamai.com/gtm/reference/get-cidr-map + GetCIDRMap(context.Context, GetCIDRMapRequest) (*GetCIDRMapResponse, error) + + // CreateCIDRMap creates the datacenter identified by the receiver argument in the specified domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-cidr-map + CreateCIDRMap(context.Context, CreateCIDRMapRequest) (*CreateCIDRMapResponse, error) + + // DeleteCIDRMap deletes the datacenter identified by the receiver argument from the domain specified. + // + // See: https://techdocs.akamai.com/gtm/reference/delete-cidr-maps + DeleteCIDRMap(context.Context, DeleteCIDRMapRequest) (*DeleteCIDRMapResponse, error) + + // UpdateCIDRMap updates the datacenter identified in the receiver argument in the provided domain. + // + // See: https://techdocs.akamai.com/gtm/reference/put-cidr-map + UpdateCIDRMap(context.Context, UpdateCIDRMapRequest) (*UpdateCIDRMapResponse, error) } gtm struct { diff --git a/pkg/gtm/mocks.go b/pkg/gtm/mocks.go index c9ecbd66..88756aaf 100644 --- a/pkg/gtm/mocks.go +++ b/pkg/gtm/mocks.go @@ -24,118 +24,118 @@ func (p *Mock) NullFieldMap(ctx context.Context, domain *Domain) (*NullFieldMapS return args.Get(0).(*NullFieldMapStruct), args.Error(1) } -func (p *Mock) GetDomainStatus(ctx context.Context, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, domain) +func (p *Mock) GetDomainStatus(ctx context.Context, req GetDomainStatusRequest) (*GetDomainStatusResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*GetDomainStatusResponse), args.Error(1) } -func (p *Mock) ListDomains(ctx context.Context) ([]*DomainItem, error) { +func (p *Mock) ListDomains(ctx context.Context) ([]DomainItem, error) { args := p.Called(ctx) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*DomainItem), args.Error(1) + return args.Get(0).([]DomainItem), args.Error(1) } -func (p *Mock) GetDomain(ctx context.Context, domain string) (*Domain, error) { - args := p.Called(ctx, domain) +func (p *Mock) GetDomain(ctx context.Context, req GetDomainRequest) (*GetDomainResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*Domain), args.Error(1) + return args.Get(0).(*GetDomainResponse), args.Error(1) } -func (p *Mock) CreateDomain(ctx context.Context, domain *Domain, queryArgs map[string]string) (*DomainResponse, error) { - args := p.Called(ctx, domain, queryArgs) +func (p *Mock) CreateDomain(ctx context.Context, req CreateDomainRequest) (*CreateDomainResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*DomainResponse), args.Error(1) + return args.Get(0).(*CreateDomainResponse), args.Error(1) } -func (p *Mock) DeleteDomain(ctx context.Context, domain *Domain) (*ResponseStatus, error) { - args := p.Called(ctx, domain) +func (p *Mock) DeleteDomain(ctx context.Context, req DeleteDomainRequest) (*DeleteDomainResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteDomainResponse), args.Error(1) } -func (p *Mock) UpdateDomain(ctx context.Context, domain *Domain, queryArgs map[string]string) (*ResponseStatus, error) { - args := p.Called(ctx, domain, queryArgs) +func (p *Mock) UpdateDomain(ctx context.Context, req UpdateDomainRequest) (*UpdateDomainResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateDomainResponse), args.Error(1) } -func (p *Mock) GetProperty(ctx context.Context, prop string, domain string) (*Property, error) { - args := p.Called(ctx, prop, domain) +func (p *Mock) GetProperty(ctx context.Context, req GetPropertyRequest) (*GetPropertyResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*Property), args.Error(1) + return args.Get(0).(*GetPropertyResponse), args.Error(1) } -func (p *Mock) DeleteProperty(ctx context.Context, prop *Property, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, prop, domain) +func (p *Mock) DeleteProperty(ctx context.Context, req DeletePropertyRequest) (*DeletePropertyResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeletePropertyResponse), args.Error(1) } -func (p *Mock) CreateProperty(ctx context.Context, prop *Property, domain string) (*PropertyResponse, error) { - args := p.Called(ctx, prop, domain) +func (p *Mock) CreateProperty(ctx context.Context, req CreatePropertyRequest) (*CreatePropertyResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*PropertyResponse), args.Error(1) + return args.Get(0).(*CreatePropertyResponse), args.Error(1) } -func (p *Mock) UpdateProperty(ctx context.Context, prop *Property, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, prop, domain) +func (p *Mock) UpdateProperty(ctx context.Context, req UpdatePropertyRequest) (*UpdatePropertyResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdatePropertyResponse), args.Error(1) } -func (p *Mock) ListProperties(ctx context.Context, domain string) ([]*Property, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListProperties(ctx context.Context, req ListPropertiesRequest) ([]Property, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*Property), args.Error(1) + return args.Get(0).([]Property), args.Error(1) } -func (p *Mock) GetDatacenter(ctx context.Context, dcID int, domain string) (*Datacenter, error) { - args := p.Called(ctx, dcID, domain) +func (p *Mock) GetDatacenter(ctx context.Context, req GetDatacenterRequest) (*Datacenter, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) @@ -144,44 +144,44 @@ func (p *Mock) GetDatacenter(ctx context.Context, dcID int, domain string) (*Dat return args.Get(0).(*Datacenter), args.Error(1) } -func (p *Mock) CreateDatacenter(ctx context.Context, dc *Datacenter, domain string) (*DatacenterResponse, error) { - args := p.Called(ctx, dc, domain) +func (p *Mock) CreateDatacenter(ctx context.Context, req CreateDatacenterRequest) (*CreateDatacenterResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*DatacenterResponse), args.Error(1) + return args.Get(0).(*CreateDatacenterResponse), args.Error(1) } -func (p *Mock) DeleteDatacenter(ctx context.Context, dc *Datacenter, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, dc, domain) +func (p *Mock) DeleteDatacenter(ctx context.Context, req DeleteDatacenterRequest) (*DeleteDatacenterResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteDatacenterResponse), args.Error(1) } -func (p *Mock) UpdateDatacenter(ctx context.Context, dc *Datacenter, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, dc, domain) +func (p *Mock) UpdateDatacenter(ctx context.Context, req UpdateDatacenterRequest) (*UpdateDatacenterResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateDatacenterResponse), args.Error(1) } -func (p *Mock) ListDatacenters(ctx context.Context, domain string) ([]*Datacenter, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListDatacenters(ctx context.Context, req ListDatacentersRequest) ([]Datacenter, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*Datacenter), args.Error(1) + return args.Get(0).([]Datacenter), args.Error(1) } func (p *Mock) CreateIPv4DefaultDatacenter(ctx context.Context, domain string) (*Datacenter, error) { @@ -214,203 +214,202 @@ func (p *Mock) CreateMapsDefaultDatacenter(ctx context.Context, domainName strin return args.Get(0).(*Datacenter), args.Error(1) } -func (p *Mock) GetResource(ctx context.Context, resource string, domain string) (*Resource, error) { - args := p.Called(ctx, resource, domain) +func (p *Mock) GetResource(ctx context.Context, req GetResourceRequest) (*GetResourceResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*Resource), args.Error(1) + return args.Get(0).(*GetResourceResponse), args.Error(1) } -func (p *Mock) CreateResource(ctx context.Context, resource *Resource, domain string) (*ResourceResponse, error) { - args := p.Called(ctx, resource, domain) +func (p *Mock) CreateResource(ctx context.Context, req CreateResourceRequest) (*CreateResourceResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResourceResponse), args.Error(1) + return args.Get(0).(*CreateResourceResponse), args.Error(1) } -func (p *Mock) DeleteResource(ctx context.Context, resource *Resource, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, resource, domain) +func (p *Mock) DeleteResource(ctx context.Context, req DeleteResourceRequest) (*DeleteResourceResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteResourceResponse), args.Error(1) } -func (p *Mock) UpdateResource(ctx context.Context, resource *Resource, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, resource, domain) +func (p *Mock) UpdateResource(ctx context.Context, req UpdateResourceRequest) (*UpdateResourceResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateResourceResponse), args.Error(1) } -func (p *Mock) ListResources(ctx context.Context, domain string) ([]*Resource, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListResources(ctx context.Context, req ListResourcesRequest) ([]Resource, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*Resource), args.Error(1) + return args.Get(0).([]Resource), args.Error(1) } -func (p *Mock) GetASMap(ctx context.Context, asMap string, domain string) (*ASMap, error) { - args := p.Called(ctx, asMap, domain) +func (p *Mock) GetASMap(ctx context.Context, req GetASMapRequest) (*GetASMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ASMap), args.Error(1) + return args.Get(0).(*GetASMapResponse), args.Error(1) } -func (p *Mock) CreateASMap(ctx context.Context, asMap *ASMap, domain string) (*ASMapResponse, error) { - args := p.Called(ctx, asMap, domain) +func (p *Mock) CreateASMap(ctx context.Context, req CreateASMapRequest) (*CreateASMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ASMapResponse), args.Error(1) + return args.Get(0).(*CreateASMapResponse), args.Error(1) } -func (p *Mock) DeleteASMap(ctx context.Context, asMap *ASMap, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, asMap, domain) +func (p *Mock) DeleteASMap(ctx context.Context, req DeleteASMapRequest) (*DeleteASMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteASMapResponse), args.Error(1) } -func (p *Mock) UpdateASMap(ctx context.Context, asMap *ASMap, domain string) (*ResponseStatus, error) { - - args := p.Called(ctx, asMap, domain) +func (p *Mock) UpdateASMap(ctx context.Context, req UpdateASMapRequest) (*UpdateASMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateASMapResponse), args.Error(1) } -func (p *Mock) ListASMaps(ctx context.Context, domain string) ([]*ASMap, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListASMaps(ctx context.Context, req ListASMapsRequest) ([]ASMap, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*ASMap), args.Error(1) + return args.Get(0).([]ASMap), args.Error(1) } -func (p *Mock) GetGeoMap(ctx context.Context, geo string, domain string) (*GeoMap, error) { - args := p.Called(ctx, geo, domain) +func (p *Mock) GetGeoMap(ctx context.Context, req GetGeoMapRequest) (*GetGeoMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*GeoMap), args.Error(1) + return args.Get(0).(*GetGeoMapResponse), args.Error(1) } -func (p *Mock) CreateGeoMap(ctx context.Context, geo *GeoMap, domain string) (*GeoMapResponse, error) { - args := p.Called(ctx, geo, domain) +func (p *Mock) CreateGeoMap(ctx context.Context, req CreateGeoMapRequest) (*CreateGeoMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*GeoMapResponse), args.Error(1) + return args.Get(0).(*CreateGeoMapResponse), args.Error(1) } -func (p *Mock) DeleteGeoMap(ctx context.Context, geo *GeoMap, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, geo, domain) +func (p *Mock) DeleteGeoMap(ctx context.Context, req DeleteGeoMapRequest) (*DeleteGeoMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteGeoMapResponse), args.Error(1) } -func (p *Mock) UpdateGeoMap(ctx context.Context, geo *GeoMap, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, geo, domain) +func (p *Mock) UpdateGeoMap(ctx context.Context, req UpdateGeoMapRequest) (*UpdateGeoMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateGeoMapResponse), args.Error(1) } -func (p *Mock) ListGeoMaps(ctx context.Context, domain string) ([]*GeoMap, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListGeoMaps(ctx context.Context, req ListGeoMapsRequest) ([]GeoMap, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*GeoMap), args.Error(1) + return args.Get(0).([]GeoMap), args.Error(1) } -func (p *Mock) GetCIDRMap(ctx context.Context, cidr string, domain string) (*CIDRMap, error) { - args := p.Called(ctx, cidr, domain) +func (p *Mock) GetCIDRMap(ctx context.Context, req GetCIDRMapRequest) (*GetCIDRMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*CIDRMap), args.Error(1) + return args.Get(0).(*GetCIDRMapResponse), args.Error(1) } -func (p *Mock) CreateCIDRMap(ctx context.Context, cidr *CIDRMap, domain string) (*CIDRMapResponse, error) { - args := p.Called(ctx, cidr, domain) +func (p *Mock) CreateCIDRMap(ctx context.Context, req CreateCIDRMapRequest) (*CreateCIDRMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*CIDRMapResponse), args.Error(1) + return args.Get(0).(*CreateCIDRMapResponse), args.Error(1) } -func (p *Mock) DeleteCIDRMap(ctx context.Context, cidr *CIDRMap, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, cidr, domain) +func (p *Mock) DeleteCIDRMap(ctx context.Context, req DeleteCIDRMapRequest) (*DeleteCIDRMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*DeleteCIDRMapResponse), args.Error(1) } -func (p *Mock) UpdateCIDRMap(ctx context.Context, cidr *CIDRMap, domain string) (*ResponseStatus, error) { - args := p.Called(ctx, cidr, domain) +func (p *Mock) UpdateCIDRMap(ctx context.Context, req UpdateCIDRMapRequest) (*UpdateCIDRMapResponse, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ResponseStatus), args.Error(1) + return args.Get(0).(*UpdateCIDRMapResponse), args.Error(1) } -func (p *Mock) ListCIDRMaps(ctx context.Context, domain string) ([]*CIDRMap, error) { - args := p.Called(ctx, domain) +func (p *Mock) ListCIDRMaps(ctx context.Context, req ListCIDRMapsRequest) ([]CIDRMap, error) { + args := p.Called(ctx, req) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).([]*CIDRMap), args.Error(1) + return args.Get(0).([]CIDRMap), args.Error(1) } diff --git a/pkg/gtm/property.go b/pkg/gtm/property.go index 86bb5322..6afb6e5d 100644 --- a/pkg/gtm/property.go +++ b/pkg/gtm/property.go @@ -2,6 +2,7 @@ package gtm import ( "context" + "errors" "fmt" "net/http" @@ -9,128 +10,207 @@ import ( validation "github.com/go-ozzo/ozzo-validation/v4" ) -// Properties contains operations available on a Property resource. -type Properties interface { - // ListProperties retrieves all Properties for the provided domainName. - // - // See: https://techdocs.akamai.com/gtm/reference/get-properties - ListProperties(context.Context, string) ([]*Property, error) - // GetProperty retrieves a Property with the given domain and property names. - // - // See: https://techdocs.akamai.com/gtm/reference/get-property - GetProperty(context.Context, string, string) (*Property, error) - // CreateProperty creates property. - // - // See: https://techdocs.akamai.com/gtm/reference/put-property - CreateProperty(context.Context, *Property, string) (*PropertyResponse, error) - // DeleteProperty is a method applied to a property object resulting in removal. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-property - DeleteProperty(context.Context, *Property, string) (*ResponseStatus, error) - // UpdateProperty is a method applied to a property object resulting in an update. - // - // See: https://techdocs.akamai.com/gtm/reference/put-property - UpdateProperty(context.Context, *Property, string) (*ResponseStatus, error) -} +type ( + // TrafficTarget struct contains information about where to direct data center traffic + TrafficTarget struct { + DatacenterID int `json:"datacenterId"` + Enabled bool `json:"enabled"` + Weight float64 `json:"weight,omitempty"` + Servers []string `json:"servers,omitempty"` + Name string `json:"name,omitempty"` + HandoutCName string `json:"handoutCName,omitempty"` + Precedence *int `json:"precedence,omitempty"` + } -// TrafficTarget struct contains information about where to direct data center traffic -type TrafficTarget struct { - DatacenterID int `json:"datacenterId"` - Enabled bool `json:"enabled"` - Weight float64 `json:"weight,omitempty"` - Servers []string `json:"servers,omitempty"` - Name string `json:"name,omitempty"` - HandoutCName string `json:"handoutCName,omitempty"` - Precedence *int `json:"precedence,omitempty"` -} + // HTTPHeader struct contains HTTP headers to send if the testObjectProtocol is http or https + HTTPHeader struct { + Name string `json:"name"` + Value string `json:"value"` + } + + // LivenessTest contains configuration of liveness tests to determine whether your servers respond to requests + LivenessTest struct { + Name string `json:"name"` + ErrorPenalty float64 `json:"errorPenalty,omitempty"` + PeerCertificateVerification bool `json:"peerCertificateVerification"` + TestInterval int `json:"testInterval,omitempty"` + TestObject string `json:"testObject,omitempty"` + Links []Link `json:"links,omitempty"` + RequestString string `json:"requestString,omitempty"` + ResponseString string `json:"responseString,omitempty"` + HTTPError3xx bool `json:"httpError3xx"` + HTTPError4xx bool `json:"httpError4xx"` + HTTPError5xx bool `json:"httpError5xx"` + HTTPMethod *string `json:"httpMethod"` + HTTPRequestBody *string `json:"httpRequestBody"` + Disabled bool `json:"disabled"` + TestObjectProtocol string `json:"testObjectProtocol,omitempty"` + TestObjectPassword string `json:"testObjectPassword,omitempty"` + TestObjectPort int `json:"testObjectPort,omitempty"` + SSLClientPrivateKey string `json:"sslClientPrivateKey,omitempty"` + SSLClientCertificate string `json:"sslClientCertificate,omitempty"` + Pre2023SecurityPosture bool `json:"pre2023SecurityPosture"` + DisableNonstandardPortWarning bool `json:"disableNonstandardPortWarning"` + HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"` + TestObjectUsername string `json:"testObjectUsername,omitempty"` + TestTimeout float32 `json:"testTimeout,omitempty"` + TimeoutPenalty float64 `json:"timeoutPenalty,omitempty"` + AnswersRequired bool `json:"answersRequired"` + ResourceType string `json:"resourceType,omitempty"` + RecursionRequested bool `json:"recursionRequested"` + AlternateCACertificates []string `json:"alternateCACertificates"` + } + + // StaticRRSet contains static recordset + StaticRRSet struct { + Type string `json:"type"` + TTL int `json:"ttl"` + Rdata []string `json:"rdata"` + } + + // Property represents a GTM property + Property struct { + Name string `json:"name"` + Type string `json:"type"` + IPv6 bool `json:"ipv6"` + ScoreAggregationType string `json:"scoreAggregationType"` + StickinessBonusPercentage int `json:"stickinessBonusPercentage,omitempty"` + StickinessBonusConstant int `json:"stickinessBonusConstant,omitempty"` + HealthThreshold float64 `json:"healthThreshold,omitempty"` + UseComputedTargets bool `json:"useComputedTargets"` + BackupIP string `json:"backupIp,omitempty"` + BalanceByDownloadScore bool `json:"balanceByDownloadScore"` + StaticTTL int `json:"staticTTL,omitempty"` + StaticRRSets []StaticRRSet `json:"staticRRSets,omitempty"` + LastModified string `json:"lastModified"` + UnreachableThreshold float64 `json:"unreachableThreshold,omitempty"` + MinLiveFraction float64 `json:"minLiveFraction,omitempty"` + HealthMultiplier float64 `json:"healthMultiplier,omitempty"` + DynamicTTL int `json:"dynamicTTL,omitempty"` + MaxUnreachablePenalty int `json:"maxUnreachablePenalty,omitempty"` + MapName string `json:"mapName,omitempty"` + HandoutLimit int `json:"handoutLimit"` + HandoutMode string `json:"handoutMode"` + FailoverDelay int `json:"failoverDelay,omitempty"` + BackupCName string `json:"backupCName,omitempty"` + FailbackDelay int `json:"failbackDelay,omitempty"` + LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` + HealthMax float64 `json:"healthMax,omitempty"` + GhostDemandReporting bool `json:"ghostDemandReporting"` + Comments string `json:"comments,omitempty"` + CName string `json:"cname,omitempty"` + WeightedHashBitsForIPv4 int `json:"weightedHashBitsForIPv4,omitempty"` + WeightedHashBitsForIPv6 int `json:"weightedHashBitsForIPv6,omitempty"` + TrafficTargets []TrafficTarget `json:"trafficTargets,omitempty"` + Links []Link `json:"links,omitempty"` + LivenessTests []LivenessTest `json:"livenessTests,omitempty"` + } + + // PropertyRequest contains request parameters + PropertyRequest struct { + Property *Property + DomainName string + } + + // PropertyList contains a list of property items + PropertyList struct { + PropertyItems []Property `json:"items"` + } + // GetPropertyRequest contains request parameters for GetProperty + GetPropertyRequest struct { + DomainName string + PropertyName string + } + + // GetPropertyResponse contains the response data from GetProperty operation + GetPropertyResponse Property -// HTTPHeader struct contains HTTP headers to send if the testObjectProtocol is http or https -type HTTPHeader struct { - Name string `json:"name"` - Value string `json:"value"` + // ListPropertiesRequest contains request parameters for ListProperties + ListPropertiesRequest struct { + DomainName string + } + + // CreatePropertyRequest contains request parameters for CreateProperty + CreatePropertyRequest PropertyRequest + + // CreatePropertyResponse contains the response data from CreateProperty operation + CreatePropertyResponse struct { + Resource *Property `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdatePropertyRequest contains request parameters for UpdatePropertyResponse + UpdatePropertyRequest PropertyRequest + + // UpdatePropertyResponse contains the response data from UpdatePropertyResponse operation + UpdatePropertyResponse struct { + Resource *Property `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeletePropertyRequest contains request parameters for DeleteProperty + DeletePropertyRequest struct { + DomainName string + PropertyName string + } + + // DeletePropertyResponse contains the response data from DeleteProperty operation + DeletePropertyResponse struct { + Resource *Property `json:"resource"` + Status *ResponseStatus `json:"status"` + } +) + +var ( + // ErrGetProperty is returned when GetProperty fails. + ErrGetProperty = errors.New("get property") + // ErrListProperties is returned when ListProperties fails. + ErrListProperties = errors.New("list properties") + // ErrCreateProperty is returned when CreateProperty fails. + ErrCreateProperty = errors.New("create Property") + // ErrUpdateProperty is returned when UpdateProperty fails + ErrUpdateProperty = errors.New("update Property") + // ErrDeleteProperty is returned when DeleteProperty fails + ErrDeleteProperty = errors.New("delete Property") +) + +// Validate validates GetPropertyRequest +func (r GetPropertyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "PropertyName": validation.Validate(r.PropertyName, validation.Required), + }) } -// LivenessTest contains configuration of liveness tests to determine whether your servers respond to requests -type LivenessTest struct { - Name string `json:"name"` - ErrorPenalty float64 `json:"errorPenalty,omitempty"` - PeerCertificateVerification bool `json:"peerCertificateVerification"` - TestInterval int `json:"testInterval,omitempty"` - TestObject string `json:"testObject,omitempty"` - Links []*Link `json:"links,omitempty"` - RequestString string `json:"requestString,omitempty"` - ResponseString string `json:"responseString,omitempty"` - HTTPError3xx bool `json:"httpError3xx"` - HTTPError4xx bool `json:"httpError4xx"` - HTTPError5xx bool `json:"httpError5xx"` - HTTPMethod *string `json:"httpMethod"` - HTTPRequestBody *string `json:"httpRequestBody"` - Disabled bool `json:"disabled"` - TestObjectProtocol string `json:"testObjectProtocol,omitempty"` - TestObjectPassword string `json:"testObjectPassword,omitempty"` - TestObjectPort int `json:"testObjectPort,omitempty"` - SSLClientPrivateKey string `json:"sslClientPrivateKey,omitempty"` - SSLClientCertificate string `json:"sslClientCertificate,omitempty"` - Pre2023SecurityPosture bool `json:"pre2023SecurityPosture"` - DisableNonstandardPortWarning bool `json:"disableNonstandardPortWarning"` - HTTPHeaders []*HTTPHeader `json:"httpHeaders,omitempty"` - TestObjectUsername string `json:"testObjectUsername,omitempty"` - TestTimeout float32 `json:"testTimeout,omitempty"` - TimeoutPenalty float64 `json:"timeoutPenalty,omitempty"` - AnswersRequired bool `json:"answersRequired"` - ResourceType string `json:"resourceType,omitempty"` - RecursionRequested bool `json:"recursionRequested"` - AlternateCACertificates []string `json:"alternateCACertificates"` +// Validate validates ListPropertiesRequest +func (r ListPropertiesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) } -// StaticRRSet contains static recordset -type StaticRRSet struct { - Type string `json:"type"` - TTL int `json:"ttl"` - Rdata []string `json:"rdata"` +// Validate validates CreatePropertyRequest +func (r CreatePropertyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Property": validation.Validate(r.Property, validation.Required), + }) } -// Property represents a GTM property -type Property struct { - Name string `json:"name"` - Type string `json:"type"` - IPv6 bool `json:"ipv6"` - ScoreAggregationType string `json:"scoreAggregationType"` - StickinessBonusPercentage int `json:"stickinessBonusPercentage,omitempty"` - StickinessBonusConstant int `json:"stickinessBonusConstant,omitempty"` - HealthThreshold float64 `json:"healthThreshold,omitempty"` - UseComputedTargets bool `json:"useComputedTargets"` - BackupIP string `json:"backupIp,omitempty"` - BalanceByDownloadScore bool `json:"balanceByDownloadScore"` - StaticTTL int `json:"staticTTL,omitempty"` - StaticRRSets []*StaticRRSet `json:"staticRRSets,omitempty"` - LastModified string `json:"lastModified"` - UnreachableThreshold float64 `json:"unreachableThreshold,omitempty"` - MinLiveFraction float64 `json:"minLiveFraction,omitempty"` - HealthMultiplier float64 `json:"healthMultiplier,omitempty"` - DynamicTTL int `json:"dynamicTTL,omitempty"` - MaxUnreachablePenalty int `json:"maxUnreachablePenalty,omitempty"` - MapName string `json:"mapName,omitempty"` - HandoutLimit int `json:"handoutLimit"` - HandoutMode string `json:"handoutMode"` - FailoverDelay int `json:"failoverDelay,omitempty"` - BackupCName string `json:"backupCName,omitempty"` - FailbackDelay int `json:"failbackDelay,omitempty"` - LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` - HealthMax float64 `json:"healthMax,omitempty"` - GhostDemandReporting bool `json:"ghostDemandReporting"` - Comments string `json:"comments,omitempty"` - CName string `json:"cname,omitempty"` - WeightedHashBitsForIPv4 int `json:"weightedHashBitsForIPv4,omitempty"` - WeightedHashBitsForIPv6 int `json:"weightedHashBitsForIPv6,omitempty"` - TrafficTargets []*TrafficTarget `json:"trafficTargets,omitempty"` - Links []*Link `json:"links,omitempty"` - LivenessTests []*LivenessTest `json:"livenessTests,omitempty"` +// Validate validates UpdatePropertyRequest +func (r UpdatePropertyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Property": validation.Validate(r.Property, validation.Required), + }) } -// PropertyList contains a list of property items -type PropertyList struct { - PropertyItems []*Property `json:"items"` +// Validate validates DeletePropertyRequest +func (r DeletePropertyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "PropertyName": validation.Validate(r.PropertyName, validation.Required), + }) } // Validate validates Property @@ -146,7 +226,7 @@ func (p *Property) Validate() error { // validateRankedFailoverTrafficTargets validates traffic targets when property type is 'ranked-failover' func validateRankedFailoverTrafficTargets(value interface{}) error { - tt := value.([]*TrafficTarget) + tt := value.([]TrafficTarget) if len(tt) == 0 { return fmt.Errorf("no traffic targets are enabled") } @@ -173,11 +253,15 @@ func validateRankedFailoverTrafficTargets(value interface{}) error { return nil } -func (g *gtm) ListProperties(ctx context.Context, domainName string) ([]*Property, error) { +func (g *gtm) ListProperties(ctx context.Context, params ListPropertiesRequest) ([]Property, error) { logger := g.Log(ctx) logger.Debug("ListProperties") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListProperties, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListProperties request: %w", err) @@ -197,18 +281,22 @@ func (g *gtm) ListProperties(ctx context.Context, domainName string) ([]*Propert return result.PropertyItems, nil } -func (g *gtm) GetProperty(ctx context.Context, propertyName, domainName string) (*Property, error) { +func (g *gtm) GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) { logger := g.Log(ctx) logger.Debug("GetProperty") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, propertyName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetProperty, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", params.DomainName, params.PropertyName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetProperty request: %w", err) } setVersionHeader(req, schemaVersion) - var result Property + var result GetPropertyResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetProperty request failed: %w", err) @@ -221,67 +309,78 @@ func (g *gtm) GetProperty(ctx context.Context, propertyName, domainName string) return &result, nil } -func (g *gtm) CreateProperty(ctx context.Context, property *Property, domainName string) (*PropertyResponse, error) { +func (g *gtm) CreateProperty(ctx context.Context, params CreatePropertyRequest) (*CreatePropertyResponse, error) { logger := g.Log(ctx) logger.Debug("CreateProperty") - return property.save(ctx, g, domainName) -} + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateProperty, ErrStructValidation, err) + } -func (g *gtm) UpdateProperty(ctx context.Context, property *Property, domainName string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateProperty") + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", params.DomainName, params.Property.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create Property request: %w", err) + } + setVersionHeader(req, schemaVersion) - stat, err := property.save(ctx, g, domainName) + var result CreatePropertyResponse + resp, err := g.Exec(req, &result, params.Property) if err != nil { - return nil, err + return nil, fmt.Errorf("property request failed: %w", err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, g.Error(resp) } - return stat.Status, err + + return &result, nil } -// Save Property updates method -func (p *Property) save(ctx context.Context, g *gtm, domainName string) (*PropertyResponse, error) { +func (g *gtm) UpdateProperty(ctx context.Context, params UpdatePropertyRequest) (*UpdatePropertyResponse, error) { + logger := g.Log(ctx) + logger.Debug("UpdateProperty") - if err := p.Validate(); err != nil { - return nil, fmt.Errorf("property validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateProperty, ErrStructValidation, err) } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, p.Name) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", params.DomainName, params.Property.Name) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Property request: %w", err) } setVersionHeader(req, schemaVersion) - var result PropertyResponse - resp, err := g.Exec(req, &result, p) + var result UpdatePropertyResponse + resp, err := g.Exec(req, &result, params.Property) if err != nil { return nil, fmt.Errorf("property request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusOK { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) DeleteProperty(ctx context.Context, property *Property, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteProperty(ctx context.Context, params DeletePropertyRequest) (*DeletePropertyResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteProperty") - if err := property.Validate(); err != nil { - return nil, fmt.Errorf("DeleteProperty validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteProperty, ErrStructValidation, err) } - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, property.Name) + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", params.DomainName, params.PropertyName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Property request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeletePropertyResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("DeleteProperty request failed: %w", err) @@ -291,5 +390,5 @@ func (g *gtm) DeleteProperty(ctx context.Context, property *Property, domainName return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/property_test.go b/pkg/gtm/property_test.go index 90e7beeb..dc9c0b41 100644 --- a/pkg/gtm/property_test.go +++ b/pkg/gtm/property_test.go @@ -28,16 +28,18 @@ func TestGTM_ListProperties(t *testing.T) { } tests := map[string]struct { - domain string + params ListPropertiesRequest responseStatus int responseBody string expectedPath string - expectedResponse []*Property + expectedResponse []Property withError error headers http.Header }{ "200 OK": { - domain: "example.akadns.net", + params: ListPropertiesRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -47,7 +49,9 @@ func TestGTM_ListProperties(t *testing.T) { expectedResponse: result.PropertyItems, }, "500 internal server error": { - domain: "example.akadns.net", + params: ListPropertiesRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -80,7 +84,7 @@ func TestGTM_ListProperties(t *testing.T) { result, err := client.ListProperties( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -92,7 +96,7 @@ func TestGTM_ListProperties(t *testing.T) { } func TestGTM_GetProperty(t *testing.T) { - var result Property + var result GetPropertyResponse respData, err := loadTestData("TestGTM_GetProperty.resp.json") if err != nil { @@ -104,25 +108,28 @@ func TestGTM_GetProperty(t *testing.T) { } tests := map[string]struct { - name string - domain string + params GetPropertyRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *Property + expectedResponse *GetPropertyResponse withError error }{ "200 OK": { - name: "www", - domain: "example.akadns.net", + params: GetPropertyRequest{ + PropertyName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusOK, responseBody: respData, expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/www", expectedResponse: &result, }, "500 internal server error": { - name: "www", - domain: "example.akadns.net", + params: GetPropertyRequest{ + PropertyName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -150,7 +157,7 @@ func TestGTM_GetProperty(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetProperty(context.Background(), test.name, test.domain) + result, err := client.GetProperty(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -163,57 +170,58 @@ func TestGTM_GetProperty(t *testing.T) { func TestGTM_CreateProperty(t *testing.T) { tests := map[string]struct { - domain string - property *Property + params CreatePropertyRequest responseStatus int responseBody string expectedPath string - expectedResponse *PropertyResponse + expectedResponse *CreatePropertyResponse withError bool assertError func(*testing.T, error) headers http.Header }{ "201 Created": { - property: &Property{ - BalanceByDownloadScore: false, - HandoutMode: "normal", - IPv6: false, - Name: "origin", - ScoreAggregationType: "mean", - StaticTTL: 600, - Type: "weighted-round-robin", - UseComputedTargets: false, - LivenessTests: []*LivenessTest{ - { - DisableNonstandardPortWarning: false, - HTTPError3xx: true, - HTTPError4xx: true, - HTTPError5xx: true, - Name: "health-check", - TestInterval: 60, - TestObject: "/status", - TestObjectPort: 80, - TestObjectProtocol: "HTTP", - TestTimeout: 25.0, - }, - }, - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 3134, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.5"}, + params: CreatePropertyRequest{ + Property: &Property{ + BalanceByDownloadScore: false, + HandoutMode: "normal", + IPv6: false, + Name: "origin", + ScoreAggregationType: "mean", + StaticTTL: 600, + Type: "weighted-round-robin", + UseComputedTargets: false, + LivenessTests: []LivenessTest{ + { + DisableNonstandardPortWarning: false, + HTTPError3xx: true, + HTTPError4xx: true, + HTTPError5xx: true, + Name: "health-check", + TestInterval: 60, + TestObject: "/status", + TestObjectPort: 80, + TestObjectProtocol: "HTTP", + TestTimeout: 25.0, + }, }, - { - DatacenterID: 3133, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.4"}, - Precedence: nil, + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 3134, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.5"}, + }, + { + DatacenterID: 3133, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.4"}, + Precedence: nil, + }, }, }, + DomainName: "example.akadns.net", }, - domain: "example.akadns.net", headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -314,7 +322,7 @@ func TestGTM_CreateProperty(t *testing.T) { } } `, - expectedResponse: &PropertyResponse{ + expectedResponse: &CreatePropertyResponse{ Resource: &Property{ BalanceByDownloadScore: false, HandoutMode: "normal", @@ -325,7 +333,7 @@ func TestGTM_CreateProperty(t *testing.T) { DynamicTTL: 300, Type: "weighted-round-robin", UseComputedTargets: false, - LivenessTests: []*LivenessTest{ + LivenessTests: []LivenessTest{ { DisableNonstandardPortWarning: false, HTTPError3xx: true, @@ -339,7 +347,7 @@ func TestGTM_CreateProperty(t *testing.T) { TestTimeout: 25.0, }, }, - TrafficTargets: []*TrafficTarget{ + TrafficTargets: []TrafficTarget{ { DatacenterID: 3134, Enabled: true, @@ -353,7 +361,7 @@ func TestGTM_CreateProperty(t *testing.T) { Servers: []string{"1.2.3.4"}, }, }, - Links: []*Link{ + Links: []Link{ { Href: "/config-gtm/v1/domains/example.akadns.net/properties/origin", Rel: "self", @@ -366,7 +374,7 @@ func TestGTM_CreateProperty(t *testing.T) { PassingValidation: true, PropagationStatus: "PENDING", PropagationStatusDate: "2014-04-15T11:30:27.000+0000", - Links: &[]Link{ + Links: []Link{ { Href: "/config-gtm/v1/domains/example.akadns.net/status/current", Rel: "self", @@ -374,54 +382,56 @@ func TestGTM_CreateProperty(t *testing.T) { }, }, }, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/origin", }, "201 Created - ranked-failover": { - property: &Property{ - BalanceByDownloadScore: false, - HandoutMode: "normal", - IPv6: false, - Name: "origin", - ScoreAggregationType: "mean", - StaticTTL: 600, - Type: "ranked-failover", - UseComputedTargets: false, - LivenessTests: []*LivenessTest{ - { - DisableNonstandardPortWarning: false, - HTTPError3xx: true, - HTTPError4xx: true, - HTTPError5xx: true, - HTTPMethod: tools.StringPtr("GET"), - HTTPRequestBody: tools.StringPtr("TestBody"), - Name: "health-check", - TestInterval: 60, - TestObject: "/status", - TestObjectPort: 80, - TestObjectProtocol: "HTTP", - TestTimeout: 25.0, - Pre2023SecurityPosture: true, - AlternateCACertificates: []string{"test1"}, - }, - }, - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 3134, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + params: CreatePropertyRequest{ + Property: &Property{ + BalanceByDownloadScore: false, + HandoutMode: "normal", + IPv6: false, + Name: "origin", + ScoreAggregationType: "mean", + StaticTTL: 600, + Type: "ranked-failover", + UseComputedTargets: false, + LivenessTests: []LivenessTest{ + { + DisableNonstandardPortWarning: false, + HTTPError3xx: true, + HTTPError4xx: true, + HTTPError5xx: true, + HTTPMethod: tools.StringPtr("GET"), + HTTPRequestBody: tools.StringPtr("TestBody"), + Name: "health-check", + TestInterval: 60, + TestObject: "/status", + TestObjectPort: 80, + TestObjectProtocol: "HTTP", + TestTimeout: 25.0, + Pre2023SecurityPosture: true, + AlternateCACertificates: []string{"test1"}, + }, }, - { - DatacenterID: 3133, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.4"}, - Precedence: nil, + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 3134, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.5"}, + Precedence: tools.IntPtr(255), + }, + { + DatacenterID: 3133, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.4"}, + Precedence: nil, + }, }, }, + DomainName: "example.akadns.net", }, - domain: "example.akadns.net", headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -526,7 +536,7 @@ func TestGTM_CreateProperty(t *testing.T) { } } `, - expectedResponse: &PropertyResponse{ + expectedResponse: &CreatePropertyResponse{ Resource: &Property{ BalanceByDownloadScore: false, HandoutMode: "normal", @@ -537,7 +547,7 @@ func TestGTM_CreateProperty(t *testing.T) { DynamicTTL: 300, Type: "weighted-round-robin", UseComputedTargets: false, - LivenessTests: []*LivenessTest{ + LivenessTests: []LivenessTest{ { DisableNonstandardPortWarning: false, HTTPError3xx: true, @@ -555,7 +565,7 @@ func TestGTM_CreateProperty(t *testing.T) { TestTimeout: 25.0, }, }, - TrafficTargets: []*TrafficTarget{ + TrafficTargets: []TrafficTarget{ { DatacenterID: 3134, Enabled: true, @@ -571,7 +581,7 @@ func TestGTM_CreateProperty(t *testing.T) { Precedence: nil, }, }, - Links: []*Link{ + Links: []Link{ { Href: "/config-gtm/v1/domains/example.akadns.net/properties/origin", Rel: "self", @@ -584,7 +594,7 @@ func TestGTM_CreateProperty(t *testing.T) { PassingValidation: true, PropagationStatus: "PENDING", PropagationStatusDate: "2014-04-15T11:30:27.000+0000", - Links: &[]Link{ + Links: []Link{ { Href: "/config-gtm/v1/domains/example.akadns.net/status/current", Rel: "self", @@ -592,24 +602,26 @@ func TestGTM_CreateProperty(t *testing.T) { }, }, }, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/origin", }, "validation error - missing precedence for ranked-failover property type": { - property: &Property{ - Type: "ranked-failover", - Name: "property", - HandoutMode: "normal", - ScoreAggregationType: "mean", - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 1, - Enabled: false, - Precedence: nil, - }, - { - DatacenterID: 2, - Enabled: false, - Precedence: nil, + params: CreatePropertyRequest{ + Property: &Property{ + Type: "ranked-failover", + Name: "property", + HandoutMode: "normal", + ScoreAggregationType: "mean", + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 1, + Enabled: false, + Precedence: nil, + }, + { + DatacenterID: 2, + Enabled: false, + Precedence: nil, + }, }, }, }, @@ -619,32 +631,36 @@ func TestGTM_CreateProperty(t *testing.T) { }, }, "validation error - precedence value over the limit": { - property: &Property{ - Type: "ranked-failover", - Name: "property", - HandoutMode: "normal", - ScoreAggregationType: "mean", - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 1, - Enabled: false, - Precedence: tools.IntPtr(256), + params: CreatePropertyRequest{ + Property: &Property{ + Type: "ranked-failover", + Name: "property", + HandoutMode: "normal", + ScoreAggregationType: "mean", + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 1, + Enabled: false, + Precedence: tools.IntPtr(256), + }, }, }, }, withError: true, assertError: func(t *testing.T, err error) { - assert.ErrorContains(t, err, "property validation failed. TrafficTargets: 'Precedence' value has to be between 0 and 255") + assert.ErrorContains(t, err, "TrafficTargets: 'Precedence' value has to be between 0 and 255") }, }, "500 internal server error": { - property: &Property{ - Name: "testName", - HandoutMode: "normal", - ScoreAggregationType: "mean", - Type: "failover", + params: CreatePropertyRequest{ + Property: &Property{ + Name: "testName", + HandoutMode: "normal", + ScoreAggregationType: "mean", + Type: "failover", + }, + DomainName: "example.akadns.net", }, - domain: "example.akadns.net", responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -652,7 +668,7 @@ func TestGTM_CreateProperty(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating domain" }`, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/testName", withError: true, assertError: func(t *testing.T, err error) { want := &Error{ @@ -669,6 +685,7 @@ func TestGTM_CreateProperty(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -680,7 +697,7 @@ func TestGTM_CreateProperty(t *testing.T) { result, err := client.CreateProperty( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.property, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError { test.assertError(t, err) return @@ -693,62 +710,63 @@ func TestGTM_CreateProperty(t *testing.T) { func TestGTM_UpdateProperty(t *testing.T) { tests := map[string]struct { - property *Property - domain string + params UpdatePropertyRequest responseStatus int responseBody string expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdatePropertyResponse withError bool assertError func(*testing.T, error) headers http.Header }{ "200 Success": { - property: &Property{ - BalanceByDownloadScore: false, - HandoutMode: "normal", - IPv6: false, - Name: "origin", - ScoreAggregationType: "mean", - StaticTTL: 600, - Type: "weighted-round-robin", - UseComputedTargets: false, - LivenessTests: []*LivenessTest{ - { - DisableNonstandardPortWarning: false, - HTTPError3xx: true, - HTTPError4xx: true, - HTTPError5xx: true, - Name: "health-check", - TestInterval: 60, - TestObject: "/status", - TestObjectPort: 80, - TestObjectProtocol: "HTTP", - TestTimeout: 25.0, - }, - }, - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 3134, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + params: UpdatePropertyRequest{ + Property: &Property{ + BalanceByDownloadScore: false, + HandoutMode: "normal", + IPv6: false, + Name: "origin", + ScoreAggregationType: "mean", + StaticTTL: 600, + Type: "weighted-round-robin", + UseComputedTargets: false, + LivenessTests: []LivenessTest{ + { + DisableNonstandardPortWarning: false, + HTTPError3xx: true, + HTTPError4xx: true, + HTTPError5xx: true, + Name: "health-check", + TestInterval: 60, + TestObject: "/status", + TestObjectPort: 80, + TestObjectProtocol: "HTTP", + TestTimeout: 25.0, + }, }, - { - DatacenterID: 3133, - Enabled: true, - Weight: 50.0, - Servers: []string{"1.2.3.4"}, - Precedence: nil, + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 3134, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.5"}, + Precedence: tools.IntPtr(255), + }, + { + DatacenterID: 3133, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.4"}, + Precedence: nil, + }, }, }, + DomainName: "example.akadns.net", }, - domain: "example.akadns.net", headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusCreated, + responseStatus: http.StatusOK, responseBody: ` { "resource": { @@ -845,39 +863,90 @@ func TestGTM_UpdateProperty(t *testing.T) { } } `, - expectedResponse: &ResponseStatus{ - ChangeID: "eee0c3b4-0e45-4f4b-822c-7dbc60764d18", - Message: "Change Pending", - PassingValidation: true, - PropagationStatus: "PENDING", - PropagationStatusDate: "2014-04-15T11:30:27.000+0000", - Links: &[]Link{ - { - Href: "/config-gtm/v1/domains/example.akadns.net/status/current", - Rel: "self", + expectedResponse: &UpdatePropertyResponse{ + Resource: &Property{ + BalanceByDownloadScore: false, + HandoutMode: "normal", + IPv6: false, + Name: "origin", + ScoreAggregationType: "mean", + StaticTTL: 600, + DynamicTTL: 300, + Type: "weighted-round-robin", + UseComputedTargets: false, + LivenessTests: []LivenessTest{ + { + DisableNonstandardPortWarning: false, + HTTPError3xx: true, + HTTPError4xx: true, + HTTPError5xx: true, + Name: "health-check", + TestInterval: 60, + TestObject: "/status", + TestObjectPort: 80, + TestObjectProtocol: "HTTP", + TestTimeout: 25.0, + }, + }, + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 3134, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.5"}, + Precedence: tools.IntPtr(255), + }, + { + DatacenterID: 3133, + Enabled: true, + Weight: 50.0, + Servers: []string{"1.2.3.4"}, + }, + }, + Links: []Link{ + { + Href: "/config-gtm/v1/domains/example.akadns.net/properties/origin", + Rel: "self", + }, + }, + }, + Status: &ResponseStatus{ + ChangeID: "eee0c3b4-0e45-4f4b-822c-7dbc60764d18", + Message: "Change Pending", + PassingValidation: true, + PropagationStatus: "PENDING", + PropagationStatusDate: "2014-04-15T11:30:27.000+0000", + Links: []Link{ + { + Href: "/config-gtm/v1/domains/example.akadns.net/status/current", + Rel: "self", + }, }, }, }, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/origin", }, "validation error - missing precedence for ranked-failover property type": { - property: &Property{ - Type: "ranked-failover", - Name: "property", - HandoutMode: "normal", - ScoreAggregationType: "mean", - TrafficTargets: []*TrafficTarget{ - { - DatacenterID: 1, - Enabled: false, - Precedence: nil, - }, - { - DatacenterID: 2, - Enabled: false, - Precedence: nil, + params: UpdatePropertyRequest{ + Property: &Property{ + Type: "ranked-failover", + Name: "property", + HandoutMode: "normal", + ScoreAggregationType: "mean", + TrafficTargets: []TrafficTarget{ + { + DatacenterID: 1, + Enabled: false, + Precedence: nil, + }, + { + DatacenterID: 2, + Enabled: false, + Precedence: nil, + }, }, }, + DomainName: "example.akadns.net", }, withError: true, assertError: func(t *testing.T, err error) { @@ -885,25 +954,30 @@ func TestGTM_UpdateProperty(t *testing.T) { }, }, "validation error - no traffic targets": { - property: &Property{ - Type: "ranked-failover", - Name: "property", - HandoutMode: "normal", - ScoreAggregationType: "mean", + params: UpdatePropertyRequest{ + Property: &Property{ + Type: "ranked-failover", + Name: "property", + HandoutMode: "normal", + ScoreAggregationType: "mean", + }, + DomainName: "example.akadns.net", }, withError: true, assertError: func(t *testing.T, err error) { - assert.ErrorContains(t, err, "property validation failed. TrafficTargets: no traffic targets are enabled") + assert.ErrorContains(t, err, "TrafficTargets: no traffic targets are enabled") }, }, "500 internal server error": { - property: &Property{ - Name: "testName", - HandoutMode: "normal", - ScoreAggregationType: "mean", - Type: "failover", + params: UpdatePropertyRequest{ + Property: &Property{ + Name: "testName", + HandoutMode: "normal", + ScoreAggregationType: "mean", + Type: "failover", + }, + DomainName: "example.akadns.net", }, - domain: "example.akadns.net", responseStatus: http.StatusInternalServerError, responseBody: ` { @@ -911,7 +985,7 @@ func TestGTM_UpdateProperty(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating zone" }`, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/testName", withError: true, assertError: func(t *testing.T, err error) { want := &Error{ @@ -928,6 +1002,7 @@ func TestGTM_UpdateProperty(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -939,7 +1014,7 @@ func TestGTM_UpdateProperty(t *testing.T) { result, err := client.UpdateProperty( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.property, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError { test.assertError(t, err) return @@ -951,7 +1026,7 @@ func TestGTM_UpdateProperty(t *testing.T) { } func TestGTM_DeleteProperty(t *testing.T) { - var result PropertyResponse + var result DeletePropertyResponse var req Property respData, err := loadTestData("TestGTM_CreateProperty.resp.json") @@ -973,29 +1048,32 @@ func TestGTM_DeleteProperty(t *testing.T) { } tests := map[string]struct { - prop *Property - domain string + params DeletePropertyRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeletePropertyResponse withError error headers http.Header }{ "200 Success": { - prop: &req, - domain: "example.akadns.net", + params: DeletePropertyRequest{ + PropertyName: "www", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: respData, - expectedResponse: result.Status, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedResponse: &result, + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/www", }, "500 internal server error": { - prop: &req, - domain: "example.akadns.net", + params: DeletePropertyRequest{ + PropertyName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -1003,7 +1081,7 @@ func TestGTM_DeleteProperty(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating zone" }`), - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/properties/www", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -1016,6 +1094,7 @@ func TestGTM_DeleteProperty(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -1027,7 +1106,7 @@ func TestGTM_DeleteProperty(t *testing.T) { result, err := client.DeleteProperty( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.prop, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/resource.go b/pkg/gtm/resource.go index 92a7d8c9..662b43fd 100644 --- a/pkg/gtm/resource.go +++ b/pkg/gtm/resource.go @@ -2,81 +2,166 @@ package gtm import ( "context" + "errors" "fmt" "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // ResourceInstance contains information about the resources that constrain the properties within the data center + ResourceInstance struct { + DatacenterID int `json:"datacenterId"` + UseDefaultLoadObject bool `json:"useDefaultLoadObject"` + LoadObject + } + + // Resource represents a GTM resource + Resource struct { + Type string `json:"type"` + HostHeader string `json:"hostHeader,omitempty"` + LeastSquaresDecay float64 `json:"leastSquaresDecay,omitempty"` + Description string `json:"description,omitempty"` + LeaderString string `json:"leaderString,omitempty"` + ConstrainedProperty string `json:"constrainedProperty,omitempty"` + ResourceInstances []ResourceInstance `json:"resourceInstances,omitempty"` + AggregationType string `json:"aggregationType,omitempty"` + Links []Link `json:"links,omitempty"` + LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` + UpperBound int `json:"upperBound,omitempty"` + Name string `json:"name"` + MaxUMultiplicativeIncrement float64 `json:"maxUMultiplicativeIncrement,omitempty"` + DecayRate float64 `json:"decayRate,omitempty"` + } + + // ResourceList is the structure returned by List Resources + ResourceList struct { + ResourceItems []Resource `json:"items"` + } + + // ListResourcesRequest contains request parameters for ListResources + ListResourcesRequest struct { + DomainName string + } + + // GetResourceRequest contains request parameters for GetResource + GetResourceRequest struct { + DomainName string + ResourceName string + } + + // GetResourceResponse contains the response data from GetResource operation + GetResourceResponse Resource + + // ResourceRequest contains request parameters + ResourceRequest struct { + Resource *Resource + DomainName string + } + + // CreateResourceRequest contains request parameters for CreateResource + CreateResourceRequest ResourceRequest + + // CreateResourceResponse contains the response data from CreateResource operation + CreateResourceResponse struct { + Resource *Resource `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // UpdateResourceRequest contains request parameters for UpdateResource + UpdateResourceRequest ResourceRequest + + // UpdateResourceResponse contains the response data from UpdateResource operation + UpdateResourceResponse struct { + Resource *Resource `json:"resource"` + Status *ResponseStatus `json:"status"` + } + + // DeleteResourceRequest contains request parameters for DeleteResource + DeleteResourceRequest struct { + DomainName string + ResourceName string + } + + // DeleteResourceResponse contains the response data from DeleteResource operation + DeleteResourceResponse struct { + Resource *Resource `json:"resource"` + Status *ResponseStatus `json:"status"` + } ) -// Resources contains operations available on a Resource resource. -type Resources interface { - // ListResources retrieves all Resources - // - // See: https://techdocs.akamai.com/gtm/reference/get-resources - ListResources(context.Context, string) ([]*Resource, error) - // GetResource retrieves a Resource with the given name. - // - // See: https://techdocs.akamai.com/gtm/reference/get-resource - GetResource(context.Context, string, string) (*Resource, error) - // CreateResource creates the datacenter identified by the receiver argument in the specified domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-resource - CreateResource(context.Context, *Resource, string) (*ResourceResponse, error) - // DeleteResource deletes the datacenter identified by the receiver argument from the domain specified. - // - // See: https://techdocs.akamai.com/gtm/reference/delete-resource - DeleteResource(context.Context, *Resource, string) (*ResponseStatus, error) - // UpdateResource updates the datacenter identified in the receiver argument in the provided domain. - // - // See: https://techdocs.akamai.com/gtm/reference/put-resource - UpdateResource(context.Context, *Resource, string) (*ResponseStatus, error) +var ( + // ErrListResources is returned when ListResources fails + ErrListResources = errors.New("list resources") + // ErrGetResource is returned when GetResource fails + ErrGetResource = errors.New("get resource") + // ErrCreateResource is returned when CreateResource fails + ErrCreateResource = errors.New("create resource") + // ErrUpdateResource is returned when UpdateResource fails + ErrUpdateResource = errors.New("update resource") + // ErrDeleteResource is returned when DeleteResource fails + ErrDeleteResource = errors.New("delete resource") +) + +// Validate validates ListResourcesRequest +func (r ListResourcesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + }) +} + +// Validate validates GetResourceRequest +func (r GetResourceRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "ResourceName": validation.Validate(r.ResourceName, validation.Required), + }) } -// ResourceInstance contains information about the resources that constrain the properties within the data center -type ResourceInstance struct { - DatacenterID int `json:"datacenterId"` - UseDefaultLoadObject bool `json:"useDefaultLoadObject"` - LoadObject +// Validate validates CreateResourceRequest +func (r CreateResourceRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Resource": validation.Validate(r.Resource, validation.Required), + }) } -// Resource represents a GTM resource -type Resource struct { - Type string `json:"type"` - HostHeader string `json:"hostHeader,omitempty"` - LeastSquaresDecay float64 `json:"leastSquaresDecay,omitempty"` - Description string `json:"description,omitempty"` - LeaderString string `json:"leaderString,omitempty"` - ConstrainedProperty string `json:"constrainedProperty,omitempty"` - ResourceInstances []*ResourceInstance `json:"resourceInstances,omitempty"` - AggregationType string `json:"aggregationType,omitempty"` - Links []*Link `json:"links,omitempty"` - LoadImbalancePercentage float64 `json:"loadImbalancePercentage,omitempty"` - UpperBound int `json:"upperBound,omitempty"` - Name string `json:"name"` - MaxUMultiplicativeIncrement float64 `json:"maxUMultiplicativeIncrement,omitempty"` - DecayRate float64 `json:"decayRate,omitempty"` +// Validate validates UpdateResourceRequest +func (r UpdateResourceRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "Resource": validation.Validate(r.Resource, validation.Required), + }) } -// ResourceList is the structure returned by List Resources -type ResourceList struct { - ResourceItems []*Resource `json:"items"` +// Validate validates DeleteResourceRequest +func (r DeleteResourceRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "DomainName": validation.Validate(r.DomainName, validation.Required), + "ResourceName": validation.Validate(r.ResourceName, validation.Required), + }) } // Validate validates Resource func (r *Resource) Validate() error { - if len(r.Name) < 1 { - return fmt.Errorf("resource is missing Name") - } - if len(r.Type) < 1 { - return fmt.Errorf("resource is missing Type") - } - - return nil + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Name": validation.Validate(r.Name, validation.Required), + "Type": validation.Validate(r.Type, validation.Required), + "AggregationType": validation.Validate(r.AggregationType, validation.Required), + }) } -func (g *gtm) ListResources(ctx context.Context, domainName string) ([]*Resource, error) { +func (g *gtm) ListResources(ctx context.Context, params ListResourcesRequest) ([]Resource, error) { logger := g.Log(ctx) logger.Debug("ListResources") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources", domainName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrListResources, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources", params.DomainName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create ListResources request: %w", err) @@ -96,18 +181,22 @@ func (g *gtm) ListResources(ctx context.Context, domainName string) ([]*Resource return result.ResourceItems, nil } -func (g *gtm) GetResource(ctx context.Context, resourceName, domainName string) (*Resource, error) { +func (g *gtm) GetResource(ctx context.Context, params GetResourceRequest) (*GetResourceResponse, error) { logger := g.Log(ctx) logger.Debug("GetResource") - getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, resourceName) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetResource, ErrStructValidation, err) + } + + getURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", params.DomainName, params.ResourceName) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { return nil, fmt.Errorf("failed to create GetResource request: %w", err) } setVersionHeader(req, schemaVersion) - var result Resource + var result GetResourceResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("GetResource request failed: %w", err) @@ -120,67 +209,78 @@ func (g *gtm) GetResource(ctx context.Context, resourceName, domainName string) return &result, nil } -func (g *gtm) CreateResource(ctx context.Context, resource *Resource, domainName string) (*ResourceResponse, error) { +func (g *gtm) CreateResource(ctx context.Context, params CreateResourceRequest) (*CreateResourceResponse, error) { logger := g.Log(ctx) logger.Debug("CreateResource") - return resource.save(ctx, g, domainName) -} + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateResource, ErrStructValidation, err) + } -func (g *gtm) UpdateResource(ctx context.Context, resource *Resource, domainName string) (*ResponseStatus, error) { - logger := g.Log(ctx) - logger.Debug("UpdateResource") + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", params.DomainName, params.Resource.Name) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create Resource request: %w", err) + } + setVersionHeader(req, schemaVersion) - stat, err := resource.save(ctx, g, domainName) + var result CreateResourceResponse + resp, err := g.Exec(req, &result, params.Resource) if err != nil { - return nil, err + return nil, fmt.Errorf("resource request failed: %w", err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, g.Error(resp) } - return stat.Status, err + + return &result, nil } -// save is a function that saves Resource in given domain. Common path for Create and Update. -func (r *Resource) save(ctx context.Context, g *gtm, domainName string) (*ResourceResponse, error) { - if err := r.Validate(); err != nil { - return nil, fmt.Errorf("resource validation failed. %w", err) +func (g *gtm) UpdateResource(ctx context.Context, params UpdateResourceRequest) (*UpdateResourceResponse, error) { + logger := g.Log(ctx) + logger.Debug("UpdateResource") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateResource, ErrStructValidation, err) } - putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, r.Name) + putURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", params.DomainName, params.Resource.Name) req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Resource request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResourceResponse - resp, err := g.Exec(req, &result, r) + var result UpdateResourceResponse + resp, err := g.Exec(req, &result, params.Resource) if err != nil { return nil, fmt.Errorf("resource request failed: %w", err) } - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + if resp.StatusCode != http.StatusOK { return nil, g.Error(resp) } return &result, nil } -func (g *gtm) DeleteResource(ctx context.Context, resource *Resource, domainName string) (*ResponseStatus, error) { +func (g *gtm) DeleteResource(ctx context.Context, params DeleteResourceRequest) (*DeleteResourceResponse, error) { logger := g.Log(ctx) logger.Debug("DeleteResource") - if err := resource.Validate(); err != nil { - logger.Errorf("Resource validation failed. %w", err) - return nil, fmt.Errorf("DeleteResource validation failed. %w", err) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrDeleteResource, ErrStructValidation, err) } - delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, resource.Name) + delURL := fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", params.DomainName, params.ResourceName) req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) if err != nil { return nil, fmt.Errorf("failed to create Delete request: %w", err) } setVersionHeader(req, schemaVersion) - var result ResponseBody + var result DeleteResourceResponse resp, err := g.Exec(req, &result) if err != nil { return nil, fmt.Errorf("DeleteResource request failed: %w", err) @@ -190,5 +290,5 @@ func (g *gtm) DeleteResource(ctx context.Context, resource *Resource, domainName return nil, g.Error(resp) } - return result.Status, nil + return &result, nil } diff --git a/pkg/gtm/resource_test.go b/pkg/gtm/resource_test.go index 56bae885..b1c8622e 100644 --- a/pkg/gtm/resource_test.go +++ b/pkg/gtm/resource_test.go @@ -27,16 +27,18 @@ func TestGTM_ListResources(t *testing.T) { } tests := map[string]struct { - domain string + params ListResourcesRequest responseStatus int responseBody string expectedPath string - expectedResponse []*Resource + expectedResponse []Resource withError error headers http.Header }{ "200 OK": { - domain: "example.akadns.net", + params: ListResourcesRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, @@ -46,7 +48,9 @@ func TestGTM_ListResources(t *testing.T) { expectedResponse: result.ResourceItems, }, "500 internal server error": { - domain: "example.akadns.net", + params: ListResourcesRequest{ + DomainName: "example.akadns.net", + }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -79,7 +83,7 @@ func TestGTM_ListResources(t *testing.T) { result, err := client.ListResources( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -91,7 +95,7 @@ func TestGTM_ListResources(t *testing.T) { } func TestGTM_GetResource(t *testing.T) { - var result Resource + var result GetResourceResponse respData, err := loadTestData("TestGTM_GetResource.resp.json") if err != nil { @@ -103,25 +107,28 @@ func TestGTM_GetResource(t *testing.T) { } tests := map[string]struct { - name string - domain string + params GetResourceRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *Resource + expectedResponse *GetResourceResponse withError error }{ "200 OK": { - name: "www", - domain: "example.akadns.net", + params: GetResourceRequest{ + ResourceName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusOK, responseBody: respData, expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/www", expectedResponse: &result, }, "500 internal server error": { - name: "www", - domain: "example.akadns.net", + params: GetResourceRequest{ + ResourceName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -149,7 +156,7 @@ func TestGTM_GetResource(t *testing.T) { assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetResource(context.Background(), test.name, test.domain) + result, err := client.GetResource(context.Background(), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -161,7 +168,7 @@ func TestGTM_GetResource(t *testing.T) { } func TestGTM_CreateResource(t *testing.T) { - var result ResourceResponse + var result CreateResourceResponse var req Resource respData, err := loadTestData("TestGTM_CreateResource.resp.json") @@ -183,29 +190,32 @@ func TestGTM_CreateResource(t *testing.T) { } tests := map[string]struct { - domain string - prop *Resource + params CreateResourceRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *ResourceResponse + expectedResponse *CreateResourceResponse withError error headers http.Header }{ "201 Created": { - prop: &req, - domain: "example.akadns.net", + params: CreateResourceRequest{ + Resource: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusCreated, responseBody: respData, expectedResponse: &result, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/origin", }, "500 internal server error": { - prop: &req, - domain: "example.akadns.net", + params: CreateResourceRequest{ + Resource: &req, + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -213,7 +223,7 @@ func TestGTM_CreateResource(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating domain" }`), - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/origin", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -226,6 +236,7 @@ func TestGTM_CreateResource(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -237,7 +248,7 @@ func TestGTM_CreateResource(t *testing.T) { result, err := client.CreateResource( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.prop, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -249,7 +260,7 @@ func TestGTM_CreateResource(t *testing.T) { } func TestGTM_UpdateResource(t *testing.T) { - var result ResourceResponse + var result UpdateResourceResponse var req Resource respData, err := loadTestData("TestGTM_CreateResource.resp.json") @@ -271,29 +282,32 @@ func TestGTM_UpdateResource(t *testing.T) { } tests := map[string]struct { - prop *Resource - domain string + params UpdateResourceRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *ResponseStatus + expectedResponse *UpdateResourceResponse withError error headers http.Header }{ "200 Success": { - prop: &req, - domain: "example.akadns.net", + params: UpdateResourceRequest{ + Resource: &req, + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, - responseStatus: http.StatusCreated, + responseStatus: http.StatusOK, responseBody: respData, - expectedResponse: result.Status, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedResponse: &result, + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/origin", }, "500 internal server error": { - prop: &req, - domain: "example.akadns.net", + params: UpdateResourceRequest{ + Resource: &req, + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -301,7 +315,7 @@ func TestGTM_UpdateResource(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating zone" }`), - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/origin", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -314,6 +328,7 @@ func TestGTM_UpdateResource(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -325,7 +340,7 @@ func TestGTM_UpdateResource(t *testing.T) { result, err := client.UpdateResource( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.prop, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return @@ -337,7 +352,7 @@ func TestGTM_UpdateResource(t *testing.T) { } func TestGTM_DeleteResource(t *testing.T) { - var result ResourceResponse + var result DeleteResourceResponse var req Resource respData, err := loadTestData("TestGTM_CreateResource.resp.json") @@ -359,29 +374,32 @@ func TestGTM_DeleteResource(t *testing.T) { } tests := map[string]struct { - prop *Resource - domain string + params DeleteResourceRequest responseStatus int responseBody []byte expectedPath string - expectedResponse *ResponseStatus + expectedResponse *DeleteResourceResponse withError error headers http.Header }{ "200 Success": { - prop: &req, - domain: "example.akadns.net", + params: DeleteResourceRequest{ + ResourceName: "www", + DomainName: "example.akadns.net", + }, headers: http.Header{ "Content-Type": []string{"application/vnd.config-gtm.v1.4+json;charset=UTF-8"}, }, responseStatus: http.StatusOK, responseBody: respData, - expectedResponse: result.Status, - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedResponse: &result, + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/www", }, "500 internal server error": { - prop: &req, - domain: "example.akadns.net", + params: DeleteResourceRequest{ + ResourceName: "www", + DomainName: "example.akadns.net", + }, responseStatus: http.StatusInternalServerError, responseBody: []byte(` { @@ -389,7 +407,7 @@ func TestGTM_DeleteResource(t *testing.T) { "title": "Internal Server Error", "detail": "Error creating zone" }`), - expectedPath: "/config-gtm/v1/domains/example.akadns.net?contractId=1-2ABCDE", + expectedPath: "/config-gtm/v1/domains/example.akadns.net/resources/www", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -402,6 +420,7 @@ func TestGTM_DeleteResource(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) w.WriteHeader(test.responseStatus) if len(test.responseBody) > 0 { @@ -413,7 +432,7 @@ func TestGTM_DeleteResource(t *testing.T) { result, err := client.DeleteResource( session.ContextWithOptions( context.Background(), - session.WithContextHeaders(test.headers)), test.prop, test.domain) + session.WithContextHeaders(test.headers)), test.params) if test.withError != nil { assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) return diff --git a/pkg/gtm/testdata/TestGTM_CreateResource.req.json b/pkg/gtm/testdata/TestGTM_CreateResource.req.json index 6f4727ce..2433f2dd 100644 --- a/pkg/gtm/testdata/TestGTM_CreateResource.req.json +++ b/pkg/gtm/testdata/TestGTM_CreateResource.req.json @@ -8,7 +8,7 @@ "healthThreshold": null, "ipv6": false, "name": "origin", - "scoreAggregationType": "mean", + "aggregationType": "mean", "staticTTL": 600, "stickinessBonusConstant": 0, "stickinessBonusPercentage": 0, From 6f69825456e7951889913d8624712da11663956b Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Mon, 13 May 2024 12:06:22 +0000 Subject: [PATCH 05/34] DXE-3640 Refactor response/request/objects struct names in GTM and DNS (CHANGELOG) --- CHANGELOG.md | 186 +++++++++++++++++++++++++++++++++++++++++++++++ pkg/dns/mocks.go | 6 -- 2 files changed, 186 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e68bc6..b24daaaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,192 @@ + + + + + + + + + + + +* DNS + * Refactored parameters in following methods: + * `GetAuthorities` - from (context.Context, string) into (context.Context, `GetAuthoritiesRequest`) + * `GetNameServerRecordList` - from (context.Context, string) into (context.Context, `GetNameServerRecordListRequest`) + * `GetRecord` - from (context.Context, string, string, string) into (context.Context, `GetRecordRequest`) + * `GetRecordList` - from (context.Context, string, string, string) into (context.Context, `GetRecordListRequest`) + * `CreateRecord` - from (context.Context, *RecordBody, string, ...bool) into (context.Context, `CreateRecordRequest`) + * `UpdateRecord` - from (context.Context, *RecordBody, string, ...bool) into (context.Context, `UpdateRecordRequest`) + * `DeleteRecord` - from (context.Context, *RecordBody, string, ...bool) into (context.Context, `DeleteRecordRequest`) + * `GetRecordSets` - from (context.Context, string, ...RecordSetQueryArgs) into (context.Context, `GetRecordSetsRequest`) + * `CreateRecordSets` - from (context.Context, *RecordSets, string, ...bool) into (context.Context, `CreateRecordSetsRequest`) + * `UpdateRecordSets` - from (context.Context, *RecordSets, string, ...bool) into (context.Context, `UpdateRecordSetsRequest`) + * `ListTSIGKeys` - from (context.Context, *TSIGQueryString) into (context.Context, `ListTSIGKeysRequest`) + * `GetTSIGKeyZones` - from (context.Context, *TSIGKey) into (context.Context, `GetTSIGKeyZonesRequest`) + * `GetTSIGKeyAliases` - from (context.Context, string) into (context.Context, `GetTSIGKeyAliasesRequest`) + * `UpdateTSIGKeyBulk` - from (context.Context, *TSIGKeyBulkPost) into (context.Context, `UpdateTSIGKeyBulkRequest`) + * `GetTSIGKey` - from (context.Context, string) into (context.Context, `GetTSIGKeyRequest`) + * `DeleteTSIGKey` - from (context.Context, string) into (context.Context, `DeleteTSIGKeyRequest`) + * `UpdateTSIGKey` - from (context.Context, *TSIGKey, string) into (context.Context, `UpdateTSIGKeyRequest`) + * `ListZones` - from (context.Context, ...ZoneListQueryArgs) into (context.Context, `ListZonesRequest`) + * `GetZone` - from (context.Context, string) into (context.Context, `GetZoneRequest`) + * `GetChangeList` - from (context.Context, string) into (context.Context, `GetChangeListRequest`) + * `GetMasterZoneFile` - from (context.Context, string) into (context.Context, `GetMasterZoneFileRequest`) + * `PostMasterZoneFile` - from (context.Context, string, string) into (context.Context, `PostMasterZoneFileRequest`) + * `CreateZone` - from (context.Context, *ZoneCreate, ZoneQueryString, ...bool) into (context.Context, `CreateZoneRequest`) + * `SaveChangeList` - from (context.Context, *ZoneCreate) into (context.Context, `SaveChangeListRequest`) + * `SubmitChangeList` - from (context.Context, *ZoneCreate) into (context.Context, `SubmitChangeListRequest`) + * `UpdateZone` - from (context.Context, *ZoneCreate) into (context.Context, `UpdateZoneRequest`) + * `GetZoneNames` - from (context.Context, string) into (context.Context, `GetZoneNamesRequest`) + * `GetZoneNameTypes` - from (context.Context, string, string) into (context.Context, `GetZoneNameTypesRequest`) + * `GetBulkZoneCreateStatus` - from (context.Context, string) into (context.Context, `GetBulkZoneCreateStatusRequest`) + * `GetBulkZoneDeleteStatus` - from (context.Context, string) into (context.Context, `GetBulkZoneDeleteStatusRequest`) + * `GetBulkZoneCreateResult` - from (context.Context, string) into (context.Context, `GetBulkZoneCreateResultRequest`) + * `GetBulkZoneDeleteResult` - from (context.Context, string) into (context.Context, `GetBulkZoneDeleteResultRequest`) + * `CreateBulkZones` - from (context.Context, *BulkZonesCreate, ZoneQueryString) into (context.Context, `CreateBulkZonesRequest`) + * `DeleteBulkZones` - from (context.Context, *ZoneNameListResponse, ...bool) into (context.Context, `DeleteBulkZonesRequest`) + * `GetRdata` - from (context.Context, string, string, string) into (context.Context, `GetRdataRequest`) + + * Refactored response in following methods: + * `GetAuthorities` - `*AuthorityResponse` into `*GetAuthoritiesResponse` + * `GetRecord` - `*RecordBody` into `*GetRecordResponse` + * `GetRecordList` - `*RecordSetResponse` into `*GetRecordListResponse` + * `GetRecordSets` - `*RecordSetResponse` into `*GetRecordSetsResponse` + * `GetTSIGKey` - `*TSIGKeyResponse` into `*GetTSIGKeyResponse` + * `ListTSIGKeys` - `*TSIGReportResponse` into `*ListTSIGKeysResponse` + * `GetTSIGKeyZones` - `*ZoneNameListResponse` into `*GetTSIGKeyZonesResponse` + * `GetTSIGKeyAliases` - `*ZoneNameListResponse` into `*GetTSIGKeyAliasesResponse` + * `GetZone` - `*ZoneResponse` into `*GetZoneResponse` + * `GetChangeList` - `*ChangeListResponse` into `*GetChangeListResponse` + * `GetZoneNames` - `*ZoneNamesResponse` into `*GetZoneNamesResponse` + * `GetZoneNameTypes` - `*ZoneNameTypesResponse` into `*GetZoneNameTypesResponse` + * `GetBulkZoneCreateStatus` - `*BulkStatusResponse` into `*GetBulkZoneCreateStatusResponse` + * `GetBulkZoneDeleteStatus` - `*BulkStatusResponse` into `*GetBulkZoneDeleteStatusResponse` + * `GetBulkZoneCreateResult` - `*BulkCreateResultResponse` into `*GetBulkZoneCreateResultResponse` + * `GetBulkZoneDeleteResult` - `*BulkDeleteResultResponse` into `*GetBulkZoneDeleteResultResponse` + * `CreateBulkZones` - `*BulkZonesResponse` into `*CreateBulkZonesResponse` + * `DeleteBulkZones` - `*BulkZonesResponse` into `*DeleteBulkZonesResponse` + + * Removed following interfaces: + * `Authorities` + * `Data` + * `Records` + * `Recordsets` + * `TSIGKeys` + * `Zones` + + * Renamed following methods: + * `SaveChangelist` into `SaveChangeList` + * `SubmitChangelist` into `SubmitChangeList` + * `TSIGKeyBulkUpdate` into `UpdateTSIGKeyBulk` + +* GTM + * Refactored parameters in following methods: + * `ListASMaps` - from (context.Context, string) into (context.Context, `ListASMapsRequest`) + * `GetASMap` - from (context.Context, string, string) into (context.Context, `GetASMapRequests`) + * `CreateASMap` - from (context.Context, *ASMap, string) into (context.Context, `CreateASMapRequest`) + * `UpdateASMap` - from (context.Context, *ASMap, string) into (context.Context, `UpdateASMapRequest`) + * `DeleteASMap` - from (context.Context, *ASMap, string) into (context.Context, `DeleteASMapRequest`) + * `ListCIDRMaps` - from (context.Context, string) into (context.Context, `ListCIDRMapsRequest`) + * `GetCIDRMap` - from (context.Context, string, string) into (context.Context, `GetCIDRMapRequest`) + * `CreateCIDRMap` - from (context.Context, *CIDRMap, string) into (context.Context, `CreateCIDRMapRequest`) + * `UpdateCIDRMap` - from (context.Context, *CIDRMap, string) into (context.Context, `UpdateCIDRMapRequest`) + * `DeleteCIDRMap` - from (context.Context, *CIDRMap, string) into (context.Context, `DeleteCIDRMapRequest`) + * `ListDatacenters` - from (context.Context, string) into (context.Context, `ListDatacentersRequest`) + * `GetDatacenter` - from (context.Context, int, string) into (context.Context, `GetDatacenterRequest`) + * `CreateDatacenter` - from (context.Context, *Datacenter, string) into (context.Context, `CreateDatacenterRequest`) + * `UpdateDatacenter` - from (context.Context, *Datacenter, string) into (context.Context, `UpdateDatacenterRequest`) + * `DeleteDatacenter` - from (context.Context, *Datacenter, string) into (context.Context, `DeleteDatacenterRequest`) + * `GetDomainStatus` - from (context.Context, string) into (context.Context, `GetDomainStatusRequest`) + * `GetDomain` - from (context.Context, string) into (context.Context, `GetDomainRequest`) + * `CreateDomain` - from (context.Context, *Domain, map[string]string) into (context.Context, `CreateDomainRequest`) + * `UpdateDomain` - from (context.Context, *Domain, map[string]string) into (context.Context, `UpdateDomainRequest`) + * `DeleteDomain` - from (context.Context, *Domain) into (context.Context, `DeleteDomainRequest`) + * `ListGeoMaps` - from (context.Context, string) into (context.Context, `ListGeoMapsRequest`) + * `GetGeoMap` - from (context.Context, string, string) into (context.Context, `GetGeoMapRequest`) + * `CreateGeoMap` - from (context.Context, *GeoMap, string) into (context.Context, `CreateGeoMapRequest`) + * `UpdateGeoMap` - from (context.Context, *GeoMap, string) into (context.Context, `UpdateGeoMapRequest`) + * `DeleteGeoMap` - from (context.Context, *GeoMap, string) into (context.Context, `DeleteGeoMapRequest`) + * `ListProperties` - from (context.Context, string) into (context.Context, `ListPropertiesRequest`) + * `GetProperty` - from (context.Context, string, string) into (context.Context, `GetPropertyRequest`) + * `CreateProperty` - from (context.Context, *Property, string) into (context.Context, `CreatePropertyRequest`) + * `UpdateProperty` - from (context.Context, *Property, string) into (context.Context, `UpdatePropertyRequest`) + * `DeleteProperty` - from (context.Context, *Property, string) into (context.Context, `DeletePropertyRequest`) + * `ListResources` - from (context.Context, string) into (context.Context, `ListResourcesRequest`) + * `GetResource` - from (context.Context, string, string) into (context.Context, `GetResourceRequest`) + * `CreateResource` - from (context.Context, *Resource, string) into (context.Context, `CreateResourceRequest`) + * `UpdateResource` - from (context.Context, *Resource, string) into (context.Context, `UpdateResourceRequest`) + * `DeleteResource` - from (context.Context, *Resource, string) into (context.Context, `DeleteResourceRequest`) + + * Refactored response in following methods: + * `ListASMaps` - `[]*ASMap` into `[]ASMap` + * `GetASMap` - `*ASMap` into `*GetASMapResponse` + * `CreateASMap` - `*ASMapResponse` into `*CreateASMapResponse` + * `UpdateASMap` - `*ResponseStatus` into `*UpdateASMapResponse` + * `DeleteASMap` -`*ResponseStatus` into `*DeleteASMapResponse` + * `ListCIDRMaps` - `[]*CIDRMap` into `[]CIDRMap` + * `GetCIDRMap` - `*CIDRMap` into `*GetCIDRMapResponse` + * `CreateCIDRMap` - `*CIDRMapResponse` into `*CreateCIDRMapResponse` + * `UpdateCIDRMap` - `*ResponseStatus` into `*UpdateCIDRMapResponse` + * `DeleteCIDRMap` - `*ResponseStatus` into `*DeleteCIDRMapResponse` + * `ListDatacenters` - `[]*Datacenter` into `[]Datacenter` + * `CreateDatacenter` - `*DatacenterResponse` into `*CreateDatacenterResponse` + * `UpdateDatacenter` - `*ResponseStatus` into `*UpdateDatacenterResponse` + * `DeleteDatacenter` - `*ResponseStatus` into `*DeleteDatacenterResponse` + * `ListDomains` - `[]*DomainItem` into `[]DomainItem` + * `GetDomain` - `*Domain` into `*GetDomainResponse` + * `CreateDomain` - `*DomainResponse` into `*CreateDomainResponse` + * `UpdateDomain` - `*ResponseStatus` into `*UpdateDomainResponse` + * `DeleteDomain` - `*ResponseStatus` into `*DeleteDomainResponse` + * `GetDomainStatus` - `*ResponseStatus` into `*GetDomainStatusResponse` + * `ListGeoMaps` - `[]*GeoMap` into `[]GeoMap` + * `GetGeoMap` - `*GeoMap` into `*GetGeoMapResponse` + * `CreateGeoMap` - `*GeoMapResponse` into `*CreateGeoMapResponse` + * `UpdateGeoMap` - `*ResponseStatus` into `*UpdateGeoMapResponse` + * `DeleteGeoMap` - `*ResponseStatus` into `*DeleteGeoMapResponse` + * `ListProperties` - `[]*Property` into `[]Property` + * `GetProperty` - `*Property` into `*GetPropertyResponse` + * `CreateProperty` - `*PropertyResponse` into `*CreatePropertyResponse` + * `UpdateProperty` - `*ResponseStatus` into `*UpdatePropertyResponse` + * `DeleteProperty` - `*ResponseStatus` into `*DeletePropertyResponse` + * `ListResources` - `[]*Resource` into `[]Resource` + * `GetResource` - `*Resource` into `*GetResourceResponse` + * `CreateResource` - `*ResourceResponse` into `*CreateResourceResponse` + * `UpdateResource` - `*ResponseStatus` into `*UpdateResourceResponse` + * `DeleteResource` - `*ResponseStatus` into `*DeleteResourceResponse` + + * Extended response for following methods - previously only status was returned, now status and resource are returned: + * `UpdateASMap` + * `DeleteASMap` + * `UpdateCIDRMap` + * `DeleteCIDRMap` + * `UpdateDatacenter` + * `DeleteDatacenter` + * `UpdateDomain` + * `UpdateGeoMap` + * `DeleteGeoMap` + * `UpdateProperty` + * `DeleteProperty` + * `UpdateResource` + * `DeleteResource` + + * Removed following interfaces: + * `ASMaps` + * `CIDRMaps` + * `Datacenters` + * `Domains` + * `GeoMaps` + * `Properties` + * `Resources` + + + + + + diff --git a/pkg/dns/mocks.go b/pkg/dns/mocks.go index 161b82a2..7bbb0393 100644 --- a/pkg/dns/mocks.go +++ b/pkg/dns/mocks.go @@ -85,12 +85,6 @@ func (d *Mock) UpdateZone(ctx context.Context, req UpdateZoneRequest) error { return args.Error(0) } -func (d *Mock) DeleteZone(ctx context.Context, req DeleteRecordRequest) error { - args := d.Called(ctx, req) - - return args.Error(0) -} - func (d *Mock) GetZoneNames(ctx context.Context, req GetZoneNamesRequest) (*GetZoneNamesResponse, error) { args := d.Called(ctx, req) From d419f50e90f756205fc936c37196f334a3d7d0f0 Mon Sep 17 00:00:00 2001 From: Rahul Bhatvedekar Date: Tue, 24 Sep 2024 07:36:08 +0000 Subject: [PATCH 06/34] DXE-4060 Consolidate sub-interfaces Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/DXE-4060 to feature/sp-breaking-changes --- CHANGELOG.md | 3 +- pkg/clientlists/client_list.go | 33 -- pkg/clientlists/client_list_activation.go | 18 - pkg/clientlists/clientlists.go | 53 ++- pkg/cloudlets/cloudlets.go | 142 +++++++- pkg/cloudlets/loadbalancer.go | 26 -- pkg/cloudlets/loadbalancer_activation.go | 13 - pkg/cloudlets/loadbalancer_version.go | 23 -- pkg/cloudlets/policy.go | 28 -- pkg/cloudlets/policy_property.go | 11 - pkg/cloudlets/policy_version.go | 28 -- pkg/cloudlets/policy_version_activation.go | 13 - pkg/cloudwrapper/capacity.go | 9 - pkg/cloudwrapper/cloudwrapper.go | 76 ++++- pkg/cloudwrapper/configurations.go | 28 -- pkg/cloudwrapper/locations.go | 8 - pkg/cloudwrapper/multi_cdn.go | 13 - pkg/cloudwrapper/properties.go | 12 - pkg/cps/change_management_info.go | 19 -- pkg/cps/changes.go | 22 -- pkg/cps/cps.go | 169 +++++++++- pkg/cps/deployment_schedules.go | 13 - pkg/cps/deployments.go | 18 - pkg/cps/dv_challenges.go | 13 - pkg/cps/enrollments.go | 28 -- pkg/cps/history.go | 18 - pkg/cps/post_verification_warnings.go | 12 - pkg/cps/pre_verification_warnings.go | 13 - pkg/cps/third_party_csr.go | 13 - pkg/datastream/ds.go | 59 +++- pkg/datastream/mocks.go | 2 +- pkg/datastream/properties.go | 13 - pkg/datastream/stream.go | 28 -- pkg/datastream/stream_activation.go | 18 - pkg/dns/dns.go | 26 +- pkg/edgeworkers/activations.go | 23 -- pkg/edgeworkers/contracts.go | 8 - pkg/edgeworkers/deactivations.go | 18 - pkg/edgeworkers/edgekv_access_tokens.go | 23 -- pkg/edgeworkers/edgekv_groups.go | 8 - pkg/edgeworkers/edgekv_initialize.go | 12 - pkg/edgeworkers/edgekv_items.go | 23 -- pkg/edgeworkers/edgekv_namespaces.go | 23 -- pkg/edgeworkers/edgeworker_id.go | 33 -- pkg/edgeworkers/edgeworker_version.go | 28 -- pkg/edgeworkers/edgeworkers.go | 268 ++++++++++++++- pkg/edgeworkers/permission_group.go | 13 - pkg/edgeworkers/properties.go | 8 - pkg/edgeworkers/report.go | 18 - pkg/edgeworkers/resource_tier.go | 13 - pkg/edgeworkers/secure_tokens.go | 8 - pkg/edgeworkers/validations.go | 8 - pkg/gtm/gtm.go | 14 + pkg/hapi/change_requests.go | 9 - pkg/hapi/edgehostname.go | 26 -- pkg/hapi/hapi.go | 35 +- pkg/imaging/imaging.go | 40 ++- pkg/imaging/policy.go | 25 -- pkg/imaging/policyset.go | 20 -- pkg/networklists/activations.go | 25 -- pkg/networklists/network_list.go | 28 -- pkg/networklists/network_list_description.go | 13 - pkg/networklists/network_list_subscription.go | 18 - pkg/networklists/networklists.go | 90 ++++- pkg/networklists/networklists_test.go | 2 +- pkg/papi/activation.go | 23 -- pkg/papi/clientsettings.go | 13 - pkg/papi/contract.go | 8 - pkg/papi/cpcode.go | 28 -- pkg/papi/edgehostname.go | 18 - pkg/papi/group.go | 8 - pkg/papi/include.go | 28 -- pkg/papi/include_activations.go | 28 -- pkg/papi/include_rule.go | 13 - pkg/papi/include_versions.go | 28 -- pkg/papi/papi.go | 316 +++++++++++++++++- pkg/papi/products.go | 8 - pkg/papi/property.go | 28 -- pkg/papi/propertyhostname.go | 13 - pkg/papi/propertyversion.go | 43 --- pkg/papi/rule.go | 13 - pkg/papi/ruleformats.go | 8 - pkg/papi/search.go | 8 - 83 files changed, 1213 insertions(+), 1320 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b24daaaf..f70b4d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ #### BREAKING CHANGES: - +* General + * Consolidated multiple sub-interfaces into a single interface for each sub-provider. diff --git a/pkg/clientlists/client_list.go b/pkg/clientlists/client_list.go index bae14f21..37f455ec 100644 --- a/pkg/clientlists/client_list.go +++ b/pkg/clientlists/client_list.go @@ -12,39 +12,6 @@ import ( ) type ( - // Lists interface to support creating, retrieving, updating and removing client lists. - Lists interface { - // GetClientLists lists all client lists accessible for an authenticated user - // - // See: https://techdocs.akamai.com/client-lists/reference/get-lists - GetClientLists(ctx context.Context, params GetClientListsRequest) (*GetClientListsResponse, error) - - // GetClientList retrieves client list with specific list id - // - // See: https://techdocs.akamai.com/client-lists/reference/get-list - GetClientList(ctx context.Context, params GetClientListRequest) (*GetClientListResponse, error) - - // CreateClientList creates a new client list - // - // See: https://techdocs.akamai.com/client-lists/reference/post-create-list - CreateClientList(ctx context.Context, params CreateClientListRequest) (*CreateClientListResponse, error) - - // UpdateClientList updates existing client list - // - // See: https://techdocs.akamai.com/client-lists/reference/put-update-list - UpdateClientList(ctx context.Context, params UpdateClientListRequest) (*UpdateClientListResponse, error) - - // UpdateClientListItems updates items/entries of an existing client lists - // - // See: https://techdocs.akamai.com/client-lists/reference/post-update-items - UpdateClientListItems(ctx context.Context, params UpdateClientListItemsRequest) (*UpdateClientListItemsResponse, error) - - // DeleteClientList removes a client list - // - // See: https://techdocs.akamai.com/client-lists/reference/delete-list - DeleteClientList(ctx context.Context, params DeleteClientListRequest) error - } - // ClientListType represents client list type ClientListType string diff --git a/pkg/clientlists/client_list_activation.go b/pkg/clientlists/client_list_activation.go index b29ae558..466458c6 100644 --- a/pkg/clientlists/client_list_activation.go +++ b/pkg/clientlists/client_list_activation.go @@ -10,24 +10,6 @@ import ( ) type ( - // Activation interface to support activating client lists. - Activation interface { - // GetActivation retrieves details of a specified activation ID. - // - // See: https://techdocs.akamai.com/client-lists/reference/get-retrieve-activation-status - GetActivation(ctx context.Context, params GetActivationRequest) (*GetActivationResponse, error) - - // GetActivationStatus retrieves activation status for a client list in a network environment. - // - // See: https://techdocs.akamai.com/client-lists/reference/get-activation-status - GetActivationStatus(ctx context.Context, params GetActivationStatusRequest) (*GetActivationStatusResponse, error) - - // CreateActivation activates a client list - // - // See: https://techdocs.akamai.com/client-lists/reference/post-activate-list - CreateActivation(ctx context.Context, params CreateActivationRequest) (*CreateActivationResponse, error) - } - // ActivationParams contains activation general parameters ActivationParams struct { Action ActivationAction `json:"action"` diff --git a/pkg/clientlists/clientlists.go b/pkg/clientlists/clientlists.go index b358c3c2..72d6e48f 100644 --- a/pkg/clientlists/clientlists.go +++ b/pkg/clientlists/clientlists.go @@ -4,6 +4,7 @@ package clientlists import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,10 +16,56 @@ var ( ) type ( - // ClientLists is the clientlists api interface + // ClientLists is the API interface for Client Lists ClientLists interface { - Activation - Lists + // Activations + + // GetActivation retrieves details of a specified activation ID. + // + // See: https://techdocs.akamai.com/client-lists/reference/get-retrieve-activation-status + GetActivation(ctx context.Context, params GetActivationRequest) (*GetActivationResponse, error) + + // GetActivationStatus retrieves activation status for a client list in a network environment. + // + // See: https://techdocs.akamai.com/client-lists/reference/get-activation-status + GetActivationStatus(ctx context.Context, params GetActivationStatusRequest) (*GetActivationStatusResponse, error) + + // CreateActivation activates a client list + // + // See: https://techdocs.akamai.com/client-lists/reference/post-activate-list + CreateActivation(ctx context.Context, params CreateActivationRequest) (*CreateActivationResponse, error) + + // Lists + + // GetClientLists lists all client lists accessible for an authenticated user + // + // See: https://techdocs.akamai.com/client-lists/reference/get-lists + GetClientLists(ctx context.Context, params GetClientListsRequest) (*GetClientListsResponse, error) + + // GetClientList retrieves client list with specific list id + // + // See: https://techdocs.akamai.com/client-lists/reference/get-list + GetClientList(ctx context.Context, params GetClientListRequest) (*GetClientListResponse, error) + + // CreateClientList creates a new client list + // + // See: https://techdocs.akamai.com/client-lists/reference/post-create-list + CreateClientList(ctx context.Context, params CreateClientListRequest) (*CreateClientListResponse, error) + + // UpdateClientList updates existing client list + // + // See: https://techdocs.akamai.com/client-lists/reference/put-update-list + UpdateClientList(ctx context.Context, params UpdateClientListRequest) (*UpdateClientListResponse, error) + + // UpdateClientListItems updates items/entries of an existing client lists + // + // See: https://techdocs.akamai.com/client-lists/reference/post-update-items + UpdateClientListItems(ctx context.Context, params UpdateClientListItemsRequest) (*UpdateClientListItemsResponse, error) + + // DeleteClientList removes a client list + // + // See: https://techdocs.akamai.com/client-lists/reference/delete-list + DeleteClientList(ctx context.Context, params DeleteClientListRequest) error } clientlists struct { diff --git a/pkg/cloudlets/cloudlets.go b/pkg/cloudlets/cloudlets.go index 407e3894..0ca3414f 100644 --- a/pkg/cloudlets/cloudlets.go +++ b/pkg/cloudlets/cloudlets.go @@ -2,6 +2,7 @@ package cloudlets import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,13 +16,140 @@ var ( type ( // Cloudlets is the api interface for cloudlets Cloudlets interface { - LoadBalancers - LoadBalancerVersions - LoadBalancerActivations - Policies - PolicyProperties - PolicyVersions - PolicyVersionActivations + //LoadBalancers + + // ListOrigins lists all origins of specified type for the current account. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origins + ListOrigins(context.Context, ListOriginsRequest) ([]OriginResponse, error) + + // GetOrigin gets specific origin by originID. + // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin + GetOrigin(context.Context, GetOriginRequest) (*Origin, error) + + // CreateOrigin creates configuration for an origin. + // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin + CreateOrigin(context.Context, CreateOriginRequest) (*Origin, error) + + // UpdateOrigin creates configuration for an origin. + // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-origin + UpdateOrigin(context.Context, UpdateOriginRequest) (*Origin, error) + + // LoadBalancerVersions + + // CreateLoadBalancerVersion creates load balancer version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin-versions + CreateLoadBalancerVersion(context.Context, CreateLoadBalancerVersionRequest) (*LoadBalancerVersion, error) + + // GetLoadBalancerVersion gets specific load balancer version by originID and version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-version + GetLoadBalancerVersion(context.Context, GetLoadBalancerVersionRequest) (*LoadBalancerVersion, error) + + // UpdateLoadBalancerVersion updates specific load balancer version by originID and version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-origin-version + UpdateLoadBalancerVersion(context.Context, UpdateLoadBalancerVersionRequest) (*LoadBalancerVersion, error) + + // ListLoadBalancerVersions lists all versions of Origin with type APPLICATION_LOAD_BALANCER. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-versions + ListLoadBalancerVersions(context.Context, ListLoadBalancerVersionsRequest) ([]LoadBalancerVersion, error) + + // LoadBalancerActivations + + // ListLoadBalancerActivations fetches activations with the most recent listed first. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-activations + ListLoadBalancerActivations(context.Context, ListLoadBalancerActivationsRequest) ([]LoadBalancerActivation, error) + + // ActivateLoadBalancerVersion activates the load balancing version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin-activations + ActivateLoadBalancerVersion(context.Context, ActivateLoadBalancerVersionRequest) (*LoadBalancerActivation, error) + + // Policies + + // ListPolicies lists policies. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policies + ListPolicies(context.Context, ListPoliciesRequest) ([]Policy, error) + + // GetPolicy gets policy by policyID. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy + GetPolicy(context.Context, GetPolicyRequest) (*Policy, error) + + // CreatePolicy creates policy. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy + CreatePolicy(context.Context, CreatePolicyRequest) (*Policy, error) + + // RemovePolicy removes policy. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/delete-policy + RemovePolicy(context.Context, RemovePolicyRequest) error + + // UpdatePolicy updates policy. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-policy + UpdatePolicy(context.Context, UpdatePolicyRequest) (*Policy, error) + + // PolicyProperties + + // GetPolicyProperties gets all the associated properties by the policyID. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-properties + GetPolicyProperties(context.Context, GetPolicyPropertiesRequest) (map[string]PolicyProperty, error) + + // DeletePolicyProperty removes a property from a policy activation associated_properties list. + DeletePolicyProperty(context.Context, DeletePolicyPropertyRequest) error + + // PolicyVersions + + // ListPolicyVersions lists policy versions by policyID. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-versions + ListPolicyVersions(context.Context, ListPolicyVersionsRequest) ([]PolicyVersion, error) + + // GetPolicyVersion gets policy version by policyID and version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-version + GetPolicyVersion(context.Context, GetPolicyVersionRequest) (*PolicyVersion, error) + + // CreatePolicyVersion creates policy version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy-versions + CreatePolicyVersion(context.Context, CreatePolicyVersionRequest) (*PolicyVersion, error) + + // DeletePolicyVersion deletes policy version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/delete-policy-version + DeletePolicyVersion(context.Context, DeletePolicyVersionRequest) error + + // UpdatePolicyVersion updates policy version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-policy-version + UpdatePolicyVersion(context.Context, UpdatePolicyVersionRequest) (*PolicyVersion, error) + + // PolicyVersionActivations + + // ListPolicyActivations returns the complete activation history for the selected policy in reverse chronological order. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-activations + ListPolicyActivations(context.Context, ListPolicyActivationsRequest) ([]PolicyActivation, error) + + // ActivatePolicyVersion activates the selected cloudlet policy version. + // + // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy-version-activations + ActivatePolicyVersion(context.Context, ActivatePolicyVersionRequest) ([]PolicyActivation, error) } cloudlets struct { diff --git a/pkg/cloudlets/loadbalancer.go b/pkg/cloudlets/loadbalancer.go index 0f9e0b6f..c390d8cc 100644 --- a/pkg/cloudlets/loadbalancer.go +++ b/pkg/cloudlets/loadbalancer.go @@ -13,32 +13,6 @@ import ( ) type ( - // LoadBalancers is a cloudlets LoadBalancer API interface. - LoadBalancers interface { - // ListOrigins lists all origins of specified type for the current account. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origins - ListOrigins(context.Context, ListOriginsRequest) ([]OriginResponse, error) - - // GetOrigin gets specific origin by originID. - // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin - GetOrigin(context.Context, GetOriginRequest) (*Origin, error) - - // CreateOrigin creates configuration for an origin. - // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin - CreateOrigin(context.Context, CreateOriginRequest) (*Origin, error) - - // UpdateOrigin creates configuration for an origin. - // This operation is only available for the APPLICATION_LOAD_BALANCER origin type. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-origin - UpdateOrigin(context.Context, UpdateOriginRequest) (*Origin, error) - } - // OriginResponse is an Origin returned in ListOrigins OriginResponse struct { Hostname string `json:"hostname"` diff --git a/pkg/cloudlets/loadbalancer_activation.go b/pkg/cloudlets/loadbalancer_activation.go index 269f9574..39da4ce2 100644 --- a/pkg/cloudlets/loadbalancer_activation.go +++ b/pkg/cloudlets/loadbalancer_activation.go @@ -14,19 +14,6 @@ import ( ) type ( - // LoadBalancerActivations is a cloudlets LoadBalancer Activation API interface. - LoadBalancerActivations interface { - // ListLoadBalancerActivations fetches activations with the most recent listed first. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-activations - ListLoadBalancerActivations(context.Context, ListLoadBalancerActivationsRequest) ([]LoadBalancerActivation, error) - - // ActivateLoadBalancerVersion activates the load balancing version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin-activations - ActivateLoadBalancerVersion(context.Context, ActivateLoadBalancerVersionRequest) (*LoadBalancerActivation, error) - } - // ListLoadBalancerActivationsRequest contains request parameters for ListLoadBalancerActivations ListLoadBalancerActivationsRequest struct { OriginID string diff --git a/pkg/cloudlets/loadbalancer_version.go b/pkg/cloudlets/loadbalancer_version.go index 8859b21f..24bf407f 100644 --- a/pkg/cloudlets/loadbalancer_version.go +++ b/pkg/cloudlets/loadbalancer_version.go @@ -15,29 +15,6 @@ import ( ) type ( - // LoadBalancerVersions is a cloudlets LoadBalancer version API interface. - LoadBalancerVersions interface { - // CreateLoadBalancerVersion creates load balancer version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-origin-versions - CreateLoadBalancerVersion(context.Context, CreateLoadBalancerVersionRequest) (*LoadBalancerVersion, error) - - // GetLoadBalancerVersion gets specific load balancer version by originID and version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-version - GetLoadBalancerVersion(context.Context, GetLoadBalancerVersionRequest) (*LoadBalancerVersion, error) - - // UpdateLoadBalancerVersion updates specific load balancer version by originID and version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-origin-version - UpdateLoadBalancerVersion(context.Context, UpdateLoadBalancerVersionRequest) (*LoadBalancerVersion, error) - - // ListLoadBalancerVersions lists all versions of Origin with type APPLICATION_LOAD_BALANCER. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-origin-versions - ListLoadBalancerVersions(context.Context, ListLoadBalancerVersionsRequest) ([]LoadBalancerVersion, error) - } - // DataCenter represents the dataCenter field of load balancer version DataCenter struct { City string `json:"city,omitempty"` diff --git a/pkg/cloudlets/policy.go b/pkg/cloudlets/policy.go index e161690c..b508638d 100644 --- a/pkg/cloudlets/policy.go +++ b/pkg/cloudlets/policy.go @@ -13,34 +13,6 @@ import ( ) type ( - // Policies is a cloudlets policies API interface. - Policies interface { - // ListPolicies lists policies. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policies - ListPolicies(context.Context, ListPoliciesRequest) ([]Policy, error) - - // GetPolicy gets policy by policyID. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy - GetPolicy(context.Context, GetPolicyRequest) (*Policy, error) - - // CreatePolicy creates policy. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy - CreatePolicy(context.Context, CreatePolicyRequest) (*Policy, error) - - // RemovePolicy removes policy. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/delete-policy - RemovePolicy(context.Context, RemovePolicyRequest) error - - // UpdatePolicy updates policy. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-policy - UpdatePolicy(context.Context, UpdatePolicyRequest) (*Policy, error) - } - // Policy is response returned by GetPolicy or UpdatePolicy Policy struct { Location string `json:"location"` diff --git a/pkg/cloudlets/policy_property.go b/pkg/cloudlets/policy_property.go index dd466fa0..4b9dc4f0 100644 --- a/pkg/cloudlets/policy_property.go +++ b/pkg/cloudlets/policy_property.go @@ -13,17 +13,6 @@ import ( ) type ( - // PolicyProperties interface is a cloudlets API interface for policy associated properties. - PolicyProperties interface { - // GetPolicyProperties gets all the associated properties by the policyID. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-properties - GetPolicyProperties(context.Context, GetPolicyPropertiesRequest) (map[string]PolicyProperty, error) - - // DeletePolicyProperty removes a property from a policy activation associated_properties list. - DeletePolicyProperty(context.Context, DeletePolicyPropertyRequest) error - } - // GetPolicyPropertiesRequest contains request parameters for GetPolicyPropertiesRequest GetPolicyPropertiesRequest struct { PolicyID int64 diff --git a/pkg/cloudlets/policy_version.go b/pkg/cloudlets/policy_version.go index 42777378..63b757a8 100644 --- a/pkg/cloudlets/policy_version.go +++ b/pkg/cloudlets/policy_version.go @@ -14,34 +14,6 @@ import ( ) type ( - // PolicyVersions is a cloudlets policy versions API interface. - PolicyVersions interface { - // ListPolicyVersions lists policy versions by policyID. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-versions - ListPolicyVersions(context.Context, ListPolicyVersionsRequest) ([]PolicyVersion, error) - - // GetPolicyVersion gets policy version by policyID and version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-version - GetPolicyVersion(context.Context, GetPolicyVersionRequest) (*PolicyVersion, error) - - // CreatePolicyVersion creates policy version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy-versions - CreatePolicyVersion(context.Context, CreatePolicyVersionRequest) (*PolicyVersion, error) - - // DeletePolicyVersion deletes policy version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/delete-policy-version - DeletePolicyVersion(context.Context, DeletePolicyVersionRequest) error - - // UpdatePolicyVersion updates policy version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/put-policy-version - UpdatePolicyVersion(context.Context, UpdatePolicyVersionRequest) (*PolicyVersion, error) - } - // PolicyVersion is response returned by GetPolicyVersion, CreatePolicyVersion or UpdatePolicyVersion PolicyVersion struct { Location string `json:"location"` diff --git a/pkg/cloudlets/policy_version_activation.go b/pkg/cloudlets/policy_version_activation.go index 1b2ce15b..21ff164d 100644 --- a/pkg/cloudlets/policy_version_activation.go +++ b/pkg/cloudlets/policy_version_activation.go @@ -14,19 +14,6 @@ import ( ) type ( - // PolicyVersionActivations is a cloudlets PolicyVersionActivations API interface. - PolicyVersionActivations interface { - // ListPolicyActivations returns the complete activation history for the selected policy in reverse chronological order. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/get-policy-activations - ListPolicyActivations(context.Context, ListPolicyActivationsRequest) ([]PolicyActivation, error) - - // ActivatePolicyVersion activates the selected cloudlet policy version. - // - // See: https://techdocs.akamai.com/cloudlets/v2/reference/post-policy-version-activations - ActivatePolicyVersion(context.Context, ActivatePolicyVersionRequest) ([]PolicyActivation, error) - } - // ListPolicyActivationsRequest contains the request parameters for ListPolicyActivations ListPolicyActivationsRequest struct { PolicyID int64 diff --git a/pkg/cloudwrapper/capacity.go b/pkg/cloudwrapper/capacity.go index f7f97024..66a04523 100644 --- a/pkg/cloudwrapper/capacity.go +++ b/pkg/cloudwrapper/capacity.go @@ -9,15 +9,6 @@ import ( ) type ( - // Capacities is a Cloud Wrapper API interface. - Capacities interface { - // ListCapacities fetches capacities available for a given contractId. - // If no contract id is provided, lists all available capacity locations - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-capacity-inventory - ListCapacities(context.Context, ListCapacitiesRequest) (*ListCapacitiesResponse, error) - } - // ListCapacitiesRequest is a request struct ListCapacitiesRequest struct { ContractIDs []string diff --git a/pkg/cloudwrapper/cloudwrapper.go b/pkg/cloudwrapper/cloudwrapper.go index 46b8bbcf..e61662e8 100644 --- a/pkg/cloudwrapper/cloudwrapper.go +++ b/pkg/cloudwrapper/cloudwrapper.go @@ -2,6 +2,7 @@ package cloudwrapper import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,11 +16,76 @@ var ( type ( // CloudWrapper is the api interface for Cloud Wrapper CloudWrapper interface { - Capacities - Configurations - Locations - MultiCDN - Properties + // Capacities + + // ListCapacities fetches capacities available for a given contractId. + // If no contract id is provided, lists all available capacity locations + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-capacity-inventory + ListCapacities(context.Context, ListCapacitiesRequest) (*ListCapacitiesResponse, error) + + // Configurations + + // GetConfiguration gets a specific Cloud Wrapper configuration + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-configuration + GetConfiguration(context.Context, GetConfigurationRequest) (*Configuration, error) + + // ListConfigurations lists all Cloud Wrapper configurations on your contract + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-configurations + ListConfigurations(context.Context) (*ListConfigurationsResponse, error) + + // CreateConfiguration creates a Cloud Wrapper configuration + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/post-configuration + CreateConfiguration(context.Context, CreateConfigurationRequest) (*Configuration, error) + + // UpdateConfiguration updates a saved or inactive configuration + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/put-configuration + UpdateConfiguration(context.Context, UpdateConfigurationRequest) (*Configuration, error) + + // DeleteConfiguration deletes configuration + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/delete-configuration + DeleteConfiguration(context.Context, DeleteConfigurationRequest) error + + // ActivateConfiguration activates a Cloud Wrapper configuration + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/post-configuration-activations + ActivateConfiguration(context.Context, ActivateConfigurationRequest) error + + // Locations + + // ListLocations returns a list of locations available to distribute Cloud Wrapper capacity + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-locations + ListLocations(context.Context) (*ListLocationResponse, error) + + // MultiCDN + + // ListAuthKeys lists the cdnAuthKeys for a specified contractId and cdnCode + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-auth-keys + ListAuthKeys(context.Context, ListAuthKeysRequest) (*ListAuthKeysResponse, error) + + // ListCDNProviders lists CDN providers + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-providers + ListCDNProviders(context.Context) (*ListCDNProvidersResponse, error) + + // Properties + + // ListProperties lists unused properties + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-properties + ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) + + // ListOrigins lists property origins + // + // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-origins + ListOrigins(context.Context, ListOriginsRequest) (*ListOriginsResponse, error) } cloudwrapper struct { diff --git a/pkg/cloudwrapper/configurations.go b/pkg/cloudwrapper/configurations.go index 6d47041b..f03c090b 100644 --- a/pkg/cloudwrapper/configurations.go +++ b/pkg/cloudwrapper/configurations.go @@ -13,34 +13,6 @@ import ( ) type ( - // Configurations is a CloudWrapper configurations API interface - Configurations interface { - // GetConfiguration gets a specific Cloud Wrapper configuration - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-configuration - GetConfiguration(context.Context, GetConfigurationRequest) (*Configuration, error) - // ListConfigurations lists all Cloud Wrapper configurations on your contract - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-configurations - ListConfigurations(context.Context) (*ListConfigurationsResponse, error) - // CreateConfiguration creates a Cloud Wrapper configuration - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/post-configuration - CreateConfiguration(context.Context, CreateConfigurationRequest) (*Configuration, error) - // UpdateConfiguration updates a saved or inactive configuration - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/put-configuration - UpdateConfiguration(context.Context, UpdateConfigurationRequest) (*Configuration, error) - // DeleteConfiguration deletes configuration - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/delete-configuration - DeleteConfiguration(context.Context, DeleteConfigurationRequest) error - // ActivateConfiguration activates a Cloud Wrapper configuration - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/post-configuration-activations - ActivateConfiguration(context.Context, ActivateConfigurationRequest) error - } - // GetConfigurationRequest holds parameters for GetConfiguration GetConfigurationRequest struct { ConfigID int64 diff --git a/pkg/cloudwrapper/locations.go b/pkg/cloudwrapper/locations.go index 1ed99ab2..53f6f986 100644 --- a/pkg/cloudwrapper/locations.go +++ b/pkg/cloudwrapper/locations.go @@ -8,14 +8,6 @@ import ( ) type ( - // Locations is the cloudwrapper location API interface - Locations interface { - // ListLocations returns a list of locations available to distribute Cloud Wrapper capacity - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-locations - ListLocations(context.Context) (*ListLocationResponse, error) - } - // ListLocationResponse represents a response object returned by ListLocations ListLocationResponse struct { Locations []Location `json:"locations"` diff --git a/pkg/cloudwrapper/multi_cdn.go b/pkg/cloudwrapper/multi_cdn.go index 8824ea2e..4189b1ff 100644 --- a/pkg/cloudwrapper/multi_cdn.go +++ b/pkg/cloudwrapper/multi_cdn.go @@ -12,19 +12,6 @@ import ( ) type ( - // MultiCDN is the cloudwrapper Multi-CDN API interface - MultiCDN interface { - // ListAuthKeys lists the cdnAuthKeys for a specified contractId and cdnCode - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-auth-keys - ListAuthKeys(context.Context, ListAuthKeysRequest) (*ListAuthKeysResponse, error) - - // ListCDNProviders lists CDN providers - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-providers - ListCDNProviders(context.Context) (*ListCDNProvidersResponse, error) - } - // ListAuthKeysRequest is a request struct ListAuthKeysRequest struct { ContractID string diff --git a/pkg/cloudwrapper/properties.go b/pkg/cloudwrapper/properties.go index e4b12f89..604d21e4 100644 --- a/pkg/cloudwrapper/properties.go +++ b/pkg/cloudwrapper/properties.go @@ -13,18 +13,6 @@ import ( ) type ( - // Properties is a CloudWrapper properties API interface - Properties interface { - // ListProperties lists unused properties - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-properties - ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) - // ListOrigins lists property origins - // - // See: https://techdocs.akamai.com/cloud-wrapper/reference/get-origins - ListOrigins(context.Context, ListOriginsRequest) (*ListOriginsResponse, error) - } - // ListPropertiesRequest holds parameters for ListProperties ListPropertiesRequest struct { Unused bool diff --git a/pkg/cps/change_management_info.go b/pkg/cps/change_management_info.go index 4e3c222f..ad44f800 100644 --- a/pkg/cps/change_management_info.go +++ b/pkg/cps/change_management_info.go @@ -8,25 +8,6 @@ import ( ) type ( - // ChangeManagementInfo is a CPS API enabling change management - ChangeManagementInfo interface { - // GetChangeManagementInfo gets information about acknowledgement status, - // and may include warnings about potential conflicts that may occur if you proceed with acknowledgement - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangeManagementInfo(ctx context.Context, params GetChangeRequest) (*ChangeManagementInfoResponse, error) - - // GetChangeDeploymentInfo gets deployment currently deployed to the staging network - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangeDeploymentInfo(ctx context.Context, params GetChangeRequest) (*ChangeDeploymentInfoResponse, error) - - // AcknowledgeChangeManagement sends acknowledgement request to CPS to proceed deploying the certificate to the production network - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - AcknowledgeChangeManagement(context.Context, AcknowledgementRequest) error - } - // ChangeManagementInfoResponse contains response from GetChangeManagementInfo ChangeManagementInfoResponse struct { AcknowledgementDeadline *string `json:"acknowledgementDeadline"` diff --git a/pkg/cps/changes.go b/pkg/cps/changes.go index 785ebb70..161c3b4b 100644 --- a/pkg/cps/changes.go +++ b/pkg/cps/changes.go @@ -11,28 +11,6 @@ import ( ) type ( - // ChangeOperations is a CPS change API interface - ChangeOperations interface { - // GetChangeStatus fetches change status for given enrollment and change ID - // - // See: https://techdocs.akamai.com/cps/reference/get-enrollment-change - GetChangeStatus(context.Context, GetChangeStatusRequest) (*Change, error) - - // CancelChange cancels a pending change - // - // See: https://techdocs.akamai.com/cps/reference/delete-enrollment-change - CancelChange(context.Context, CancelChangeRequest) (*CancelChangeResponse, error) - - // UpdateChange updates a pending change - // Deprecated: this function will be removed in a future release. Use one of: - // AcknowledgeChangeManagement(), AcknowledgePostVerificationWarnings(), - // AcknowledgePreVerificationWarnings(), UploadThirdPartyCertAndTrustChain() - // or AcknowledgeDVChallenges() - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - UpdateChange(context.Context, UpdateChangeRequest) (*UpdateChangeResponse, error) - } - // Change contains change status information Change struct { AllowedInput []AllowedInput `json:"allowedInput"` diff --git a/pkg/cps/cps.go b/pkg/cps/cps.go index c8166158..a774d933 100644 --- a/pkg/cps/cps.go +++ b/pkg/cps/cps.go @@ -2,6 +2,7 @@ package cps import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,16 +16,164 @@ var ( type ( // CPS is the cps api interface CPS interface { - ChangeManagementInfo - ChangeOperations - Deployments - DeploymentSchedules - DVChallenges - Enrollments - History - PostVerification - PreVerification - ThirdPartyCSR + // ChangeManagementInfo + + // GetChangeManagementInfo gets information about acknowledgement status, + // and may include warnings about potential conflicts that may occur if you proceed with acknowledgement + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangeManagementInfo(ctx context.Context, params GetChangeRequest) (*ChangeManagementInfoResponse, error) + + // GetChangeDeploymentInfo gets deployment currently deployed to the staging network + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangeDeploymentInfo(ctx context.Context, params GetChangeRequest) (*ChangeDeploymentInfoResponse, error) + + // AcknowledgeChangeManagement sends acknowledgement request to CPS to proceed deploying the certificate to the production network + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + AcknowledgeChangeManagement(context.Context, AcknowledgementRequest) error + + // GetChangeStatus fetches change status for given enrollment and change ID + // + // See: https://techdocs.akamai.com/cps/reference/get-enrollment-change + GetChangeStatus(context.Context, GetChangeStatusRequest) (*Change, error) + + // ChangeOperations + + // CancelChange cancels a pending change + // + // See: https://techdocs.akamai.com/cps/reference/delete-enrollment-change + CancelChange(context.Context, CancelChangeRequest) (*CancelChangeResponse, error) + + // UpdateChange updates a pending change + // Deprecated: this function will be removed in a future release. Use one of: + // AcknowledgeChangeManagement(), AcknowledgePostVerificationWarnings(), + // AcknowledgePreVerificationWarnings(), UploadThirdPartyCertAndTrustChain() + // or AcknowledgeDVChallenges() + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + UpdateChange(context.Context, UpdateChangeRequest) (*UpdateChangeResponse, error) + + // Deployments + + // ListDeployments fetches deployments for given enrollment + // + // See: https://techdocs.akamai.com/cps/reference/get-deployments + ListDeployments(context.Context, ListDeploymentsRequest) (*ListDeploymentsResponse, error) + + // GetProductionDeployment fetches production deployment for given enrollment + // + // See: https://techdocs.akamai.com/cps/reference/get-deployments-production + GetProductionDeployment(context.Context, GetDeploymentRequest) (*GetProductionDeploymentResponse, error) + + // GetStagingDeployment fetches staging deployment for given enrollment + // + // See: https://techdocs.akamai.com/cps/reference/get-deployment-staging + GetStagingDeployment(context.Context, GetDeploymentRequest) (*GetStagingDeploymentResponse, error) + + // DeploymentSchedules + + // GetDeploymentSchedule fetches the current deployment schedule settings describing when a change deploys to the network + // + // See: https://techdocs.akamai.com/cps/reference/get-change-deployment-schedule + GetDeploymentSchedule(context.Context, GetDeploymentScheduleRequest) (*DeploymentSchedule, error) + + // UpdateDeploymentSchedule updates the current deployment schedule + // + // See: https://techdocs.akamai.com/cps/reference/put-change-deployment-schedule + UpdateDeploymentSchedule(context.Context, UpdateDeploymentScheduleRequest) (*UpdateDeploymentScheduleResponse, error) + + // DVChallenges + + // GetChangeLetsEncryptChallenges gets detailed information about Domain Validation challenges + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangeLetsEncryptChallenges(context.Context, GetChangeRequest) (*DVArray, error) + + // AcknowledgeDVChallenges sends acknowledgement request to CPS informing that the validation is completed + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + AcknowledgeDVChallenges(context.Context, AcknowledgementRequest) error + + // Enrollments + + // ListEnrollments fetches all enrollments with given contractId + // + // See https://techdocs.akamai.com/cps/reference/get-enrollments + ListEnrollments(context.Context, ListEnrollmentsRequest) (*ListEnrollmentsResponse, error) + + // GetEnrollment fetches enrollment object with given ID + // + // See: https://techdocs.akamai.com/cps/reference/get-enrollment + GetEnrollment(context.Context, GetEnrollmentRequest) (*GetEnrollmentResponse, error) + + // CreateEnrollment creates a new enrollment + // + // See: https://techdocs.akamai.com/cps/reference/post-enrollment + CreateEnrollment(context.Context, CreateEnrollmentRequest) (*CreateEnrollmentResponse, error) + + // UpdateEnrollment updates a single enrollment entry with given ID + // + // See: https://techdocs.akamai.com/cps/reference/put-enrollment + UpdateEnrollment(context.Context, UpdateEnrollmentRequest) (*UpdateEnrollmentResponse, error) + + // RemoveEnrollment removes an enrollment with given ID + // + // See: https://techdocs.akamai.com/cps/reference/delete-enrollment + RemoveEnrollment(context.Context, RemoveEnrollmentRequest) (*RemoveEnrollmentResponse, error) + + // History + + // GetDVHistory is a domain name validation history for the enrollment + // + // See: https://techdocs.akamai.com/cps/reference/get-dv-history + GetDVHistory(context.Context, GetDVHistoryRequest) (*GetDVHistoryResponse, error) + + // GetCertificateHistory views the certificate history. + // + // See: https://techdocs.akamai.com/cps/reference/get-history-certificates + GetCertificateHistory(context.Context, GetCertificateHistoryRequest) (*GetCertificateHistoryResponse, error) + + // GetChangeHistory views the change history for enrollment. + // + // See: https://techdocs.akamai.com/cps/reference/get-history-changes + GetChangeHistory(context.Context, GetChangeHistoryRequest) (*GetChangeHistoryResponse, error) + + // PostVerification + + // GetChangePostVerificationWarnings gets information about post verification warnings + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangePostVerificationWarnings(ctx context.Context, params GetChangeRequest) (*PostVerificationWarnings, error) + // AcknowledgePostVerificationWarnings sends acknowledgement request to CPS informing that the warnings should be ignored + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + AcknowledgePostVerificationWarnings(context.Context, AcknowledgementRequest) error + + // PreVerification + + // GetChangePreVerificationWarnings gets detailed information about Domain Validation challenges + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangePreVerificationWarnings(ctx context.Context, params GetChangeRequest) (*PreVerificationWarnings, error) + + // AcknowledgePreVerificationWarnings sends acknowledgement request to CPS informing that the warnings should be ignored + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + AcknowledgePreVerificationWarnings(context.Context, AcknowledgementRequest) error + + // ThirdPartyCSR + + // GetChangeThirdPartyCSR gets certificate signing request + // + // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param + GetChangeThirdPartyCSR(ctx context.Context, params GetChangeRequest) (*ThirdPartyCSRResponse, error) + + // UploadThirdPartyCertAndTrustChain uploads signed certificate and trust chain to cps + // + // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param + UploadThirdPartyCertAndTrustChain(context.Context, UploadThirdPartyCertAndTrustChainRequest) error } cps struct { diff --git a/pkg/cps/deployment_schedules.go b/pkg/cps/deployment_schedules.go index 54bdd75a..1c622e69 100644 --- a/pkg/cps/deployment_schedules.go +++ b/pkg/cps/deployment_schedules.go @@ -10,19 +10,6 @@ import ( ) type ( - // DeploymentSchedules is a CPS deployment schedules API interface - DeploymentSchedules interface { - // GetDeploymentSchedule fetches the current deployment schedule settings describing when a change deploys to the network - // - // See: https://techdocs.akamai.com/cps/reference/get-change-deployment-schedule - GetDeploymentSchedule(context.Context, GetDeploymentScheduleRequest) (*DeploymentSchedule, error) - - // UpdateDeploymentSchedule updates the current deployment schedule - // - // See: https://techdocs.akamai.com/cps/reference/put-change-deployment-schedule - UpdateDeploymentSchedule(context.Context, UpdateDeploymentScheduleRequest) (*UpdateDeploymentScheduleResponse, error) - } - // GetDeploymentScheduleRequest contains parameters for GetDeploymentSchedule GetDeploymentScheduleRequest struct { ChangeID int diff --git a/pkg/cps/deployments.go b/pkg/cps/deployments.go index b89f9ec1..b46551a5 100644 --- a/pkg/cps/deployments.go +++ b/pkg/cps/deployments.go @@ -10,24 +10,6 @@ import ( ) type ( - // Deployments is a CPS deployments API interface - Deployments interface { - // ListDeployments fetches deployments for given enrollment - // - // See: https://techdocs.akamai.com/cps/reference/get-deployments - ListDeployments(context.Context, ListDeploymentsRequest) (*ListDeploymentsResponse, error) - - // GetProductionDeployment fetches production deployment for given enrollment - // - // See: https://techdocs.akamai.com/cps/reference/get-deployments-production - GetProductionDeployment(context.Context, GetDeploymentRequest) (*GetProductionDeploymentResponse, error) - - // GetStagingDeployment fetches staging deployment for given enrollment - // - // See: https://techdocs.akamai.com/cps/reference/get-deployment-staging - GetStagingDeployment(context.Context, GetDeploymentRequest) (*GetStagingDeploymentResponse, error) - } - // ListDeploymentsRequest contains parameters for ListDeployments ListDeploymentsRequest struct { EnrollmentID int diff --git a/pkg/cps/dv_challenges.go b/pkg/cps/dv_challenges.go index 3767dd85..91356f0d 100644 --- a/pkg/cps/dv_challenges.go +++ b/pkg/cps/dv_challenges.go @@ -9,19 +9,6 @@ import ( ) type ( - // DVChallenges is a CPS DV challenges API interface - DVChallenges interface { - // GetChangeLetsEncryptChallenges gets detailed information about Domain Validation challenges - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangeLetsEncryptChallenges(context.Context, GetChangeRequest) (*DVArray, error) - - // AcknowledgeDVChallenges sends acknowledgement request to CPS informing that the validation is completed - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - AcknowledgeDVChallenges(context.Context, AcknowledgementRequest) error - } - // DVArray is an array of DV objects DVArray struct { DV []DV `json:"dv"` diff --git a/pkg/cps/enrollments.go b/pkg/cps/enrollments.go index ae83b04a..a471ff05 100644 --- a/pkg/cps/enrollments.go +++ b/pkg/cps/enrollments.go @@ -12,34 +12,6 @@ import ( ) type ( - // Enrollments is a CPS enrollments API interface - Enrollments interface { - // ListEnrollments fetches all enrollments with given contractId - // - // See https://techdocs.akamai.com/cps/reference/get-enrollments - ListEnrollments(context.Context, ListEnrollmentsRequest) (*ListEnrollmentsResponse, error) - - // GetEnrollment fetches enrollment object with given ID - // - // See: https://techdocs.akamai.com/cps/reference/get-enrollment - GetEnrollment(context.Context, GetEnrollmentRequest) (*GetEnrollmentResponse, error) - - // CreateEnrollment creates a new enrollment - // - // See: https://techdocs.akamai.com/cps/reference/post-enrollment - CreateEnrollment(context.Context, CreateEnrollmentRequest) (*CreateEnrollmentResponse, error) - - // UpdateEnrollment updates a single enrollment entry with given ID - // - // See: https://techdocs.akamai.com/cps/reference/put-enrollment - UpdateEnrollment(context.Context, UpdateEnrollmentRequest) (*UpdateEnrollmentResponse, error) - - // RemoveEnrollment removes an enrollment with given ID - // - // See: https://techdocs.akamai.com/cps/reference/delete-enrollment - RemoveEnrollment(context.Context, RemoveEnrollmentRequest) (*RemoveEnrollmentResponse, error) - } - // ListEnrollmentsResponse represents list of CPS enrollment objects under given contractId. It is used as a response body while fetching enrollments by contractId ListEnrollmentsResponse struct { Enrollments []Enrollment `json:"enrollments"` diff --git a/pkg/cps/history.go b/pkg/cps/history.go index 51366f1a..957f88fe 100644 --- a/pkg/cps/history.go +++ b/pkg/cps/history.go @@ -10,24 +10,6 @@ import ( ) type ( - // History is a CPS interface for History management - History interface { - // GetDVHistory is a domain name validation history for the enrollment - // - // See: https://techdocs.akamai.com/cps/reference/get-dv-history - GetDVHistory(context.Context, GetDVHistoryRequest) (*GetDVHistoryResponse, error) - - // GetCertificateHistory views the certificate history. - // - // See: https://techdocs.akamai.com/cps/reference/get-history-certificates - GetCertificateHistory(context.Context, GetCertificateHistoryRequest) (*GetCertificateHistoryResponse, error) - - // GetChangeHistory views the change history for enrollment. - // - // See: https://techdocs.akamai.com/cps/reference/get-history-changes - GetChangeHistory(context.Context, GetChangeHistoryRequest) (*GetChangeHistoryResponse, error) - } - // GetDVHistoryRequest represents request for GetDVHistory operation GetDVHistoryRequest struct { EnrollmentID int diff --git a/pkg/cps/post_verification_warnings.go b/pkg/cps/post_verification_warnings.go index 6fa39cfc..bad0a129 100644 --- a/pkg/cps/post_verification_warnings.go +++ b/pkg/cps/post_verification_warnings.go @@ -8,18 +8,6 @@ import ( ) type ( - // PostVerification is a CPS API enabling management of post-verification-warnings - PostVerification interface { - // GetChangePostVerificationWarnings gets information about post verification warnings - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangePostVerificationWarnings(ctx context.Context, params GetChangeRequest) (*PostVerificationWarnings, error) - // AcknowledgePostVerificationWarnings sends acknowledgement request to CPS informing that the warnings should be ignored - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - AcknowledgePostVerificationWarnings(context.Context, AcknowledgementRequest) error - } - // PostVerificationWarnings is a response object containing all warnings encountered during enrollment post-verification PostVerificationWarnings struct { Warnings string `json:"warnings"` diff --git a/pkg/cps/pre_verification_warnings.go b/pkg/cps/pre_verification_warnings.go index 1f236ad9..b0960a2d 100644 --- a/pkg/cps/pre_verification_warnings.go +++ b/pkg/cps/pre_verification_warnings.go @@ -9,19 +9,6 @@ import ( ) type ( - // PreVerification is a CPS API enabling management of pre-verification-warnings - PreVerification interface { - // GetChangePreVerificationWarnings gets detailed information about Domain Validation challenges - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangePreVerificationWarnings(ctx context.Context, params GetChangeRequest) (*PreVerificationWarnings, error) - - // AcknowledgePreVerificationWarnings sends acknowledgement request to CPS informing that the warnings should be ignored - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - AcknowledgePreVerificationWarnings(context.Context, AcknowledgementRequest) error - } - // PreVerificationWarnings is a response object containing all warnings encountered during enrollment pre-verification PreVerificationWarnings struct { Warnings string `json:"warnings"` diff --git a/pkg/cps/third_party_csr.go b/pkg/cps/third_party_csr.go index fba00799..2e8de423 100644 --- a/pkg/cps/third_party_csr.go +++ b/pkg/cps/third_party_csr.go @@ -11,19 +11,6 @@ import ( ) type ( - // ThirdPartyCSR is a CPS API enabling management of third-party certificates - ThirdPartyCSR interface { - // GetChangeThirdPartyCSR gets certificate signing request - // - // See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param - GetChangeThirdPartyCSR(ctx context.Context, params GetChangeRequest) (*ThirdPartyCSRResponse, error) - - // UploadThirdPartyCertAndTrustChain uploads signed certificate and trust chain to cps - // - // See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param - UploadThirdPartyCertAndTrustChain(context.Context, UploadThirdPartyCertAndTrustChainRequest) error - } - // ThirdPartyCSRResponse is a response object containing list of csrs ThirdPartyCSRResponse struct { CSRs []CertSigningRequest `json:"csrs"` diff --git a/pkg/datastream/ds.go b/pkg/datastream/ds.go index e89ceca2..c78193f9 100644 --- a/pkg/datastream/ds.go +++ b/pkg/datastream/ds.go @@ -4,6 +4,7 @@ package datastream import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -17,9 +18,61 @@ var ( type ( // DS is the ds api interface DS interface { - Activation - Properties - Stream + // Activation + + // ActivateStream activates stream with given ID. + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream-activate + ActivateStream(context.Context, ActivateStreamRequest) (*DetailedStreamVersion, error) + + // DeactivateStream deactivates stream with given ID. + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream-deactivate + DeactivateStream(context.Context, DeactivateStreamRequest) (*DetailedStreamVersion, error) + + // GetActivationHistory returns a history of activation status changes for all versions of a stream. + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/get-stream-activation-history + GetActivationHistory(context.Context, GetActivationHistoryRequest) ([]ActivationHistoryEntry, error) + + // Properties + + // GetProperties returns properties that are active on the production and staging network for a specific product type that are available within a group + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/get-group-properties + GetProperties(context.Context, GetPropertiesRequest) (*PropertiesDetails, error) + + // GetDatasetFields returns groups of data set fields available in the template. + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/get-dataset-fields + GetDatasetFields(context.Context, GetDatasetFieldsRequest) (*DataSets, error) + + // Stream + + // CreateStream creates a stream + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/post-stream + CreateStream(context.Context, CreateStreamRequest) (*DetailedStreamVersion, error) + + // GetStream gets stream details + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/get-stream + GetStream(context.Context, GetStreamRequest) (*DetailedStreamVersion, error) + + // UpdateStream updates a stream + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream + UpdateStream(context.Context, UpdateStreamRequest) (*DetailedStreamVersion, error) + + // DeleteStream deletes a stream + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/delete-stream + DeleteStream(context.Context, DeleteStreamRequest) error + + // ListStreams retrieves list of streams + // + // See: https://techdocs.akamai.com/datastream2/v2/reference/get-streams + ListStreams(context.Context, ListStreamsRequest) ([]StreamDetails, error) } ds struct { diff --git a/pkg/datastream/mocks.go b/pkg/datastream/mocks.go index 8310e3bf..a7542ef9 100644 --- a/pkg/datastream/mocks.go +++ b/pkg/datastream/mocks.go @@ -12,7 +12,7 @@ type Mock struct { mock.Mock } -var _ Stream = &Mock{} +var _ DS = &Mock{} func (m *Mock) CreateStream(ctx context.Context, r CreateStreamRequest) (*DetailedStreamVersion, error) { args := m.Called(ctx, r) diff --git a/pkg/datastream/properties.go b/pkg/datastream/properties.go index f916ef26..c3aa9019 100644 --- a/pkg/datastream/properties.go +++ b/pkg/datastream/properties.go @@ -11,19 +11,6 @@ import ( ) type ( - // Properties is an interface for listing various DS API properties - Properties interface { - // GetProperties returns properties that are active on the production and staging network for a specific product type that are available within a group - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/get-group-properties - GetProperties(context.Context, GetPropertiesRequest) (*PropertiesDetails, error) - - // GetDatasetFields returns groups of data set fields available in the template. - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/get-dataset-fields - GetDatasetFields(context.Context, GetDatasetFieldsRequest) (*DataSets, error) - } - // GetPropertiesRequest contains parameters necessary to send a GetProperties request GetPropertiesRequest struct { GroupId int diff --git a/pkg/datastream/stream.go b/pkg/datastream/stream.go index a68958db..3e62aff8 100644 --- a/pkg/datastream/stream.go +++ b/pkg/datastream/stream.go @@ -12,34 +12,6 @@ import ( ) type ( - // Stream is a ds stream operations API interface - Stream interface { - // CreateStream creates a stream - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/post-stream - CreateStream(context.Context, CreateStreamRequest) (*DetailedStreamVersion, error) - - // GetStream gets stream details - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/get-stream - GetStream(context.Context, GetStreamRequest) (*DetailedStreamVersion, error) - - // UpdateStream updates a stream - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream - UpdateStream(context.Context, UpdateStreamRequest) (*DetailedStreamVersion, error) - - // DeleteStream deletes a stream - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/delete-stream - DeleteStream(context.Context, DeleteStreamRequest) error - - // ListStreams retrieves list of streams - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/get-streams - ListStreams(context.Context, ListStreamsRequest) ([]StreamDetails, error) - } - // DetailedStreamVersion is returned from GetStream DetailedStreamVersion struct { ContractID string `json:"contractId"` diff --git a/pkg/datastream/stream_activation.go b/pkg/datastream/stream_activation.go index 566363a9..9d0fc3f5 100644 --- a/pkg/datastream/stream_activation.go +++ b/pkg/datastream/stream_activation.go @@ -11,24 +11,6 @@ import ( ) type ( - // Activation is a ds stream activations API interface. - Activation interface { - // ActivateStream activates stream with given ID. - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream-activate - ActivateStream(context.Context, ActivateStreamRequest) (*DetailedStreamVersion, error) - - // DeactivateStream deactivates stream with given ID. - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/put-stream-deactivate - DeactivateStream(context.Context, DeactivateStreamRequest) (*DetailedStreamVersion, error) - - // GetActivationHistory returns a history of activation status changes for all versions of a stream. - // - // See: https://techdocs.akamai.com/datastream2/v2/reference/get-stream-activation-history - GetActivationHistory(context.Context, GetActivationHistoryRequest) ([]ActivationHistoryEntry, error) - } - // ActivationHistoryEntry contains single ActivationHistory item ActivationHistoryEntry struct { ModifiedBy string `json:"modifiedBy"` diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go index 15f29237..c7b25139 100644 --- a/pkg/dns/dns.go +++ b/pkg/dns/dns.go @@ -19,6 +19,8 @@ var ( type ( // DNS is the dns api interface DNS interface { + // Authorities + // GetAuthorities provides a list of structured read-only list of name servers. // // See: https://techdocs.akamai.com/edge-dns/reference/get-data-authorities @@ -34,6 +36,17 @@ type ( // See: https://techdocs.akamai.com/edge-dns/reference/get-data-groups ListGroups(context.Context, ListGroupRequest) (*ListGroupResponse, error) + // Data + + // GetRdata retrieves record rdata, e.g. target. + GetRdata(ctx context.Context, params GetRdataRequest) ([]string, error) + // ProcessRdata process rdata. + ProcessRdata(context.Context, []string, string) []string + // ParseRData parses rdata. returning map. + ParseRData(context.Context, string, []string) map[string]interface{} + + // Recordsets + // GetRecordSets retrieves record sets with Query Args. No formatting of arg values. // // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets @@ -51,12 +64,9 @@ type ( // // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets GetRecordList(context.Context, GetRecordListRequest) (*GetRecordListResponse, error) - // GetRdata retrieves record rdata, e.g. target. - GetRdata(context.Context, GetRdataRequest) ([]string, error) - // ProcessRdata process rdata. - ProcessRdata(context.Context, []string, string) []string - // ParseRData parses rdata. returning map. - ParseRData(context.Context, string, []string) map[string]interface{} + + // Records + // GetRecord retrieves a recordset and returns as RecordBody. // // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-type @@ -74,6 +84,8 @@ type ( // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-names-name-types-type UpdateRecord(context.Context, UpdateRecordRequest) error + // TSIGKeys + // ListTSIGKeys lists the TSIG keys used by zones that you are allowed to manage. // // See: https://techdocs.akamai.com/edge-dns/reference/get-keys @@ -103,6 +115,8 @@ type ( // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-key UpdateTSIGKey(context.Context, UpdateTSIGKeyRequest) error + // Zones + // ListZones retrieves a list of all zones user can access. // // See: https://techdocs.akamai.com/edge-dns/reference/get-zones diff --git a/pkg/edgeworkers/activations.go b/pkg/edgeworkers/activations.go index 23fcd8ec..7cf78398 100644 --- a/pkg/edgeworkers/activations.go +++ b/pkg/edgeworkers/activations.go @@ -11,29 +11,6 @@ import ( ) type ( - // Activations is an edgeworkers activations API interface - Activations interface { - // ListActivations lists all activations for an EdgeWorker - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-activations-1 - ListActivations(context.Context, ListActivationsRequest) (*ListActivationsResponse, error) - - // GetActivation fetches an EdgeWorker activation by id - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-activation-1 - GetActivation(context.Context, GetActivationRequest) (*Activation, error) - - // ActivateVersion activates an EdgeWorker version on a given network - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-activations-1 - ActivateVersion(context.Context, ActivateVersionRequest) (*Activation, error) - - // CancelPendingActivation cancels pending activation with a given id - // - // See: https://techdocs.akamai.com/edgeworkers/reference/cancel-activation - CancelPendingActivation(context.Context, CancelActivationRequest) (*Activation, error) - } - // ListActivationsRequest contains parameters used to list activations ListActivationsRequest struct { EdgeWorkerID int diff --git a/pkg/edgeworkers/contracts.go b/pkg/edgeworkers/contracts.go index 40cec967..c6c0fd59 100644 --- a/pkg/edgeworkers/contracts.go +++ b/pkg/edgeworkers/contracts.go @@ -8,14 +8,6 @@ import ( ) type ( - // Contracts is an edgeworkers contracts API interface - Contracts interface { - // ListContracts lists contract IDs that can be used to list resource tiers - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-contracts-1 - ListContracts(context.Context) (*ListContractsResponse, error) - } - // ListContractsResponse represents a response object returned by ListContracts ListContractsResponse struct { ContractIDs []string `json:"contractIds"` diff --git a/pkg/edgeworkers/deactivations.go b/pkg/edgeworkers/deactivations.go index 87a17567..625e78e8 100644 --- a/pkg/edgeworkers/deactivations.go +++ b/pkg/edgeworkers/deactivations.go @@ -11,24 +11,6 @@ import ( ) type ( - // Deactivations is an EdgeWorkers deactivations API interface - Deactivations interface { - // ListDeactivations lists all deactivations for a given EdgeWorker ID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-deactivations-1 - ListDeactivations(context.Context, ListDeactivationsRequest) (*ListDeactivationsResponse, error) - - // GetDeactivation gets details for a specific deactivation - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-deactivation-1 - GetDeactivation(context.Context, GetDeactivationRequest) (*Deactivation, error) - - // DeactivateVersion deactivates an existing EdgeWorker version on the akamai network - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-deactivations-1 - DeactivateVersion(context.Context, DeactivateVersionRequest) (*Deactivation, error) - } - // Deactivation is the response returned by GetDeactivation, DeactivateVersion and ListDeactivation Deactivation struct { EdgeWorkerID int `json:"edgeWorkerId"` diff --git a/pkg/edgeworkers/edgekv_access_tokens.go b/pkg/edgeworkers/edgekv_access_tokens.go index 244d937e..87e2e5c1 100644 --- a/pkg/edgeworkers/edgekv_access_tokens.go +++ b/pkg/edgeworkers/edgekv_access_tokens.go @@ -12,29 +12,6 @@ import ( ) type ( - // EdgeKVAccessTokens is EdgeKV access token API interface - EdgeKVAccessTokens interface { - // CreateEdgeKVAccessToken generates EdgeKV specific access token - // - // See: https://techdocs.akamai.com/edgekv/reference/post-tokens - CreateEdgeKVAccessToken(context.Context, CreateEdgeKVAccessTokenRequest) (*CreateEdgeKVAccessTokenResponse, error) - - // GetEdgeKVAccessToken retrieves an EdgeKV access token - // - // See: https://techdocs.akamai.com/edgekv/reference/get-token - GetEdgeKVAccessToken(context.Context, GetEdgeKVAccessTokenRequest) (*GetEdgeKVAccessTokenResponse, error) - - // ListEdgeKVAccessTokens lists EdgeKV access tokens - // - // See: https://techdocs.akamai.com/edgekv/reference/get-tokens - ListEdgeKVAccessTokens(context.Context, ListEdgeKVAccessTokensRequest) (*ListEdgeKVAccessTokensResponse, error) - - // DeleteEdgeKVAccessToken revokes an EdgeKV access token - // - // See: https://techdocs.akamai.com/edgekv/reference/delete-token - DeleteEdgeKVAccessToken(context.Context, DeleteEdgeKVAccessTokenRequest) (*DeleteEdgeKVAccessTokenResponse, error) - } - // CreateEdgeKVAccessTokenRequest contains parameters used to create EdgeKV access token CreateEdgeKVAccessTokenRequest struct { // Whether to allow this token access to the Akamai production network diff --git a/pkg/edgeworkers/edgekv_groups.go b/pkg/edgeworkers/edgekv_groups.go index a951ee80..4a252617 100644 --- a/pkg/edgeworkers/edgekv_groups.go +++ b/pkg/edgeworkers/edgekv_groups.go @@ -12,14 +12,6 @@ import ( ) type ( - // Groups is EdgeKV groups within a namespace API interface - Groups interface { - // ListGroupsWithinNamespace lists group identifiers created when writing items to a namespace - // - // See: https://techdocs.akamai.com/edgekv/reference/get-groups - ListGroupsWithinNamespace(context.Context, ListGroupsWithinNamespaceRequest) ([]string, error) - } - // ListGroupsWithinNamespaceRequest contains parameters used to get groups within a namespace ListGroupsWithinNamespaceRequest struct { Network NamespaceNetwork diff --git a/pkg/edgeworkers/edgekv_initialize.go b/pkg/edgeworkers/edgekv_initialize.go index 36049e0e..5e4fe4e0 100644 --- a/pkg/edgeworkers/edgekv_initialize.go +++ b/pkg/edgeworkers/edgekv_initialize.go @@ -9,18 +9,6 @@ import ( // EdgeKVInitialize is EdgeKV Initialize API interface type ( - EdgeKVInitialize interface { - // InitializeEdgeKV Initialize the EdgeKV database - // - // See: https://techdocs.akamai.com/edgekv/reference/put-initialize - InitializeEdgeKV(ctx context.Context) (*EdgeKVInitializationStatus, error) - - // GetEdgeKVInitializationStatus is used to check on the current initialization status - // - // See: https://techdocs.akamai.com/edgekv/reference/get-initialize - GetEdgeKVInitializationStatus(ctx context.Context) (*EdgeKVInitializationStatus, error) - } - // EdgeKVInitializationStatus represents a response object returned by InitializeEdgeKV and GetEdgeKVInitializeStatus EdgeKVInitializationStatus struct { AccountStatus string `json:"accountStatus"` diff --git a/pkg/edgeworkers/edgekv_items.go b/pkg/edgeworkers/edgekv_items.go index f1dfe506..c233c5eb 100644 --- a/pkg/edgeworkers/edgekv_items.go +++ b/pkg/edgeworkers/edgekv_items.go @@ -13,29 +13,6 @@ import ( ) type ( - // EdgeKVItems is EdgeKV Item API interface - EdgeKVItems interface { - // ListItems lists items in EdgeKV group - // - // See: https://techdocs.akamai.com/edgekv/reference/get-group-1 - ListItems(context.Context, ListItemsRequest) (*ListItemsResponse, error) - - // GetItem reads an item from EdgeKV group - // - // See: https://techdocs.akamai.com/edgekv/reference/get-item - GetItem(context.Context, GetItemRequest) (*Item, error) - - // UpsertItem creates or updates an item in EdgeKV group - // - // See: https://techdocs.akamai.com/edgekv/reference/put-item - UpsertItem(context.Context, UpsertItemRequest) (*string, error) - - // DeleteItem deletes an item from EdgeKV group - // - // See: https://techdocs.akamai.com/edgekv/reference/delete-item - DeleteItem(context.Context, DeleteItemRequest) (*string, error) - } - // ListItemsRequest represents the request params used to list items ListItemsRequest struct { ItemsRequestParams diff --git a/pkg/edgeworkers/edgekv_namespaces.go b/pkg/edgeworkers/edgekv_namespaces.go index afbefc8b..fa497e35 100644 --- a/pkg/edgeworkers/edgekv_namespaces.go +++ b/pkg/edgeworkers/edgekv_namespaces.go @@ -11,29 +11,6 @@ import ( ) type ( - // EdgeKVNamespaces is an EdgeKV namespaces API interface - EdgeKVNamespaces interface { - // ListEdgeKVNamespaces lists all namespaces in the given network - // - // See: https://techdocs.akamai.com/edgekv/reference/get-namespaces - ListEdgeKVNamespaces(context.Context, ListEdgeKVNamespacesRequest) (*ListEdgeKVNamespacesResponse, error) - - // GetEdgeKVNamespace fetches a namespace by name - // - // See: https://techdocs.akamai.com/edgekv/reference/get-namespace - GetEdgeKVNamespace(context.Context, GetEdgeKVNamespaceRequest) (*Namespace, error) - - // CreateEdgeKVNamespace creates a namespace on the given network - // - // See: https://techdocs.akamai.com/edgekv/reference/post-namespace - CreateEdgeKVNamespace(context.Context, CreateEdgeKVNamespaceRequest) (*Namespace, error) - - // UpdateEdgeKVNamespace updates a namespace - // - // See: https://techdocs.akamai.com/edgekv/reference/put-namespace - UpdateEdgeKVNamespace(context.Context, UpdateEdgeKVNamespaceRequest) (*Namespace, error) - } - // ListEdgeKVNamespacesRequest contains path parameters used to list namespaces ListEdgeKVNamespacesRequest struct { Network NamespaceNetwork diff --git a/pkg/edgeworkers/edgeworker_id.go b/pkg/edgeworkers/edgeworker_id.go index d6a6fa6b..ca603928 100644 --- a/pkg/edgeworkers/edgeworker_id.go +++ b/pkg/edgeworkers/edgeworker_id.go @@ -11,39 +11,6 @@ import ( ) type ( - // EdgeWorkerIDs is EdgeWorker ID API interface - EdgeWorkerIDs interface { - // GetEdgeWorkerID gets details for a specific EdgeWorkerID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-id - GetEdgeWorkerID(context.Context, GetEdgeWorkerIDRequest) (*EdgeWorkerID, error) - - // ListEdgeWorkersID lists EdgeWorkerIDs in the identified group - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-ids - ListEdgeWorkersID(context.Context, ListEdgeWorkersIDRequest) (*ListEdgeWorkersIDResponse, error) - - // CreateEdgeWorkerID creates a new EdgeWorkerID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-ids - CreateEdgeWorkerID(context.Context, CreateEdgeWorkerIDRequest) (*EdgeWorkerID, error) - - // UpdateEdgeWorkerID updates an EdgeWorkerID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/put-id - UpdateEdgeWorkerID(context.Context, UpdateEdgeWorkerIDRequest) (*EdgeWorkerID, error) - - // CloneEdgeWorkerID clones an EdgeWorkerID to change the resource tier - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-id-clone - CloneEdgeWorkerID(context.Context, CloneEdgeWorkerIDRequest) (*EdgeWorkerID, error) - - // DeleteEdgeWorkerID deletes an EdgeWorkerID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/delete-id - DeleteEdgeWorkerID(context.Context, DeleteEdgeWorkerIDRequest) error - } - // GetEdgeWorkerIDRequest contains parameters used to get an EdgeWorkerID GetEdgeWorkerIDRequest struct { EdgeWorkerID int diff --git a/pkg/edgeworkers/edgeworker_version.go b/pkg/edgeworkers/edgeworker_version.go index 11ec997c..9b0502f3 100644 --- a/pkg/edgeworkers/edgeworker_version.go +++ b/pkg/edgeworkers/edgeworker_version.go @@ -13,34 +13,6 @@ import ( ) type ( - // EdgeWorkerVersions is EdgeWorker Version API interface - EdgeWorkerVersions interface { - // GetEdgeWorkerVersion gets details for a specific EdgeWorkerVersion - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-version - GetEdgeWorkerVersion(context.Context, GetEdgeWorkerVersionRequest) (*EdgeWorkerVersion, error) - - // ListEdgeWorkerVersions lists EdgeWorkerVersions in the identified group - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-versions - ListEdgeWorkerVersions(context.Context, ListEdgeWorkerVersionsRequest) (*ListEdgeWorkerVersionsResponse, error) - - // GetEdgeWorkerVersionContent gets content bundle for a specific EdgeWorkerVersion - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-version-content - GetEdgeWorkerVersionContent(context.Context, GetEdgeWorkerVersionContentRequest) (*Bundle, error) - - // CreateEdgeWorkerVersion creates a new EdgeWorkerVersion - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-versions - CreateEdgeWorkerVersion(context.Context, CreateEdgeWorkerVersionRequest) (*EdgeWorkerVersion, error) - - // DeleteEdgeWorkerVersion deletes an EdgeWorkerVersion - // - // See: https://techdocs.akamai.com/edgeworkers/reference/delete-version - DeleteEdgeWorkerVersion(context.Context, DeleteEdgeWorkerVersionRequest) error - } - // GetEdgeWorkerVersionRequest contains parameters used to get an EdgeWorkerVersion GetEdgeWorkerVersionRequest EdgeWorkerVersionRequest diff --git a/pkg/edgeworkers/edgeworkers.go b/pkg/edgeworkers/edgeworkers.go index 2d643ac8..6b521f38 100644 --- a/pkg/edgeworkers/edgeworkers.go +++ b/pkg/edgeworkers/edgeworkers.go @@ -2,6 +2,7 @@ package edgeworkers import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,22 +16,257 @@ var ( type ( // Edgeworkers is the api interface for EdgeWorkers and EdgeKV Edgeworkers interface { - Activations - Contracts - Deactivations - EdgeKVAccessTokens - EdgeKVInitialize - EdgeKVItems - EdgeKVNamespaces - EdgeWorkerIDs - EdgeWorkerVersions - Groups - PermissionGroups - Properties - Reports - ResourceTiers - SecureTokens - Validations + // Activations + + // ListActivations lists all activations for an EdgeWorker + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-activations-1 + ListActivations(context.Context, ListActivationsRequest) (*ListActivationsResponse, error) + + // GetActivation fetches an EdgeWorker activation by id + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-activation-1 + GetActivation(context.Context, GetActivationRequest) (*Activation, error) + + // ActivateVersion activates an EdgeWorker version on a given network + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-activations-1 + ActivateVersion(context.Context, ActivateVersionRequest) (*Activation, error) + + // CancelPendingActivation cancels pending activation with a given id + // + // See: https://techdocs.akamai.com/edgeworkers/reference/cancel-activation + CancelPendingActivation(context.Context, CancelActivationRequest) (*Activation, error) + + // Contracts + + // ListContracts lists contract IDs that can be used to list resource tiers + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-contracts-1 + ListContracts(context.Context) (*ListContractsResponse, error) + + // Deactivations + + // ListDeactivations lists all deactivations for a given EdgeWorker ID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-deactivations-1 + ListDeactivations(context.Context, ListDeactivationsRequest) (*ListDeactivationsResponse, error) + + // GetDeactivation gets details for a specific deactivation + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-deactivation-1 + GetDeactivation(context.Context, GetDeactivationRequest) (*Deactivation, error) + + // DeactivateVersion deactivates an existing EdgeWorker version on the akamai network + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-deactivations-1 + DeactivateVersion(context.Context, DeactivateVersionRequest) (*Deactivation, error) + + // EdgeKVAccessTokens + + // CreateEdgeKVAccessToken generates EdgeKV specific access token + // + // See: https://techdocs.akamai.com/edgekv/reference/post-tokens + CreateEdgeKVAccessToken(context.Context, CreateEdgeKVAccessTokenRequest) (*CreateEdgeKVAccessTokenResponse, error) + + // GetEdgeKVAccessToken retrieves an EdgeKV access token + // + // See: https://techdocs.akamai.com/edgekv/reference/get-token + GetEdgeKVAccessToken(context.Context, GetEdgeKVAccessTokenRequest) (*GetEdgeKVAccessTokenResponse, error) + + // ListEdgeKVAccessTokens lists EdgeKV access tokens + // + // See: https://techdocs.akamai.com/edgekv/reference/get-tokens + ListEdgeKVAccessTokens(context.Context, ListEdgeKVAccessTokensRequest) (*ListEdgeKVAccessTokensResponse, error) + + // DeleteEdgeKVAccessToken revokes an EdgeKV access token + // + // See: https://techdocs.akamai.com/edgekv/reference/delete-token + DeleteEdgeKVAccessToken(context.Context, DeleteEdgeKVAccessTokenRequest) (*DeleteEdgeKVAccessTokenResponse, error) + + // EdgeKVInitialize + + // InitializeEdgeKV Initialize the EdgeKV database + // + // See: https://techdocs.akamai.com/edgekv/reference/put-initialize + InitializeEdgeKV(ctx context.Context) (*EdgeKVInitializationStatus, error) + + // GetEdgeKVInitializationStatus is used to check on the current initialization status + // + // See: https://techdocs.akamai.com/edgekv/reference/get-initialize + GetEdgeKVInitializationStatus(ctx context.Context) (*EdgeKVInitializationStatus, error) + + // EdgeKVItems + + // ListItems lists items in EdgeKV group + // + // See: https://techdocs.akamai.com/edgekv/reference/get-group-1 + ListItems(context.Context, ListItemsRequest) (*ListItemsResponse, error) + + // GetItem reads an item from EdgeKV group + // + // See: https://techdocs.akamai.com/edgekv/reference/get-item + GetItem(context.Context, GetItemRequest) (*Item, error) + + // UpsertItem creates or updates an item in EdgeKV group + // + // See: https://techdocs.akamai.com/edgekv/reference/put-item + UpsertItem(context.Context, UpsertItemRequest) (*string, error) + + // DeleteItem deletes an item from EdgeKV group + // + // See: https://techdocs.akamai.com/edgekv/reference/delete-item + DeleteItem(context.Context, DeleteItemRequest) (*string, error) + + // EdgeKVNamespaces + + // ListEdgeKVNamespaces lists all namespaces in the given network + // + // See: https://techdocs.akamai.com/edgekv/reference/get-namespaces + ListEdgeKVNamespaces(context.Context, ListEdgeKVNamespacesRequest) (*ListEdgeKVNamespacesResponse, error) + + // GetEdgeKVNamespace fetches a namespace by name + // + // See: https://techdocs.akamai.com/edgekv/reference/get-namespace + GetEdgeKVNamespace(context.Context, GetEdgeKVNamespaceRequest) (*Namespace, error) + + // CreateEdgeKVNamespace creates a namespace on the given network + // + // See: https://techdocs.akamai.com/edgekv/reference/post-namespace + CreateEdgeKVNamespace(context.Context, CreateEdgeKVNamespaceRequest) (*Namespace, error) + + // UpdateEdgeKVNamespace updates a namespace + // + // See: https://techdocs.akamai.com/edgekv/reference/put-namespace + UpdateEdgeKVNamespace(context.Context, UpdateEdgeKVNamespaceRequest) (*Namespace, error) + + // EdgeWorkerIDs + + // GetEdgeWorkerID gets details for a specific EdgeWorkerID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-id + GetEdgeWorkerID(context.Context, GetEdgeWorkerIDRequest) (*EdgeWorkerID, error) + + // ListEdgeWorkersID lists EdgeWorkerIDs in the identified group + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-ids + ListEdgeWorkersID(context.Context, ListEdgeWorkersIDRequest) (*ListEdgeWorkersIDResponse, error) + + // CreateEdgeWorkerID creates a new EdgeWorkerID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-ids + CreateEdgeWorkerID(context.Context, CreateEdgeWorkerIDRequest) (*EdgeWorkerID, error) + + // UpdateEdgeWorkerID updates an EdgeWorkerID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/put-id + UpdateEdgeWorkerID(context.Context, UpdateEdgeWorkerIDRequest) (*EdgeWorkerID, error) + + // CloneEdgeWorkerID clones an EdgeWorkerID to change the resource tier + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-id-clone + CloneEdgeWorkerID(context.Context, CloneEdgeWorkerIDRequest) (*EdgeWorkerID, error) + + // DeleteEdgeWorkerID deletes an EdgeWorkerID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/delete-id + DeleteEdgeWorkerID(context.Context, DeleteEdgeWorkerIDRequest) error + + // EdgeWorkerVersions + + // GetEdgeWorkerVersion gets details for a specific EdgeWorkerVersion + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-version + GetEdgeWorkerVersion(context.Context, GetEdgeWorkerVersionRequest) (*EdgeWorkerVersion, error) + + // ListEdgeWorkerVersions lists EdgeWorkerVersions in the identified group + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-versions + ListEdgeWorkerVersions(context.Context, ListEdgeWorkerVersionsRequest) (*ListEdgeWorkerVersionsResponse, error) + + // GetEdgeWorkerVersionContent gets content bundle for a specific EdgeWorkerVersion + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-version-content + GetEdgeWorkerVersionContent(context.Context, GetEdgeWorkerVersionContentRequest) (*Bundle, error) + + // CreateEdgeWorkerVersion creates a new EdgeWorkerVersion + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-versions + CreateEdgeWorkerVersion(context.Context, CreateEdgeWorkerVersionRequest) (*EdgeWorkerVersion, error) + + // DeleteEdgeWorkerVersion deletes an EdgeWorkerVersion + // + // See: https://techdocs.akamai.com/edgeworkers/reference/delete-version + DeleteEdgeWorkerVersion(context.Context, DeleteEdgeWorkerVersionRequest) error + + // Groups + + // ListGroupsWithinNamespace lists group identifiers created when writing items to a namespace + // + // See: https://techdocs.akamai.com/edgekv/reference/get-groups + ListGroupsWithinNamespace(context.Context, ListGroupsWithinNamespaceRequest) ([]string, error) + + // PermissionGroups + + // GetPermissionGroup gets details on the capabilities enabled within a specified group + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-group + GetPermissionGroup(context.Context, GetPermissionGroupRequest) (*PermissionGroup, error) + + // ListPermissionGroups lists groups and the associated permission capabilities + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-groups + ListPermissionGroups(context.Context) (*ListPermissionGroupsResponse, error) + + // Properties + + // ListProperties lists all properties for a given edgeworker ID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-properties + ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) + + // Reports + + // GetSummaryReport gets summary overview for EdgeWorker reports. Report id is 1 + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-report + GetSummaryReport(context.Context, GetSummaryReportRequest) (*GetSummaryReportResponse, error) + + // GetReport gets details for an EdgeWorker + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-report + GetReport(context.Context, GetReportRequest) (*GetReportResponse, error) + + // ListReports lists EdgeWorker reports + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-reports + ListReports(context.Context) (*ListReportsResponse, error) + + // ResourceTiers + + // ListResourceTiers lists all resource tiers for a given contract + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-resource-tiers + ListResourceTiers(context.Context, ListResourceTiersRequest) (*ListResourceTiersResponse, error) + + // GetResourceTier returns resource tier for a given edgeworker ID + // + // See: https://techdocs.akamai.com/edgeworkers/reference/get-id-resource-tier + GetResourceTier(context.Context, GetResourceTierRequest) (*ResourceTier, error) + + // SecureTokens + + // CreateSecureToken creates a new secure token + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-secure-token + CreateSecureToken(context.Context, CreateSecureTokenRequest) (*CreateSecureTokenResponse, error) + + // Validations + + // ValidateBundle given bundle validates it and returns a list of errors and/or warnings + // + // See: https://techdocs.akamai.com/edgeworkers/reference/post-validations + ValidateBundle(context.Context, ValidateBundleRequest) (*ValidateBundleResponse, error) } edgeworkers struct { diff --git a/pkg/edgeworkers/permission_group.go b/pkg/edgeworkers/permission_group.go index 10f70a68..f91404d6 100644 --- a/pkg/edgeworkers/permission_group.go +++ b/pkg/edgeworkers/permission_group.go @@ -10,19 +10,6 @@ import ( ) type ( - // PermissionGroups is an edgeworkers permission groups API interface - PermissionGroups interface { - // GetPermissionGroup gets details on the capabilities enabled within a specified group - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-group - GetPermissionGroup(context.Context, GetPermissionGroupRequest) (*PermissionGroup, error) - - // ListPermissionGroups lists groups and the associated permission capabilities - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-groups - ListPermissionGroups(context.Context) (*ListPermissionGroupsResponse, error) - } - // GetPermissionGroupRequest contains parameters used to get a permission group GetPermissionGroupRequest struct { GroupID string diff --git a/pkg/edgeworkers/properties.go b/pkg/edgeworkers/properties.go index be939ecf..bb2236f5 100644 --- a/pkg/edgeworkers/properties.go +++ b/pkg/edgeworkers/properties.go @@ -12,14 +12,6 @@ import ( ) type ( - // Properties is an edgeworkers properties API interface - Properties interface { - // ListProperties lists all properties for a given edgeworker ID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-properties - ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) - } - // ListPropertiesRequest contains parameters used to list properties ListPropertiesRequest struct { EdgeWorkerID int diff --git a/pkg/edgeworkers/report.go b/pkg/edgeworkers/report.go index 1a71035e..3f21a21b 100644 --- a/pkg/edgeworkers/report.go +++ b/pkg/edgeworkers/report.go @@ -11,24 +11,6 @@ import ( ) type ( - // Reports is an edgeworkers reports API interface - Reports interface { - // GetSummaryReport gets summary overview for EdgeWorker reports. Report id is 1 - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-report - GetSummaryReport(context.Context, GetSummaryReportRequest) (*GetSummaryReportResponse, error) - - // GetReport gets details for an EdgeWorker - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-report - GetReport(context.Context, GetReportRequest) (*GetReportResponse, error) - - // ListReports lists EdgeWorker reports - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-reports - ListReports(context.Context) (*ListReportsResponse, error) - } - // GetSummaryReportRequest contains parameters used to get summary overview for EdgeWorker reports GetSummaryReportRequest struct { Start string diff --git a/pkg/edgeworkers/resource_tier.go b/pkg/edgeworkers/resource_tier.go index 204f3cf3..053c2dd2 100644 --- a/pkg/edgeworkers/resource_tier.go +++ b/pkg/edgeworkers/resource_tier.go @@ -11,19 +11,6 @@ import ( ) type ( - // ResourceTiers is an edgeworkers resource tiers API interface - ResourceTiers interface { - // ListResourceTiers lists all resource tiers for a given contract - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-resource-tiers - ListResourceTiers(context.Context, ListResourceTiersRequest) (*ListResourceTiersResponse, error) - - // GetResourceTier returns resource tier for a given edgeworker ID - // - // See: https://techdocs.akamai.com/edgeworkers/reference/get-id-resource-tier - GetResourceTier(context.Context, GetResourceTierRequest) (*ResourceTier, error) - } - // ListResourceTiersRequest contains parameters used to list resource tiers ListResourceTiersRequest struct { ContractID string diff --git a/pkg/edgeworkers/secure_tokens.go b/pkg/edgeworkers/secure_tokens.go index ee816b89..97af4d54 100644 --- a/pkg/edgeworkers/secure_tokens.go +++ b/pkg/edgeworkers/secure_tokens.go @@ -10,14 +10,6 @@ import ( ) type ( - // SecureTokens is EdgeWorker Secure Token API interface - SecureTokens interface { - // CreateSecureToken creates a new secure token - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-secure-token - CreateSecureToken(context.Context, CreateSecureTokenRequest) (*CreateSecureTokenResponse, error) - } - // CreateSecureTokenRequest represents parameters for CreateSecureToken CreateSecureTokenRequest struct { ACL string `json:"acl,omitempty"` diff --git a/pkg/edgeworkers/validations.go b/pkg/edgeworkers/validations.go index 9010eda7..90982aa1 100644 --- a/pkg/edgeworkers/validations.go +++ b/pkg/edgeworkers/validations.go @@ -11,14 +11,6 @@ import ( ) type ( - // Validations is an edgeworkers validations API interface - Validations interface { - // ValidateBundle given bundle validates it and returns a list of errors and/or warnings - // - // See: https://techdocs.akamai.com/edgeworkers/reference/post-validations - ValidateBundle(context.Context, ValidateBundleRequest) (*ValidateBundleResponse, error) - } - // ValidateBundleRequest contains request bundle parameter to validate ValidateBundleRequest struct { Bundle diff --git a/pkg/gtm/gtm.go b/pkg/gtm/gtm.go index 78f429da..68920d49 100644 --- a/pkg/gtm/gtm.go +++ b/pkg/gtm/gtm.go @@ -19,6 +19,8 @@ var ( type ( // GTM is the gtm api interface GTM interface { + // Domains + // NullFieldMap retrieves map of null fields. NullFieldMap(context.Context, *Domain) (*NullFieldMapStruct, error) @@ -52,6 +54,8 @@ type ( // See: https://techdocs.akamai.com/gtm/reference/put-domain UpdateDomain(context.Context, UpdateDomainRequest) (*UpdateDomainResponse, error) + // Properties + // ListProperties retrieves all Properties for the provided domainName. // // See: https://techdocs.akamai.com/gtm/reference/get-properties @@ -77,6 +81,8 @@ type ( // See: https://techdocs.akamai.com/gtm/reference/put-property UpdateProperty(context.Context, UpdatePropertyRequest) (*UpdatePropertyResponse, error) + // Datacenters + // ListDatacenters retrieves all Datacenters. // // See: https://techdocs.akamai.com/gtm/reference/get-datacenters @@ -111,6 +117,8 @@ type ( // CreateIPv6DefaultDatacenter creates Default Datacenter for IPv6 Selector. CreateIPv6DefaultDatacenter(context.Context, string) (*Datacenter, error) + // Resources + // ListResources retrieves all Resources // // See: https://techdocs.akamai.com/gtm/reference/get-resources @@ -136,6 +144,8 @@ type ( // See: https://techdocs.akamai.com/gtm/reference/put-resource UpdateResource(context.Context, UpdateResourceRequest) (*UpdateResourceResponse, error) + // ASMaps + // ListASMaps retrieves all AsMaps. // // See: https://techdocs.akamai.com/gtm/reference/get-as-maps @@ -161,6 +171,8 @@ type ( // See: https://techdocs.akamai.com/gtm/reference/put-as-map UpdateASMap(context.Context, UpdateASMapRequest) (*UpdateASMapResponse, error) + // GeoMaps + // ListGeoMaps retrieves all GeoMaps. // // See: https://techdocs.akamai.com/gtm/reference/get-geographic-maps @@ -186,6 +198,8 @@ type ( // See: https://techdocs.akamai.com/gtm/reference/put-geographic-map UpdateGeoMap(context.Context, UpdateGeoMapRequest) (*UpdateGeoMapResponse, error) + // CIDRMaps + // ListCIDRMaps retrieves all CIDRMaps. // // See: https://techdocs.akamai.com/gtm/reference/get-cidr-maps diff --git a/pkg/hapi/change_requests.go b/pkg/hapi/change_requests.go index a913a16f..5ff77fd4 100644 --- a/pkg/hapi/change_requests.go +++ b/pkg/hapi/change_requests.go @@ -8,15 +8,6 @@ import ( ) type ( - // ChangeRequests contains operations to query for Change Requests. - ChangeRequests interface { - // GetChangeRequest request status and details specified by the change ID - // that is provided when you make a change request. - // - // See: https://techdocs.akamai.com/edge-hostnames/reference/get-changeid - GetChangeRequest(context.Context, GetChangeRequest) (*ChangeRequest, error) - } - // GetChangeRequest is a request struct GetChangeRequest struct { ChangeID int diff --git a/pkg/hapi/edgehostname.go b/pkg/hapi/edgehostname.go index 738fed8c..bb165894 100644 --- a/pkg/hapi/edgehostname.go +++ b/pkg/hapi/edgehostname.go @@ -17,32 +17,6 @@ import ( ) type ( - // EdgeHostnames contains operations available on Edge Hostname resource. - EdgeHostnames interface { - // DeleteEdgeHostname allows deleting a specific edge hostname. - // You must have an Admin or Technical role in order to delete an edge hostname. - // You can delete any hostname that’s not currently part of an active Property Manager configuration. - // - // See: https://techdocs.akamai.com/edge-hostnames/reference/delete-edgehostname - DeleteEdgeHostname(context.Context, DeleteEdgeHostnameRequest) (*DeleteEdgeHostnameResponse, error) - - // GetEdgeHostname gets a specific edge hostname's details including its product ID, IP version behavior, - // and China CDN or Edge IP Binding status. - // - // See: https://techdocs.akamai.com/edge-hostnames/reference/get-edgehostnameid - GetEdgeHostname(context.Context, int) (*GetEdgeHostnameResponse, error) - - // UpdateEdgeHostname allows update ttl (path = "/ttl") or IpVersionBehaviour (path = "/ipVersionBehavior") - // - // See: https://techdocs.akamai.com/edge-hostnames/reference/patch-edgehostnames - UpdateEdgeHostname(context.Context, UpdateEdgeHostnameRequest) (*UpdateEdgeHostnameResponse, error) - - // GetCertificate gets the certificate associated with an enhanced TLS edge hostname - // - // See: https://techdocs.akamai.com/edge-hostnames/reference/get-edge-hostname-certificate - GetCertificate(context.Context, GetCertificateRequest) (*GetCertificateResponse, error) - } - // DeleteEdgeHostnameRequest is used to delete edge hostname DeleteEdgeHostnameRequest struct { DNSZone string diff --git a/pkg/hapi/hapi.go b/pkg/hapi/hapi.go index d3959ac0..13a0ba7f 100644 --- a/pkg/hapi/hapi.go +++ b/pkg/hapi/hapi.go @@ -4,6 +4,7 @@ package hapi import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -17,8 +18,38 @@ var ( type ( // HAPI is the hapi api interface HAPI interface { - ChangeRequests - EdgeHostnames + // ChangeRequests + + // GetChangeRequest request status and details specified by the change ID + // that is provided when you make a change request. + // + // See: https://techdocs.akamai.com/edge-hostnames/reference/get-changeid + GetChangeRequest(context.Context, GetChangeRequest) (*ChangeRequest, error) + + // EdgeHostnames + + // DeleteEdgeHostname allows deleting a specific edge hostname. + // You must have an Admin or Technical role in order to delete an edge hostname. + // You can delete any hostname that’s not currently part of an active Property Manager configuration. + // + // See: https://techdocs.akamai.com/edge-hostnames/reference/delete-edgehostname + DeleteEdgeHostname(context.Context, DeleteEdgeHostnameRequest) (*DeleteEdgeHostnameResponse, error) + + // GetEdgeHostname gets a specific edge hostname's details including its product ID, IP version behavior, + // and China CDN or Edge IP Binding status. + // + // See: https://techdocs.akamai.com/edge-hostnames/reference/get-edgehostnameid + GetEdgeHostname(context.Context, int) (*GetEdgeHostnameResponse, error) + + // UpdateEdgeHostname allows update ttl (path = "/ttl") or IpVersionBehaviour (path = "/ipVersionBehavior") + // + // See: https://techdocs.akamai.com/edge-hostnames/reference/patch-edgehostnames + UpdateEdgeHostname(context.Context, UpdateEdgeHostnameRequest) (*UpdateEdgeHostnameResponse, error) + + // GetCertificate gets the certificate associated with an enhanced TLS edge hostname + // + // See: https://techdocs.akamai.com/edge-hostnames/reference/get-edge-hostname-certificate + GetCertificate(context.Context, GetCertificateRequest) (*GetCertificateResponse, error) } hapi struct { diff --git a/pkg/imaging/imaging.go b/pkg/imaging/imaging.go index f8e701b7..47f04e16 100644 --- a/pkg/imaging/imaging.go +++ b/pkg/imaging/imaging.go @@ -2,6 +2,7 @@ package imaging import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,8 +16,43 @@ var ( type ( // Imaging is the api interface for Image and Video Manager Imaging interface { - Policies - PolicySets + // Policies + + // ListPolicies lists all Policies for the given network and an account + // See: https://techdocs.akamai.com/ivm/reference/get-policies + ListPolicies(context.Context, ListPoliciesRequest) (*ListPoliciesResponse, error) + + // GetPolicy gets specific policy by PolicyID + GetPolicy(context.Context, GetPolicyRequest) (PolicyOutput, error) + + // UpsertPolicy creates or updates the configuration for a policy + UpsertPolicy(context.Context, UpsertPolicyRequest) (*PolicyResponse, error) + + // DeletePolicy deletes a policy + DeletePolicy(context.Context, DeletePolicyRequest) (*PolicyResponse, error) + + // GetPolicyHistory retrieves history of changes for a policy + GetPolicyHistory(context.Context, GetPolicyHistoryRequest) (*GetPolicyHistoryResponse, error) + + // RollbackPolicy reverts a policy to its previous version and deploys it to the network + RollbackPolicy(ctx context.Context, request RollbackPolicyRequest) (*PolicyResponse, error) + + // PolicySets + + // ListPolicySets lists all PolicySets of specified type for the current account + ListPolicySets(context.Context, ListPolicySetsRequest) ([]PolicySet, error) + + // GetPolicySet gets specific PolicySet by PolicySetID + GetPolicySet(context.Context, GetPolicySetRequest) (*PolicySet, error) + + // CreatePolicySet creates configuration for an PolicySet + CreatePolicySet(context.Context, CreatePolicySetRequest) (*PolicySet, error) + + // UpdatePolicySet creates configuration for an PolicySet + UpdatePolicySet(context.Context, UpdatePolicySetRequest) (*PolicySet, error) + + // DeletePolicySet deletes configuration for an PolicySet + DeletePolicySet(context.Context, DeletePolicySetRequest) error } imaging struct { diff --git a/pkg/imaging/policy.go b/pkg/imaging/policy.go index 58365590..c72e34e4 100644 --- a/pkg/imaging/policy.go +++ b/pkg/imaging/policy.go @@ -17,31 +17,6 @@ import ( // https://git.source.akamai.com/users/eleclair/repos/terraform/browse/docs/schemas type ( - // Policies is an Image and Video Manager API interface for Policy - // - // See: https://techdocs.akamai.com/ivm/reference/api - Policies interface { - // ListPolicies lists all Policies for the given network and an account - // - // See: https://techdocs.akamai.com/ivm/reference/get-policies - ListPolicies(context.Context, ListPoliciesRequest) (*ListPoliciesResponse, error) - - // GetPolicy gets specific policy by PolicyID - GetPolicy(context.Context, GetPolicyRequest) (PolicyOutput, error) - - // UpsertPolicy creates or updates the configuration for a policy - UpsertPolicy(context.Context, UpsertPolicyRequest) (*PolicyResponse, error) - - // DeletePolicy deletes a policy - DeletePolicy(context.Context, DeletePolicyRequest) (*PolicyResponse, error) - - // GetPolicyHistory retrieves history of changes for a policy - GetPolicyHistory(context.Context, GetPolicyHistoryRequest) (*GetPolicyHistoryResponse, error) - - // RollbackPolicy reverts a policy to its previous version and deploys it to the network - RollbackPolicy(ctx context.Context, request RollbackPolicyRequest) (*PolicyResponse, error) - } - // ListPoliciesRequest describes the parameters of the ListPolicies request ListPoliciesRequest struct { Network PolicyNetwork diff --git a/pkg/imaging/policyset.go b/pkg/imaging/policyset.go index 5e846a56..aa318c1e 100644 --- a/pkg/imaging/policyset.go +++ b/pkg/imaging/policyset.go @@ -13,26 +13,6 @@ import ( ) type ( - // PolicySets is an Image and Video Manager API interface for PolicySets - // - // See: https://techdocs.akamai.com/ivm/reference/api - PolicySets interface { - // ListPolicySets lists all PolicySets of specified type for the current account - ListPolicySets(context.Context, ListPolicySetsRequest) ([]PolicySet, error) - - // GetPolicySet gets specific PolicySet by PolicySetID - GetPolicySet(context.Context, GetPolicySetRequest) (*PolicySet, error) - - // CreatePolicySet creates configuration for an PolicySet - CreatePolicySet(context.Context, CreatePolicySetRequest) (*PolicySet, error) - - // UpdatePolicySet creates configuration for an PolicySet - UpdatePolicySet(context.Context, UpdatePolicySetRequest) (*PolicySet, error) - - // DeletePolicySet deletes configuration for an PolicySet - DeletePolicySet(context.Context, DeletePolicySetRequest) error - } - // ListPolicySetsRequest describes the parameters of the ListPolicySets request ListPolicySetsRequest struct { ContractID string diff --git a/pkg/networklists/activations.go b/pkg/networklists/activations.go index 9f1754cb..9be1e0ba 100644 --- a/pkg/networklists/activations.go +++ b/pkg/networklists/activations.go @@ -10,31 +10,6 @@ import ( ) type ( - // The Activations interface supports activating and deactivating network lists. - // - // https://techdocs.akamai.com/network-lists/reference/api - Activations interface { - // GetActivations retrieves list of network list activations. - // - // See: https://techdocs.akamai.com/network-lists/reference/get-network-list-status - GetActivations(ctx context.Context, params GetActivationsRequest) (*GetActivationsResponse, error) - - // GetActivation retrieves network list activation. - // - // See: https://techdocs.akamai.com/network-lists/reference/get-activation - GetActivation(ctx context.Context, params GetActivationRequest) (*GetActivationResponse, error) - - // CreateActivations activates network list. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-network-list-activate - CreateActivations(ctx context.Context, params CreateActivationsRequest) (*CreateActivationsResponse, error) - - // RemoveActivations deactivates network list. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-network-list-activate - RemoveActivations(ctx context.Context, params RemoveActivationsRequest) (*RemoveActivationsResponse, error) - } - // GetActivationsRequest contains request parameters for getting activation status GetActivationsRequest struct { UniqueID string `json:"-"` diff --git a/pkg/networklists/network_list.go b/pkg/networklists/network_list.go index 52456e8f..8622b9b0 100644 --- a/pkg/networklists/network_list.go +++ b/pkg/networklists/network_list.go @@ -10,34 +10,6 @@ import ( ) type ( - // The NetworkList interface supports creating, retrieving, modifying and removing network lists. - NetworkList interface { - // GetNetworkLists lists all network lists available for an authenticated user. - // - // See: https://techdocs.akamai.com/network-lists/reference/get-network-lists - GetNetworkLists(ctx context.Context, params GetNetworkListsRequest) (*GetNetworkListsResponse, error) - - // GetNetworkList retrieves network list with specific network list id. - // - // See: https://techdocs.akamai.com/network-lists/reference/get-network-list - GetNetworkList(ctx context.Context, params GetNetworkListRequest) (*GetNetworkListResponse, error) - - // CreateNetworkList creates a new network list. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-network-lists - CreateNetworkList(ctx context.Context, params CreateNetworkListRequest) (*CreateNetworkListResponse, error) - - // UpdateNetworkList modifies the network list. - // - //See: https://techdocs.akamai.com/network-lists/reference/put-network-list - UpdateNetworkList(ctx context.Context, params UpdateNetworkListRequest) (*UpdateNetworkListResponse, error) - - // RemoveNetworkList removes a network list. - // - // See: https://techdocs.akamai.com/network-lists/reference/delete-network-list - RemoveNetworkList(ctx context.Context, params RemoveNetworkListRequest) (*RemoveNetworkListResponse, error) - } - // GetNetworkListRequest contains request parameters for GetNetworkList method GetNetworkListRequest struct { UniqueID string `json:"-"` diff --git a/pkg/networklists/network_list_description.go b/pkg/networklists/network_list_description.go index 1ab2233a..9f1f2bcd 100644 --- a/pkg/networklists/network_list_description.go +++ b/pkg/networklists/network_list_description.go @@ -9,19 +9,6 @@ import ( ) type ( - // The NetworkListDescription interface supports retrieving and updating a network list's description. - NetworkListDescription interface { - // GetNetworkListDescription retrieves network list with description. - // - // See: https://techdocs.akamai.com/network-lists/reference/get-network-list - GetNetworkListDescription(ctx context.Context, params GetNetworkListDescriptionRequest) (*GetNetworkListDescriptionResponse, error) - - // UpdateNetworkListDescription modifies network list description. - // - // See: https://techdocs.akamai.com/network-lists/reference/put-network-list-details - UpdateNetworkListDescription(ctx context.Context, params UpdateNetworkListDescriptionRequest) (*UpdateNetworkListDescriptionResponse, error) - } - // GetNetworkListDescriptionRequest contains request parameters for GetNetworkListDescription method GetNetworkListDescriptionRequest struct { UniqueID string `json:"uniqueId"` diff --git a/pkg/networklists/network_list_subscription.go b/pkg/networklists/network_list_subscription.go index dd6120b8..b02824f2 100644 --- a/pkg/networklists/network_list_subscription.go +++ b/pkg/networklists/network_list_subscription.go @@ -7,24 +7,6 @@ import ( ) type ( - // The NetworkListSubscription interface supports creating, modifying and removing network list subscriptions. - NetworkListSubscription interface { - // GetNetworkListSubscription retrieves networklist subscription. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-subscribe - GetNetworkListSubscription(ctx context.Context, params GetNetworkListSubscriptionRequest) (*GetNetworkListSubscriptionResponse, error) - - // UpdateNetworkListSubscription updates networklist subscription. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-subscribe - UpdateNetworkListSubscription(ctx context.Context, params UpdateNetworkListSubscriptionRequest) (*UpdateNetworkListSubscriptionResponse, error) - - // RemoveNetworkListSubscription unsubscribes networklist. - // - // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-unsubscribe - RemoveNetworkListSubscription(ctx context.Context, params RemoveNetworkListSubscriptionRequest) (*RemoveNetworkListSubscriptionResponse, error) - } - // GetNetworkListSubscriptionRequest contains request parameters for GetNetworkListSubscription GetNetworkListSubscriptionRequest struct { Recipients []string `json:"-"` diff --git a/pkg/networklists/networklists.go b/pkg/networklists/networklists.go index 752a5044..efea9d4e 100644 --- a/pkg/networklists/networklists.go +++ b/pkg/networklists/networklists.go @@ -4,6 +4,7 @@ package networklists import ( + "context" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" @@ -15,12 +16,85 @@ var ( ) type ( - // NTWRKLISTS is the networklist api interface - NTWRKLISTS interface { - Activations - NetworkList - NetworkListDescription - NetworkListSubscription + // NetworkList is the networklist api interface + NetworkList interface { + // Activations + + // GetActivations retrieves list of network list activations. + // + // See: https://techdocs.akamai.com/network-lists/reference/get-network-list-status + GetActivations(ctx context.Context, params GetActivationsRequest) (*GetActivationsResponse, error) + + // GetActivation retrieves network list activation. + // + // See: https://techdocs.akamai.com/network-lists/reference/get-activation + GetActivation(ctx context.Context, params GetActivationRequest) (*GetActivationResponse, error) + + // CreateActivations activates network list. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-network-list-activate + CreateActivations(ctx context.Context, params CreateActivationsRequest) (*CreateActivationsResponse, error) + + // RemoveActivations deactivates network list. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-network-list-activate + RemoveActivations(ctx context.Context, params RemoveActivationsRequest) (*RemoveActivationsResponse, error) + + // NetworkList + + // GetNetworkLists lists all network lists available for an authenticated user. + // + // See: https://techdocs.akamai.com/network-lists/reference/get-network-lists + GetNetworkLists(ctx context.Context, params GetNetworkListsRequest) (*GetNetworkListsResponse, error) + + // GetNetworkList retrieves network list with specific network list id. + // + // See: https://techdocs.akamai.com/network-lists/reference/get-network-list + GetNetworkList(ctx context.Context, params GetNetworkListRequest) (*GetNetworkListResponse, error) + + // CreateNetworkList creates a new network list. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-network-lists + CreateNetworkList(ctx context.Context, params CreateNetworkListRequest) (*CreateNetworkListResponse, error) + + // UpdateNetworkList modifies the network list. + // + //See: https://techdocs.akamai.com/network-lists/reference/put-network-list + UpdateNetworkList(ctx context.Context, params UpdateNetworkListRequest) (*UpdateNetworkListResponse, error) + + // RemoveNetworkList removes a network list. + // + // See: https://techdocs.akamai.com/network-lists/reference/delete-network-list + RemoveNetworkList(ctx context.Context, params RemoveNetworkListRequest) (*RemoveNetworkListResponse, error) + + // NetworkListDescription + + // GetNetworkListDescription retrieves network list with description. + // + // See: https://techdocs.akamai.com/network-lists/reference/get-network-list + GetNetworkListDescription(ctx context.Context, params GetNetworkListDescriptionRequest) (*GetNetworkListDescriptionResponse, error) + + // UpdateNetworkListDescription modifies network list description. + // + // See: https://techdocs.akamai.com/network-lists/reference/put-network-list-details + UpdateNetworkListDescription(ctx context.Context, params UpdateNetworkListDescriptionRequest) (*UpdateNetworkListDescriptionResponse, error) + + // NetworkListSubscription + + // GetNetworkListSubscription retrieves networklist subscription. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-subscribe + GetNetworkListSubscription(ctx context.Context, params GetNetworkListSubscriptionRequest) (*GetNetworkListSubscriptionResponse, error) + + // UpdateNetworkListSubscription updates networklist subscription. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-subscribe + UpdateNetworkListSubscription(ctx context.Context, params UpdateNetworkListSubscriptionRequest) (*UpdateNetworkListSubscriptionResponse, error) + + // RemoveNetworkListSubscription unsubscribes networklist. + // + // See: https://techdocs.akamai.com/network-lists/reference/post-notifications-unsubscribe + RemoveNetworkListSubscription(ctx context.Context, params RemoveNetworkListSubscriptionRequest) (*RemoveNetworkListSubscriptionResponse, error) } networklists struct { @@ -32,11 +106,11 @@ type ( Option func(*networklists) // ClientFunc is a networklist client new method, this can used for mocking - ClientFunc func(sess session.Session, opts ...Option) NTWRKLISTS + ClientFunc func(sess session.Session, opts ...Option) NetworkList ) // Client returns a new networklist Client instance with the specified controller -func Client(sess session.Session, opts ...Option) NTWRKLISTS { +func Client(sess session.Session, opts ...Option) NetworkList { p := &networklists{ Session: sess, } diff --git a/pkg/networklists/networklists_test.go b/pkg/networklists/networklists_test.go index 4e9a9a2d..921ba433 100644 --- a/pkg/networklists/networklists_test.go +++ b/pkg/networklists/networklists_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/require" ) -func mockAPIClient(t *testing.T, mockServer *httptest.Server) NTWRKLISTS { +func mockAPIClient(t *testing.T, mockServer *httptest.Server) NetworkList { serverURL, err := url.Parse(mockServer.URL) require.NoError(t, err) certPool := x509.NewCertPool() diff --git a/pkg/papi/activation.go b/pkg/papi/activation.go index eeba52c1..80f3d6ab 100644 --- a/pkg/papi/activation.go +++ b/pkg/papi/activation.go @@ -12,29 +12,6 @@ import ( ) type ( - // Activations contains operations available on Activation resource - Activations interface { - // CreateActivation creates a new activation or deactivation request - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-property-activations - CreateActivation(context.Context, CreateActivationRequest) (*CreateActivationResponse, error) - - // GetActivations returns a list of the property activations - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-activations - GetActivations(ctx context.Context, params GetActivationsRequest) (*GetActivationsResponse, error) - - // GetActivation gets details about an activation - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-activation - GetActivation(context.Context, GetActivationRequest) (*GetActivationResponse, error) - - // CancelActivation allows for canceling an activation while it is still PENDING - // - // https://techdocs.akamai.com/property-mgr/reference/delete-property-activation - CancelActivation(context.Context, CancelActivationRequest) (*CancelActivationResponse, error) - } - // ActivationFallbackInfo encapsulates information about fast fallback, which may allow you to fallback to a previous activation when // POSTing an activation with useFastFallback enabled. ActivationFallbackInfo struct { diff --git a/pkg/papi/clientsettings.go b/pkg/papi/clientsettings.go index 9bb73c3d..053ad5ea 100644 --- a/pkg/papi/clientsettings.go +++ b/pkg/papi/clientsettings.go @@ -8,19 +8,6 @@ import ( ) type ( - // ClientSettings contains operations available on ClientSettings resource - ClientSettings interface { - // GetClientSettings returns client's settings. - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-client-settings - GetClientSettings(context.Context) (*ClientSettingsBody, error) - - // UpdateClientSettings updates client's settings. - // - // See: https://techdocs.akamai.com/property-mgr/reference/put-client-settings - UpdateClientSettings(context.Context, ClientSettingsBody) (*ClientSettingsBody, error) - } - // ClientSettingsBody represents both the request and response bodies for operating on client settings resource ClientSettingsBody struct { RuleFormat string `json:"ruleFormat"` diff --git a/pkg/papi/contract.go b/pkg/papi/contract.go index 70969c55..3015b1a9 100644 --- a/pkg/papi/contract.go +++ b/pkg/papi/contract.go @@ -8,14 +8,6 @@ import ( ) type ( - // Contracts contains operations available on Contract resource - Contracts interface { - // GetContracts provides a read-only list of contract names and identifiers - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-contracts - GetContracts(context.Context) (*GetContractsResponse, error) - } - // Contract represents a property contract resource Contract struct { ContractID string `json:"contractId"` diff --git a/pkg/papi/cpcode.go b/pkg/papi/cpcode.go index eccf5116..da9b5a0a 100644 --- a/pkg/papi/cpcode.go +++ b/pkg/papi/cpcode.go @@ -10,34 +10,6 @@ import ( ) type ( - // CPCodes contains operations available on CPCode resource - CPCodes interface { - // GetCPCodes lists all available CP codes - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-cpcodes - GetCPCodes(context.Context, GetCPCodesRequest) (*GetCPCodesResponse, error) - - // GetCPCode gets the CP code with provided ID - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-cpcode - GetCPCode(context.Context, GetCPCodeRequest) (*GetCPCodesResponse, error) - - // GetCPCodeDetail lists detailed information about a specific CP code - // - // See: https://techdocs.akamai.com/cp-codes/reference/get-cpcode - GetCPCodeDetail(context.Context, int) (*CPCodeDetailResponse, error) - - // CreateCPCode creates a new CP code - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-cpcodes - CreateCPCode(context.Context, CreateCPCodeRequest) (*CreateCPCodeResponse, error) - - // UpdateCPCode modifies a specific CP code. You should only modify a CP code's name, time zone, and purgeable member - // - // See: https://techdocs.akamai.com/cp-codes/reference/put-cpcode - UpdateCPCode(context.Context, UpdateCPCodeRequest) (*CPCodeDetailResponse, error) - } - // CPCode contains CP code resource data CPCode struct { ID string `json:"cpcodeId"` diff --git a/pkg/papi/edgehostname.go b/pkg/papi/edgehostname.go index 6fce8a78..17ec8a9d 100644 --- a/pkg/papi/edgehostname.go +++ b/pkg/papi/edgehostname.go @@ -12,24 +12,6 @@ import ( ) type ( - // EdgeHostnames contains operations available on EdgeHostnames resource - EdgeHostnames interface { - // GetEdgeHostnames fetches a list of edge hostnames - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-edgehostnames - GetEdgeHostnames(context.Context, GetEdgeHostnamesRequest) (*GetEdgeHostnamesResponse, error) - - // GetEdgeHostname fetches edge hostname with given ID - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-edgehostname - GetEdgeHostname(context.Context, GetEdgeHostnameRequest) (*GetEdgeHostnamesResponse, error) - - // CreateEdgeHostname creates a new edge hostname - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-edgehostnames - CreateEdgeHostname(context.Context, CreateEdgeHostnameRequest) (*CreateEdgeHostnameResponse, error) - } - // GetEdgeHostnamesRequest contains query params used for listing edge hostnames GetEdgeHostnamesRequest struct { ContractID string diff --git a/pkg/papi/group.go b/pkg/papi/group.go index d47fe834..1d35cee6 100644 --- a/pkg/papi/group.go +++ b/pkg/papi/group.go @@ -8,14 +8,6 @@ import ( ) type ( - // Groups contains operations available on Group resource - Groups interface { - // GetGroups provides a read-only list of groups, which may contain properties. - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-groups - GetGroups(context.Context) (*GetGroupsResponse, error) - } - // Group represents a property group resource Group struct { GroupID string `json:"groupId"` diff --git a/pkg/papi/include.go b/pkg/papi/include.go index 47c73df2..5d0447c4 100644 --- a/pkg/papi/include.go +++ b/pkg/papi/include.go @@ -13,34 +13,6 @@ import ( ) type ( - // Includes contains operations available on Include resource - Includes interface { - // ListIncludes lists Includes available for the current contract and group - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-includes - ListIncludes(context.Context, ListIncludesRequest) (*ListIncludesResponse, error) - - // ListIncludeParents lists parents of a specific Include - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-parents - ListIncludeParents(context.Context, ListIncludeParentsRequest) (*ListIncludeParentsResponse, error) - - // GetInclude gets information about a specific Include - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include - GetInclude(context.Context, GetIncludeRequest) (*GetIncludeResponse, error) - - // CreateInclude creates a new Include - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-includes - CreateInclude(context.Context, CreateIncludeRequest) (*CreateIncludeResponse, error) - - // DeleteInclude deletes an Include - // - // See: https://techdocs.akamai.com/property-mgr/reference/delete-include - DeleteInclude(context.Context, DeleteIncludeRequest) (*DeleteIncludeResponse, error) - } - // ListIncludesRequest contains parameters used to list includes ListIncludesRequest struct { ContractID string diff --git a/pkg/papi/include_activations.go b/pkg/papi/include_activations.go index 09a68eb0..0a438942 100644 --- a/pkg/papi/include_activations.go +++ b/pkg/papi/include_activations.go @@ -15,34 +15,6 @@ import ( ) type ( - // IncludeActivations contains operations available on IncludeVersion resource - IncludeActivations interface { - // ActivateInclude creates a new include activation, which deactivates any current activation - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-include-activation - ActivateInclude(context.Context, ActivateIncludeRequest) (*ActivationIncludeResponse, error) - - // DeactivateInclude deactivates the include activation - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-include-activation - DeactivateInclude(context.Context, DeactivateIncludeRequest) (*DeactivationIncludeResponse, error) - - // CancelIncludeActivation cancels specified include activation, if it is still in `PENDING` state - // - // See: https://techdocs.akamai.com/property-mgr/reference/delete-include-activation - CancelIncludeActivation(context.Context, CancelIncludeActivationRequest) (*CancelIncludeActivationResponse, error) - - // GetIncludeActivation gets details about an activation - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-activation - GetIncludeActivation(context.Context, GetIncludeActivationRequest) (*GetIncludeActivationResponse, error) - - // ListIncludeActivations lists all activations for all versions of the include, on both production and staging networks - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-activations - ListIncludeActivations(context.Context, ListIncludeActivationsRequest) (*ListIncludeActivationsResponse, error) - } - // ActivateIncludeRequest contains parameters used to activate include ActivateIncludeRequest ActivateOrDeactivateIncludeRequest diff --git a/pkg/papi/include_rule.go b/pkg/papi/include_rule.go index 7fcdd21a..d3644602 100644 --- a/pkg/papi/include_rule.go +++ b/pkg/papi/include_rule.go @@ -13,19 +13,6 @@ import ( ) type ( - // IncludeRules contains operations available on IncludeRule resource - IncludeRules interface { - // GetIncludeRuleTree gets the entire rule tree for an include version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-version-rules - GetIncludeRuleTree(context.Context, GetIncludeRuleTreeRequest) (*GetIncludeRuleTreeResponse, error) - - // UpdateIncludeRuleTree updates the rule tree for an include version - // - // See: https://techdocs.akamai.com/property-mgr/reference/patch-include-version-rules - UpdateIncludeRuleTree(context.Context, UpdateIncludeRuleTreeRequest) (*UpdateIncludeRuleTreeResponse, error) - } - // GetIncludeRuleTreeRequest contains path and query params necessary to perform GetIncludeRuleTree GetIncludeRuleTreeRequest struct { ContractID string diff --git a/pkg/papi/include_versions.go b/pkg/papi/include_versions.go index e0a6b829..64c9f84f 100644 --- a/pkg/papi/include_versions.go +++ b/pkg/papi/include_versions.go @@ -13,34 +13,6 @@ import ( ) type ( - // IncludeVersions contains operations available on IncludeVersion resource - IncludeVersions interface { - // CreateIncludeVersion creates a new include version based on any previous version - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-include-versions - CreateIncludeVersion(context.Context, CreateIncludeVersionRequest) (*CreateIncludeVersionResponse, error) - - // GetIncludeVersion polls the state of a specific include version, for example to check its activation status - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-version - GetIncludeVersion(context.Context, GetIncludeVersionRequest) (*GetIncludeVersionResponse, error) - - // ListIncludeVersions lists the include versions, with results limited to the 500 most recent versions - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-versions - ListIncludeVersions(context.Context, ListIncludeVersionsRequest) (*ListIncludeVersionsResponse, error) - - // ListIncludeVersionAvailableCriteria lists available criteria for the include version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-available-criteria - ListIncludeVersionAvailableCriteria(context.Context, ListAvailableCriteriaRequest) (*AvailableCriteriaResponse, error) - - // ListIncludeVersionAvailableBehaviors lists available behaviors for the include version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-include-available-behaviors - ListIncludeVersionAvailableBehaviors(context.Context, ListAvailableBehaviorsRequest) (*AvailableBehaviorsResponse, error) - } - // CreateIncludeVersionRequest contains parameters used to create a new include version CreateIncludeVersionRequest struct { IncludeID string diff --git a/pkg/papi/papi.go b/pkg/papi/papi.go index 6c31b961..9804bcaa 100644 --- a/pkg/papi/papi.go +++ b/pkg/papi/papi.go @@ -2,6 +2,7 @@ package papi import ( + "context" "errors" "net/http" @@ -29,23 +30,304 @@ var ( type ( // PAPI is the papi api interface PAPI interface { - Activations - ClientSettings - Contracts - CPCodes - EdgeHostnames - Groups - Includes - IncludeRules - IncludeActivations - IncludeVersions - Products - Properties - PropertyRules - PropertyVersionHostnames - PropertyVersions - RuleFormats - Search + // Activations + + // CreateActivation creates a new activation or deactivation request + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-property-activations + CreateActivation(context.Context, CreateActivationRequest) (*CreateActivationResponse, error) + + // GetActivations returns a list of the property activations + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-activations + GetActivations(ctx context.Context, params GetActivationsRequest) (*GetActivationsResponse, error) + + // GetActivation gets details about an activation + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-activation + GetActivation(context.Context, GetActivationRequest) (*GetActivationResponse, error) + + // CancelActivation allows for canceling an activation while it is still PENDING + // + // https://techdocs.akamai.com/property-mgr/reference/delete-property-activation + CancelActivation(context.Context, CancelActivationRequest) (*CancelActivationResponse, error) + + // ClientSettings + + // GetClientSettings returns client's settings. + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-client-settings + GetClientSettings(context.Context) (*ClientSettingsBody, error) + + // UpdateClientSettings updates client's settings. + // + // See: https://techdocs.akamai.com/property-mgr/reference/put-client-settings + UpdateClientSettings(context.Context, ClientSettingsBody) (*ClientSettingsBody, error) + + // Contracts + + // GetContracts provides a read-only list of contract names and identifiers + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-contracts + GetContracts(context.Context) (*GetContractsResponse, error) + + // CPCodes + + // GetCPCodes lists all available CP codes + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-cpcodes + GetCPCodes(context.Context, GetCPCodesRequest) (*GetCPCodesResponse, error) + + // GetCPCode gets the CP code with provided ID + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-cpcode + GetCPCode(context.Context, GetCPCodeRequest) (*GetCPCodesResponse, error) + + // GetCPCodeDetail lists detailed information about a specific CP code + // + // See: https://techdocs.akamai.com/cp-codes/reference/get-cpcode + GetCPCodeDetail(context.Context, int) (*CPCodeDetailResponse, error) + + // CreateCPCode creates a new CP code + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-cpcodes + CreateCPCode(context.Context, CreateCPCodeRequest) (*CreateCPCodeResponse, error) + + // UpdateCPCode modifies a specific CP code. You should only modify a CP code's name, time zone, and purgeable member + // + // See: https://techdocs.akamai.com/cp-codes/reference/put-cpcode + UpdateCPCode(context.Context, UpdateCPCodeRequest) (*CPCodeDetailResponse, error) + + // EdgeHostnames + + // GetEdgeHostnames fetches a list of edge hostnames + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-edgehostnames + GetEdgeHostnames(context.Context, GetEdgeHostnamesRequest) (*GetEdgeHostnamesResponse, error) + + // GetEdgeHostname fetches edge hostname with given ID + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-edgehostname + GetEdgeHostname(context.Context, GetEdgeHostnameRequest) (*GetEdgeHostnamesResponse, error) + + // CreateEdgeHostname creates a new edge hostname + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-edgehostnames + CreateEdgeHostname(context.Context, CreateEdgeHostnameRequest) (*CreateEdgeHostnameResponse, error) + + // Groups + + // GetGroups provides a read-only list of groups, which may contain properties. + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-groups + GetGroups(context.Context) (*GetGroupsResponse, error) + + // Includes + + // ListIncludes lists Includes available for the current contract and group + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-includes + ListIncludes(context.Context, ListIncludesRequest) (*ListIncludesResponse, error) + + // ListIncludeParents lists parents of a specific Include + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-parents + ListIncludeParents(context.Context, ListIncludeParentsRequest) (*ListIncludeParentsResponse, error) + + // GetInclude gets information about a specific Include + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include + GetInclude(context.Context, GetIncludeRequest) (*GetIncludeResponse, error) + + // CreateInclude creates a new Include + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-includes + CreateInclude(context.Context, CreateIncludeRequest) (*CreateIncludeResponse, error) + + // DeleteInclude deletes an Include + // + // See: https://techdocs.akamai.com/property-mgr/reference/delete-include + DeleteInclude(context.Context, DeleteIncludeRequest) (*DeleteIncludeResponse, error) + + // IncludeRules + + // GetIncludeRuleTree gets the entire rule tree for an include version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-version-rules + GetIncludeRuleTree(context.Context, GetIncludeRuleTreeRequest) (*GetIncludeRuleTreeResponse, error) + + // UpdateIncludeRuleTree updates the rule tree for an include version + // + // See: https://techdocs.akamai.com/property-mgr/reference/patch-include-version-rules + UpdateIncludeRuleTree(context.Context, UpdateIncludeRuleTreeRequest) (*UpdateIncludeRuleTreeResponse, error) + + // IncludeActivations + + // ActivateInclude creates a new include activation, which deactivates any current activation + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-include-activation + ActivateInclude(context.Context, ActivateIncludeRequest) (*ActivationIncludeResponse, error) + + // DeactivateInclude deactivates the include activation + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-include-activation + DeactivateInclude(context.Context, DeactivateIncludeRequest) (*DeactivationIncludeResponse, error) + + // CancelIncludeActivation cancels specified include activation, if it is still in `PENDING` state + // + // See: https://techdocs.akamai.com/property-mgr/reference/delete-include-activation + CancelIncludeActivation(context.Context, CancelIncludeActivationRequest) (*CancelIncludeActivationResponse, error) + + // GetIncludeActivation gets details about an activation + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-activation + GetIncludeActivation(context.Context, GetIncludeActivationRequest) (*GetIncludeActivationResponse, error) + + // ListIncludeActivations lists all activations for all versions of the include, on both production and staging networks + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-activations + ListIncludeActivations(context.Context, ListIncludeActivationsRequest) (*ListIncludeActivationsResponse, error) + + // IncludeVersions + + // CreateIncludeVersion creates a new include version based on any previous version + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-include-versions + CreateIncludeVersion(context.Context, CreateIncludeVersionRequest) (*CreateIncludeVersionResponse, error) + + // GetIncludeVersion polls the state of a specific include version, for example to check its activation status + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-version + GetIncludeVersion(context.Context, GetIncludeVersionRequest) (*GetIncludeVersionResponse, error) + + // ListIncludeVersions lists the include versions, with results limited to the 500 most recent versions + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-versions + ListIncludeVersions(context.Context, ListIncludeVersionsRequest) (*ListIncludeVersionsResponse, error) + + // ListIncludeVersionAvailableCriteria lists available criteria for the include version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-available-criteria + ListIncludeVersionAvailableCriteria(context.Context, ListAvailableCriteriaRequest) (*AvailableCriteriaResponse, error) + + // ListIncludeVersionAvailableBehaviors lists available behaviors for the include version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-include-available-behaviors + ListIncludeVersionAvailableBehaviors(context.Context, ListAvailableBehaviorsRequest) (*AvailableBehaviorsResponse, error) + + // Products + + // GetProducts lists all available Products + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-products + GetProducts(context.Context, GetProductsRequest) (*GetProductsResponse, error) + + // Properties + + // GetProperties lists properties available for the current contract and group + // + // https://techdocs.akamai.com/property-mgr/reference/get-properties + GetProperties(ctx context.Context, r GetPropertiesRequest) (*GetPropertiesResponse, error) + + // CreateProperty creates a new property from scratch or bases one on another property's rule tree and optionally its set of assigned hostnames + // + // https://techdocs.akamai.com/property-mgr/reference/post-properties + CreateProperty(ctx context.Context, params CreatePropertyRequest) (*CreatePropertyResponse, error) + + // GetProperty gets a specific property + // + // https://techdocs.akamai.com/property-mgr/reference/get-property + GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) + + // RemoveProperty removes a specific property, which you can only do if none of its versions are currently active + // + // https://techdocs.akamai.com/property-mgr/reference/delete-property + RemoveProperty(ctx context.Context, params RemovePropertyRequest) (*RemovePropertyResponse, error) + + // MapPropertyNameToID returns (PAPI) property ID for given property name + // Mainly to be used to map (IAM) Property ID to (PAPI) Property ID + // To get property name for the mapping, please use iam.MapPropertyIDToName + MapPropertyNameToID(context.Context, MapPropertyNameToIDRequest) (*string, error) + + // PropertyRules + + // GetRuleTree gets the entire rule tree for a property version. + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-rules + GetRuleTree(context.Context, GetRuleTreeRequest) (*GetRuleTreeResponse, error) + + // UpdateRuleTree updates the rule tree for a property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/put-property-version-rules + UpdateRuleTree(context.Context, UpdateRulesRequest) (*UpdateRulesResponse, error) + + // PropertyVersionHostnames + + // GetPropertyVersionHostnames lists all the hostnames assigned to a property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-hostnames + GetPropertyVersionHostnames(context.Context, GetPropertyVersionHostnamesRequest) (*GetPropertyVersionHostnamesResponse, error) + + // UpdatePropertyVersionHostnames modifies the set of hostnames for a property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/patch-property-version-hostnames + UpdatePropertyVersionHostnames(context.Context, UpdatePropertyVersionHostnamesRequest) (*UpdatePropertyVersionHostnamesResponse, error) + + // PropertyVersions + + // GetPropertyVersions fetches available property versions + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-versions + GetPropertyVersions(context.Context, GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error) + + // GetPropertyVersion fetches specific property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version + GetPropertyVersion(context.Context, GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error) + + // CreatePropertyVersion creates a new property version and returns location and number for the new version + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-property-versions + CreatePropertyVersion(context.Context, CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error) + + // GetLatestVersion fetches the latest property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-latest-property-version + GetLatestVersion(context.Context, GetLatestVersionRequest) (*GetPropertyVersionsResponse, error) + + // GetAvailableBehaviors fetches a list of available behaviors for given property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-available-behaviors + GetAvailableBehaviors(context.Context, GetAvailableBehaviorsRequest) (*GetBehaviorsResponse, error) + + // GetAvailableCriteria fetches a list of available criteria for given property version + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-available-criteria + GetAvailableCriteria(context.Context, GetAvailableCriteriaRequest) (*GetCriteriaResponse, error) + + // ListAvailableIncludes lists external resources that can be applied within a property version's rules + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-external-resources + ListAvailableIncludes(context.Context, ListAvailableIncludesRequest) (*ListAvailableIncludesResponse, error) + + // ListReferencedIncludes lists referenced includes for parent property + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-includes + ListReferencedIncludes(context.Context, ListReferencedIncludesRequest) (*ListReferencedIncludesResponse, error) + + // RuleFormats + + // GetRuleFormats provides a list of rule formats + // + // See: https://techdocs.akamai.com/property-mgr/reference/get-rule-formats + GetRuleFormats(context.Context) (*GetRuleFormatsResponse, error) + + // Search + + // SearchProperties searches properties by name, or by the hostname or edge hostname for which it’s currently active + // + // See: https://techdocs.akamai.com/property-mgr/reference/post-search-find-by-value + SearchProperties(context.Context, SearchRequest) (*SearchResponse, error) } papi struct { diff --git a/pkg/papi/products.go b/pkg/papi/products.go index c58ee041..51cf5397 100644 --- a/pkg/papi/products.go +++ b/pkg/papi/products.go @@ -10,14 +10,6 @@ import ( ) type ( - // Products contains operations available on Products resource - Products interface { - // GetProducts lists all available Products - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-products - GetProducts(context.Context, GetProductsRequest) (*GetProductsResponse, error) - } - // GetProductsRequest contains data required to list products associated to a contract GetProductsRequest struct { ContractID string diff --git a/pkg/papi/property.go b/pkg/papi/property.go index 05e80a64..74485492 100644 --- a/pkg/papi/property.go +++ b/pkg/papi/property.go @@ -12,34 +12,6 @@ import ( ) type ( - // Properties contains operations available on Property resource - Properties interface { - // GetProperties lists properties available for the current contract and group - // - // https://techdocs.akamai.com/property-mgr/reference/get-properties - GetProperties(ctx context.Context, r GetPropertiesRequest) (*GetPropertiesResponse, error) - - // CreateProperty creates a new property from scratch or bases one on another property's rule tree and optionally its set of assigned hostnames - // - // https://techdocs.akamai.com/property-mgr/reference/post-properties - CreateProperty(ctx context.Context, params CreatePropertyRequest) (*CreatePropertyResponse, error) - - // GetProperty gets a specific property - // - // https://techdocs.akamai.com/property-mgr/reference/get-property - GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) - - // RemoveProperty removes a specific property, which you can only do if none of its versions are currently active - // - // https://techdocs.akamai.com/property-mgr/reference/delete-property - RemoveProperty(ctx context.Context, params RemovePropertyRequest) (*RemovePropertyResponse, error) - - // MapPropertyNameToID returns (PAPI) property ID for given property name - // Mainly to be used to map (IAM) Property ID to (PAPI) Property ID - // To get property name for the mapping, please use iam.MapPropertyIDToName - MapPropertyNameToID(context.Context, MapPropertyNameToIDRequest) (*string, error) - } - // PropertyCloneFrom optionally identifies another property instance to clone when making a POST request to create a new property PropertyCloneFrom struct { CloneFromVersionEtag string `json:"cloneFromVersionEtag,omitempty"` diff --git a/pkg/papi/propertyhostname.go b/pkg/papi/propertyhostname.go index 14813894..9900e43a 100644 --- a/pkg/papi/propertyhostname.go +++ b/pkg/papi/propertyhostname.go @@ -10,19 +10,6 @@ import ( ) type ( - // PropertyVersionHostnames contains operations available on PropertyVersionHostnames resource - PropertyVersionHostnames interface { - // GetPropertyVersionHostnames lists all the hostnames assigned to a property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-hostnames - GetPropertyVersionHostnames(context.Context, GetPropertyVersionHostnamesRequest) (*GetPropertyVersionHostnamesResponse, error) - - // UpdatePropertyVersionHostnames modifies the set of hostnames for a property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/patch-property-version-hostnames - UpdatePropertyVersionHostnames(context.Context, UpdatePropertyVersionHostnamesRequest) (*UpdatePropertyVersionHostnamesResponse, error) - } - // GetPropertyVersionHostnamesRequest contains parameters required to list property version hostnames GetPropertyVersionHostnamesRequest struct { PropertyID string diff --git a/pkg/papi/propertyversion.go b/pkg/papi/propertyversion.go index 8c881fea..59399a1e 100644 --- a/pkg/papi/propertyversion.go +++ b/pkg/papi/propertyversion.go @@ -14,49 +14,6 @@ import ( ) type ( - // PropertyVersions contains operations available on PropertyVersions resource - PropertyVersions interface { - // GetPropertyVersions fetches available property versions - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-versions - GetPropertyVersions(context.Context, GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error) - - // GetPropertyVersion fetches specific property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version - GetPropertyVersion(context.Context, GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error) - - // CreatePropertyVersion creates a new property version and returns location and number for the new version - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-property-versions - CreatePropertyVersion(context.Context, CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error) - - // GetLatestVersion fetches the latest property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-latest-property-version - GetLatestVersion(context.Context, GetLatestVersionRequest) (*GetPropertyVersionsResponse, error) - - // GetAvailableBehaviors fetches a list of available behaviors for given property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-available-behaviors - GetAvailableBehaviors(context.Context, GetAvailableBehaviorsRequest) (*GetBehaviorsResponse, error) - - // GetAvailableCriteria fetches a list of available criteria for given property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-available-criteria - GetAvailableCriteria(context.Context, GetAvailableCriteriaRequest) (*GetCriteriaResponse, error) - - // ListAvailableIncludes lists external resources that can be applied within a property version's rules - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-external-resources - ListAvailableIncludes(context.Context, ListAvailableIncludesRequest) (*ListAvailableIncludesResponse, error) - - // ListReferencedIncludes lists referenced includes for parent property - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-includes - ListReferencedIncludes(context.Context, ListReferencedIncludesRequest) (*ListReferencedIncludesResponse, error) - } - // GetPropertyVersionsRequest contains path and query params used for listing property versions GetPropertyVersionsRequest struct { PropertyID string diff --git a/pkg/papi/rule.go b/pkg/papi/rule.go index dd5de22e..7eb3099c 100644 --- a/pkg/papi/rule.go +++ b/pkg/papi/rule.go @@ -12,19 +12,6 @@ import ( ) type ( - // PropertyRules contains operations available on PropertyRule resource - PropertyRules interface { - // GetRuleTree gets the entire rule tree for a property version. - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-property-version-rules - GetRuleTree(context.Context, GetRuleTreeRequest) (*GetRuleTreeResponse, error) - - // UpdateRuleTree updates the rule tree for a property version - // - // See: https://techdocs.akamai.com/property-mgr/reference/put-property-version-rules - UpdateRuleTree(context.Context, UpdateRulesRequest) (*UpdateRulesResponse, error) - } - // GetRuleTreeRequest contains path and query params necessary to perform GET /rules request GetRuleTreeRequest struct { PropertyID string diff --git a/pkg/papi/ruleformats.go b/pkg/papi/ruleformats.go index dc20df06..7fa3518f 100644 --- a/pkg/papi/ruleformats.go +++ b/pkg/papi/ruleformats.go @@ -8,14 +8,6 @@ import ( ) type ( - // RuleFormats contains operations available on RuleFormat resource - RuleFormats interface { - // GetRuleFormats provides a list of rule formats - // - // See: https://techdocs.akamai.com/property-mgr/reference/get-rule-formats - GetRuleFormats(context.Context) (*GetRuleFormatsResponse, error) - } - // GetRuleFormatsResponse contains the response body of GET /rule-formats request GetRuleFormatsResponse struct { RuleFormats RuleFormatItems `json:"ruleFormats"` diff --git a/pkg/papi/search.go b/pkg/papi/search.go index b996f59c..08266b82 100644 --- a/pkg/papi/search.go +++ b/pkg/papi/search.go @@ -10,14 +10,6 @@ import ( ) type ( - // Search contains SearchProperty method used for fetching properties - Search interface { - // SearchProperties searches properties by name, or by the hostname or edge hostname for which it’s currently active - // - // See: https://techdocs.akamai.com/property-mgr/reference/post-search-find-by-value - SearchProperties(context.Context, SearchRequest) (*SearchResponse, error) - } - // SearchResponse contains response body of POST /search request SearchResponse struct { Versions SearchItems `json:"versions"` From 4526e7734c86affb9b9f810baa6a189b75980777 Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Thu, 26 Sep 2024 09:11:26 +0000 Subject: [PATCH 07/34] DXE-3962 Remove tools package --- CHANGELOG.md | 3 +- pkg/clientlists/client_list_test.go | 6 +- pkg/cloudaccess/properties_test.go | 10 +- pkg/cloudlets/loadbalancer_activation_test.go | 7 +- pkg/cloudlets/loadbalancer_version_test.go | 68 ++--- pkg/cloudlets/match_rule_test.go | 31 ++- pkg/cloudlets/policy_test.go | 7 +- pkg/cloudlets/policy_version_test.go | 25 +- pkg/cloudlets/v3/match_rule_test.go | 17 +- pkg/cloudlets/v3/policy_test.go | 21 +- pkg/cloudlets/v3/policy_version_test.go | 41 ++- pkg/cloudwrapper/configurations_test.go | 48 ++-- pkg/cps/change_management_info_test.go | 5 +- pkg/cps/deployment_schedules_test.go | 22 +- pkg/cps/deployments_test.go | 10 +- pkg/cps/enrollments_test.go | 6 +- pkg/datastream/properties_test.go | 4 +- pkg/datastream/stream_test.go | 4 +- pkg/dns/zonebulk_test.go | 6 +- pkg/edgeworkers/edgekv_namespaces_test.go | 94 +++---- pkg/edgeworkers/report_test.go | 44 ++-- pkg/gtm/property_test.go | 20 +- pkg/iam/user_test.go | 26 +- pkg/imaging/policy_test.go | 238 +++++++++--------- pkg/papi/cpcode_test.go | 4 +- pkg/papi/errors_test.go | 6 +- pkg/papi/include_activations.go | 6 +- pkg/papi/include_rule_test.go | 43 ++-- pkg/papi/include_test.go | 15 +- pkg/papi/property_test.go | 7 +- pkg/papi/propertyversion_test.go | 5 +- pkg/papi/rule_test.go | 70 +++--- pkg/tools/ptr.go | 44 ---- 33 files changed, 454 insertions(+), 509 deletions(-) delete mode 100644 pkg/tools/ptr.go diff --git a/CHANGELOG.md b/CHANGELOG.md index f70b4d10..3d301a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ - +* Global + * Removed `tools` package in favour of `ptr` package diff --git a/pkg/clientlists/client_list_test.go b/pkg/clientlists/client_list_test.go index 373457f8..9a277407 100644 --- a/pkg/clientlists/client_list_test.go +++ b/pkg/clientlists/client_list_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -225,8 +225,8 @@ func TestGetClientLists(t *testing.T) { IncludeItems: true, IncludeDeprecated: true, IncludeNetworkList: true, - Page: tools.IntPtr(0), - PageSize: tools.IntPtr(2), + Page: ptr.To(0), + PageSize: ptr.To(2), Sort: []string{"updatedBy:desc", "value:desc"}, }, responseStatus: http.StatusOK, diff --git a/pkg/cloudaccess/properties_test.go b/pkg/cloudaccess/properties_test.go index c5aa1135..e2340818 100644 --- a/pkg/cloudaccess/properties_test.go +++ b/pkg/cloudaccess/properties_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -68,14 +68,14 @@ func TestLookupProperties(t *testing.T) { PropertyID: "prp_5678", PropertyName: "test-property", ProductionVersion: nil, - StagingVersion: tools.Int64Ptr(1), + StagingVersion: ptr.To(int64(1)), }, { AccessKeyUID: 1234, Version: 1, PropertyID: "prp_6789", PropertyName: "test-property2", - ProductionVersion: tools.Int64Ptr(1), + ProductionVersion: ptr.To(int64(1)), StagingVersion: nil, }, }, @@ -330,14 +330,14 @@ func TestPerformAsyncPropertiesLookup(t *testing.T) { PropertyID: "prp_5678", PropertyName: "test-property", ProductionVersion: nil, - StagingVersion: tools.Int64Ptr(1), + StagingVersion: ptr.To(int64(1)), }, { AccessKeyUID: 1234, Version: 1, PropertyID: "prp_6789", PropertyName: "test-property2", - ProductionVersion: tools.Int64Ptr(1), + ProductionVersion: ptr.To(int64(1)), StagingVersion: nil, }, }, diff --git a/pkg/cloudlets/loadbalancer_activation_test.go b/pkg/cloudlets/loadbalancer_activation_test.go index 54ffc9fb..bdc1382d 100644 --- a/pkg/cloudlets/loadbalancer_activation_test.go +++ b/pkg/cloudlets/loadbalancer_activation_test.go @@ -7,8 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -73,8 +72,8 @@ func TestGetLoadBalancerActivations(t *testing.T) { OriginID: "clorigin1", Network: "prod", LatestOnly: true, - PageSize: tools.Int64Ptr(3), - Page: tools.Int64Ptr(1), + PageSize: ptr.To(int64(3)), + Page: ptr.To(int64(1)), }, responseStatus: http.StatusOK, responseBody: ` diff --git a/pkg/cloudlets/loadbalancer_version_test.go b/pkg/cloudlets/loadbalancer_version_test.go index 21914e24..69f0f35e 100644 --- a/pkg/cloudlets/loadbalancer_version_test.go +++ b/pkg/cloudlets/loadbalancer_version_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/stretchr/testify/require" @@ -36,12 +36,12 @@ func TestCreateLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -123,12 +123,12 @@ func TestCreateLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -277,22 +277,22 @@ func TestDataCenterValidate(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, "valid data center, minimal set of params": { DataCenter: DataCenter{ - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, "longitude, latitude and percent can be 0": { @@ -302,12 +302,12 @@ func TestDataCenterValidate(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(0), - Longitude: tools.Float64Ptr(0), + Latitude: ptr.To(float64(0)), + Longitude: ptr.To(float64(0)), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(0), + Percent: ptr.To(float64(0)), }, }, "missing all required parameters error": { @@ -438,12 +438,12 @@ func TestGetLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -533,12 +533,12 @@ func TestUpdateLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -611,12 +611,12 @@ func TestUpdateLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -651,12 +651,12 @@ func TestUpdateLoadBalancerVersion(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Description: "Test load balancing configuration.", @@ -811,12 +811,12 @@ func TestListLoadBalancerVersions(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, @@ -842,12 +842,12 @@ func TestListLoadBalancerVersions(t *testing.T) { LivenessHosts: []string{ "clorigin3.www.example.com", }, - Latitude: tools.Float64Ptr(102.78108), - Longitude: tools.Float64Ptr(-116.07064), + Latitude: ptr.To(102.78108), + Longitude: ptr.To(-116.07064), Continent: "NA", Country: "US", OriginID: "clorigin3", - Percent: tools.Float64Ptr(100.0), + Percent: ptr.To(100.0), }, }, Deleted: false, diff --git a/pkg/cloudlets/match_rule_test.go b/pkg/cloudlets/match_rule_test.go index b299448f..558f559b 100644 --- a/pkg/cloudlets/match_rule_test.go +++ b/pkg/cloudlets/match_rule_test.go @@ -6,10 +6,9 @@ import ( "strings" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" - - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" ) func TestUnmarshalJSONMatchRules(t *testing.T) { @@ -574,7 +573,7 @@ func TestUnmarshalJSONMatchRules(t *testing.T) { &MatchRuleVP{ Type: "vpMatchRule", End: 0, - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), ID: 0, MatchURL: "", Matches: []MatchCriteriaVP{ @@ -640,7 +639,7 @@ func TestUnmarshalJSONMatchRules(t *testing.T) { &MatchRuleAP{ Type: "apMatchRule", End: 0, - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), ID: 0, MatchURL: "", Matches: []MatchCriteriaAP{ @@ -1029,19 +1028,19 @@ MatchRules[1]: { input: MatchRules{ MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(50.5), + PassThroughPercent: ptr.To(50.5), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(0), + PassThroughPercent: ptr.To(float64(0)), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(100), + PassThroughPercent: ptr.To(float64(100)), }, }, }, @@ -1052,11 +1051,11 @@ MatchRules[1]: { }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(100.1), + PassThroughPercent: ptr.To(100.1), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(-1.1), + PassThroughPercent: ptr.To(-1.1), }, }, withError: ` @@ -1361,19 +1360,19 @@ MatchRules[2]: { input: MatchRules{ MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), }, MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(50.5), + PassThroughPercent: ptr.To(50.5), }, MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(0), + PassThroughPercent: ptr.To(float64(0)), }, MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(100), + PassThroughPercent: ptr.To(float64(100)), }, }, }, @@ -1384,11 +1383,11 @@ MatchRules[2]: { }, MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(100.1), + PassThroughPercent: ptr.To(100.1), }, MatchRuleVP{ Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(-1.1), + PassThroughPercent: ptr.To(-1.1), }, }, withError: ` diff --git a/pkg/cloudlets/policy_test.go b/pkg/cloudlets/policy_test.go index 80233ea1..b28cc7da 100644 --- a/pkg/cloudlets/policy_test.go +++ b/pkg/cloudlets/policy_test.go @@ -7,8 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -154,10 +153,10 @@ func TestListPolicies(t *testing.T) { }, "200 OK with params": { params: ListPoliciesRequest{ - CloudletID: tools.Int64Ptr(2), + CloudletID: ptr.To(int64(2)), IncludeDeleted: true, Offset: 4, - PageSize: tools.IntPtr(5), + PageSize: ptr.To(5), }, responseStatus: http.StatusOK, responseBody: `[]`, diff --git a/pkg/cloudlets/policy_version_test.go b/pkg/cloudlets/policy_version_test.go index 57786a96..1c50439f 100644 --- a/pkg/cloudlets/policy_version_test.go +++ b/pkg/cloudlets/policy_version_test.go @@ -9,8 +9,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -108,7 +107,7 @@ func TestListPolicyVersions(t *testing.T) { IncludeDeleted: true, IncludeActivations: true, Offset: 2, - PageSize: tools.IntPtr(3), + PageSize: ptr.To(3), }, responseStatus: http.StatusOK, responseBody: ` @@ -3327,7 +3326,7 @@ func TestCreatePolicyVersion(t *testing.T) { End: 0, Type: "vpMatchRule", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), ID: 0, Matches: []MatchCriteriaVP{ { @@ -3409,7 +3408,7 @@ func TestCreatePolicyVersion(t *testing.T) { ID: 0, MatchURL: "", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), Start: 0, Matches: []MatchCriteriaVP{ { @@ -3437,7 +3436,7 @@ func TestCreatePolicyVersion(t *testing.T) { End: 0, Type: "apMatchRule", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(0), + PassThroughPercent: ptr.To(float64(0)), ID: 0, Matches: []MatchCriteriaAP{ { @@ -3520,7 +3519,7 @@ func TestCreatePolicyVersion(t *testing.T) { ID: 0, MatchURL: "", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), Start: 0, Matches: []MatchCriteriaAP{ { @@ -3547,7 +3546,7 @@ func TestCreatePolicyVersion(t *testing.T) { End: 0, Type: "apMatchRule", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), ID: 0, Matches: []MatchCriteriaAP{ { @@ -3637,7 +3636,7 @@ func TestCreatePolicyVersion(t *testing.T) { ID: 0, MatchURL: "", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), Start: 0, Matches: []MatchCriteriaAP{ { @@ -3877,7 +3876,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), Name: "rul3", ID: 0, Matches: []MatchCriteriaVP{ @@ -3907,7 +3906,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), Name: "rul3", ID: 0, Matches: []MatchCriteriaAP{ @@ -3990,7 +3989,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "vpMatchRule", - PassThroughPercent: tools.Float64Ptr(101), + PassThroughPercent: ptr.To(float64(101)), Name: "rul3", ID: 0, }, @@ -4009,7 +4008,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(101), + PassThroughPercent: ptr.To(float64(101)), Name: "rul3", ID: 0, }, diff --git a/pkg/cloudlets/v3/match_rule_test.go b/pkg/cloudlets/v3/match_rule_test.go index 68ea0637..dc409dfb 100644 --- a/pkg/cloudlets/v3/match_rule_test.go +++ b/pkg/cloudlets/v3/match_rule_test.go @@ -6,10 +6,9 @@ import ( "strings" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" - - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" ) func TestUnmarshalJSONMatchRules(t *testing.T) { @@ -351,7 +350,7 @@ func TestUnmarshalJSONMatchRules(t *testing.T) { &MatchRuleAP{ Type: "apMatchRule", End: 0, - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), ID: 0, MatchURL: "", Matches: []MatchCriteriaAP{ @@ -698,19 +697,19 @@ func TestValidateMatchRules(t *testing.T) { input: MatchRules{ MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(50.5), + PassThroughPercent: ptr.To(50.5), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(0), + PassThroughPercent: ptr.To(float64(0)), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(100), + PassThroughPercent: ptr.To(float64(100)), }, }, }, @@ -721,11 +720,11 @@ func TestValidateMatchRules(t *testing.T) { }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(100.1), + PassThroughPercent: ptr.To(100.1), }, MatchRuleAP{ Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(-1.1), + PassThroughPercent: ptr.To(-1.1), }, }, withError: ` diff --git a/pkg/cloudlets/v3/policy_test.go b/pkg/cloudlets/v3/policy_test.go index e6ceef4e..a34d92e3 100644 --- a/pkg/cloudlets/v3/policy_test.go +++ b/pkg/cloudlets/v3/policy_test.go @@ -11,7 +11,6 @@ import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -274,7 +273,7 @@ func TestListPolicies(t *testing.T) { }, }, }, - Description: tools.StringPtr("Test"), + Description: ptr.To("Test"), GroupID: 1, ID: 22, Links: []Link{ @@ -567,7 +566,7 @@ func TestCreatePolicy(t *testing.T) { "200 OK - all data": { params: CreatePolicyRequest{ CloudletType: CloudletTypeFR, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, Name: "TestName", PolicyType: PolicyTypeShared, @@ -618,7 +617,7 @@ func TestCreatePolicy(t *testing.T) { CreatedBy: "User1", CreatedDate: test.NewTimeFromString(t, "2023-10-23T11:21:19.896Z"), CurrentActivations: CurrentActivations{}, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, ID: 11, Links: []Link{ @@ -636,7 +635,7 @@ func TestCreatePolicy(t *testing.T) { "validation errors": { params: CreatePolicyRequest{ CloudletType: "Wrong Cloudlet Type", - Description: tools.StringPtr(strings.Repeat("Too long description", 20)), + Description: ptr.To(strings.Repeat("Too long description", 20)), GroupID: 1, Name: "TestName not match", PolicyType: "Wrong Policy Type", @@ -979,7 +978,7 @@ func TestGetPolicy(t *testing.T) { }, }, }, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, ID: 11, Links: []Link{ @@ -1115,7 +1114,7 @@ func TestGetPolicy(t *testing.T) { }, }, }, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, ID: 11, Links: []Link{ @@ -1238,7 +1237,7 @@ func TestUpdatePolicy(t *testing.T) { PolicyID: 1, BodyParams: UpdatePolicyBodyParams{ GroupID: 11, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), }, }, responseStatus: http.StatusOK, @@ -1429,7 +1428,7 @@ func TestUpdatePolicy(t *testing.T) { }, }, }, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, ID: 11, Links: []Link{ @@ -1455,7 +1454,7 @@ func TestUpdatePolicy(t *testing.T) { PolicyID: 1, BodyParams: UpdatePolicyBodyParams{ GroupID: 11, - Description: tools.StringPtr(strings.Repeat("TestDescription", 30)), + Description: ptr.To(strings.Repeat("TestDescription", 30)), }, }, withError: func(t *testing.T, err error) { @@ -1762,7 +1761,7 @@ func TestClonePolicy(t *testing.T) { }, }, }, - Description: tools.StringPtr("Description"), + Description: ptr.To("Description"), GroupID: 1, ID: 11, Links: []Link{ diff --git a/pkg/cloudlets/v3/policy_version_test.go b/pkg/cloudlets/v3/policy_version_test.go index 82aeb101..e884d0f4 100644 --- a/pkg/cloudlets/v3/policy_version_test.go +++ b/pkg/cloudlets/v3/policy_version_test.go @@ -11,7 +11,6 @@ import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -282,7 +281,7 @@ func TestGetPolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedBy: "jsmith", CreatedDate: test.NewTimeFromString(t, "2023-10-19T09:46:57.395Z"), - Description: tools.StringPtr("test description"), + Description: ptr.To("test description"), ID: 6551191, MatchRules: nil, MatchRulesWarnings: []MatchRulesWarning{}, @@ -403,7 +402,7 @@ func TestGetPolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedBy: "jsmith", CreatedDate: test.NewTimeFromString(t, "2023-10-19T09:46:57.395Z"), - Description: tools.StringPtr("Initial version"), + Description: ptr.To("Initial version"), MatchRules: MatchRules{ &MatchRuleAS{ Type: "asMatchRule", @@ -690,7 +689,7 @@ func TestCreatePolicyVersion(t *testing.T) { "201 created, simple ER": { request: CreatePolicyVersionRequest{ CreatePolicyVersion: CreatePolicyVersion{ - Description: tools.StringPtr("Description for the policy"), + Description: ptr.To("Description for the policy"), }, PolicyID: 276858, }, @@ -710,7 +709,7 @@ func TestCreatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("Description for the policy"), + Description: ptr.To("Description for the policy"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z")), MatchRules: nil, @@ -850,7 +849,7 @@ func TestCreatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("Initial version"), + Description: ptr.To("Initial version"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z")), MatchRules: MatchRules{ @@ -2279,7 +2278,7 @@ func TestCreatePolicyVersion(t *testing.T) { "201 created, complex FR with objectMatchValue - object": { request: CreatePolicyVersionRequest{ CreatePolicyVersion: CreatePolicyVersion{ - Description: tools.StringPtr("New version 1630480693371"), + Description: ptr.To("New version 1630480693371"), MatchRules: MatchRules{ &MatchRuleFR{ ForwardSettings: ForwardSettingsFR{}, @@ -2359,7 +2358,7 @@ func TestCreatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("New version 1630480693371"), + Description: ptr.To("New version 1630480693371"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z")), MatchRules: MatchRules{ @@ -2399,7 +2398,7 @@ func TestCreatePolicyVersion(t *testing.T) { "201 created, complex FR with objectMatchValue - simple": { request: CreatePolicyVersionRequest{ CreatePolicyVersion: CreatePolicyVersion{ - Description: tools.StringPtr("New version 1630480693371"), + Description: ptr.To("New version 1630480693371"), MatchRules: MatchRules{ &MatchRuleFR{ ForwardSettings: ForwardSettingsFR{ @@ -2472,7 +2471,7 @@ func TestCreatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("New version 1630480693371"), + Description: ptr.To("New version 1630480693371"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z")), MatchRules: MatchRules{ @@ -2513,7 +2512,7 @@ func TestCreatePolicyVersion(t *testing.T) { End: 0, Type: "apMatchRule", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(0), + PassThroughPercent: ptr.To(float64(0)), ID: 0, Matches: []MatchCriteriaAP{ { @@ -2584,7 +2583,7 @@ func TestCreatePolicyVersion(t *testing.T) { ID: 0, MatchURL: "", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), Start: 0, Matches: []MatchCriteriaAP{ { @@ -2611,7 +2610,7 @@ func TestCreatePolicyVersion(t *testing.T) { End: 0, Type: "apMatchRule", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), ID: 0, Matches: []MatchCriteriaAP{ { @@ -2689,7 +2688,7 @@ func TestCreatePolicyVersion(t *testing.T) { ID: 0, MatchURL: "", Name: "rul3", - PassThroughPercent: tools.Float64Ptr(-1), + PassThroughPercent: ptr.To(float64(-1)), Start: 0, Matches: []MatchCriteriaAP{ { @@ -2917,7 +2916,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(50.50), + PassThroughPercent: ptr.To(50.50), Name: "rul3", ID: 0, Matches: []MatchCriteriaAP{ @@ -2983,7 +2982,7 @@ func TestCreatePolicyVersion(t *testing.T) { Start: 0, End: 0, Type: "apMatchRule", - PassThroughPercent: tools.Float64Ptr(101), + PassThroughPercent: ptr.To(float64(101)), Name: "rul3", ID: 0, }, @@ -3125,7 +3124,7 @@ func TestUpdatePolicyVersion(t *testing.T) { "201 updated simple ER": { request: UpdatePolicyVersionRequest{ UpdatePolicyVersion: UpdatePolicyVersion{ - Description: tools.StringPtr("Updated description"), + Description: ptr.To("Updated description"), }, PolicyID: 276858, PolicyVersion: 5, @@ -3146,7 +3145,7 @@ func TestUpdatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("Updated description"), + Description: ptr.To("Updated description"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-19T08:50:47.350Z")), MatchRules: nil, @@ -3157,7 +3156,7 @@ func TestUpdatePolicyVersion(t *testing.T) { "201 updated simple ER with warnings": { request: UpdatePolicyVersionRequest{ UpdatePolicyVersion: UpdatePolicyVersion{ - Description: tools.StringPtr("Updated description"), + Description: ptr.To("Updated description"), MatchRules: MatchRules{ &MatchRuleER{ Name: "er_rule", @@ -3225,7 +3224,7 @@ func TestUpdatePolicyVersion(t *testing.T) { expectedResponse: &PolicyVersion{ CreatedDate: test.NewTimeFromString(t, "2023-10-20T09:21:04.180Z"), CreatedBy: "jsmith", - Description: tools.StringPtr("Updated description"), + Description: ptr.To("Updated description"), ModifiedBy: "jsmith", ModifiedDate: ptr.To(test.NewTimeFromString(t, "2023-10-20T10:32:56.316Z")), ID: 6552305, @@ -3273,7 +3272,7 @@ func TestUpdatePolicyVersion(t *testing.T) { expectedPath: "/cloudlets/v3/policies/0", request: UpdatePolicyVersionRequest{ UpdatePolicyVersion: UpdatePolicyVersion{ - Description: tools.StringPtr(strings.Repeat("A", 256)), + Description: ptr.To(strings.Repeat("A", 256)), }, }, withError: ErrStructValidation, diff --git a/pkg/cloudwrapper/configurations_test.go b/pkg/cloudwrapper/configurations_test.go index 9f5cc7ed..1619f1c5 100644 --- a/pkg/cloudwrapper/configurations_test.go +++ b/pkg/cloudwrapper/configurations_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -130,7 +130,7 @@ func TestGetConfiguration(t *testing.T) { }`, expectedPath: "/cloud-wrapper/v1/configurations/1", expectedResponse: &Configuration{ - CapacityAlertsThreshold: tools.IntPtr(75), + CapacityAlertsThreshold: ptr.To(75), Comments: "TestComments", ContractID: "TestContractID", ConfigID: 1, @@ -195,7 +195,7 @@ func TestGetConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{11, 22}, Enabled: true, - SamplingRate: tools.IntPtr(999), + SamplingRate: ptr.To(999), }, EnableSoftAlerts: true, Origins: []Origin{ @@ -215,8 +215,8 @@ func TestGetConfiguration(t *testing.T) { ConfigName: "TestConfigName", LastUpdatedBy: "user", LastUpdatedDate: "2023-05-10T09:55:37.000Z", - LastActivatedBy: tools.StringPtr("user"), - LastActivatedDate: tools.StringPtr("2023-05-10T10:14:49.379Z"), + LastActivatedBy: ptr.To("user"), + LastActivatedDate: ptr.To("2023-05-10T10:14:49.379Z"), NotificationEmails: []string{"test@akamai.com"}, PropertyIDs: []string{ "321", @@ -455,7 +455,7 @@ func TestListConfigurations(t *testing.T) { expectedResponse: &ListConfigurationsResponse{ Configurations: []Configuration{ { - CapacityAlertsThreshold: tools.IntPtr(75), + CapacityAlertsThreshold: ptr.To(75), Comments: "testComments", ContractID: "testContract", ConfigID: 1, @@ -474,8 +474,8 @@ func TestListConfigurations(t *testing.T) { ConfigName: "testcloudwrapper", LastUpdatedBy: "user", LastUpdatedDate: "2023-05-10T09:55:37.000Z", - LastActivatedBy: tools.StringPtr("user"), - LastActivatedDate: tools.StringPtr("2023-05-10T10:14:49.379Z"), + LastActivatedBy: ptr.To("user"), + LastActivatedDate: ptr.To("2023-05-10T10:14:49.379Z"), NotificationEmails: []string{"user@akamai.com"}, PropertyIDs: []string{ "11", @@ -483,7 +483,7 @@ func TestListConfigurations(t *testing.T) { RetainIdleObjects: false, }, { - CapacityAlertsThreshold: tools.IntPtr(75), + CapacityAlertsThreshold: ptr.To(75), Comments: "mcdn", ContractID: "testContract2", ConfigID: 2, @@ -534,8 +534,8 @@ func TestListConfigurations(t *testing.T) { ConfigName: "testcloudwrappermcdn", LastUpdatedBy: "user", LastUpdatedDate: "2023-05-10T09:55:37.000Z", - LastActivatedBy: tools.StringPtr("user"), - LastActivatedDate: tools.StringPtr("2023-05-10T10:14:49.379Z"), + LastActivatedBy: ptr.To("user"), + LastActivatedDate: ptr.To("2023-05-10T10:14:49.379Z"), NotificationEmails: []string{"user@akamai.com"}, PropertyIDs: []string{"22"}, RetainIdleObjects: false, @@ -668,7 +668,7 @@ func TestCreateConfiguration(t *testing.T) { "lastActivatedBy":null }`, expectedResponse: &Configuration{ - CapacityAlertsThreshold: tools.IntPtr(50), + CapacityAlertsThreshold: ptr.To(50), Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationResp{ @@ -765,7 +765,7 @@ func TestCreateConfiguration(t *testing.T) { "lastActivatedBy":null }`, expectedResponse: &Configuration{ - CapacityAlertsThreshold: tools.IntPtr(50), + CapacityAlertsThreshold: ptr.To(50), Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationResp{ @@ -1006,7 +1006,7 @@ func TestCreateConfiguration(t *testing.T) { "200 OK - full MultiCDNSettings": { params: CreateConfigurationRequest{ Body: CreateConfigurationBody{ - CapacityAlertsThreshold: tools.IntPtr(70), + CapacityAlertsThreshold: ptr.To(70), Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1061,7 +1061,7 @@ func TestCreateConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{1}, Enabled: true, - SamplingRate: tools.IntPtr(10), + SamplingRate: ptr.To(10), }, Origins: []Origin{ { @@ -1266,7 +1266,7 @@ func TestCreateConfiguration(t *testing.T) { "lastActivatedBy":null }`, expectedResponse: &Configuration{ - CapacityAlertsThreshold: tools.IntPtr(70), + CapacityAlertsThreshold: ptr.To(70), Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationResp{ @@ -1322,7 +1322,7 @@ func TestCreateConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{1}, Enabled: true, - SamplingRate: tools.IntPtr(10), + SamplingRate: ptr.To(10), }, Origins: []Origin{ { @@ -1975,7 +1975,7 @@ func TestCreateConfiguration(t *testing.T) { "struct fields validations": { params: CreateConfigurationRequest{ Body: CreateConfigurationBody{ - CapacityAlertsThreshold: tools.IntPtr(20), + CapacityAlertsThreshold: ptr.To(20), Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -2013,7 +2013,7 @@ func TestCreateConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{1}, Enabled: true, - SamplingRate: tools.IntPtr(-10), + SamplingRate: ptr.To(-10), }, Origins: []Origin{ { @@ -2185,7 +2185,7 @@ func TestUpdateConfiguration(t *testing.T) { }`, expectedResponse: &Configuration{ ConfigID: 111, - CapacityAlertsThreshold: tools.IntPtr(50), + CapacityAlertsThreshold: ptr.To(50), Comments: "TestCommentsUpdated", ContractID: "TestContractID", Locations: []ConfigLocationResp{ @@ -2406,7 +2406,7 @@ func TestUpdateConfiguration(t *testing.T) { params: UpdateConfigurationRequest{ ConfigID: 111, Body: UpdateConfigurationBody{ - CapacityAlertsThreshold: tools.IntPtr(80), + CapacityAlertsThreshold: ptr.To(80), Comments: "TestCommentsUpdated", Locations: []ConfigLocationReq{ { @@ -2447,7 +2447,7 @@ func TestUpdateConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{1}, Enabled: true, - SamplingRate: tools.IntPtr(10), + SamplingRate: ptr.To(10), }, Origins: []Origin{ { @@ -2606,7 +2606,7 @@ func TestUpdateConfiguration(t *testing.T) { "lastActivatedBy":null }`, expectedResponse: &Configuration{ - CapacityAlertsThreshold: tools.IntPtr(80), + CapacityAlertsThreshold: ptr.To(80), Comments: "TestCommentsUpdated", ContractID: "TestContractID", ConfigID: 111, @@ -2650,7 +2650,7 @@ func TestUpdateConfiguration(t *testing.T) { DataStreams: &DataStreams{ DataStreamIDs: []int64{1}, Enabled: true, - SamplingRate: tools.IntPtr(10), + SamplingRate: ptr.To(10), }, EnableSoftAlerts: true, Origins: []Origin{ diff --git a/pkg/cps/change_management_info_test.go b/pkg/cps/change_management_info_test.go index 9e1bc348..482b0714 100644 --- a/pkg/cps/change_management_info_test.go +++ b/pkg/cps/change_management_info_test.go @@ -7,8 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -225,7 +224,7 @@ func TestGetChangeDeploymentInfo(t *testing.T) { }, MultiStackedCertificates: []DeploymentCertificate{}, OCSPURIs: []string{}, - OCSPStapled: tools.BoolPtr(false), + OCSPStapled: ptr.To(false), }, }, "500 internal server error": { diff --git a/pkg/cps/deployment_schedules_test.go b/pkg/cps/deployment_schedules_test.go index 4f145882..8e9dc127 100644 --- a/pkg/cps/deployment_schedules_test.go +++ b/pkg/cps/deployment_schedules_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -38,8 +38,8 @@ func TestGetDeploymentSchedule(t *testing.T) { "Accept": "application/vnd.akamai.cps.deployment-schedule.v1+json", }, expectedResponse: &DeploymentSchedule{ - NotAfter: tools.StringPtr("2021-11-03T08:02:46.655484Z"), - NotBefore: tools.StringPtr("2021-10-03T08:02:46.655484Z"), + NotAfter: ptr.To("2021-11-03T08:02:46.655484Z"), + NotBefore: ptr.To("2021-10-03T08:02:46.655484Z"), }, }, "500 internal server error": { @@ -128,8 +128,8 @@ func TestUpdateDeploymentSchedule(t *testing.T) { ChangeID: 1, EnrollmentID: 10, DeploymentSchedule: DeploymentSchedule{ - NotAfter: tools.StringPtr("2021-11-03T08:02:46.655484Z"), - NotBefore: tools.StringPtr("2021-10-03T08:02:46.655484Z"), + NotAfter: ptr.To("2021-11-03T08:02:46.655484Z"), + NotBefore: ptr.To("2021-10-03T08:02:46.655484Z"), }, }, responseStatus: http.StatusOK, @@ -151,8 +151,8 @@ func TestUpdateDeploymentSchedule(t *testing.T) { ChangeID: 1, EnrollmentID: 10, DeploymentSchedule: DeploymentSchedule{ - NotAfter: tools.StringPtr("2021-11-03T08:02:46.655484Z"), - NotBefore: tools.StringPtr("2021-10-03T08:02:46.655484Z"), + NotAfter: ptr.To("2021-11-03T08:02:46.655484Z"), + NotBefore: ptr.To("2021-10-03T08:02:46.655484Z"), }, }, responseStatus: http.StatusInternalServerError, @@ -178,8 +178,8 @@ func TestUpdateDeploymentSchedule(t *testing.T) { params: UpdateDeploymentScheduleRequest{ EnrollmentID: 10, DeploymentSchedule: DeploymentSchedule{ - NotAfter: tools.StringPtr("2021-11-03T08:02:46.655484Z"), - NotBefore: tools.StringPtr("2021-10-03T08:02:46.655484Z"), + NotAfter: ptr.To("2021-11-03T08:02:46.655484Z"), + NotBefore: ptr.To("2021-10-03T08:02:46.655484Z"), }, }, expectedPath: "/cps/v2/enrollments/10/changes/1/deployment-schedule", @@ -192,8 +192,8 @@ func TestUpdateDeploymentSchedule(t *testing.T) { params: UpdateDeploymentScheduleRequest{ ChangeID: 1, DeploymentSchedule: DeploymentSchedule{ - NotAfter: tools.StringPtr("2021-11-03T08:02:46.655484Z"), - NotBefore: tools.StringPtr("2021-10-03T08:02:46.655484Z"), + NotAfter: ptr.To("2021-11-03T08:02:46.655484Z"), + NotBefore: ptr.To("2021-10-03T08:02:46.655484Z"), }, }, expectedPath: "/cps/v2/enrollments/10/changes/1/deployment-schedule", diff --git a/pkg/cps/deployments_test.go b/pkg/cps/deployments_test.go index 385a6989..42de650e 100644 --- a/pkg/cps/deployments_test.go +++ b/pkg/cps/deployments_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -103,7 +103,7 @@ func TestListDeployments(t *testing.T) { }, expectedResponse: &ListDeploymentsResponse{ Production: &Deployment{ - OCSPStapled: tools.BoolPtr(false), + OCSPStapled: ptr.To(false), OCSPURIs: []string{}, NetworkConfiguration: DeploymentNetworkConfiguration{ Geography: "core", @@ -138,7 +138,7 @@ func TestListDeployments(t *testing.T) { }, }, Staging: &Deployment{ - OCSPStapled: tools.BoolPtr(false), + OCSPStapled: ptr.To(false), OCSPURIs: []string{}, NetworkConfiguration: DeploymentNetworkConfiguration{ Geography: "core", @@ -277,7 +277,7 @@ func TestGetProductionDeployment(t *testing.T) { "Accept": "application/vnd.akamai.cps.deployment.v8+json", }, expectedResponse: &GetProductionDeploymentResponse{ - OCSPStapled: tools.BoolPtr(false), + OCSPStapled: ptr.To(false), OCSPURIs: []string{}, NetworkConfiguration: DeploymentNetworkConfiguration{ Geography: "core", @@ -422,7 +422,7 @@ func TestGetStagingDeployment(t *testing.T) { }, expectedResponse: &GetStagingDeploymentResponse{ - OCSPStapled: tools.BoolPtr(false), + OCSPStapled: ptr.To(false), OCSPURIs: []string{}, NetworkConfiguration: DeploymentNetworkConfiguration{ Geography: "core", diff --git a/pkg/cps/enrollments_test.go b/pkg/cps/enrollments_test.go index 451f02fc..fd5409b5 100644 --- a/pkg/cps/enrollments_test.go +++ b/pkg/cps/enrollments_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1110,7 +1110,7 @@ func TestCreateEnrollment(t *testing.T) { }, NetworkConfiguration: &NetworkConfiguration{}, Org: &Org{Name: "Akamai"}, - OrgID: tools.IntPtr(10), + OrgID: ptr.To(10), RA: "third-party", TechContact: &Contact{ Email: "r2d2@akamai.com", @@ -1374,7 +1374,7 @@ func TestUpdateEnrollment(t *testing.T) { }, NetworkConfiguration: &NetworkConfiguration{}, Org: &Org{Name: "Akamai"}, - OrgID: tools.IntPtr(20), + OrgID: ptr.To(20), RA: "third-party", TechContact: &Contact{ Email: "r2d2@akamai.com", diff --git a/pkg/datastream/properties_test.go b/pkg/datastream/properties_test.go index 5542f767..cd097d25 100644 --- a/pkg/datastream/properties_test.go +++ b/pkg/datastream/properties_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -246,7 +246,7 @@ func TestDs_GetDatasetFields(t *testing.T) { }, }, "validation error - invalid product id": { - request: GetDatasetFieldsRequest{ProductID: tools.StringPtr("INVALID_PROD_ID")}, + request: GetDatasetFieldsRequest{ProductID: ptr.To("INVALID_PROD_ID")}, responseStatus: http.StatusBadRequest, responseBody: ` { diff --git a/pkg/datastream/stream_test.go b/pkg/datastream/stream_test.go index 63d7731a..c64f48e5 100644 --- a/pkg/datastream/stream_test.go +++ b/pkg/datastream/stream_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1547,7 +1547,7 @@ func TestDs_ListStreams(t *testing.T) { }, "200 OK - with groupId": { request: ListStreamsRequest{ - GroupID: tools.IntPtr(1234), + GroupID: ptr.To(1234), }, responseStatus: http.StatusOK, responseBody: ` diff --git a/pkg/dns/zonebulk_test.go b/pkg/dns/zonebulk_test.go index 818d2c77..abaff272 100644 --- a/pkg/dns/zonebulk_test.go +++ b/pkg/dns/zonebulk_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -438,7 +438,7 @@ func TestDNS_DeleteBulkZones(t *testing.T) { ZonesList: &ZoneNameListResponse{ Zones: []string{"one.testbulk.net", "two.testbulk.net"}, }, - BypassSafetyChecks: tools.BoolPtr(true), + BypassSafetyChecks: ptr.To(true), }, responseStatus: http.StatusCreated, responseBody: ` @@ -457,7 +457,7 @@ func TestDNS_DeleteBulkZones(t *testing.T) { ZonesList: &ZoneNameListResponse{ Zones: []string{"one.testbulk.net", "two.testbulk.net"}, }, - BypassSafetyChecks: tools.BoolPtr(true), + BypassSafetyChecks: ptr.To(true), }, responseStatus: http.StatusInternalServerError, responseBody: ` diff --git a/pkg/edgeworkers/edgekv_namespaces_test.go b/pkg/edgeworkers/edgekv_namespaces_test.go index 8b18321a..2761c088 100644 --- a/pkg/edgeworkers/edgekv_namespaces_test.go +++ b/pkg/edgeworkers/edgekv_namespaces_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -120,21 +120,21 @@ func TestListNamespaces(t *testing.T) { Namespaces: []Namespace{ { Name: "testNs_1", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "EU", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, { Name: "testNs_2", - Retention: tools.IntPtr(86400), + Retention: ptr.To(86400), GeoLocation: "JP", - GroupID: tools.IntPtr(123), + GroupID: ptr.To(123), }, { Name: "testNs_3", - Retention: tools.IntPtr(315360000), + Retention: ptr.To(315360000), GeoLocation: "US", - GroupID: tools.IntPtr(234), + GroupID: ptr.To(234), }, }, }, @@ -203,9 +203,9 @@ func TestGetNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "EU", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, "200 OK - staging": { @@ -223,9 +223,9 @@ func TestGetNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(86400), + Retention: ptr.To(86400), GeoLocation: "US", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, "400 bad request - namespace does not exist": { @@ -317,9 +317,9 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceProductionNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "EU", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, expectedPath: "/edgekv/v1/networks/production/namespaces", @@ -332,9 +332,9 @@ func TestCreateNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "EU", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, "200 OK - staging": { @@ -342,8 +342,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(86400), - GroupID: tools.IntPtr(123), + Retention: ptr.To(86400), + GroupID: ptr.To(123), }, }, expectedPath: "/edgekv/v1/networks/staging/namespaces", @@ -356,9 +356,9 @@ func TestCreateNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(86400), + Retention: ptr.To(86400), GeoLocation: "US", - GroupID: tools.IntPtr(123), + GroupID: ptr.To(123), }, }, "400 bad request - invalid geoLocation for staging network": { @@ -366,9 +366,9 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "JP", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -404,9 +404,9 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceProductionNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), + Retention: ptr.To(0), GeoLocation: "INVALID", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -442,8 +442,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(0), + Retention: ptr.To(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -489,8 +489,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(86399), - GroupID: tools.IntPtr(0), + Retention: ptr.To(86399), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -503,8 +503,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "testNs", - Retention: tools.IntPtr(315360001), - GroupID: tools.IntPtr(0), + Retention: ptr.To(315360001), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -517,8 +517,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "namespaceNameThatHasMoreThan32Letters", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(0), + Retention: ptr.To(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -531,8 +531,8 @@ func TestCreateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, Namespace: Namespace{ Name: "groupIDLessThan0", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(-1), + Retention: ptr.To(0), + GroupID: ptr.To(-1), }, }, withError: func(t *testing.T, err error) { @@ -578,8 +578,8 @@ func TestUpdateNamespace(t *testing.T) { Network: NamespaceProductionNetwork, UpdateNamespace: UpdateNamespace{ Name: "testNs", - Retention: tools.IntPtr(86400), - GroupID: tools.IntPtr(0), + Retention: ptr.To(86400), + GroupID: ptr.To(0), }, }, expectedPath: "/edgekv/v1/networks/production/namespaces/testNs", @@ -592,9 +592,9 @@ func TestUpdateNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(86400), + Retention: ptr.To(86400), GeoLocation: "EU", - GroupID: tools.IntPtr(0), + GroupID: ptr.To(0), }, }, "200 OK - staging": { @@ -602,8 +602,8 @@ func TestUpdateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, UpdateNamespace: UpdateNamespace{ Name: "testNs", - Retention: tools.IntPtr(86400), - GroupID: tools.IntPtr(123), + Retention: ptr.To(86400), + GroupID: ptr.To(123), }, }, expectedPath: "/edgekv/v1/networks/staging/namespaces/testNs", @@ -616,9 +616,9 @@ func TestUpdateNamespace(t *testing.T) { }`, expectedResult: &Namespace{ Name: "testNs", - Retention: tools.IntPtr(86400), + Retention: ptr.To(86400), GeoLocation: "US", - GroupID: tools.IntPtr(123), + GroupID: ptr.To(123), }, }, "409 conflict": { @@ -626,8 +626,8 @@ func TestUpdateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, UpdateNamespace: UpdateNamespace{ Name: "testNs_2", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(0), + Retention: ptr.To(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -673,8 +673,8 @@ func TestUpdateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, UpdateNamespace: UpdateNamespace{ Name: "namespaceNameThatHasMoreThan32Letters", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(0), + Retention: ptr.To(0), + GroupID: ptr.To(0), }, }, withError: func(t *testing.T, err error) { @@ -687,8 +687,8 @@ func TestUpdateNamespace(t *testing.T) { Network: NamespaceStagingNetwork, UpdateNamespace: UpdateNamespace{ Name: "groupIDLessThan0", - Retention: tools.IntPtr(0), - GroupID: tools.IntPtr(-1), + Retention: ptr.To(0), + GroupID: ptr.To(-1), }, }, withError: func(t *testing.T, err error) { diff --git a/pkg/edgeworkers/report_test.go b/pkg/edgeworkers/report_test.go index 4ca380cc..9452514f 100644 --- a/pkg/edgeworkers/report_test.go +++ b/pkg/edgeworkers/report_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -26,7 +26,7 @@ func TestGetSummaryReport(t *testing.T) { Start: "2022-01-10T03:00:00Z", End: "2022-01-14T13:22:28Z", EdgeWorker: "1234", - Status: tools.StringPtr(StatusSuccess), + Status: ptr.To(StatusSuccess), }, expectedPath: "/edgeworkers/v1/reports/1?edgeWorker=1234&end=2022-01-14T13%3A22%3A28Z&start=2022-01-10T03%3A00%3A00Z&status=success", responseBody: ` @@ -101,7 +101,7 @@ func TestGetSummaryReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - Status: tools.StringPtr("not_valid"), + Status: ptr.To("not_valid"), }, withError: ErrStructValidation, }, @@ -110,7 +110,7 @@ func TestGetSummaryReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - Status: tools.StringPtr(""), + Status: ptr.To(""), }, expectedPath: "/edgeworkers/v1/reports/1?edgeWorker=37017&end=2022-01-01T00%3A00%3A00Z&start=2021-12-04T00%3A00%3A00Z", withError: ErrStructValidation, @@ -120,7 +120,7 @@ func TestGetSummaryReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - EventHandler: tools.StringPtr("not_valid"), + EventHandler: ptr.To("not_valid"), }, withError: ErrStructValidation, }, @@ -129,7 +129,7 @@ func TestGetSummaryReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - EventHandler: tools.StringPtr(""), + EventHandler: ptr.To(""), }, expectedPath: "/edgeworkers/v1/reports/1?edgeWorker=37017&end=2022-01-01T00%3A00%3A00Z&start=2021-12-04T00%3A00%3A00Z", withError: ErrStructValidation, @@ -644,13 +644,13 @@ func TestGetReport(t *testing.T) { StartDateTime: "2022-01-10T03:45:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, { StartDateTime: "2022-01-10T06:00:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, }, OnOriginRequest: &OnOriginRequest{ @@ -658,13 +658,13 @@ func TestGetReport(t *testing.T) { StartDateTime: "2022-01-10T03:45:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, { StartDateTime: "2022-01-10T06:00:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, }, OnClientResponse: &OnClientResponse{ @@ -672,13 +672,13 @@ func TestGetReport(t *testing.T) { StartDateTime: "2022-01-10T03:00:00Z", EdgeWorkerVersion: "10.18", Invocations: 8, - Status: tools.StringPtr("success"), + Status: ptr.To("success"), }, { StartDateTime: "2022-01-10T03:05:00Z", EdgeWorkerVersion: "10.18", Invocations: 15, - Status: tools.StringPtr("success"), + Status: ptr.To("success"), }, }, OnOriginResponse: &OnOriginResponse{ @@ -686,13 +686,13 @@ func TestGetReport(t *testing.T) { StartDateTime: "2022-01-10T03:45:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, { StartDateTime: "2022-01-10T06:00:00Z", EdgeWorkerVersion: "10.18", Invocations: 1, - Status: tools.StringPtr("unimplementedEventHandler"), + Status: ptr.To("unimplementedEventHandler"), }, }, OnClientRequest: &OnClientRequest{ @@ -700,13 +700,13 @@ func TestGetReport(t *testing.T) { StartDateTime: "2022-01-10T03:00:00Z", EdgeWorkerVersion: "10.18", Invocations: 8, - Status: tools.StringPtr("success"), + Status: ptr.To("success"), }, { StartDateTime: "2022-01-10T03:05:00Z", EdgeWorkerVersion: "10.18", Invocations: 15, - Status: tools.StringPtr("success"), + Status: ptr.To("success"), }, }, }, @@ -979,8 +979,8 @@ func TestGetReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - Status: tools.StringPtr(StatusSuccess), - EventHandler: tools.StringPtr(EventHandlerOnClientRequest), + Status: ptr.To(StatusSuccess), + EventHandler: ptr.To(EventHandlerOnClientRequest), }, responseStatus: http.StatusOK, expectedPath: "/edgeworkers/v1/reports/4?edgeWorker=37017&end=2022-01-01T00%3A00%3A00Z&eventHandler=onClientRequest&start=2021-12-04T00%3A00%3A00Z&status=success", @@ -1011,7 +1011,7 @@ func TestGetReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - Status: tools.StringPtr("not_valid"), + Status: ptr.To("not_valid"), }, withError: ErrStructValidation, }, @@ -1021,7 +1021,7 @@ func TestGetReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - Status: tools.StringPtr(""), + Status: ptr.To(""), }, expectedPath: "/edgeworkers/v1/reports/4?edgeWorker=37017&end=2022-01-01T00%3A00%3A00Z&start=2021-12-04T00%3A00%3A00Z", withError: ErrStructValidation, @@ -1032,7 +1032,7 @@ func TestGetReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - EventHandler: tools.StringPtr("not_valid"), + EventHandler: ptr.To("not_valid"), }, withError: ErrStructValidation, }, @@ -1042,7 +1042,7 @@ func TestGetReport(t *testing.T) { Start: "2021-12-04T00:00:00Z", End: "2022-01-01T00:00:00Z", EdgeWorker: "37017", - EventHandler: tools.StringPtr(""), + EventHandler: ptr.To(""), }, expectedPath: "/edgeworkers/v1/reports/4?edgeWorker=37017&end=2022-01-01T00%3A00%3A00Z&start=2021-12-04T00%3A00%3A00Z", withError: ErrStructValidation, diff --git a/pkg/gtm/property_test.go b/pkg/gtm/property_test.go index dc9c0b41..bf49d951 100644 --- a/pkg/gtm/property_test.go +++ b/pkg/gtm/property_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -401,8 +401,8 @@ func TestGTM_CreateProperty(t *testing.T) { HTTPError3xx: true, HTTPError4xx: true, HTTPError5xx: true, - HTTPMethod: tools.StringPtr("GET"), - HTTPRequestBody: tools.StringPtr("TestBody"), + HTTPMethod: ptr.To("GET"), + HTTPRequestBody: ptr.To("TestBody"), Name: "health-check", TestInterval: 60, TestObject: "/status", @@ -419,7 +419,7 @@ func TestGTM_CreateProperty(t *testing.T) { Enabled: true, Weight: 50.0, Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + Precedence: ptr.To(255), }, { DatacenterID: 3133, @@ -553,8 +553,8 @@ func TestGTM_CreateProperty(t *testing.T) { HTTPError3xx: true, HTTPError4xx: true, HTTPError5xx: true, - HTTPMethod: tools.StringPtr("GET"), - HTTPRequestBody: tools.StringPtr("TestBody"), + HTTPMethod: ptr.To("GET"), + HTTPRequestBody: ptr.To("TestBody"), Pre2023SecurityPosture: true, AlternateCACertificates: []string{"test1"}, Name: "health-check", @@ -571,7 +571,7 @@ func TestGTM_CreateProperty(t *testing.T) { Enabled: true, Weight: 50.0, Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + Precedence: ptr.To(255), }, { DatacenterID: 3133, @@ -641,7 +641,7 @@ func TestGTM_CreateProperty(t *testing.T) { { DatacenterID: 1, Enabled: false, - Precedence: tools.IntPtr(256), + Precedence: ptr.To(256), }, }, }, @@ -750,7 +750,7 @@ func TestGTM_UpdateProperty(t *testing.T) { Enabled: true, Weight: 50.0, Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + Precedence: ptr.To(255), }, { DatacenterID: 3133, @@ -894,7 +894,7 @@ func TestGTM_UpdateProperty(t *testing.T) { Enabled: true, Weight: 50.0, Servers: []string{"1.2.3.5"}, - Precedence: tools.IntPtr(255), + Precedence: ptr.To(255), }, { DatacenterID: 3133, diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index ff5ce976..bf7f6458 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -33,7 +33,7 @@ func TestIAM_CreateUser(t *testing.T) { Country: "USA", State: "CA", }, - AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: tools.IntPtr(1)}}, + AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, Notifications: UserNotifications{}, }, requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}],"notifications":{"enableEmailNotifications":false,"options":{"newUserNotification":false,"passwordExpiry":false,"proactive":null,"upgrade":null}}}`, @@ -71,7 +71,7 @@ func TestIAM_CreateUser(t *testing.T) { Country: "USA", State: "CA", }, - AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: tools.IntPtr(1)}}, + AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, Notifications: UserNotifications{}, }, responseStatus: http.StatusInternalServerError, @@ -217,7 +217,7 @@ func TestIam_ListUsers(t *testing.T) { }{ "200 OK": { params: ListUsersRequest{ - GroupID: tools.Int64Ptr(12345), + GroupID: ptr.To(int64(12345)), AuthGrants: true, Actions: true, }, @@ -281,7 +281,7 @@ func TestIam_ListUsers(t *testing.T) { AuthGrants: []AuthGrant{ { GroupID: 12345, - RoleID: tools.IntPtr(12), + RoleID: ptr.To(12), GroupName: "mygroup", RoleName: "admin", RoleDescription: "This is a new role that has been created to", @@ -292,7 +292,7 @@ func TestIam_ListUsers(t *testing.T) { }, "200 OK, no actions nor grants": { params: ListUsersRequest{ - GroupID: tools.Int64Ptr(12345), + GroupID: ptr.To(int64(12345)), }, responseStatus: http.StatusOK, expectedPath: "/identity-management/v2/user-admin/ui-identities?actions=false&authGrants=false&groupId=12345", @@ -360,7 +360,7 @@ func TestIam_ListUsers(t *testing.T) { }, "500 internal server error": { params: ListUsersRequest{ - GroupID: tools.Int64Ptr(12345), + GroupID: ptr.To(int64(12345)), AuthGrants: true, Actions: true, }, @@ -427,7 +427,7 @@ func TestIAM_UpdateUserInfo(t *testing.T) { State: "CA", PreferredLanguage: "English", ContactType: "Billing", - SessionTimeOut: tools.IntPtr(30), + SessionTimeOut: ptr.To(30), TimeZone: "GMT", }, }, @@ -456,7 +456,7 @@ func TestIAM_UpdateUserInfo(t *testing.T) { State: "CA", PreferredLanguage: "English", ContactType: "Billing", - SessionTimeOut: tools.IntPtr(30), + SessionTimeOut: ptr.To(30), TimeZone: "GMT", }, }, @@ -472,7 +472,7 @@ func TestIAM_UpdateUserInfo(t *testing.T) { State: "CA", PreferredLanguage: "English", ContactType: "Billing", - SessionTimeOut: tools.IntPtr(30), + SessionTimeOut: ptr.To(30), TimeZone: "GMT", }, }, @@ -654,7 +654,7 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { AuthGrants: []AuthGrantRequest{ { GroupID: 12345, - RoleID: tools.IntPtr(16), + RoleID: ptr.To(16), Subgroups: []AuthGrantRequest{ { GroupID: 54321, @@ -680,7 +680,7 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { expectedResponse: []AuthGrant{ { GroupID: 12345, - RoleID: tools.IntPtr(16), + RoleID: ptr.To(16), Subgroups: []AuthGrant{ { GroupID: 54321, @@ -695,7 +695,7 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { AuthGrants: []AuthGrantRequest{ { GroupID: 12345, - RoleID: tools.IntPtr(16), + RoleID: ptr.To(16), Subgroups: []AuthGrantRequest{ { GroupID: 54321, diff --git a/pkg/imaging/policy_test.go b/pkg/imaging/policy_test.go index 5be95c58..cc03d7c5 100644 --- a/pkg/imaging/policy_test.go +++ b/pkg/imaging/policy_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -269,7 +269,7 @@ func TestListPolicies(t *testing.T) { EndTime: 1626379177, RolloutDuration: 1, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "system", DateCreated: "2021-07-15 19:59:35+0000", }, @@ -294,10 +294,10 @@ func TestListPolicies(t *testing.T) { &Composite{ Transformation: "Composite", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr(GravityNorthWest), @@ -308,19 +308,19 @@ func TestListPolicies(t *testing.T) { Image: &TextImageType{ Type: "Text", Fill: &StringVariableInline{ - Value: tools.StringPtr("#000000"), + Value: ptr.To("#000000"), }, Size: &NumberVariableInline{ - Value: tools.Float64Ptr(72), + Value: ptr.To(float64(72)), }, Stroke: &StringVariableInline{ - Value: tools.StringPtr("#FFFFFF"), + Value: ptr.To("#FFFFFF"), }, StrokeSize: &NumberVariableInline{ - Value: tools.Float64Ptr(0), + Value: ptr.To(float64(0)), }, Text: &StringVariableInline{ - Value: tools.StringPtr("Hello There"), + Value: ptr.To("Hello There"), }, Transformation: &Compound{ Transformation: "Compound", @@ -328,7 +328,7 @@ func TestListPolicies(t *testing.T) { }, }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2021-12-07 16:20:34+0000", }, @@ -349,7 +349,7 @@ func TestListPolicies(t *testing.T) { Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh), }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2021-08-06 19:46:32+0000", }, @@ -374,13 +374,13 @@ func TestListPolicies(t *testing.T) { &Blur{ Transformation: "Blur", Sigma: &NumberVariableInline{ - Name: tools.StringPtr("blurVar"), + Name: ptr.To("blurVar"), }, }, &MaxColors{ Transformation: "MaxColors", Colors: &IntegerVariableInline{ - Value: tools.IntPtr(2), + Value: ptr.To(2), }, }, }, @@ -391,7 +391,7 @@ func TestListPolicies(t *testing.T) { DefaultValue: "5", }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "foofoo5", DateCreated: "2021-12-16 18:46:38+0000", }, @@ -416,13 +416,13 @@ func TestListPolicies(t *testing.T) { &Blur{ Transformation: "Blur", Sigma: &NumberVariableInline{ - Name: tools.StringPtr("blurVar"), + Name: ptr.To("blurVar"), }, }, &MaxColors{ Transformation: "MaxColors", Colors: &IntegerVariableInline{ - Value: tools.IntPtr(2), + Value: ptr.To(2), }, }, }, @@ -433,7 +433,7 @@ func TestListPolicies(t *testing.T) { DefaultValue: "5", }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "foofoo5", DateCreated: "2021-12-16 18:47:36+0000", }, @@ -446,7 +446,7 @@ func TestListPolicies(t *testing.T) { EndTime: 1643052401, RolloutDuration: 1, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2022-01-24 19:26:39+0000", }, @@ -459,7 +459,7 @@ func TestListPolicies(t *testing.T) { EndTime: 1643052165, RolloutDuration: 1, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2022-01-24 19:22:43+0000", }, @@ -477,7 +477,7 @@ func TestListPolicies(t *testing.T) { Value: OutputVideoPerceptualQualityPtr(OutputVideoPerceptualQualityMediumHigh), }, }, - Video: tools.BoolPtr(true), + Video: ptr.To(true), User: "jsmith", DateCreated: "2022-01-24 20:17:10+0000", }, @@ -760,10 +760,10 @@ func TestListPolicies(t *testing.T) { &Trim{ Transformation: "Trim", Fuzz: &NumberVariableInline{ - Value: tools.Float64Ptr(0.08), + Value: ptr.To(0.08), }, Padding: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, }, &IfDimension{ @@ -772,7 +772,7 @@ func TestListPolicies(t *testing.T) { Value: IfDimensionDimensionPtr("width"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MaxDimOld"), + Name: ptr.To("MaxDimOld"), }, Default: &Compound{ Transformation: "Compound", @@ -783,7 +783,7 @@ func TestListPolicies(t *testing.T) { Value: IfDimensionDimensionPtr("width"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MinDim"), + Name: ptr.To("MinDim"), }, LessThan: &Compound{ Transformation: "Compound", @@ -797,37 +797,37 @@ func TestListPolicies(t *testing.T) { Value: ResizeTypePtr("normal"), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, }, &Crop{ Transformation: "Crop", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr("Center"), }, AllowExpansion: &BooleanVariableInline{ - Value: tools.BoolPtr(true), + Value: ptr.To(true), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, }, &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#ffffff"), + Value: ptr.To("#ffffff"), }, }, }, @@ -841,7 +841,7 @@ func TestListPolicies(t *testing.T) { Value: IfDimensionDimensionPtr("height"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MinDim"), + Name: ptr.To("MinDim"), }, LessThan: &Compound{ Transformation: "Compound", @@ -855,37 +855,37 @@ func TestListPolicies(t *testing.T) { Value: ResizeTypePtr("normal"), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, }, &Crop{ Transformation: "Crop", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr("Center"), }, AllowExpansion: &BooleanVariableInline{ - Value: tools.BoolPtr(true), + Value: ptr.To(true), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, }, &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#ffffff"), + Value: ptr.To("#ffffff"), }, }, }, @@ -899,7 +899,7 @@ func TestListPolicies(t *testing.T) { Value: IfDimensionDimensionPtr("height"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MaxDimOld"), + Name: ptr.To("MaxDimOld"), }, GreaterThan: &Compound{ Transformation: "Compound", @@ -914,37 +914,37 @@ func TestListPolicies(t *testing.T) { }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDimWithBorder"), + Name: ptr.To("ResizeDimWithBorder"), }, }, &Crop{ Transformation: "Crop", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr("Center"), }, AllowExpansion: &BooleanVariableInline{ - Value: tools.BoolPtr(true), + Value: ptr.To(true), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, }, &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#ffffff"), + Value: ptr.To("#ffffff"), }, }, }, @@ -961,37 +961,37 @@ func TestListPolicies(t *testing.T) { Value: ResizeTypePtr("normal"), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, }, &Crop{ Transformation: "Crop", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr("Center"), }, AllowExpansion: &BooleanVariableInline{ - Value: tools.BoolPtr(true), + Value: ptr.To(true), }, Width: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, Height: &IntegerVariableInline{ - Name: tools.StringPtr("ResizeDim"), + Name: ptr.To("ResizeDim"), }, }, &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#ffffff"), + Value: ptr.To("#ffffff"), }, }, }, @@ -1014,9 +1014,9 @@ func TestListPolicies(t *testing.T) { PerceptualQuality: &OutputImagePerceptualQualityVariableInline{ Value: OutputImagePerceptualQualityPtr("mediumHigh"), }, - AdaptiveQuality: tools.IntPtr(50), + AdaptiveQuality: ptr.To(50), }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), ID: "multidimension", DateCreated: "2022-01-01 12:00:00+0000", PreviousVersion: 0, @@ -1274,14 +1274,14 @@ func TestGetPolicy(t *testing.T) { Transformation: "Append", Gravity: &GravityVariableInline{Value: GravityPtr("Center")}, GravityPriority: &AppendGravityPriorityVariableInline{Value: AppendGravityPriorityPtr("horizontal")}, - PreserveMinorDimension: &BooleanVariableInline{Value: tools.BoolPtr(true)}, + PreserveMinorDimension: &BooleanVariableInline{Value: ptr.To(true)}, Image: &TextImageType{ Type: "Text", - Fill: &StringVariableInline{Value: tools.StringPtr("#000000")}, - Size: &NumberVariableInline{Value: tools.Float64Ptr(72)}, - Stroke: &StringVariableInline{Value: tools.StringPtr("#FFFFFF")}, - StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)}, - Text: &StringVariableInline{Value: tools.StringPtr("test")}, + Fill: &StringVariableInline{Value: ptr.To("#000000")}, + Size: &NumberVariableInline{Value: ptr.To(float64(72))}, + Stroke: &StringVariableInline{Value: ptr.To("#FFFFFF")}, + StrokeSize: &NumberVariableInline{Value: ptr.To(float64(0))}, + Text: &StringVariableInline{Value: ptr.To("test")}, Transformation: &Compound{ Transformation: "Compound", }, @@ -1291,24 +1291,24 @@ func TestGetPolicy(t *testing.T) { Transformation: "RegionOfInterestCrop", Style: &RegionOfInterestCropStyleVariableInline{Value: RegionOfInterestCropStylePtr("fill")}, Gravity: &GravityVariableInline{Value: GravityPtr("Center")}, - Width: &IntegerVariableInline{Value: tools.IntPtr(7)}, - Height: &IntegerVariableInline{Value: tools.IntPtr(8)}, + Width: &IntegerVariableInline{Value: ptr.To(7)}, + Height: &IntegerVariableInline{Value: ptr.To(8)}, RegionOfInterest: &RectangleShapeType{ Anchor: &PointShapeType{ - X: &NumberVariableInline{Value: tools.Float64Ptr(4)}, - Y: &NumberVariableInline{Value: tools.Float64Ptr(5)}, + X: &NumberVariableInline{Value: ptr.To(float64(4))}, + Y: &NumberVariableInline{Value: ptr.To(float64(5))}, }, - Width: &NumberVariableInline{Value: tools.Float64Ptr(8)}, - Height: &NumberVariableInline{Value: tools.Float64Ptr(9)}, + Width: &NumberVariableInline{Value: ptr.To(float64(8))}, + Height: &NumberVariableInline{Value: ptr.To(float64(9))}, }, }, &Composite{ Transformation: "Composite", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr(GravityNorthWest), @@ -1319,19 +1319,19 @@ func TestGetPolicy(t *testing.T) { Image: &TextImageType{ Type: "Text", Fill: &StringVariableInline{ - Value: tools.StringPtr("#000000"), + Value: ptr.To("#000000"), }, Size: &NumberVariableInline{ - Value: tools.Float64Ptr(72), + Value: ptr.To(float64(72)), }, Stroke: &StringVariableInline{ - Value: tools.StringPtr("#FFFFFF"), + Value: ptr.To("#FFFFFF"), }, StrokeSize: &NumberVariableInline{ - Value: tools.Float64Ptr(0), + Value: ptr.To(float64(0)), }, Text: &StringVariableInline{ - Value: tools.StringPtr("Hello There"), + Value: ptr.To("Hello There"), }, Transformation: &Compound{ Transformation: "Compound", @@ -1339,7 +1339,7 @@ func TestGetPolicy(t *testing.T) { }, }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2021-12-07 16:20:34+0000", }, @@ -1512,14 +1512,14 @@ func TestGetPolicy(t *testing.T) { Transformation: "Append", Gravity: &GravityVariableInline{Value: GravityPtr("Center")}, GravityPriority: &AppendGravityPriorityVariableInline{Value: AppendGravityPriorityPtr("horizontal")}, - PreserveMinorDimension: &BooleanVariableInline{Value: tools.BoolPtr(true)}, + PreserveMinorDimension: &BooleanVariableInline{Value: ptr.To(true)}, Image: &TextImageType{ Type: "Text", - Fill: &StringVariableInline{Value: tools.StringPtr("#000000")}, - Size: &NumberVariableInline{Value: tools.Float64Ptr(72)}, - Stroke: &StringVariableInline{Value: tools.StringPtr("#FFFFFF")}, - StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)}, - Text: &StringVariableInline{Value: tools.StringPtr("test")}, + Fill: &StringVariableInline{Value: ptr.To("#000000")}, + Size: &NumberVariableInline{Value: ptr.To(float64(72))}, + Stroke: &StringVariableInline{Value: ptr.To("#FFFFFF")}, + StrokeSize: &NumberVariableInline{Value: ptr.To(float64(0))}, + Text: &StringVariableInline{Value: ptr.To("test")}, Transformation: &Compound{ Transformation: "Compound", }, @@ -1529,24 +1529,24 @@ func TestGetPolicy(t *testing.T) { Transformation: "RegionOfInterestCrop", Style: &RegionOfInterestCropStyleVariableInline{Value: RegionOfInterestCropStylePtr("fill")}, Gravity: &GravityVariableInline{Value: GravityPtr("Center")}, - Width: &IntegerVariableInline{Value: tools.IntPtr(7)}, - Height: &IntegerVariableInline{Value: tools.IntPtr(8)}, + Width: &IntegerVariableInline{Value: ptr.To(7)}, + Height: &IntegerVariableInline{Value: ptr.To(8)}, RegionOfInterest: &RectangleShapeType{ Anchor: &PointShapeType{ - X: &NumberVariableInline{Value: tools.Float64Ptr(4)}, - Y: &NumberVariableInline{Value: tools.Float64Ptr(5)}, + X: &NumberVariableInline{Value: ptr.To(float64(4))}, + Y: &NumberVariableInline{Value: ptr.To(float64(5))}, }, - Width: &NumberVariableInline{Value: tools.Float64Ptr(8)}, - Height: &NumberVariableInline{Value: tools.Float64Ptr(9)}, + Width: &NumberVariableInline{Value: ptr.To(float64(8))}, + Height: &NumberVariableInline{Value: ptr.To(float64(9))}, }, }, &Composite{ Transformation: "Composite", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr(GravityNorthWest), @@ -1557,19 +1557,19 @@ func TestGetPolicy(t *testing.T) { Image: &TextImageType{ Type: "Text", Fill: &StringVariableInline{ - Value: tools.StringPtr("#000000"), + Value: ptr.To("#000000"), }, Size: &NumberVariableInline{ - Value: tools.Float64Ptr(72), + Value: ptr.To(float64(72)), }, Stroke: &StringVariableInline{ - Value: tools.StringPtr("#FFFFFF"), + Value: ptr.To("#FFFFFF"), }, StrokeSize: &NumberVariableInline{ - Value: tools.Float64Ptr(0), + Value: ptr.To(float64(0)), }, Text: &StringVariableInline{ - Value: tools.StringPtr("Hello There"), + Value: ptr.To("Hello There"), }, Transformation: &Compound{ Transformation: "Compound", @@ -1584,7 +1584,7 @@ func TestGetPolicy(t *testing.T) { Value: IfDimensionPostDimensionPtr("width"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MaxDimOld"), + Name: ptr.To("MaxDimOld"), }, Default: &CompoundPost{ Transformation: "Compound", @@ -1595,7 +1595,7 @@ func TestGetPolicy(t *testing.T) { Value: IfDimensionPostDimensionPtr("width"), }, Value: &IntegerVariableInline{ - Name: tools.StringPtr("MinDim"), + Name: ptr.To("MinDim"), }, LessThan: &CompoundPost{ Transformation: "Compound", @@ -1603,13 +1603,13 @@ func TestGetPolicy(t *testing.T) { &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#ffffff"), + Value: ptr.To("#ffffff"), }, }, &BackgroundColor{ Transformation: "BackgroundColor", Color: &StringVariableInline{ - Value: tools.StringPtr("#00ffff"), + Value: ptr.To("#00ffff"), }, }, }, @@ -1621,11 +1621,11 @@ func TestGetPolicy(t *testing.T) { &CompositePost{ Gravity: &GravityPostVariableInline{Value: GravityPostPtr("NorthWest")}, Image: &TextImageTypePost{ - Fill: &StringVariableInline{Value: tools.StringPtr("#000000")}, - Size: &NumberVariableInline{Value: tools.Float64Ptr(72)}, - Stroke: &StringVariableInline{Value: tools.StringPtr("#FFFFFF")}, - StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)}, - Text: &StringVariableInline{Value: tools.StringPtr("test")}, + Fill: &StringVariableInline{Value: ptr.To("#000000")}, + Size: &NumberVariableInline{Value: ptr.To(float64(72))}, + Stroke: &StringVariableInline{Value: ptr.To("#FFFFFF")}, + StrokeSize: &NumberVariableInline{Value: ptr.To(float64(0))}, + Text: &StringVariableInline{Value: ptr.To("test")}, Type: TextImageTypePostTypeText, Transformation: &CompoundPost{ Transformation: CompoundPostTransformationCompound, @@ -1633,11 +1633,11 @@ func TestGetPolicy(t *testing.T) { }, Placement: &CompositePostPlacementVariableInline{Value: CompositePostPlacementPtr(CompositePostPlacementOver)}, Transformation: CompositePostTransformationComposite, - XPosition: &IntegerVariableInline{Value: tools.IntPtr(0)}, - YPosition: &IntegerVariableInline{Value: tools.IntPtr(0)}, + XPosition: &IntegerVariableInline{Value: ptr.To(0)}, + YPosition: &IntegerVariableInline{Value: ptr.To(0)}, }, }, - Video: tools.BoolPtr(false), + Video: ptr.To(false), User: "jsmith", DateCreated: "2021-12-07 16:20:34+0000", }, @@ -1682,7 +1682,7 @@ func TestGetPolicy(t *testing.T) { Value: OutputVideoPerceptualQualityPtr(OutputVideoPerceptualQualityMediumHigh), }, }, - Video: tools.BoolPtr(true), + Video: ptr.To(true), User: "jsmith", DateCreated: "2022-01-24 20:17:10+0000", }, @@ -1862,10 +1862,10 @@ func TestPutPolicy(t *testing.T) { &Composite{ Transformation: "Composite", XPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, YPosition: &IntegerVariableInline{ - Value: tools.IntPtr(0), + Value: ptr.To(0), }, Gravity: &GravityVariableInline{ Value: GravityPtr(GravityNorthWest), @@ -1876,19 +1876,19 @@ func TestPutPolicy(t *testing.T) { Image: &TextImageType{ Type: "Text", Fill: &StringVariableInline{ - Value: tools.StringPtr("#000000"), + Value: ptr.To("#000000"), }, Size: &NumberVariableInline{ - Value: tools.Float64Ptr(72), + Value: ptr.To(float64(72)), }, Stroke: &StringVariableInline{ - Value: tools.StringPtr("#FFFFFF"), + Value: ptr.To("#FFFFFF"), }, StrokeSize: &NumberVariableInline{ - Value: tools.Float64Ptr(0), + Value: ptr.To(float64(0)), }, Text: &StringVariableInline{ - Value: tools.StringPtr("Hello There"), + Value: ptr.To("Hello There"), }, Transformation: &Compound{ Transformation: "Compound", diff --git a/pkg/papi/cpcode_test.go b/pkg/papi/cpcode_test.go index 32f70e08..e0ca334f 100644 --- a/pkg/papi/cpcode_test.go +++ b/pkg/papi/cpcode_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -724,7 +724,7 @@ func TestUpdateCPCode(t *testing.T) { params: UpdateCPCodeRequest{ ID: 123, Name: "test-cp-code", - Purgeable: tools.BoolPtr(false), + Purgeable: ptr.To(false), Contracts: []CPCodeContract{ { ContractID: "test-contract-id", diff --git a/pkg/papi/errors_test.go b/pkg/papi/errors_test.go index 94b53934..07664e32 100644 --- a/pkg/papi/errors_test.go +++ b/pkg/papi/errors_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -95,7 +95,7 @@ func TestErrorIs(t *testing.T) { err: Error{ StatusCode: http.StatusTooManyRequests, LimitKey: "DEFAULT_CERTS_PER_CONTRACT", - Remaining: tools.IntPtr(0), + Remaining: ptr.To(0), }, given: ErrDefaultCertLimitReached, expected: true, @@ -104,7 +104,7 @@ func TestErrorIs(t *testing.T) { err: Error{ StatusCode: http.StatusTooManyRequests, LimitKey: "DEFAULT_CERTS_PER_CONTRACT", - Remaining: tools.IntPtr(0), + Remaining: ptr.To(0), }, given: ErrSBDNotEnabled, expected: false, diff --git a/pkg/papi/include_activations.go b/pkg/papi/include_activations.go index 0a438942..d54f924b 100644 --- a/pkg/papi/include_activations.go +++ b/pkg/papi/include_activations.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" validation "github.com/go-ozzo/ozzo-validation/v4" ) @@ -350,7 +350,7 @@ func (p *papi) ActivateInclude(ctx context.Context, params ActivateIncludeReques } if params.IgnoreHTTPErrors == nil { - params.IgnoreHTTPErrors = tools.BoolPtr(true) + params.IgnoreHTTPErrors = ptr.To(true) } requestBody := struct { @@ -396,7 +396,7 @@ func (p *papi) DeactivateInclude(ctx context.Context, params DeactivateIncludeRe } if params.IgnoreHTTPErrors == nil { - params.IgnoreHTTPErrors = tools.BoolPtr(true) + params.IgnoreHTTPErrors = ptr.To(true) } requestBody := struct { diff --git a/pkg/papi/include_rule_test.go b/pkg/papi/include_rule_test.go index b47ed227..ceaabaee 100644 --- a/pkg/papi/include_rule_test.go +++ b/pkg/papi/include_rule_test.go @@ -8,8 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -185,11 +184,11 @@ func TestGetIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -358,11 +357,11 @@ func TestGetIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -562,11 +561,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -783,11 +782,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { TemplateLink: "/platformtoolkit/service/ruletemplate/30582260/1?accountId=1-1TJZFB&gid=61726&ck=16.3.1.1", Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -863,11 +862,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -958,11 +957,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1039,11 +1038,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1120,11 +1119,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1201,11 +1200,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1283,11 +1282,11 @@ func TestUpdateIncludeRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, diff --git a/pkg/papi/include_test.go b/pkg/papi/include_test.go index d47b2658..c41cbc75 100644 --- a/pkg/papi/include_test.go +++ b/pkg/papi/include_test.go @@ -8,8 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -83,7 +82,7 @@ func TestListIncludes(t *testing.T) { IncludeName: "test_include_1", IncludeType: IncludeTypeCommonSettings, LatestVersion: 1, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), }, }, }, @@ -148,7 +147,7 @@ func TestListIncludes(t *testing.T) { IncludeName: "test_include_1", IncludeType: IncludeTypeCommonSettings, LatestVersion: 1, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), }, }, }, @@ -262,7 +261,7 @@ func TestListIncludeParents(t *testing.T) { GroupID: "test_group", PropertyID: "prp_123456", PropertyName: "test_property", - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), }, }, }, @@ -301,7 +300,7 @@ func TestListIncludeParents(t *testing.T) { GroupID: "test_group", PropertyID: "prp_123456", PropertyName: "test_property", - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), }, }, }, @@ -423,7 +422,7 @@ func TestGetInclude(t *testing.T) { IncludeName: "test_include", IncludeType: "MICROSERVICES", LatestVersion: 1, - PropertyType: tools.StringPtr("INCLUDE"), + PropertyType: ptr.To("INCLUDE"), }, }, }, @@ -436,7 +435,7 @@ func TestGetInclude(t *testing.T) { IncludeName: "test_include", IncludeType: "MICROSERVICES", LatestVersion: 1, - PropertyType: tools.StringPtr("INCLUDE"), + PropertyType: ptr.To("INCLUDE"), }, }, }, diff --git a/pkg/papi/property_test.go b/pkg/papi/property_test.go index 5fe154da..02d98f3e 100644 --- a/pkg/papi/property_test.go +++ b/pkg/papi/property_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -58,7 +57,7 @@ func TestPapiGetProperties(t *testing.T) { PropertyID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), ProductionVersion: nil, AssetID: "aid_101", Note: "Notes about example.com", @@ -162,7 +161,7 @@ func TestPapiGetProperty(t *testing.T) { PropertyID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), ProductionVersion: nil, AssetID: "aid_101", Note: "Notes about example.com", @@ -176,7 +175,7 @@ func TestPapiGetProperty(t *testing.T) { PropertyID: "prp_175780", PropertyName: "example.com", LatestVersion: 2, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), ProductionVersion: nil, AssetID: "aid_101", Note: "Notes about example.com", diff --git a/pkg/papi/propertyversion_test.go b/pkg/papi/propertyversion_test.go index 7f088abb..c92670e2 100644 --- a/pkg/papi/propertyversion_test.go +++ b/pkg/papi/propertyversion_test.go @@ -7,8 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" - + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1851,7 +1850,7 @@ func TestPapiListReferencedIncludes(t *testing.T) { IncludeType: IncludeTypeMicroServices, LatestVersion: 1, ProductionVersion: nil, - StagingVersion: tools.IntPtr(1), + StagingVersion: ptr.To(1), }, }, }, diff --git a/pkg/papi/rule_test.go b/pkg/papi/rule_test.go index 4075005e..bd5ffb4d 100644 --- a/pkg/papi/rule_test.go +++ b/pkg/papi/rule_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -181,11 +181,11 @@ func TestPapiGetRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -336,11 +336,11 @@ func TestPapiGetRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -488,11 +488,11 @@ func TestPapiGetRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -723,11 +723,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -921,11 +921,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { TemplateLink: "/platformtoolkit/service/ruletemplate/30582260/1?accountId=1-1TJZFB&gid=61726&ck=16.3.1.1", Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1020,15 +1020,15 @@ func TestPapiUpdateRuleTree(t *testing.T) { Variables: []RuleVariable{ { Name: "TEST_EMPTY_FIELDS", - Value: tools.StringPtr(""), - Description: tools.StringPtr(""), + Value: ptr.To(""), + Description: ptr.To(""), Hidden: true, Sensitive: false, }, { Name: "TEST_NIL_DESCRIPTION", Description: nil, - Value: tools.StringPtr(""), + Value: ptr.To(""), Hidden: true, Sensitive: false, }, @@ -1232,15 +1232,15 @@ func TestPapiUpdateRuleTree(t *testing.T) { Variables: []RuleVariable{ { Name: "TEST_EMPTY_FIELDS", - Value: tools.StringPtr(""), - Description: tools.StringPtr(""), + Value: ptr.To(""), + Description: ptr.To(""), Hidden: true, Sensitive: false, }, { Name: "TEST_NIL_FIELDS", Description: nil, - Value: tools.StringPtr(""), + Value: ptr.To(""), Hidden: true, Sensitive: false, }, @@ -1281,8 +1281,8 @@ func TestPapiUpdateRuleTree(t *testing.T) { Variables: []RuleVariable{ { Name: "TEST_EMPTY_FIELDS", - Value: tools.StringPtr(""), - Description: tools.StringPtr(""), + Value: ptr.To(""), + Description: ptr.To(""), Hidden: true, Sensitive: false, }, @@ -1373,11 +1373,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1470,11 +1470,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1553,11 +1553,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1637,11 +1637,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1721,11 +1721,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1805,11 +1805,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1889,11 +1889,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "VAR_NAME", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, @@ -1973,11 +1973,11 @@ func TestPapiUpdateRuleTree(t *testing.T) { }, Variables: []RuleVariable{ { - Description: tools.StringPtr("This is a sample Property Manager variable."), + Description: ptr.To("This is a sample Property Manager variable."), Hidden: false, Name: "", Sensitive: false, - Value: tools.StringPtr("default value"), + Value: ptr.To("default value"), }, }, }, diff --git a/pkg/tools/ptr.go b/pkg/tools/ptr.go deleted file mode 100644 index d7cfc0b7..00000000 --- a/pkg/tools/ptr.go +++ /dev/null @@ -1,44 +0,0 @@ -// Package tools contains utilities used in EdgeGrid -package tools - -// BoolPtr returns the address of the bool -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func BoolPtr(b bool) *bool { - return &b -} - -// IntPtr returns the address of the int -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func IntPtr(i int) *int { - return &i -} - -// Int64Ptr returns the address of the int64 -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func Int64Ptr(i int64) *int64 { - return &i -} - -// Float32Ptr returns the address of the float32 -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func Float32Ptr(f float32) *float32 { - return &f -} - -// Float64Ptr returns the address of the float64 -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func Float64Ptr(f float64) *float64 { - return &f -} - -// StringPtr returns the address of the string -// -// Deprecated: this function will be removed in a future release. Use [ptr.To] instead. -func StringPtr(s string) *string { - return &s -} From 405406acfd285b93d5c393ab53d31749b97de2de Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Thu, 26 Sep 2024 10:03:45 +0000 Subject: [PATCH 08/34] DXE-4194 Fix EdgeKV token endpoints --- CHANGELOG.md | 18 ++ pkg/edgeworkers/activations.go | 8 +- pkg/edgeworkers/edgekv_access_tokens.go | 36 ++- pkg/edgeworkers/edgekv_access_tokens_test.go | 230 ++++++++++--------- 4 files changed, 174 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d301a4d..3a3938f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,24 @@ * Global * Removed `tools` package in favour of `ptr` package +* EDGEKV + * For `CreateEdgeKVAccessTokenRequest` removed `Expiry` and added `RestrictToEdgeWorkerIDs` + * For `CreateEdgeKVAccessTokenResponse` removed `Expiry`, `Value` and added + * `AllowOnProduction` + * `AllowOnStaging` + * `CPCode` + * `IssueDate` + * `LatestRefreshDate` + * `NamespacePermissions` + * `NextScheduledRefreshDate` + * `RestrictToEdgeWorkerIDs` + * `TokenActivationStatus` + * For `EdgeKVAccessToken` added fields: + * `TokenActivationStatus` + * `IssueDate` + * `LatestRefreshDate` + * `NextScheduledRefreshDate` + diff --git a/pkg/edgeworkers/activations.go b/pkg/edgeworkers/activations.go index 7cf78398..070872bc 100644 --- a/pkg/edgeworkers/activations.go +++ b/pkg/edgeworkers/activations.go @@ -124,7 +124,7 @@ var ( ErrCancelActivation = errors.New("cancel activation") ) -func (e edgeworkers) ListActivations(ctx context.Context, params ListActivationsRequest) (*ListActivationsResponse, error) { +func (e *edgeworkers) ListActivations(ctx context.Context, params ListActivationsRequest) (*ListActivationsResponse, error) { logger := e.Log(ctx) logger.Debug("ListActivations") @@ -161,7 +161,7 @@ func (e edgeworkers) ListActivations(ctx context.Context, params ListActivations return &result, nil } -func (e edgeworkers) GetActivation(ctx context.Context, params GetActivationRequest) (*Activation, error) { +func (e *edgeworkers) GetActivation(ctx context.Context, params GetActivationRequest) (*Activation, error) { logger := e.Log(ctx) logger.Debug("GetActivation") @@ -189,7 +189,7 @@ func (e edgeworkers) GetActivation(ctx context.Context, params GetActivationRequ return &result, nil } -func (e edgeworkers) ActivateVersion(ctx context.Context, params ActivateVersionRequest) (*Activation, error) { +func (e *edgeworkers) ActivateVersion(ctx context.Context, params ActivateVersionRequest) (*Activation, error) { logger := e.Log(ctx) logger.Debug("ActivateVersion") @@ -218,7 +218,7 @@ func (e edgeworkers) ActivateVersion(ctx context.Context, params ActivateVersion return &result, nil } -func (e edgeworkers) CancelPendingActivation(ctx context.Context, params CancelActivationRequest) (*Activation, error) { +func (e *edgeworkers) CancelPendingActivation(ctx context.Context, params CancelActivationRequest) (*Activation, error) { logger := e.Log(ctx) logger.Debug("CancelPendingActivation") diff --git a/pkg/edgeworkers/edgekv_access_tokens.go b/pkg/edgeworkers/edgekv_access_tokens.go index 87e2e5c1..b067e7cb 100644 --- a/pkg/edgeworkers/edgekv_access_tokens.go +++ b/pkg/edgeworkers/edgekv_access_tokens.go @@ -18,12 +18,12 @@ type ( AllowOnProduction bool `json:"allowOnProduction"` // Whether to allow this token access to the Akamai staging network AllowOnStaging bool `json:"allowOnStaging"` - // Desired token expiry date in ISO format. Expiry can be up to 6 months from creation. - Expiry string `json:"expiry"` // Friendly name of the token. Used when retrieving tokens by name. Name string `json:"name"` // A list of namespace identifiers the token should have access to, plus the associated read, write, delete permissions NamespacePermissions NamespacePermissions `json:"namespacePermissions"` + // A set of EdgeWorker IDs authorized to access EdgeKV via the token. By default, if you omit this array, the token authorizes access for all IDs. + RestrictToEdgeWorkerIDs []string `json:"restrictToEdgeWorkerIds"` } // NamespacePermissions represents mapping between namespaces and permissions @@ -43,18 +43,33 @@ type ( Name string `json:"name"` // Internally generated unique identifier for the access token UUID string `json:"uuid"` + // The IN_PROGRESS status indicates token activation is still in progress, + // and it's not yet possible to make successful EdgeKV requests from EdgeWorkers that use the token. + // Once activation completes, status is COMPLETE. + // Otherwise, a value of ERROR indicates a problem that prevented activation. + TokenActivationStatus *string `json:"tokenActivationStatus"` + // Initial token creation date in ISO 8601 format. + IssueDate *string `json:"issueDate"` + // Most recent token refresh date in ISO 8601 format. A null value indicates the token has not yet been refreshed. + LatestRefreshDate *string `json:"latestRefreshDate"` + // Next scheduled date of the token refresh in ISO 8601 format. + NextScheduledRefreshDate *string `json:"nextScheduledRefreshDate"` } // CreateEdgeKVAccessTokenResponse contains response from EdgeKV access token creation CreateEdgeKVAccessTokenResponse struct { - // The expiry date - Expiry string `json:"expiry"` - // The name assigned to the access token. You can't modify an access token name. - Name string `json:"name"` - // Internally generated unique identifier for the access token - UUID string `json:"uuid"` - // The access token details - Value string `json:"value"` + AllowOnProduction bool `json:"allowOnProduction"` + AllowOnStaging bool `json:"allowOnStaging"` + CPCode string `json:"cpcode"` + Expiry string `json:"expiry"` + IssueDate string `json:"issueDate"` + LatestRefreshDate *string `json:"latestRefreshDate"` + Name string `json:"name"` + NamespacePermissions NamespacePermissions `json:"namespacePermissions"` + NextScheduledRefreshDate string `json:"nextScheduledRefreshDate"` + RestrictToEdgeWorkerIDs []string `json:"restrictToEdgeWorkerIds"` + TokenActivationStatus string `json:"tokenActivationStatus"` + UUID string `json:"uuid"` } // GetEdgeKVAccessTokenRequest represents an TokenName object @@ -106,7 +121,6 @@ func (c CreateEdgeKVAccessTokenRequest) Validate() error { return validation.Errors{ "AllowOnProduction": validation.Validate(c.AllowOnProduction, validation.Required.When(c.AllowOnStaging == false).Error("at least one of AllowOnProduction or AllowOnStaging has to be provided")), "AllowOnStaging": validation.Validate(c.AllowOnStaging, validation.Required.When(c.AllowOnProduction == false).Error("at least one of AllowOnProduction or AllowOnStaging has to be provided")), - "Expiry": validation.Validate(c.Expiry, validation.Required, validation.Date("2006-01-02").Error("the time format should be provided as per ISO-8601")), "Name": validation.Validate(c.Name, validation.Required, validation.Length(1, 32)), "NamespacePermissions.Names": validation.Validate(namespaces, validation.Required, validation.Each(validation.Required)), "NamespacePermissions": validation.Validate(c.NamespacePermissions, diff --git a/pkg/edgeworkers/edgekv_access_tokens_test.go b/pkg/edgeworkers/edgekv_access_tokens_test.go index f3710420..18828165 100644 --- a/pkg/edgeworkers/edgekv_access_tokens_test.go +++ b/pkg/edgeworkers/edgekv_access_tokens_test.go @@ -9,6 +9,7 @@ import ( "strconv" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -27,35 +28,67 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: false, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, "devexp-jsmith-test": []Permission{"r", "w"}, }, + RestrictToEdgeWorkerIDs: []string{ + "1234", + "5678", + }, }, - expectedRequestBody: `{"allowOnProduction":false,"allowOnStaging":true,"expiry":"2022-03-30","name":"devexp-token-1","namespacePermissions":{"default":["r","w","d"],"devexp-jsmith-test":["r","w"]}}`, + expectedRequestBody: `{"allowOnProduction":false,"allowOnStaging":true,"name":"devexp-token-1","namespacePermissions":{"default":["r","w","d"],"devexp-jsmith-test":["r","w"]},"restrictToEdgeWorkerIds":["1234","5678"]}`, responseStatus: http.StatusOK, responseBody: ` { "name": "devexp-token-1", "uuid": "1ab0e94b-c47e-568e-ab3e-1921ffcefe0c", - "expiry": "2022-03-30", - "value": "eyJ0eXAiOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg" + "allowOnProduction": true, + "allowOnStaging": false, + "cpcode": "1234567", + "expiry": "9999-12-31", + "issueDate": "2022-04-30", + "namespacePermissions": { + "default": [ + "r", + "w", + "d" + ], + "devexp-jsmith-test": [ + "r", + "w" + ] + }, + "nextScheduledRefreshDate": "2022-06-30", + "restrictToEdgeWorkerIds": [ + "1234", + "5678" + ], + "tokenActivationStatus": "IN_PROGRESS" }`, expectedPath: "/edgekv/v1/tokens", expectedResponse: &CreateEdgeKVAccessTokenResponse{ - Name: "devexp-token-1", - UUID: "1ab0e94b-c47e-568e-ab3e-1921ffcefe0c", - Expiry: "2022-03-30", - Value: "eyJ0eXAiOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg", + Name: "devexp-token-1", + UUID: "1ab0e94b-c47e-568e-ab3e-1921ffcefe0c", + Expiry: "9999-12-31", + AllowOnProduction: true, + AllowOnStaging: false, + CPCode: "1234567", + IssueDate: "2022-04-30", + NamespacePermissions: NamespacePermissions{ + "default": []Permission{"r", "w", "d"}, + "devexp-jsmith-test": []Permission{"r", "w"}, + }, + NextScheduledRefreshDate: "2022-06-30", + RestrictToEdgeWorkerIDs: []string{"1234", "5678"}, + TokenActivationStatus: "IN_PROGRESS", }, }, "at least one allow is required": { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: false, AllowOnStaging: false, - Expiry: "2022-03-30", Name: "name", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -68,7 +101,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -76,23 +108,10 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { }, }, withError: ErrStructValidation, }, - "invalid date": { - params: CreateEdgeKVAccessTokenRequest{ - AllowOnProduction: true, - AllowOnStaging: true, - Expiry: "30/09/2021", - Name: "name", - NamespacePermissions: NamespacePermissions{ - "default": []Permission{"r", "w", "d"}, - "devexp-jsmith-test": []Permission{"r", "w"}, - }, - }, withError: ErrStructValidation, - }, "invalid permission": { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"a", "w", "d"}, @@ -103,7 +122,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "": []Permission{"r", "w", "d"}, @@ -114,7 +132,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{}, @@ -125,7 +142,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", }, withError: ErrStructValidation, }, @@ -133,7 +149,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -169,7 +184,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -208,7 +222,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -245,7 +258,6 @@ func TestCreateEdgeKVAccessToken(t *testing.T) { params: CreateEdgeKVAccessTokenRequest{ AllowOnProduction: true, AllowOnStaging: true, - Expiry: "2022-03-30", Name: "devexp-token-1", NamespacePermissions: NamespacePermissions{ "default": []Permission{"r", "w", "d"}, @@ -325,15 +337,45 @@ func TestGetEdgeKVAccessToken(t *testing.T) { { "name": "devexp-token-1", "uuid": "10b0e94b-c47e-568e-ab3e-1921ffcefe0c", - "expiry": "2022-03-30", - "value": "eyJ0eXAxOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg" + "allowOnProduction": true, + "allowOnStaging": false, + "cpcode": "1234567", + "expiry": "9999-12-31", + "issueDate": "2022-04-30", + "namespacePermissions": { + "default": [ + "r", + "w", + "d" + ], + "devexp-jsmith-test": [ + "r", + "w" + ] + }, + "nextScheduledRefreshDate": "2022-06-30", + "restrictToEdgeWorkerIds": [ + "1234", + "5678" + ], + "tokenActivationStatus": "IN_PROGRESS" }`, expectedPath: "/edgekv/v1/tokens/devexp-token-1", expectedResponse: &GetEdgeKVAccessTokenResponse{ - Name: "devexp-token-1", - UUID: "10b0e94b-c47e-568e-ab3e-1921ffcefe0c", - Expiry: "2022-03-30", - Value: "eyJ0eXAxOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg", + Name: "devexp-token-1", + UUID: "10b0e94b-c47e-568e-ab3e-1921ffcefe0c", + AllowOnProduction: true, + AllowOnStaging: false, + CPCode: "1234567", + Expiry: "9999-12-31", + IssueDate: "2022-04-30", + NamespacePermissions: NamespacePermissions{ + "default": []Permission{"r", "w", "d"}, + "devexp-jsmith-test": []Permission{"r", "w"}, + }, + NextScheduledRefreshDate: "2022-06-30", + RestrictToEdgeWorkerIDs: []string{"1234", "5678"}, + TokenActivationStatus: "IN_PROGRESS", }, }, "missing token name": { @@ -472,47 +514,43 @@ func TestListEdgeKVAccessTokens(t *testing.T) { { "name": "my_token", "uuid": "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", - "expiry": "2022-03-30" + "expiry": "2022-03-30", + "issueDate": "2022-01-30", + "latestRefreshDate": "2022-03-30", + "nextScheduledRefreshDate": "2022-05-30", + "tokenActivationStatus": "COMPLETE" }, { "name": "token1", "uuid": "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", - "expiry": "2022-01-22" - }, - { - "name": "token2", - "uuid": "62181cfe-268a-5302-8834-67c67ec86efd", - "expiry": "2022-01-22" - }, - { - "name": "token3", - "uuid": "edb02678-ae1c-564c-8f73-c977ffdfe016", - "expiry": "2022-01-22" + "expiry": "2022-01-22", + "issueDate": "2022-04-30", + "latestRefreshDate": null, + "nextScheduledRefreshDate": "2022-06-30", + "tokenActivationStatus": "IN_PROGRESS" } - ] + ] }`, expectedPath: "/edgekv/v1/tokens", expectedResponse: &ListEdgeKVAccessTokensResponse{ []EdgeKVAccessToken{ { - Name: "my_token", - UUID: "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", - Expiry: "2022-03-30", - }, - { - Name: "token1", - UUID: "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", - Expiry: "2022-01-22", + Name: "my_token", + UUID: "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", + Expiry: "2022-03-30", + IssueDate: ptr.To("2022-01-30"), + LatestRefreshDate: ptr.To("2022-03-30"), + NextScheduledRefreshDate: ptr.To("2022-05-30"), + TokenActivationStatus: ptr.To("COMPLETE"), }, { - Name: "token2", - UUID: "62181cfe-268a-5302-8834-67c67ec86efd", - Expiry: "2022-01-22", - }, - { - Name: "token3", - UUID: "edb02678-ae1c-564c-8f73-c977ffdfe016", - Expiry: "2022-01-22", + Name: "token1", + UUID: "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", + Expiry: "2022-01-22", + IssueDate: ptr.To("2022-04-30"), + LatestRefreshDate: nil, + NextScheduledRefreshDate: ptr.To("2022-06-30"), + TokenActivationStatus: ptr.To("IN_PROGRESS"), }, }, }, @@ -528,27 +566,20 @@ func TestListEdgeKVAccessTokens(t *testing.T) { { "name": "my_token", "uuid": "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", - "expiry": "2022-03-30" + "expiry": "2022-03-30", + "issueDate": "2022-01-30", + "latestRefreshDate": "2022-03-30", + "nextScheduledRefreshDate": "2022-05-30", + "tokenActivationStatus": "COMPLETE" }, { "name": "token1", "uuid": "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", - "expiry": "2022-01-22" - }, - { - "name": "token2", - "uuid": "62181cfe-268a-5302-8834-67c67ec86efd", - "expiry": "2022-01-22" - }, - { - "name": "token3", - "uuid": "edb02678-ae1c-564c-8f73-c977ffdfe016", - "expiry": "2022-01-22" - }, - { - "name": "preexistingTokenTest", - "uuid": "7a14da8c-1709-570b-9535-2cc6e2ee5a8a", - "expiry": "2021-12-21" + "expiry": "2022-01-22", + "issueDate": "2022-04-30", + "latestRefreshDate": null, + "nextScheduledRefreshDate": "2022-06-30", + "tokenActivationStatus": "IN_PROGRESS" } ] }`, @@ -556,29 +587,22 @@ func TestListEdgeKVAccessTokens(t *testing.T) { expectedResponse: &ListEdgeKVAccessTokensResponse{ []EdgeKVAccessToken{ { - Name: "my_token", - UUID: "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", - Expiry: "2022-03-30", - }, - { - Name: "token1", - UUID: "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", - Expiry: "2022-01-22", - }, - { - Name: "token2", - UUID: "62181cfe-268a-5302-8834-67c67ec86efd", - Expiry: "2022-01-22", - }, - { - Name: "token3", - UUID: "edb02678-ae1c-564c-8f73-c977ffdfe016", - Expiry: "2022-01-22", + Name: "my_token", + UUID: "8301fef4-80e5-5efb-9bfb-8f5869a5df7b", + Expiry: "2022-03-30", + IssueDate: ptr.To("2022-01-30"), + LatestRefreshDate: ptr.To("2022-03-30"), + NextScheduledRefreshDate: ptr.To("2022-05-30"), + TokenActivationStatus: ptr.To("COMPLETE"), }, { - Name: "preexistingTokenTest", - UUID: "7a14da8c-1709-570b-9535-2cc6e2ee5a8a", - Expiry: "2021-12-21", + Name: "token1", + UUID: "5b5d3bfb-8d2e-5fbb-858d-33807edc9554", + Expiry: "2022-01-22", + IssueDate: ptr.To("2022-04-30"), + LatestRefreshDate: nil, + NextScheduledRefreshDate: ptr.To("2022-06-30"), + TokenActivationStatus: ptr.To("IN_PROGRESS"), }, }, }, From 68ab91b792bdb0b6a504fa6c1f82049ca2f8d759 Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Mon, 9 Sep 2024 13:30:57 +0000 Subject: [PATCH 09/34] DXE-4150 Unify request body naming --- CHANGELOG.md | 20 +++++++++++ pkg/cloudaccess/access_key_version.go | 14 ++++---- pkg/cloudaccess/access_key_version_test.go | 8 ++--- pkg/cloudlets/v3/policy.go | 34 +++++++++---------- pkg/cloudlets/v3/policy_test.go | 12 +++---- pkg/cloudwrapper/configurations.go | 20 +++++------ pkg/cloudwrapper/configurations_test.go | 39 ++++++++++------------ pkg/edgeworkers/edgeworker_id.go | 24 ++++++------- pkg/edgeworkers/edgeworker_id_test.go | 20 +++++------ 9 files changed, 104 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3938f6..a62a1b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,11 +49,27 @@ +* Cloudaccess + * Changed naming of request body fields for following structures: + * `BodyParams` to `Body` in `CreateAccessKeyVersionRequest` + * `CreateAccessKeyVersionBodyParams` to `CreateAccessKeyVersionRequestBody` +* Cloudlets + * Changed naming of request body fields for following structures: + * `BodyParams` to `Body` in `UpdatePolicyRequest` and `ClonePolicyRequest` + * `UpdatePolicyBodyParams` to `UpdatePolicyRequestBody` + * `ClonePolicyBodyParams` to `ClonePolicyRequestBody` + + +* Cloudwrapper + * Changed naming of request body fields for following structures: + * `CreateConfigurationBody` to `CreateConfigurationRequestBody` + * `UpdateConfigurationBody` to `UpdateConfigurationRequestBody` + * DNS * Refactored parameters in following methods: * `GetAuthorities` - from (context.Context, string) into (context.Context, `GetAuthoritiesRequest`) @@ -224,6 +240,10 @@ * `Properties` * `Resources` +* Edgeworkers + * Changed naming of request body fields for following structures: + * `EdgeWorkerIDBodyRequest` to `EdgeWorkerIDRequestBody` + diff --git a/pkg/cloudaccess/access_key_version.go b/pkg/cloudaccess/access_key_version.go index d68b0e16..87386f08 100644 --- a/pkg/cloudaccess/access_key_version.go +++ b/pkg/cloudaccess/access_key_version.go @@ -28,11 +28,11 @@ type ( // CreateAccessKeyVersionRequest holds parameters for CreateAccessKeyVersion CreateAccessKeyVersionRequest struct { AccessKeyUID int64 - BodyParams CreateAccessKeyVersionBodyParams + Body CreateAccessKeyVersionRequestBody } - // CreateAccessKeyVersionBodyParams holds body parameters for CreateAccessKeyVersion - CreateAccessKeyVersionBodyParams struct { + // CreateAccessKeyVersionRequestBody holds body parameters for CreateAccessKeyVersion + CreateAccessKeyVersionRequestBody struct { CloudAccessKeyID string `json:"cloudAccessKeyId"` CloudSecretAccessKey string `json:"cloudSecretAccessKey"` } @@ -106,12 +106,12 @@ func (r GetAccessKeyVersionStatusRequest) Validate() error { func (r CreateAccessKeyVersionRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "AccessKeyUID": validation.Validate(r.AccessKeyUID, validation.Required), - "BodyParams": validation.Validate(r.BodyParams, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } -// Validate validates CreateAccessKeyVersionBodyParams -func (r CreateAccessKeyVersionBodyParams) Validate() error { +// Validate validates CreateAccessKeyVersionRequestBody +func (r CreateAccessKeyVersionRequestBody) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CloudAccessKeyID": validation.Validate(r.CloudAccessKeyID, validation.Required), "CloudSecretAccessKey": validation.Validate(r.CloudSecretAccessKey, validation.Required), @@ -197,7 +197,7 @@ func (c *cloudaccess) CreateAccessKeyVersion(ctx context.Context, params CreateA } var result CreateAccessKeyVersionResponse - resp, err := c.Exec(req, &result, params.BodyParams) + resp, err := c.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %w", ErrCreateAccessKeyVersion, err) } diff --git a/pkg/cloudaccess/access_key_version_test.go b/pkg/cloudaccess/access_key_version_test.go index ea73d3c4..cbe0ec5a 100644 --- a/pkg/cloudaccess/access_key_version_test.go +++ b/pkg/cloudaccess/access_key_version_test.go @@ -136,7 +136,7 @@ func TestCreateAccessKeyVersion(t *testing.T) { "202 ACCEPTED": { params: CreateAccessKeyVersionRequest{ AccessKeyUID: 1, - BodyParams: CreateAccessKeyVersionBodyParams{ + Body: CreateAccessKeyVersionRequestBody{ CloudAccessKeyID: "key-1", CloudSecretAccessKey: "secret-1", }, @@ -162,13 +162,13 @@ func TestCreateAccessKeyVersion(t *testing.T) { "missing required params - validation error": { params: CreateAccessKeyVersionRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "create access key version: struct validation: AccessKeyUID: cannot be blank\nBodyParams: CloudAccessKeyID: cannot be blank\nCloudSecretAccessKey: cannot be blank", err.Error()) + assert.Equal(t, "create access key version: struct validation: AccessKeyUID: cannot be blank\nBody: CloudAccessKeyID: cannot be blank\nCloudSecretAccessKey: cannot be blank", err.Error()) }, }, "404 error": { params: CreateAccessKeyVersionRequest{ AccessKeyUID: 1, - BodyParams: CreateAccessKeyVersionBodyParams{ + Body: CreateAccessKeyVersionRequestBody{ CloudAccessKeyID: "key-1", CloudSecretAccessKey: "secret-1", }, @@ -205,7 +205,7 @@ func TestCreateAccessKeyVersion(t *testing.T) { "409 error": { params: CreateAccessKeyVersionRequest{ AccessKeyUID: 1, - BodyParams: CreateAccessKeyVersionBodyParams{ + Body: CreateAccessKeyVersionRequestBody{ CloudAccessKeyID: "key-1", CloudSecretAccessKey: "secret-1", }, diff --git a/pkg/cloudlets/v3/policy.go b/pkg/cloudlets/v3/policy.go index 98e64516..0e3811f4 100644 --- a/pkg/cloudlets/v3/policy.go +++ b/pkg/cloudlets/v3/policy.go @@ -42,26 +42,26 @@ type ( // UpdatePolicyRequest contains request parameters for UpdatePolicy UpdatePolicyRequest struct { - PolicyID int64 - BodyParams UpdatePolicyBodyParams + PolicyID int64 + Body UpdatePolicyRequestBody } // ClonePolicyRequest contains request parameters for ClonePolicy ClonePolicyRequest struct { - PolicyID int64 - BodyParams ClonePolicyBodyParams + PolicyID int64 + Body ClonePolicyRequestBody } - // ClonePolicyBodyParams contains request body parameters used in ClonePolicy operation + // ClonePolicyRequestBody contains request body parameters used in ClonePolicy operation // GroupID is required only when cloning v2 - ClonePolicyBodyParams struct { + ClonePolicyRequestBody struct { AdditionalVersions []int64 `json:"additionalVersions,omitempty"` GroupID int64 `json:"groupId,omitempty"` NewName string `json:"newName"` } - // UpdatePolicyBodyParams contains request body parameters used in UpdatePolicy operation - UpdatePolicyBodyParams struct { + // UpdatePolicyRequestBody contains request body parameters used in UpdatePolicy operation + UpdatePolicyRequestBody struct { GroupID int64 `json:"groupId"` Description *string `json:"description,omitempty"` } @@ -179,13 +179,13 @@ func (r GetPolicyRequest) Validate() error { // Validate validates UpdatePolicyRequest func (r UpdatePolicyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ - "PolicyID": validation.Validate(r.PolicyID, validation.Required), - "BodyParams": validation.Validate(r.BodyParams, validation.Required), + "PolicyID": validation.Validate(r.PolicyID, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } -// Validate validates UpdatePolicyBodyParams -func (b UpdatePolicyBodyParams) Validate() error { +// Validate validates UpdatePolicyRequestBody +func (b UpdatePolicyRequestBody) Validate() error { return validation.Errors{ "GroupID": validation.Validate(b.GroupID, validation.Required), "Description": validation.Validate(b.Description, validation.Length(0, 255)), @@ -195,13 +195,13 @@ func (b UpdatePolicyBodyParams) Validate() error { // Validate validates ClonePolicyRequest func (r ClonePolicyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ - "PolicyID": validation.Validate(r.PolicyID, validation.Required), - "BodyParams": validation.Validate(r.BodyParams, validation.Required), + "PolicyID": validation.Validate(r.PolicyID, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } // Validate validates ClonePolicyBodyParams -func (b ClonePolicyBodyParams) Validate() error { +func (b ClonePolicyRequestBody) Validate() error { return validation.Errors{ "NewName": validation.Validate(b.NewName, validation.Required, validation.Length(0, 64), validation.Match(regexp.MustCompile("^[a-z_A-Z0-9]+$")). Error(fmt.Sprintf("value '%s' is invalid. Must be of format: ^[a-z_A-Z0-9]+$", b.NewName))), @@ -352,7 +352,7 @@ func (c *cloudlets) UpdatePolicy(ctx context.Context, params UpdatePolicyRequest } var result Policy - resp, err := c.Exec(req, &result, params.BodyParams) + resp, err := c.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdatePolicy, err) } @@ -380,7 +380,7 @@ func (c *cloudlets) ClonePolicy(ctx context.Context, params ClonePolicyRequest) } var result Policy - resp, err := c.Exec(req, &result, params.BodyParams) + resp, err := c.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrClonePolicy, err) } diff --git a/pkg/cloudlets/v3/policy_test.go b/pkg/cloudlets/v3/policy_test.go index a34d92e3..660b239c 100644 --- a/pkg/cloudlets/v3/policy_test.go +++ b/pkg/cloudlets/v3/policy_test.go @@ -1171,7 +1171,7 @@ func TestUpdatePolicy(t *testing.T) { "200 OK - minimal data": { params: UpdatePolicyRequest{ PolicyID: 1, - BodyParams: UpdatePolicyBodyParams{ + Body: UpdatePolicyRequestBody{ GroupID: 11, }, }, @@ -1235,7 +1235,7 @@ func TestUpdatePolicy(t *testing.T) { "200 OK - with description and activations": { params: UpdatePolicyRequest{ PolicyID: 1, - BodyParams: UpdatePolicyBodyParams{ + Body: UpdatePolicyRequestBody{ GroupID: 11, Description: ptr.To("Description"), }, @@ -1452,7 +1452,7 @@ func TestUpdatePolicy(t *testing.T) { "validation errors - description too long": { params: UpdatePolicyRequest{ PolicyID: 1, - BodyParams: UpdatePolicyBodyParams{ + Body: UpdatePolicyRequestBody{ GroupID: 11, Description: ptr.To(strings.Repeat("TestDescription", 30)), }, @@ -1502,7 +1502,7 @@ func TestClonePolicy(t *testing.T) { "200 OK - minimal data": { params: ClonePolicyRequest{ PolicyID: 1, - BodyParams: ClonePolicyBodyParams{ + Body: ClonePolicyRequestBody{ NewName: "NewName", }, }, @@ -1566,7 +1566,7 @@ func TestClonePolicy(t *testing.T) { "200 OK - all data": { params: ClonePolicyRequest{ PolicyID: 1, - BodyParams: ClonePolicyBodyParams{ + Body: ClonePolicyRequestBody{ AdditionalVersions: []int64{1, 2}, GroupID: 11, NewName: "NewName", @@ -1785,7 +1785,7 @@ func TestClonePolicy(t *testing.T) { "validation errors - newName too long": { params: ClonePolicyRequest{ PolicyID: 1, - BodyParams: ClonePolicyBodyParams{ + Body: ClonePolicyRequestBody{ GroupID: 11, NewName: strings.Repeat("TestNameTooLong", 10), }, diff --git a/pkg/cloudwrapper/configurations.go b/pkg/cloudwrapper/configurations.go index f03c090b..37537834 100644 --- a/pkg/cloudwrapper/configurations.go +++ b/pkg/cloudwrapper/configurations.go @@ -21,11 +21,11 @@ type ( // CreateConfigurationRequest holds parameters for CreateConfiguration CreateConfigurationRequest struct { Activate bool - Body CreateConfigurationBody + Body CreateConfigurationRequestBody } - // CreateConfigurationBody holds request body parameters for CreateConfiguration - CreateConfigurationBody struct { + // CreateConfigurationRequestBody holds request body parameters for CreateConfiguration + CreateConfigurationRequestBody struct { CapacityAlertsThreshold *int `json:"capacityAlertsThreshold,omitempty"` Comments string `json:"comments"` ContractID string `json:"contractId"` @@ -41,11 +41,11 @@ type ( UpdateConfigurationRequest struct { ConfigID int64 Activate bool - Body UpdateConfigurationBody + Body UpdateConfigurationRequestBody } - // UpdateConfigurationBody holds request body parameters for UpdateConfiguration - UpdateConfigurationBody struct { + // UpdateConfigurationRequestBody holds request body parameters for UpdateConfiguration + UpdateConfigurationRequestBody struct { CapacityAlertsThreshold *int `json:"capacityAlertsThreshold,omitempty"` Comments string `json:"comments"` Locations []ConfigLocationReq `json:"locations"` @@ -208,8 +208,8 @@ func (r CreateConfigurationRequest) Validate() error { }) } -// Validate validates CreateConfigurationBody -func (b CreateConfigurationBody) Validate() error { +// Validate validates CreateConfigurationRequestBody +func (b CreateConfigurationRequestBody) Validate() error { return validation.Errors{ "Comments": validation.Validate(b.Comments, validation.Required), "Locations": validation.Validate(b.Locations, validation.Required), @@ -229,8 +229,8 @@ func (r UpdateConfigurationRequest) Validate() error { }) } -// Validate validates UpdateConfigurationBody -func (b UpdateConfigurationBody) Validate() error { +// Validate validates UpdateConfigurationRequestBody +func (b UpdateConfigurationRequestBody) Validate() error { return validation.Errors{ "Comments": validation.Validate(b.Comments, validation.Required), "Locations": validation.Validate(b.Locations, validation.Required), diff --git a/pkg/cloudwrapper/configurations_test.go b/pkg/cloudwrapper/configurations_test.go index 1619f1c5..995cf54f 100644 --- a/pkg/cloudwrapper/configurations_test.go +++ b/pkg/cloudwrapper/configurations_test.go @@ -597,7 +597,7 @@ func TestCreateConfiguration(t *testing.T) { }{ "200 OK - minimal": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -694,7 +694,7 @@ func TestCreateConfiguration(t *testing.T) { "200 OK - minimal with activate query param": { params: CreateConfigurationRequest{ Activate: true, - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -790,7 +790,7 @@ func TestCreateConfiguration(t *testing.T) { }, "200 OK - minimal MultiCDNSettings": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1005,7 +1005,7 @@ func TestCreateConfiguration(t *testing.T) { }, "200 OK - full MultiCDNSettings": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ CapacityAlertsThreshold: ptr.To(70), Comments: "TestComments", ContractID: "TestContractID", @@ -1350,7 +1350,7 @@ func TestCreateConfiguration(t *testing.T) { }, "200 OK - BOCC struct fields default values": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1547,7 +1547,7 @@ func TestCreateConfiguration(t *testing.T) { }, "200 OK - DataStreams struct fields default values": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1749,7 +1749,7 @@ func TestCreateConfiguration(t *testing.T) { }, "missing required params - location fields": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1769,7 +1769,7 @@ func TestCreateConfiguration(t *testing.T) { }, "missing required params - multiCDN fields": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1793,7 +1793,7 @@ func TestCreateConfiguration(t *testing.T) { }, "missing required params - BOCC struct fields when enabled": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1840,7 +1840,7 @@ func TestCreateConfiguration(t *testing.T) { }, "missing required params - Origin struct fields": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{Comments: "TestComments", + Body: CreateConfigurationRequestBody{Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ { @@ -1880,7 +1880,7 @@ func TestCreateConfiguration(t *testing.T) { }, "validation error - at least one CDN must be enabled": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1930,7 +1930,7 @@ func TestCreateConfiguration(t *testing.T) { }, "validation error - authKeys nor IPACLCIDRs specified": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -1974,7 +1974,7 @@ func TestCreateConfiguration(t *testing.T) { }, "struct fields validations": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ CapacityAlertsThreshold: ptr.To(20), Comments: "TestComments", ContractID: "TestContractID", @@ -2033,7 +2033,7 @@ func TestCreateConfiguration(t *testing.T) { }, "500 internal server error": { params: CreateConfigurationRequest{ - Body: CreateConfigurationBody{ + Body: CreateConfigurationRequestBody{ Comments: "TestComments", ContractID: "TestContractID", Locations: []ConfigLocationReq{ @@ -2074,9 +2074,6 @@ func TestCreateConfiguration(t *testing.T) { } for name, test := range tests { - if name != "200 OK - full MultiCDNSettings" { - continue - } t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, test.expectedPath, r.URL.String()) @@ -2115,7 +2112,7 @@ func TestUpdateConfiguration(t *testing.T) { "200 OK - minimal": { params: UpdateConfigurationRequest{ ConfigID: 111, - Body: UpdateConfigurationBody{ + Body: UpdateConfigurationRequestBody{ Comments: "TestCommentsUpdated", Locations: []ConfigLocationReq{ { @@ -2211,7 +2208,7 @@ func TestUpdateConfiguration(t *testing.T) { "200 OK - minimal MultiCDNSettings": { params: UpdateConfigurationRequest{ ConfigID: 111, - Body: UpdateConfigurationBody{ + Body: UpdateConfigurationRequestBody{ Comments: "TestCommentsUpdated", Locations: []ConfigLocationReq{ { @@ -2405,7 +2402,7 @@ func TestUpdateConfiguration(t *testing.T) { "200 OK - all fields": { params: UpdateConfigurationRequest{ ConfigID: 111, - Body: UpdateConfigurationBody{ + Body: UpdateConfigurationRequestBody{ CapacityAlertsThreshold: ptr.To(80), Comments: "TestCommentsUpdated", Locations: []ConfigLocationReq{ @@ -2681,7 +2678,7 @@ func TestUpdateConfiguration(t *testing.T) { "500 internal server error": { params: UpdateConfigurationRequest{ ConfigID: 1, - Body: UpdateConfigurationBody{ + Body: UpdateConfigurationRequestBody{ Comments: "TestCommentsUpdated", Locations: []ConfigLocationReq{ { diff --git a/pkg/edgeworkers/edgeworker_id.go b/pkg/edgeworkers/edgeworker_id.go index ca603928..54be07df 100644 --- a/pkg/edgeworkers/edgeworker_id.go +++ b/pkg/edgeworkers/edgeworker_id.go @@ -53,8 +53,8 @@ type ( ResourceTierID int `json:"resourceTierId"` } - // EdgeWorkerIDBodyRequest contains body parameters used to update or clone EdgeWorkerID - EdgeWorkerIDBodyRequest struct { + // EdgeWorkerIDRequestBody contains body parameters used to update or clone EdgeWorkerID + EdgeWorkerIDRequestBody struct { Name string `json:"name"` GroupID int `json:"groupId"` ResourceTierID int `json:"resourceTierId"` @@ -62,13 +62,13 @@ type ( // UpdateEdgeWorkerIDRequest contains body and path parameters used to update EdgeWorkerID UpdateEdgeWorkerIDRequest struct { - EdgeWorkerIDBodyRequest + Body EdgeWorkerIDRequestBody EdgeWorkerID int } // CloneEdgeWorkerIDRequest contains body and path parameters used to clone EdgeWorkerID CloneEdgeWorkerIDRequest struct { - EdgeWorkerIDBodyRequest + Body EdgeWorkerIDRequestBody EdgeWorkerID int } ) @@ -92,9 +92,9 @@ func (c CreateEdgeWorkerIDRequest) Validate() error { // Validate validates CreateEdgeWorkerIDRequest func (c UpdateEdgeWorkerIDRequest) Validate() error { return validation.Errors{ - "Name": validation.Validate(c.EdgeWorkerIDBodyRequest.Name, validation.Required), - "GroupID": validation.Validate(c.EdgeWorkerIDBodyRequest.GroupID, validation.Required), - "ResourceTierID": validation.Validate(c.EdgeWorkerIDBodyRequest.ResourceTierID, validation.Required), + "Name": validation.Validate(c.Body.Name, validation.Required), + "GroupID": validation.Validate(c.Body.GroupID, validation.Required), + "ResourceTierID": validation.Validate(c.Body.ResourceTierID, validation.Required), "EdgeWorkerID": validation.Validate(c.EdgeWorkerID, validation.Required), }.Filter() } @@ -102,9 +102,9 @@ func (c UpdateEdgeWorkerIDRequest) Validate() error { // Validate validates CloneEdgeWorkerIDRequest func (c CloneEdgeWorkerIDRequest) Validate() error { return validation.Errors{ - "Name": validation.Validate(c.EdgeWorkerIDBodyRequest.Name, validation.Required), - "GroupID": validation.Validate(c.EdgeWorkerIDBodyRequest.GroupID, validation.Required), - "ResourceTierID": validation.Validate(c.EdgeWorkerIDBodyRequest.ResourceTierID, validation.Required), + "Name": validation.Validate(c.Body.Name, validation.Required), + "GroupID": validation.Validate(c.Body.GroupID, validation.Required), + "ResourceTierID": validation.Validate(c.Body.ResourceTierID, validation.Required), "EdgeWorkerID": validation.Validate(c.EdgeWorkerID, validation.Required), }.Filter() } @@ -244,7 +244,7 @@ func (e *edgeworkers) UpdateEdgeWorkerID(ctx context.Context, params UpdateEdgeW } var result EdgeWorkerID - resp, err := e.Exec(req, &result, params.EdgeWorkerIDBodyRequest) + resp, err := e.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateEdgeWorkerID, err) } @@ -275,7 +275,7 @@ func (e *edgeworkers) CloneEdgeWorkerID(ctx context.Context, params CloneEdgeWor } var result EdgeWorkerID - resp, err := e.Exec(req, &result, params.EdgeWorkerIDBodyRequest) + resp, err := e.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrCloneEdgeWorkerID, err) } diff --git a/pkg/edgeworkers/edgeworker_id_test.go b/pkg/edgeworkers/edgeworker_id_test.go index 282e2069..92185fe0 100644 --- a/pkg/edgeworkers/edgeworker_id_test.go +++ b/pkg/edgeworkers/edgeworker_id_test.go @@ -547,7 +547,7 @@ func TestUpdateEdgeWorkerID(t *testing.T) { }{ "200 OK - update EdgeWorkerID": { params: UpdateEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, @@ -583,14 +583,14 @@ func TestUpdateEdgeWorkerID(t *testing.T) { }, "validation error - empty body parameters": { params: UpdateEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{}, - EdgeWorkerID: 54321, + Body: EdgeWorkerIDRequestBody{}, + EdgeWorkerID: 54321, }, withError: ErrStructValidation, }, "validation error - empty edgeworker id": { params: UpdateEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, @@ -600,7 +600,7 @@ func TestUpdateEdgeWorkerID(t *testing.T) { }, "500 internal server error": { params: UpdateEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, @@ -635,7 +635,7 @@ func TestUpdateEdgeWorkerID(t *testing.T) { }, "403 Forbidden - incorrect credentials": { params: UpdateEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, @@ -712,7 +712,7 @@ func TestCloneEdgeWorkerID(t *testing.T) { }{ "200 OK - clone EdgeWorkerID with different resourceTierId": { params: CloneEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Clone EdgeWorkerID", ResourceTierID: 123, @@ -754,7 +754,7 @@ func TestCloneEdgeWorkerID(t *testing.T) { }, "validation error - empty edgeworker id": { params: CloneEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, @@ -764,7 +764,7 @@ func TestCloneEdgeWorkerID(t *testing.T) { }, "500 internal server error": { params: CloneEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Clone EdgeWorkerID", ResourceTierID: 123, @@ -799,7 +799,7 @@ func TestCloneEdgeWorkerID(t *testing.T) { }, "403 Forbidden - incorrect credentials": { params: CloneEdgeWorkerIDRequest{ - EdgeWorkerIDBodyRequest: EdgeWorkerIDBodyRequest{ + Body: EdgeWorkerIDRequestBody{ GroupID: 12345, Name: "Update EdgeWorkerID", ResourceTierID: 123, From 1f5626761c4b983f261b98a69d56c3f5f6afbbca Mon Sep 17 00:00:00 2001 From: Chaitanya Sanjay Bhangale Date: Mon, 16 Sep 2024 16:39:03 +0000 Subject: [PATCH 10/34] SECKSD-28444 Add support for SIEM Exceptions Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/SECKSD-28444 to feature/sp-security --- CHANGELOG.md | 7 +- pkg/appsec/siem_settings.go | 64 ++++++++++++------- pkg/appsec/siem_settings_test.go | 19 +++++- .../TestSiemSettings/SiemSettings.json | 21 +++++- 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a62a1b16..019754f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -265,7 +265,12 @@ - +* APPSEC + * Added field `Exceptions` in the following structures: + * `GetSiemSettingsResponse` + * `GetSiemSettingResponse` + * `UpdateSiemSettingsRequest` + * `UpdateSiemSettingsResponse` diff --git a/pkg/appsec/siem_settings.go b/pkg/appsec/siem_settings.go index 01cf7c1b..ec6b4eb6 100644 --- a/pkg/appsec/siem_settings.go +++ b/pkg/appsec/siem_settings.go @@ -36,11 +36,12 @@ type ( // GetSiemSettingsResponse is returned from a call to GetSiemSettings. GetSiemSettingsResponse struct { - EnableForAllPolicies bool `json:"enableForAllPolicies"` - EnableSiem bool `json:"enableSiem"` - EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` - SiemDefinitionID int `json:"siemDefinitionId"` - FirewallPolicyIds []string `json:"firewallPolicyIds"` + EnableForAllPolicies bool `json:"enableForAllPolicies"` + EnableSiem bool `json:"enableSiem"` + EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` + SiemDefinitionID int `json:"siemDefinitionId"` + FirewallPolicyIds []string `json:"firewallPolicyIds"` + Exceptions []Exception `json:"exceptions"` } // GetSiemSettingRequest is used to retrieve the SIEM settings for a configuration. @@ -49,33 +50,42 @@ type ( Version int `json:"-"` } + // Exception is used to create exceptions list for SIEM events + Exception struct { + Protection string `json:"protection"` + ActionTypes []string `json:"actionTypes"` + } + // GetSiemSettingResponse is returned from a call to GetSiemSettings. GetSiemSettingResponse struct { - EnableForAllPolicies bool `json:"enableForAllPolicies"` - EnableSiem bool `json:"enableSiem"` - EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` - SiemDefinitionID int `json:"siemDefinitionId"` - FirewallPolicyIds []string `json:"firewallPolicyIds"` + EnableForAllPolicies bool `json:"enableForAllPolicies"` + EnableSiem bool `json:"enableSiem"` + EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` + SiemDefinitionID int `json:"siemDefinitionId"` + FirewallPolicyIds []string `json:"firewallPolicyIds"` + Exceptions []Exception `json:"exceptions"` } // UpdateSiemSettingsRequest is used to modify the SIEM settings for a configuration. UpdateSiemSettingsRequest struct { - ConfigID int `json:"-"` - Version int `json:"-"` - EnableForAllPolicies bool `json:"enableForAllPolicies"` - EnableSiem bool `json:"enableSiem"` - EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` - SiemDefinitionID int `json:"siemDefinitionId"` - FirewallPolicyIds []string `json:"firewallPolicyIds"` + ConfigID int `json:"-"` + Version int `json:"-"` + EnableForAllPolicies bool `json:"enableForAllPolicies"` + EnableSiem bool `json:"enableSiem"` + EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` + SiemDefinitionID int `json:"siemDefinitionId"` + FirewallPolicyIds []string `json:"firewallPolicyIds"` + Exceptions []Exception `json:"exceptions,omitempty"` } // UpdateSiemSettingsResponse is returned from a call to UpdateSiemSettings. UpdateSiemSettingsResponse struct { - EnableForAllPolicies bool `json:"enableForAllPolicies"` - EnableSiem bool `json:"enableSiem"` - EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` - SiemDefinitionID int `json:"siemDefinitionId"` - FirewallPolicyIds []string `json:"firewallPolicyIds"` + EnableForAllPolicies bool `json:"enableForAllPolicies"` + EnableSiem bool `json:"enableSiem"` + EnabledBotmanSiemEvents bool `json:"enabledBotmanSiemEvents"` + SiemDefinitionID int `json:"siemDefinitionId"` + FirewallPolicyIds []string `json:"firewallPolicyIds"` + Exceptions []Exception `json:"exceptions"` } // RemoveSiemSettingsRequest is used to remove the SIEM settings for a configuration. @@ -117,6 +127,16 @@ func (v UpdateSiemSettingsRequest) Validate() error { }.Filter() } +// Validate validates an Exception struct. +func (v Exception) Validate() error { + return validation.Errors{ + "Protection": validation.Validate(v.Protection, validation.Required, validation.In("botmanagement", "ipgeo", "rate", "urlProtection", "slowpost", "customrules", "waf", "apirequestconstraints", "clientrep", "malwareprotection", "aprProtection"). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'botmanagement', 'ipgeo', 'rate', 'urlProtection', 'slowpost', 'customrules', 'waf', 'apirequestconstraints', 'clientrep', 'malwareprotection', 'aprProtection'", v.Protection))), + "ActionTypes": validation.Validate(v.Protection, validation.Required, validation.In("alert", "deny", "all_custom", "abort", "allow", "delay", "ignore", "monitor", "slow", "tarpit"). + Error(fmt.Sprintf("value '%v' is invalid. Must be one of: 'alert', 'deny', 'all_custom', 'abort', 'allow', 'delay', 'ignore', 'monitor', 'slow', 'tarpit'", v.ActionTypes))), + }.Filter() +} + // Validate validates a RemoveSiemSettingsRequest. // Deprecated: this method will be removed in a future release. func (v RemoveSiemSettingsRequest) Validate() error { diff --git a/pkg/appsec/siem_settings_test.go b/pkg/appsec/siem_settings_test.go index d834319d..6240673d 100644 --- a/pkg/appsec/siem_settings_test.go +++ b/pkg/appsec/siem_settings_test.go @@ -188,8 +188,23 @@ func TestAppSec_UpdateSiemSettings(t *testing.T) { }{ "200 Success": { params: UpdateSiemSettingsRequest{ - ConfigID: 43253, - Version: 15, + ConfigID: 43253, + Version: 15, + EnableSiem: true, + Exceptions: []Exception{ + { + ActionTypes: []string{"*"}, + Protection: "botmanagement", + }, + { + ActionTypes: []string{"deny"}, + Protection: "ipgeo", + }, + { + ActionTypes: []string{"alert"}, + Protection: "rate", + }, + }, }, headers: http.Header{ "Content-Type": []string{"application/json;charset=UTF-8"}, diff --git a/pkg/appsec/testdata/TestSiemSettings/SiemSettings.json b/pkg/appsec/testdata/TestSiemSettings/SiemSettings.json index 415bc545..a6c8b4f3 100644 --- a/pkg/appsec/testdata/TestSiemSettings/SiemSettings.json +++ b/pkg/appsec/testdata/TestSiemSettings/SiemSettings.json @@ -2,5 +2,24 @@ "enableForAllPolicies": true, "enableSiem": true, "enabledBotmanSiemEvents": false, - "siemDefinitionId": 1 + "siemDefinitionId": 1, + "exceptions":[ + { + "actionTypes": [ + "*" + ], + "protection": "botmanagement" + }, + { + "actionTypes": [ + "alert" + ], + "protection": "ipgeo" + }, + { + "actionTypes": [ + "alert" + ], + "protection": "rate" + }] } \ No newline at end of file From 587a14199b8142a8eea778bc4bbdac3688f691ca Mon Sep 17 00:00:00 2001 From: Chaitanya Sanjay Bhangale Date: Thu, 26 Sep 2024 07:29:39 +0000 Subject: [PATCH 11/34] SECKSD-27927 Update cli-terraform for AAP/WAP changes Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/SECKSD-27927 to feature/sp-security --- CHANGELOG.md | 2 +- pkg/appsec/export_configuration.go | 44 ++++++++++++++++--- pkg/appsec/export_configuration_test.go | 6 ++- .../ExportConfiguration.json | 1 + 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 019754f5..1703c1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -272,7 +272,7 @@ * `UpdateSiemSettingsRequest` * `UpdateSiemSettingsResponse` - + * Added field `Source` in `GetExportConfigurationRequest` and field `TargetProduct` in `GetExportConfigurationResponse` diff --git a/pkg/appsec/export_configuration.go b/pkg/appsec/export_configuration.go index 0c208542..e4a1456c 100644 --- a/pkg/appsec/export_configuration.go +++ b/pkg/appsec/export_configuration.go @@ -3,11 +3,16 @@ package appsec import ( "context" "encoding/json" + "errors" "fmt" "net/http" + "net/url" "reflect" "time" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( @@ -32,8 +37,9 @@ type ( // GetExportConfigurationRequest is used to call GetExportConfiguration. GetExportConfigurationRequest struct { - ConfigID int `json:"configId"` - Version int `json:"version"` + ConfigID int `json:"configId"` + Version int `json:"version"` + Source string `json:"source,omitempty"` } // EvaluatingSecurityPolicy is returned from a call to GetExportConfiguration. @@ -59,6 +65,7 @@ type ( Production struct { Status string `json:"status"` } `json:"production"` + TargetProduct string `json:"targetProduct"` CreateDate time.Time `json:"-"` CreatedBy string `json:"createdBy"` SelectedHosts []string `json:"selectedHosts"` @@ -816,6 +823,19 @@ type ( } ) +// Validate validates an GetExportConfigurationRequest struct. +func (v GetExportConfigurationRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Source": validation.Validate(v.Source, validation.In("TF").Error( + fmt.Sprintf("value '%s' is invalid. Must be one of: 'TF' or empty", v.Source))), + }) +} + +var ( + // ErrGetExportConfiguration is returned when ErrGetExportConfiguration fails + ErrGetExportConfiguration = errors.New("get export configuration") +) + // UnmarshalJSON reads a ConditionsValue struct from its data argument. func (c *ConditionsValue) UnmarshalJSON(data []byte) error { var nums interface{} @@ -848,12 +868,22 @@ func (p *appsec) GetExportConfiguration(ctx context.Context, params GetExportCon logger := p.Log(ctx) logger.Debug("GetExportConfiguration") - uri := fmt.Sprintf( - "/appsec/v1/export/configs/%d/versions/%d", - params.ConfigID, - params.Version) + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetExportConfiguration, ErrStructValidation, err) + } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) + uri, err := url.Parse(fmt.Sprintf("/appsec/v1/export/configs/%d/versions/%d", params.ConfigID, params.Version)) + if err != nil { + return nil, fmt.Errorf("failed to parse url: %s", err) + } + + if params.Source != "" { + q := uri.Query() + q.Add("source", params.Source) + uri.RawQuery = q.Encode() + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("failed to create GetExportConfiguration request: %w", err) } diff --git a/pkg/appsec/export_configuration_test.go b/pkg/appsec/export_configuration_test.go index 5cf0c104..fdcefe6b 100644 --- a/pkg/appsec/export_configuration_test.go +++ b/pkg/appsec/export_configuration_test.go @@ -34,19 +34,21 @@ func TestAppSec_ListExportConfiguration(t *testing.T) { params: GetExportConfigurationRequest{ ConfigID: 43253, Version: 15, + Source: "TF", }, headers: http.Header{ "Content-Type": []string{"application/json"}, }, responseStatus: http.StatusOK, responseBody: string(respData), - expectedPath: "/appsec/v1/export/configs/43253/versions/15", + expectedPath: "/appsec/v1/export/configs/43253/versions/15?source=TF", expectedResponse: &result, }, "500 internal server error": { params: GetExportConfigurationRequest{ ConfigID: 43253, Version: 15, + Source: "TF", }, headers: http.Header{}, responseStatus: http.StatusInternalServerError, @@ -57,7 +59,7 @@ func TestAppSec_ListExportConfiguration(t *testing.T) { "detail": "Error fetching propertys", "status": 500 }`, - expectedPath: "/appsec/v1/export/configs/43253/versions/15", + expectedPath: "/appsec/v1/export/configs/43253/versions/15?source=TF", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", diff --git a/pkg/appsec/testdata/TestExportConfiguration/ExportConfiguration.json b/pkg/appsec/testdata/TestExportConfiguration/ExportConfiguration.json index cd8ddfe4..d33fc933 100644 --- a/pkg/appsec/testdata/TestExportConfiguration/ExportConfiguration.json +++ b/pkg/appsec/testdata/TestExportConfiguration/ExportConfiguration.json @@ -9,6 +9,7 @@ "production": { "status": "Inactive" }, + "targetProduct" : "KSD", "createDate": "2020-10-06T18:00:20Z", "createdBy": "akava-terraform", "selectedHosts": [ From 408e3f53a0b68cb46d1a2536e8076f266c8cba0b Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Thu, 11 Jul 2024 09:52:15 +0000 Subject: [PATCH 12/34] DXE-3998 Add support for GetPasswordPolicy endpoint --- CHANGELOG.md | 80 +++++++++++++++++++++++++++++++++++++++++ pkg/iam/mocks.go | 10 ++++++ pkg/iam/support.go | 45 +++++++++++++++++++++++ pkg/iam/support_test.go | 79 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1703c1a6..b445dbb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,83 @@ +# RELEASE NOTES + +## X.X.X (X X, X) + +#### BREAKING CHANGES: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#### FEATURES/ENHANCEMENTS: + + + + + + + + + + + + +* IAM + * Added method to get the password policy for the account + * [GetPasswordPolicy](https://techdocs.akamai.com/iam-api/reference/get-common-password-policy) + + + + + + + # EDGEGRID GOLANG RELEASE NOTES ## X.X.X (X X, X) diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index f3b5a392..87710477 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -74,6 +74,16 @@ func (m *Mock) SupportedTimezones(ctx context.Context) ([]Timezone, error) { return args.Get(0).([]Timezone), args.Error(1) } +func (m *Mock) GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) { + args := m.Called(ctx) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*GetPasswordPolicyResponse), args.Error(1) +} + func (m *Mock) ListProducts(ctx context.Context) ([]string, error) { args := m.Called(ctx) diff --git a/pkg/iam/support.go b/pkg/iam/support.go index 4e5598f9..b195d045 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -12,6 +12,11 @@ import ( type ( // Support is a list of IAM supported objects API interfaces Support interface { + // GetPasswordPolicy gets the password policy for the account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-password-policy + GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) + // ListProducts lists products a user can subscribe to and receive notifications for on the account // // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-notification-products @@ -48,6 +53,19 @@ type ( SupportedTimezones(context.Context) ([]Timezone, error) } + // GetPasswordPolicyResponse holds the response data from GetPasswordPolicy. + GetPasswordPolicyResponse struct { + CaseDiff int64 `json:"caseDif"` + MaxRepeating int64 `json:"maxRepeating"` + MinDigits int64 `json:"minDigits"` + MinLength int64 `json:"minLength"` + MinLetters int64 `json:"minLetters"` + MinNonAlpha int64 `json:"minNonAlpha"` + MinReuse int64 `json:"minReuse"` + PwClass string `json:"pwclass"` + RotateFrequency int64 `json:"rotateFrequency"` + } + // TimeoutPolicy encapsulates the response of the list timeout policies endpoint TimeoutPolicy struct { Name string `json:"name"` @@ -69,6 +87,9 @@ type ( ) var ( + // ErrGetPasswordPolicy is returned when GetPasswordPolicy fails + ErrGetPasswordPolicy = errors.New("get password policy") + // ErrListProducts is returned when ListProducts fails ErrListProducts = errors.New("list products") @@ -98,6 +119,30 @@ func (r ListStatesRequest) Validate() error { }.Filter() } +func (i *iam) GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) { + logger := i.Log(ctx) + logger.Debug("GetPasswordPolicy") + + getURL := "/identity-management/v3/user-admin/common/password-policy" + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPasswordPolicy, err) + } + + var result GetPasswordPolicyResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrGetPasswordPolicy, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrGetPasswordPolicy, i.Error(resp)) + } + + return &result, nil +} + func (i *iam) ListProducts(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("ListProducts") diff --git a/pkg/iam/support_test.go b/pkg/iam/support_test.go index b03d807e..d2245e94 100644 --- a/pkg/iam/support_test.go +++ b/pkg/iam/support_test.go @@ -11,6 +11,85 @@ import ( "github.com/tj/assert" ) +func TestIAM_GetPasswordPolicy(t *testing.T) { + tests := map[string]struct { + responseStatus int + responseBody string + expectedPath string + expectedResponse *GetPasswordPolicyResponse + withError func(*testing.T, error) + }{ + "200 OK": { + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/user-admin/common/password-policy", + responseBody: ` +{ + "caseDif": 0, + "maxRepeating": 1, + "minDigits": 1, + "minLength": 1, + "minLetters": 1, + "minNonAlpha": 0, + "minReuse": 1, + "pwclass": "test_class", + "rotateFrequency": 10 +} +`, + expectedResponse: &GetPasswordPolicyResponse{ + CaseDiff: 0, + MaxRepeating: 1, + MinDigits: 1, + MinLength: 1, + MinLetters: 1, + MinNonAlpha: 0, + MinReuse: 1, + PwClass: "test_class", + RotateFrequency: 10, + }, + }, + "500 internal server error": { + responseStatus: http.StatusInternalServerError, + expectedPath: "/identity-management/v3/user-admin/common/password-policy", + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +}`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.GetPasswordPolicy(context.Background()) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + func TestIAM_SupportedCountries(t *testing.T) { tests := map[string]struct { responseStatus int From 337b80591f570bbe6ff1dfcebedb4429dcbe06b5 Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Mon, 15 Jul 2024 12:39:39 +0000 Subject: [PATCH 13/34] DXE-3999 Update response and request structs for User interface --- CHANGELOG.md | 7 ++ pkg/iam/user.go | 192 +++++++++++++++++++++------------------ pkg/iam/user_test.go | 208 ++++++++++++++++++++++++------------------- 3 files changed, 231 insertions(+), 176 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b445dbb0..526cbb2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -359,6 +359,13 @@ +* IAM + * Updated structures: + * `User` with `AdditionalAuthenticationConfigured` and `Actions` + * `UserListItem` with `AdditionalAuthenticationConfigured` and `AdditionalAuthentication` + * `UserBasicInfo` with `AdditionalAuthentication` + * `UserActions` with `CanGenerateBypassCode` + * `UserNotificationOptions` with `APIClientCredentialExpiry` diff --git a/pkg/iam/user.go b/pkg/iam/user.go index 77976d94..dff3d74b 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -9,6 +9,7 @@ import ( "path" "strconv" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is" ) @@ -23,12 +24,12 @@ type ( // GetUser gets a specific user's profile // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identity + // See: https://techdocs.akamai.com/iam-api/reference/get-ui-identity GetUser(context.Context, GetUserRequest) (*User, error) // ListUsers returns a list of users who have access on this account // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identities + // See: https://techdocs.akamai.com/iam-api/reference/get-ui-identities ListUsers(context.Context, ListUsersRequest) ([]UserListItem, error) // RemoveUser removes a user identity @@ -38,7 +39,7 @@ type ( // UpdateUserAuthGrants edits what groups a user has access to, and how the user can interact with the objects in those groups // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-uiidentity-auth-grants + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-uiidentity-auth-grants UpdateUserAuthGrants(context.Context, UpdateUserAuthGrantsRequest) ([]AuthGrant, error) // UpdateUserInfo updates a user's information @@ -46,9 +47,9 @@ type ( // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-basic-info UpdateUserInfo(context.Context, UpdateUserInfoRequest) (*UserBasicInfo, error) - // UpdateUserNotifications subscribes or un-subscribe user to product notification emails + // UpdateUserNotifications subscribes or un-subscribes user to product notification emails // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-notifications + // See: https://techdocs.akamai.com/iam-api/reference/put-notifications UpdateUserNotifications(context.Context, UpdateUserNotificationsRequest) (*UserNotifications, error) // UpdateTFA updates a user's two-factor authentication setting and can reset tfa @@ -106,64 +107,73 @@ type ( // User describes the response of the get and create user endpoints User struct { UserBasicInfo - IdentityID string `json:"uiIdentityId"` - IsLocked bool `json:"isLocked"` - LastLoginDate string `json:"lastLoginDate,omitempty"` - PasswordExpiryDate string `json:"passwordExpiryDate,omitempty"` - TFAConfigured bool `json:"tfaConfigured"` - EmailUpdatePending bool `json:"emailUpdatePending"` - AuthGrants []AuthGrant `json:"authGrants,omitempty"` - Notifications UserNotifications `json:"notifications,omitempty"` + IdentityID string `json:"uiIdentityId"` + IsLocked bool `json:"isLocked"` + LastLoginDate string `json:"lastLoginDate,omitempty"` + PasswordExpiryDate string `json:"passwordExpiryDate,omitempty"` + TFAConfigured bool `json:"tfaConfigured"` + EmailUpdatePending bool `json:"emailUpdatePending"` + AuthGrants []AuthGrant `json:"authGrants,omitempty"` + Notifications UserNotifications `json:"notifications,omitempty"` + Actions *UserActions `json:"actions,omitempty"` + AdditionalAuthenticationConfigured bool `json:"additionalAuthenticationConfigured"` } // UserListItem describes the response of the list endpoint UserListItem struct { - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - UserName string `json:"uiUserName,omitempty"` - Email string `json:"email"` - TFAEnabled bool `json:"tfaEnabled"` - IdentityID string `json:"uiIdentityId"` - IsLocked bool `json:"isLocked"` - LastLoginDate string `json:"lastLoginDate,omitempty"` - TFAConfigured bool `json:"tfaConfigured"` - AccountID string `json:"accountId"` - Actions *UserActions `json:"actions,omitempty"` - AuthGrants []AuthGrant `json:"authGrants,omitempty"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + UserName string `json:"uiUserName,omitempty"` + Email string `json:"email"` + TFAEnabled bool `json:"tfaEnabled"` + IdentityID string `json:"uiIdentityId"` + IsLocked bool `json:"isLocked"` + LastLoginDate string `json:"lastLoginDate,omitempty"` + TFAConfigured bool `json:"tfaConfigured"` + AccountID string `json:"accountId"` + Actions *UserActions `json:"actions,omitempty"` + AuthGrants []AuthGrant `json:"authGrants,omitempty"` + AdditionalAuthentication Authentication `json:"additionalAuthentication"` + AdditionalAuthenticationConfigured bool `json:"additionalAuthenticationConfigured"` } // UserBasicInfo is the user basic info structure UserBasicInfo struct { - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - UserName string `json:"uiUserName,omitempty"` - Email string `json:"email"` - Phone string `json:"phone,omitempty"` - TimeZone string `json:"timeZone,omitempty"` - JobTitle string `json:"jobTitle"` - TFAEnabled bool `json:"tfaEnabled"` - SecondaryEmail string `json:"secondaryEmail,omitempty"` - MobilePhone string `json:"mobilePhone,omitempty"` - Address string `json:"address,omitempty"` - City string `json:"city,omitempty"` - State string `json:"state,omitempty"` - ZipCode string `json:"zipCode,omitempty"` - Country string `json:"country"` - ContactType string `json:"contactType,omitempty"` - PreferredLanguage string `json:"preferredLanguage,omitempty"` - SessionTimeOut *int `json:"sessionTimeOut,omitempty"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + UserName string `json:"uiUserName,omitempty"` + Email string `json:"email"` + Phone string `json:"phone,omitempty"` + TimeZone string `json:"timeZone,omitempty"` + JobTitle string `json:"jobTitle"` + TFAEnabled bool `json:"tfaEnabled"` + SecondaryEmail string `json:"secondaryEmail,omitempty"` + MobilePhone string `json:"mobilePhone,omitempty"` + Address string `json:"address,omitempty"` + City string `json:"city,omitempty"` + State string `json:"state,omitempty"` + ZipCode string `json:"zipCode,omitempty"` + Country string `json:"country"` + ContactType string `json:"contactType,omitempty"` + PreferredLanguage string `json:"preferredLanguage,omitempty"` + SessionTimeOut *int `json:"sessionTimeOut,omitempty"` + AdditionalAuthentication Authentication `json:"additionalAuthentication"` } // UserActions encapsulates permissions available to the user for this group UserActions struct { - APIClient bool `json:"apiClient"` - Delete bool `json:"delete"` - Edit bool `json:"edit"` - IsCloneable bool `json:"isCloneable"` - ResetPassword bool `json:"resetPassword"` - ThirdPartyAccess bool `json:"thirdPartyAccess"` - CanEditTFA bool `json:"canEditTFA"` - EditProfile bool `json:"editProfile"` + APIClient bool `json:"apiClient"` + Delete bool `json:"delete"` + Edit bool `json:"edit"` + IsCloneable bool `json:"isCloneable"` + ResetPassword bool `json:"resetPassword"` + ThirdPartyAccess bool `json:"thirdPartyAccess"` + CanEditTFA bool `json:"canEditTFA"` + CanEditMFA bool `json:"canEditMFA"` + CanEditNone bool `json:"canEditNone"` + EditProfile bool `json:"editProfile"` + EditRole bool `json:"editRole"` + CanGenerateBypassCode bool `json:"canGenerateBypassCode"` } // AuthGrant is user’s role assignments, per group @@ -193,10 +203,11 @@ type ( // UserNotificationOptions types of notification emails the user receives UserNotificationOptions struct { - NewUser bool `json:"newUserNotification"` - PasswordExpiry bool `json:"passwordExpiry"` - Proactive []string `json:"proactive"` - Upgrade []string `json:"upgrade"` + NewUser bool `json:"newUserNotification"` + PasswordExpiry bool `json:"passwordExpiry"` + Proactive []string `json:"proactive"` + Upgrade []string `json:"upgrade"` + APIClientCredentialExpiry bool `json:"apiClientCredentialExpiryNotification"` } // TFAActionType is a type for tfa action constants @@ -207,15 +218,24 @@ type ( IdentityID string Action TFAActionType } + + // Authentication is a type of additional authentication + Authentication string ) const ( - // TFAActionEnable ia an action value to use to enable tfa + // TFAActionEnable is an action value to use to enable tfa TFAActionEnable TFAActionType = "enable" - // TFAActionDisable ia an action value to use to disable tfa + // TFAActionDisable is an action value to use to disable tfa TFAActionDisable TFAActionType = "disable" - // TFAActionReset ia an action value to use to reset tfa + // TFAActionReset is an action value to use to reset tfa TFAActionReset TFAActionType = "reset" + // MFAAuthentication is authentication of type MFA + MFAAuthentication Authentication = "MFA" + // TFAAuthentication is authentication of type TFA + TFAAuthentication Authentication = "TFA" + // NoneAuthentication represents a state where no authentication method is configured + NoneAuthentication Authentication = "NONE" ) var ( @@ -246,10 +266,10 @@ var ( // Validate performs validation on AuthGrant func (r AuthGrant) Validate() error { - return validation.Errors{ - "group_id": validation.Validate(r.GroupID, validation.Required), - "role_id": validation.Validate(r.RoleID, validation.Required), - }.Filter() + return edgegriderr.ParseValidationErrors(validation.Errors{ + "GroupID": validation.Validate(r.GroupID, validation.Required), + "RoleID": validation.Validate(r.RoleID, validation.Required), + }) } // Validate validates CreateUserRequest @@ -266,9 +286,9 @@ func (r CreateUserRequest) Validate() error { // Validate validates GetUserRequest func (r GetUserRequest) Validate() error { - return validation.Errors{ - "uiIdentity": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + return edgegriderr.ParseValidationErrors(validation.Errors{ + "IdentityID": validation.Validate(r.IdentityID, validation.Required), + }) } // Validate validates UpdateUserInfoRequest @@ -286,17 +306,17 @@ func (r UpdateUserInfoRequest) Validate() error { // Validate validates UpdateUserNotificationsRequest func (r UpdateUserNotificationsRequest) Validate() error { - return validation.Errors{ - "uiIdentity": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + return edgegriderr.ParseValidationErrors(validation.Errors{ + "IdentityID": validation.Validate(r.IdentityID, validation.Required), + }) } // Validate validates UpdateUserAuthGrantsRequest func (r UpdateUserAuthGrantsRequest) Validate() error { - return validation.Errors{ - "uiIdentity": validation.Validate(r.IdentityID, validation.Required), - "authGrants": validation.Validate(r.AuthGrants, validation.Required), - }.Filter() + return edgegriderr.ParseValidationErrors(validation.Errors{ + "IdentityID": validation.Validate(r.IdentityID, validation.Required), + "AuthGrants": validation.Validate(r.AuthGrants, validation.Required), + }) } // Validate validates RemoveUserRequest @@ -353,7 +373,7 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) return nil, fmt.Errorf("%s: %w:\n%s", ErrGetUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } @@ -370,8 +390,8 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } - var rval User - resp, err := i.Exec(req, &rval) + var result User + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrGetUser, err) } @@ -380,11 +400,11 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) return nil, fmt.Errorf("%s: %w", ErrGetUser, i.Error(resp)) } - return &rval, nil + return &result, nil } func (i *iam) ListUsers(ctx context.Context, params ListUsersRequest) ([]UserListItem, error) { - u, err := url.Parse("/identity-management/v2/user-admin/ui-identities") + u, err := url.Parse("/identity-management/v3/user-admin/ui-identities") if err != nil { return nil, fmt.Errorf("%w: failed to parse the URL:\n%s", ErrListUsers, err) } @@ -393,7 +413,7 @@ func (i *iam) ListUsers(ctx context.Context, params ListUsersRequest) ([]UserLis q.Add("actions", strconv.FormatBool(params.Actions)) q.Add("authGrants", strconv.FormatBool(params.AuthGrants)) if params.GroupID != nil { - q.Add("groupId", strconv.FormatInt(int64(*params.GroupID), 10)) + q.Add("groupId", strconv.FormatInt(*params.GroupID, 10)) } u.RawQuery = q.Encode() @@ -447,7 +467,7 @@ func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGra return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserAuthGrants, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/auth-grants", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/auth-grants", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err) } @@ -457,9 +477,9 @@ func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGra return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err) } - rval := make([]AuthGrant, 0) + var result []AuthGrant - resp, err := i.Exec(req, &rval, params.AuthGrants) + resp, err := i.Exec(req, &result, params.AuthGrants) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserAuthGrants, err) } @@ -468,7 +488,7 @@ func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGra return nil, fmt.Errorf("%s: %w", ErrUpdateUserAuthGrants, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) UpdateUserInfo(ctx context.Context, params UpdateUserInfoRequest) (*UserBasicInfo, error) { @@ -504,7 +524,7 @@ func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNoti return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserNotifications, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/notifications", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/notifications", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err) } @@ -514,8 +534,8 @@ func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNoti return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err) } - var rval UserNotifications - resp, err := i.Exec(req, &rval, params.Notifications) + var result UserNotifications + resp, err := i.Exec(req, &result, params.Notifications) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserNotifications, err) } @@ -524,7 +544,7 @@ func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNoti return nil, fmt.Errorf("%s: %w", ErrUpdateUserNotifications, i.Error(resp)) } - return &rval, nil + return &result, nil } func (i *iam) UpdateTFA(ctx context.Context, params UpdateTFARequest) error { diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index bf7f6458..f8c0b0a5 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -26,17 +26,18 @@ func TestIAM_CreateUser(t *testing.T) { "201 OK": { params: CreateUserRequest{ UserBasicInfo: UserBasicInfo{ - FirstName: "John", - LastName: "Doe", - Email: "john.doe@mycompany.com", - Phone: "(123) 321-1234", - Country: "USA", - State: "CA", + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + AdditionalAuthentication: NoneAuthentication, }, AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, Notifications: UserNotifications{}, }, - requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}],"notifications":{"enableEmailNotifications":false,"options":{"newUserNotification":false,"passwordExpiry":false,"proactive":null,"upgrade":null}}}`, + requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","additionalAuthentication":"NONE","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}],"notifications":{"enableEmailNotifications":false,"options":{"newUserNotification":false,"passwordExpiry":false,"proactive":null,"upgrade":null,"apiClientCredentialExpiryNotification":false}}}`, responseStatus: http.StatusCreated, responseBody: ` { @@ -46,19 +47,23 @@ func TestIAM_CreateUser(t *testing.T) { "email": "john.doe@mycompany.com", "phone": "(123) 321-1234", "state": "CA", - "country": "USA" + "country": "USA", + "additionalAuthenticationConfigured": false, + "additionalAuthentication": "NONE" }`, expectedPath: "/identity-management/v2/user-admin/ui-identities?sendEmail=false", expectedResponse: &User{ IdentityID: "A-BC-1234567", UserBasicInfo: UserBasicInfo{ - FirstName: "John", - LastName: "Doe", - Email: "john.doe@mycompany.com", - Phone: "(123) 321-1234", - Country: "USA", - State: "CA", + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + AdditionalAuthentication: NoneAuthentication, }, + AdditionalAuthenticationConfigured: false, }, }, "500 internal server error": { @@ -147,7 +152,7 @@ func TestIAM_GetUser(t *testing.T) { "state": "CA", "country": "USA" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", expectedResponse: &User{ IdentityID: "A-BC-1234567", UserBasicInfo: UserBasicInfo{ @@ -172,7 +177,7 @@ func TestIAM_GetUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -222,7 +227,7 @@ func TestIam_ListUsers(t *testing.T) { Actions: true, }, responseStatus: http.StatusOK, - expectedPath: "/identity-management/v2/user-admin/ui-identities?actions=true&authGrants=true&groupId=12345", + expectedPath: "/identity-management/v3/user-admin/ui-identities?actions=true&authGrants=true&groupId=12345", responseBody: `[ { "uiIdentityId": "A-B-123456", @@ -235,6 +240,8 @@ func TestIam_ListUsers(t *testing.T) { "tfaEnabled": true, "tfaConfigured": true, "isLocked": false, + "additionalAuthentication": "TFA", + "additionalAuthenticationConfigured": false, "actions": { "resetPassword": true, "delete": true, @@ -243,7 +250,9 @@ func TestIam_ListUsers(t *testing.T) { "thirdPartyAccess": true, "isCloneable": true, "editProfile": true, - "canEditTFA": false + "canEditTFA": true, + "canEditMFA": true, + "canEditNone": true }, "authGrants": [ { @@ -259,16 +268,18 @@ func TestIam_ListUsers(t *testing.T) { ]`, expectedResponse: []UserListItem{ { - IdentityID: "A-B-123456", - FirstName: "John", - LastName: "Doe", - UserName: "johndoe", - Email: "john.doe@mycompany.com", - AccountID: "1-123A", - TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", - TFAConfigured: true, - IsLocked: false, + IdentityID: "A-B-123456", + FirstName: "John", + LastName: "Doe", + UserName: "johndoe", + Email: "john.doe@mycompany.com", + AccountID: "1-123A", + TFAEnabled: true, + LastLoginDate: "2016-01-13T17:53:57Z", + TFAConfigured: true, + IsLocked: false, + AdditionalAuthentication: TFAAuthentication, + AdditionalAuthenticationConfigured: false, Actions: &UserActions{ APIClient: true, Delete: true, @@ -277,6 +288,9 @@ func TestIam_ListUsers(t *testing.T) { ResetPassword: true, ThirdPartyAccess: true, EditProfile: true, + CanEditMFA: true, + CanEditNone: true, + CanEditTFA: true, }, AuthGrants: []AuthGrant{ { @@ -295,7 +309,7 @@ func TestIam_ListUsers(t *testing.T) { GroupID: ptr.To(int64(12345)), }, responseStatus: http.StatusOK, - expectedPath: "/identity-management/v2/user-admin/ui-identities?actions=false&authGrants=false&groupId=12345", + expectedPath: "/identity-management/v3/user-admin/ui-identities?actions=false&authGrants=false&groupId=12345", responseBody: `[ { "uiIdentityId": "A-B-123456", @@ -307,27 +321,31 @@ func TestIam_ListUsers(t *testing.T) { "lastLoginDate": "2016-01-13T17:53:57Z", "tfaEnabled": true, "tfaConfigured": true, - "isLocked": false + "isLocked": false, + "additionalAuthentication": "MFA", + "additionalAuthenticationConfigured": true } ]`, expectedResponse: []UserListItem{ { - IdentityID: "A-B-123456", - FirstName: "John", - LastName: "Doe", - UserName: "johndoe", - Email: "john.doe@mycompany.com", - AccountID: "1-123A", - TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", - TFAConfigured: true, - IsLocked: false, + IdentityID: "A-B-123456", + FirstName: "John", + LastName: "Doe", + UserName: "johndoe", + Email: "john.doe@mycompany.com", + AccountID: "1-123A", + TFAEnabled: true, + LastLoginDate: "2016-01-13T17:53:57Z", + TFAConfigured: true, + IsLocked: false, + AdditionalAuthenticationConfigured: true, + AdditionalAuthentication: MFAAuthentication, }, }, }, - "no group id": { + "200 OK, no group id": { params: ListUsersRequest{}, - expectedPath: "/identity-management/v2/user-admin/ui-identities?actions=false&authGrants=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities?actions=false&authGrants=false", responseBody: `[ { "uiIdentityId": "A-B-123456", @@ -339,21 +357,25 @@ func TestIam_ListUsers(t *testing.T) { "lastLoginDate": "2016-01-13T17:53:57Z", "tfaEnabled": true, "tfaConfigured": true, - "isLocked": false + "isLocked": false, + "additionalAuthentication": "TFA", + "additionalAuthenticationConfigured": true } ]`, expectedResponse: []UserListItem{ { - IdentityID: "A-B-123456", - FirstName: "John", - LastName: "Doe", - UserName: "johndoe", - Email: "john.doe@mycompany.com", - AccountID: "1-123A", - TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", - TFAConfigured: true, - IsLocked: false, + IdentityID: "A-B-123456", + FirstName: "John", + LastName: "Doe", + UserName: "johndoe", + Email: "john.doe@mycompany.com", + AccountID: "1-123A", + TFAEnabled: true, + LastLoginDate: "2016-01-13T17:53:57Z", + TFAConfigured: true, + IsLocked: false, + AdditionalAuthentication: TFAAuthentication, + AdditionalAuthenticationConfigured: true, }, }, responseStatus: http.StatusOK, @@ -365,7 +387,7 @@ func TestIam_ListUsers(t *testing.T) { Actions: true, }, responseStatus: http.StatusInternalServerError, - expectedPath: "/identity-management/v2/user-admin/ui-identities?actions=true&authGrants=true&groupId=12345", + expectedPath: "/identity-management/v3/user-admin/ui-identities?actions=true&authGrants=true&groupId=12345", responseBody: ` { "type": "internal_error", @@ -419,19 +441,20 @@ func TestIAM_UpdateUserInfo(t *testing.T) { params: UpdateUserInfoRequest{ IdentityID: "1-ABCDE", User: UserBasicInfo{ - FirstName: "John", - LastName: "Doe", - Email: "john.doe@mycompany.com", - Phone: "(123) 321-1234", - Country: "USA", - State: "CA", - PreferredLanguage: "English", - ContactType: "Billing", - SessionTimeOut: ptr.To(30), - TimeZone: "GMT", + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + PreferredLanguage: "English", + ContactType: "Billing", + SessionTimeOut: ptr.To(30), + TimeZone: "GMT", + AdditionalAuthentication: NoneAuthentication, }, }, - requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","timeZone":"GMT","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","contactType":"Billing","preferredLanguage":"English","sessionTimeOut":30}`, + requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","timeZone":"GMT","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","contactType":"Billing","preferredLanguage":"English","sessionTimeOut":30,"additionalAuthentication":"NONE"}`, responseStatus: http.StatusOK, responseBody: ` { @@ -444,20 +467,22 @@ func TestIAM_UpdateUserInfo(t *testing.T) { "preferredLanguage": "English", "contactType": "Billing", "sessionTimeOut": 30, - "timeZone": "GMT" + "timeZone": "GMT", + "additionalAuthentication": "NONE" }`, expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/basic-info", expectedResponse: &UserBasicInfo{ - FirstName: "John", - LastName: "Doe", - Email: "john.doe@mycompany.com", - Phone: "(123) 321-1234", - Country: "USA", - State: "CA", - PreferredLanguage: "English", - ContactType: "Billing", - SessionTimeOut: ptr.To(30), - TimeZone: "GMT", + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + PreferredLanguage: "English", + ContactType: "Billing", + SessionTimeOut: ptr.To(30), + TimeZone: "GMT", + AdditionalAuthentication: NoneAuthentication, }, }, "500 internal server error": { @@ -541,14 +566,15 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { Notifications: UserNotifications{ EnableEmail: true, Options: UserNotificationOptions{ - Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, - Proactive: []string{"EdgeScape", "EdgeSuite (HTTP Content Delivery)"}, - PasswordExpiry: true, - NewUser: true, + Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, + Proactive: []string{"EdgeScape", "EdgeSuite (HTTP Content Delivery)"}, + PasswordExpiry: true, + NewUser: true, + APIClientCredentialExpiry: true, }, }, }, - requestBody: `{"enableEmailNotifications":true,"options":{"newUserNotification":true,"passwordExpiry":true,"proactive":["EdgeScape","EdgeSuite (HTTP Content Delivery)"],"upgrade":["NetStorage","Other Upgrade Notifications (Planned)"]}}`, + requestBody: `{"enableEmailNotifications":true,"options":{"newUserNotification":true,"passwordExpiry":true,"proactive":["EdgeScape","EdgeSuite (HTTP Content Delivery)"],"upgrade":["NetStorage","Other Upgrade Notifications (Planned)"],"apiClientCredentialExpiryNotification":true}}`, responseStatus: http.StatusOK, responseBody: ` { @@ -563,17 +589,19 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { "EdgeSuite (HTTP Content Delivery)" ], "passwordExpiry": true, - "newUserNotification": true + "newUserNotification": true, + "apiClientCredentialExpiryNotification": true } }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/notifications", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/notifications", expectedResponse: &UserNotifications{ EnableEmail: true, Options: UserNotificationOptions{ - Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, - Proactive: []string{"EdgeScape", "EdgeSuite (HTTP Content Delivery)"}, - PasswordExpiry: true, - NewUser: true, + Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, + Proactive: []string{"EdgeScape", "EdgeSuite (HTTP Content Delivery)"}, + PasswordExpiry: true, + NewUser: true, + APIClientCredentialExpiry: true, }, }, }, @@ -598,7 +626,7 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/notifications", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/notifications", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -676,7 +704,7 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { ] } ]`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/auth-grants", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/auth-grants", expectedResponse: []AuthGrant{ { GroupID: 12345, @@ -712,7 +740,7 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/auth-grants", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/auth-grants", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", From 54f02fe25fff0a5c07cdb1c46adf068abbd653da Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Thu, 18 Jul 2024 09:27:03 +0000 Subject: [PATCH 14/34] DXE-4002 Add support for IAM IP Allowlist interface --- CHANGELOG.md | 6 +- pkg/iam/iam.go | 1 + pkg/iam/ip_allowlist.go | 115 +++++++++++++++++++++ pkg/iam/ip_allowlist_test.go | 195 +++++++++++++++++++++++++++++++++++ pkg/iam/mocks.go | 22 ++++ 5 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 pkg/iam/ip_allowlist.go create mode 100644 pkg/iam/ip_allowlist_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 526cbb2b..3e90a6b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -394,7 +394,11 @@ - +* IAM + * Added support for new endpoints: + * [DisableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable) + * [EnableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable) + * [GetIPAllowlistStatus](https://techdocs.akamai.com/iam-api/reference/get-allowlist-status) diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index e3476951..d08569e1 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -17,6 +17,7 @@ type ( IAM interface { BlockedProperties Groups + IPAllowlist Properties Roles Support diff --git a/pkg/iam/ip_allowlist.go b/pkg/iam/ip_allowlist.go new file mode 100644 index 00000000..282e5972 --- /dev/null +++ b/pkg/iam/ip_allowlist.go @@ -0,0 +1,115 @@ +package iam + +import ( + "context" + "errors" + "fmt" + "net/http" +) + +type ( + // IPAllowlist is the IAM IP allowlist API interface + IPAllowlist interface { + // DisableIPAllowlist disables IP allowlist on your account. After you disable IP allowlist, + // users can access Control Center regardless of their IP address or who assigns it. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable + DisableIPAllowlist(context.Context) error + + // EnableIPAllowlist enables IP allowlist on your account. Before you enable IP allowlist, + // add at least one IP address to allow access to Control Center. + // The allowlist can't be empty with IP allowlist enabled. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable + EnableIPAllowlist(context.Context) error + + // GetIPAllowlistStatus indicates whether IP allowlist is enabled or disabled on your account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-status + GetIPAllowlistStatus(context.Context) (*GetIPAllowlistStatusResponse, error) + } + + // GetIPAllowlistStatusResponse contains response from GetIPAllowlistStatus operation + GetIPAllowlistStatusResponse struct { + Enabled bool `json:"enabled"` + } +) + +var ( + // ErrDisableIPAllowlist is returned when DisableIPAllowlist fails + ErrDisableIPAllowlist = errors.New("disable ip allowlist") + // ErrEnableIPAllowlist is returned when EnableIPAllowlist fails + ErrEnableIPAllowlist = errors.New("enable ip allowlist") + // ErrGetIPAllowlistStatus is returned when GetIPAllowlistStatus fails + ErrGetIPAllowlistStatus = errors.New("get ip allowlist status") +) + +func (i *iam) DisableIPAllowlist(ctx context.Context) error { + logger := i.Log(ctx) + logger.Debug("DisableIPAllowlist") + + uri := "/identity-management/v3/user-admin/ip-acl/allowlist/disable" + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDisableIPAllowlist, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDisableIPAllowlist, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDisableIPAllowlist, i.Error(resp)) + } + + return nil +} + +func (i *iam) EnableIPAllowlist(ctx context.Context) error { + logger := i.Log(ctx) + logger.Debug("EnableIPAllowlist") + + uri := "/identity-management/v3/user-admin/ip-acl/allowlist/enable" + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrEnableIPAllowlist, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrEnableIPAllowlist, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrEnableIPAllowlist, i.Error(resp)) + } + + return nil +} + +func (i *iam) GetIPAllowlistStatus(ctx context.Context) (*GetIPAllowlistStatusResponse, error) { + logger := i.Log(ctx) + logger.Debug("GetIPAllowlistStatus") + + uri := "/identity-management/v3/user-admin/ip-acl/allowlist/status" + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetIPAllowlistStatus, err) + } + + var result GetIPAllowlistStatusResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrGetIPAllowlistStatus, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrGetIPAllowlistStatus, i.Error(resp)) + } + + return &result, nil +} diff --git a/pkg/iam/ip_allowlist_test.go b/pkg/iam/ip_allowlist_test.go new file mode 100644 index 00000000..4e8a0c95 --- /dev/null +++ b/pkg/iam/ip_allowlist_test.go @@ -0,0 +1,195 @@ +package iam + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tj/assert" +) + +func TestDisableIPAllowlist(t *testing.T) { + tests := map[string]struct { + responseStatus int + expectedPath string + responseBody string + withError func(*testing.T, error) + }{ + "204 no content": { + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/disable", + }, + "500 internal server error": { + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/disable", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + if test.responseBody != "" { + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + } + })) + client := mockAPIClient(t, mockServer) + err := client.DisableIPAllowlist(context.Background()) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestEnableIPAllowlist(t *testing.T) { + tests := map[string]struct { + responseStatus int + expectedPath string + responseBody string + withError func(*testing.T, error) + }{ + "204 no content": { + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/enable", + }, + "500 internal server error": { + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/enable", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + if test.responseBody != "" { + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + } + })) + client := mockAPIClient(t, mockServer) + err := client.EnableIPAllowlist(context.Background()) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestGetIPAllowlistStatus(t *testing.T) { + tests := map[string]struct { + responseStatus int + responseBody string + expectedPath string + expectedResponse *GetIPAllowlistStatusResponse + withError func(*testing.T, error) + }{ + "200 OK enabled true": { + responseStatus: 200, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/status", + responseBody: ` + { + "enabled": true + }`, + expectedResponse: &GetIPAllowlistStatusResponse{ + Enabled: true, + }, + }, + "200 OK enabled false": { + responseStatus: 200, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/status", + responseBody: ` + { + "enabled": false + }`, + expectedResponse: &GetIPAllowlistStatusResponse{ + Enabled: false, + }, + }, + "500 internal server error": { + responseStatus: 500, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/status", + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +} +`, + withError: func(t *testing.T, e error) { + err := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + StatusCode: 500, + Detail: "Error making request", + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.GetIPAllowlistStatus(context.Background()) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 87710477..e27a73ea 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -372,3 +372,25 @@ func (m *Mock) MapPropertyNameToID(ctx context.Context, request MapPropertyNameT return args.Get(0).(*int64), args.Error(1) } + +func (m *Mock) DisableIPAllowlist(ctx context.Context) error { + args := m.Called(ctx) + + return args.Error(0) +} + +func (m *Mock) EnableIPAllowlist(ctx context.Context) error { + args := m.Called(ctx) + + return args.Error(0) +} + +func (m *Mock) GetIPAllowlistStatus(ctx context.Context) (*GetIPAllowlistStatusResponse, error) { + args := m.Called(ctx) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*GetIPAllowlistStatusResponse), args.Error(1) +} From 7f12b62c3175057751e3e0c0e5e2fd9b03d93bdb Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Mon, 22 Jul 2024 07:33:49 +0000 Subject: [PATCH 15/34] DXE-4000 Add support for ListAllowedCPCodes --- CHANGELOG.md | 4 + pkg/iam/helper.go | 103 ++++++++++++++++++++++ pkg/iam/helper_test.go | 188 +++++++++++++++++++++++++++++++++++++++++ pkg/iam/iam.go | 1 + pkg/iam/mocks.go | 10 +++ 5 files changed, 306 insertions(+) create mode 100644 pkg/iam/helper.go create mode 100644 pkg/iam/helper_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e90a6b1..ca760a6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -389,7 +389,11 @@ +* IAM + * Added Helper APIs + * [ListAllowedCPCodes](https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes) + diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go new file mode 100644 index 00000000..f2583cf7 --- /dev/null +++ b/pkg/iam/helper.go @@ -0,0 +1,103 @@ +package iam + +import ( + "context" + "errors" + "fmt" + "net/http" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // Helper is a list of IAM helper API interfaces + Helper interface { + // ListAllowedCPCodes lists available CP codes for a user + // + // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes + ListAllowedCPCodes(context.Context, ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) + } + + // ListAllowedCPCodesRequest contains the request parameter for the list of allowed CP codes endpoint + ListAllowedCPCodesRequest struct { + UserName string + ListAllowedCPCodesRequestBody + } + + // ListAllowedCPCodesRequestBody contains the filtering parameters for the list of allowed CP codes endpoint + ListAllowedCPCodesRequestBody struct { + ClientType string `json:"clientType"` + Groups []AllowedCPCodesGroup `json:"groups"` + } + + // AllowedCPCodesGroup contains the group parameters for the list of allowed CP codes endpoint + AllowedCPCodesGroup struct { + GroupID int64 `json:"groupId,omitempty"` + RoleID int64 `json:"roleId,omitempty"` + GroupName string `json:"groupName,omitempty"` + IsBlocked bool `json:"isBlocked,omitempty"` + ParentGroupID int64 `json:"parentGroupId,omitempty"` + RoleDescription string `json:"roleDescription,omitempty"` + RoleName string `json:"roleName,omitempty"` + SubGroups []AllowedCPCodesGroup `json:"subGroups,omitempty"` + } + + // ListAllowedCPCodesResponse contains response for the list of allowed CP codes endpoint + ListAllowedCPCodesResponse []ListAllowedCPCodesResponseItem + + // ListAllowedCPCodesResponseItem contains single item of the response for allowed CP codes endpoint + ListAllowedCPCodesResponseItem struct { + Name string `json:"name"` + Value int `json:"value"` + } +) + +var ( + // ErrListAllowedCPCodes is returned when ListAllowedCPCodes fails + ErrListAllowedCPCodes = errors.New("list allowed CP codes") +) + +// Validate validates ListAllowedCPCodesRequest +func (r ListAllowedCPCodesRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "UserName": validation.Validate(r.UserName, validation.Required), + "Body": validation.Validate(r.ListAllowedCPCodesRequestBody, validation.Required), + }) +} + +// Validate validates ListAllowedCPCodesRequestBody +func (r ListAllowedCPCodesRequestBody) Validate() error { + return validation.Errors{ + "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In("CLIENT", "USER_CLIENT", "SERVICE_ACCOUNT").Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'", r.ClientType))), + "Groups": validation.Validate(r.Groups, validation.Required.When(r.ClientType == "SERVICE_ACCOUNT")), + }.Filter() +} + +func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAllowedCPCodes") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrListAllowedCPCodes, ErrStructValidation, err) + } + + url := fmt.Sprintf("/identity-management/v3/users/%s/allowed-cpcodes", params.UserName) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedCPCodes, err) + } + + var result ListAllowedCPCodesResponse + resp, err := i.Exec(req, &result, params.ListAllowedCPCodesRequestBody) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListAllowedCPCodes, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListAllowedCPCodes, i.Error(resp)) + } + + return result, nil +} diff --git a/pkg/iam/helper_test.go b/pkg/iam/helper_test.go new file mode 100644 index 00000000..b51063d9 --- /dev/null +++ b/pkg/iam/helper_test.go @@ -0,0 +1,188 @@ +package iam + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tj/assert" +) + +func TestIAMListAllowedCPCodes(t *testing.T) { + tests := map[string]struct { + params ListAllowedCPCodesRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse ListAllowedCPCodesResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListAllowedCPCodesRequest{ + UserName: "jsmith", + ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + ClientType: "CLIENT", + }, + }, + responseStatus: http.StatusOK, + responseBody: `[ + { + "name": "Stream Analyzer (36915)", + "value": 36915 + }, + { + "name": "plopessa-uvod-ns (373118)", + "value": 373118 + }, + { + "name": "ArunNS (866797)", + "value": 866797 + }, + { + "name": "1234 (933076)", + "value": 933076 + } +]`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-cpcodes", + expectedResponse: ListAllowedCPCodesResponse{ + { + Name: "Stream Analyzer (36915)", + Value: 36915, + }, + { + Name: "plopessa-uvod-ns (373118)", + Value: 373118, + }, + { + Name: "ArunNS (866797)", + Value: 866797, + }, + { + Name: "1234 (933076)", + Value: 933076, + }, + }, + }, + "200 OK with groups": { + params: ListAllowedCPCodesRequest{ + UserName: "jsmith", + ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + ClientType: "SERVICE_ACCOUNT", + Groups: []AllowedCPCodesGroup{ + { + GroupID: 1, + }, + }, + }, + }, + responseStatus: http.StatusOK, + responseBody: `[ + { + "name": "Stream Analyzer (36915)", + "value": 36915 + }, + { + "name": "plopessa-uvod-ns (373118)", + "value": 373118 + }, + { + "name": "ArunNS (866797)", + "value": 866797 + }, + { + "name": "1234 (933076)", + "value": 933076 + } +]`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-cpcodes", + expectedResponse: ListAllowedCPCodesResponse{ + { + Name: "Stream Analyzer (36915)", + Value: 36915, + }, + { + Name: "plopessa-uvod-ns (373118)", + Value: 373118, + }, + { + Name: "ArunNS (866797)", + Value: 866797, + }, + { + Name: "1234 (933076)", + Value: 933076, + }, + }, + }, + "500 internal server error": { + params: ListAllowedCPCodesRequest{ + UserName: "jsmith", + ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + ClientType: "CLIENT", + }, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-cpcodes", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "missing user name and client type": { + params: ListAllowedCPCodesRequest{}, + withError: func(t *testing.T, err error) { + want := ErrStructValidation + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + assert.Contains(t, err.Error(), "list allowed CP codes: struct validation:\nClientType: cannot be blank\nUserName: cannot be blank") + }, + }, + "group is required for client type SERVICE_ACCOUNT": { + params: ListAllowedCPCodesRequest{ + UserName: "jsmith", + ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + ClientType: "SERVICE_ACCOUNT", + }, + }, + withError: func(t *testing.T, err error) { + want := ErrStructValidation + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + assert.Contains(t, err.Error(), "list allowed CP codes: struct validation:\nGroups: cannot be blank") + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListAllowedCPCodes(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index d08569e1..e3eee488 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -17,6 +17,7 @@ type ( IAM interface { BlockedProperties Groups + Helper IPAllowlist Properties Roles diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index e27a73ea..d175ad9a 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -394,3 +394,13 @@ func (m *Mock) GetIPAllowlistStatus(ctx context.Context) (*GetIPAllowlistStatusR return args.Get(0).(*GetIPAllowlistStatusResponse), args.Error(1) } + +func (m *Mock) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) { + args := m.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListAllowedCPCodesResponse), args.Error(1) +} From be64c7c29398eedd9b77a9a27d1a3c8ebe354d81 Mon Sep 17 00:00:00 2001 From: rbhatved Date: Thu, 18 Jul 2024 16:27:30 +0530 Subject: [PATCH 16/34] DXE-3994 Migrated V2 endpoints to V3 in IAM --- CHANGELOG.md | 5 ++ pkg/iam/blocked_properties.go | 10 +-- pkg/iam/blocked_properties_test.go | 16 ++-- pkg/iam/groups.go | 48 +++++----- pkg/iam/groups_test.go | 32 +++---- pkg/iam/iam.go | 11 +++ pkg/iam/mocks.go | 12 +++ pkg/iam/roles.go | 24 ++--- pkg/iam/roles_test.go | 30 +++---- pkg/iam/support.go | 30 +++---- pkg/iam/support_test.go | 28 +++--- pkg/iam/user.go | 130 +++++++++++++++++++++++---- pkg/iam/user_lock.go | 12 +-- pkg/iam/user_lock_test.go | 16 ++-- pkg/iam/user_password.go | 8 +- pkg/iam/user_password_test.go | 16 ++-- pkg/iam/user_test.go | 138 +++++++++++++++++++++++++++-- 17 files changed, 405 insertions(+), 161 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca760a6a..ffb03692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ #### BREAKING CHANGES: +* IAM + * Migrated V2 endpoints to V3. + * Added new methods: + * [UpdateMFA](https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication) + * [ResetMFA](https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication) diff --git a/pkg/iam/blocked_properties.go b/pkg/iam/blocked_properties.go index aa64d353..b03d17ff 100644 --- a/pkg/iam/blocked_properties.go +++ b/pkg/iam/blocked_properties.go @@ -15,12 +15,12 @@ type ( BlockedProperties interface { // ListBlockedProperties returns all properties a user doesn't have access to in a group // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-blocked-properties + // See: https://techdocs.akamai.com/iam-api/reference/get-blocked-properties ListBlockedProperties(context.Context, ListBlockedPropertiesRequest) ([]int64, error) - // UpdateBlockedProperties removes or grant user access to properties + // UpdateBlockedProperties removes or grants user access to properties // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-blocked-properties + // See: https://techdocs.akamai.com/iam-api/reference/put-blocked-properties UpdateBlockedProperties(context.Context, UpdateBlockedPropertiesRequest) ([]int64, error) } @@ -67,7 +67,7 @@ func (i *iam) ListBlockedProperties(ctx context.Context, params ListBlockedPrope return nil, fmt.Errorf("%s: %w:\n%s", ErrListBlockedProperties, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListBlockedProperties, err) } @@ -95,7 +95,7 @@ func (i *iam) UpdateBlockedProperties(ctx context.Context, params UpdateBlockedP return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateBlockedProperties, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrUpdateBlockedProperties, err) } diff --git a/pkg/iam/blocked_properties_test.go b/pkg/iam/blocked_properties_test.go index e0ece149..eaebd305 100644 --- a/pkg/iam/blocked_properties_test.go +++ b/pkg/iam/blocked_properties_test.go @@ -25,7 +25,7 @@ func TestIam_ListBlockedProperties(t *testing.T) { IdentityID: "1-ABCDE", }, responseStatus: http.StatusOK, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: `[ 10977166 ]`, @@ -39,7 +39,7 @@ func TestIam_ListBlockedProperties(t *testing.T) { IdentityID: "1-ABCDE", }, responseStatus: http.StatusOK, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: `[ ]`, @@ -52,7 +52,7 @@ func TestIam_ListBlockedProperties(t *testing.T) { IdentityID: "1-ABCDE", }, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/123450000/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/123450000/blocked-properties", responseBody: ` { "instance": "", @@ -80,7 +80,7 @@ func TestIam_ListBlockedProperties(t *testing.T) { IdentityID: "1-ABCDE", }, responseStatus: http.StatusInternalServerError, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: ` { "type": "internal_error", @@ -136,7 +136,7 @@ func TestIam_UpdateBlockedProperties(t *testing.T) { Properties: []int64{10977166, 10977167}, }, responseStatus: http.StatusOK, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: `[ 10977166,10977167 ]`, @@ -151,7 +151,7 @@ func TestIam_UpdateBlockedProperties(t *testing.T) { Properties: []int64{0, 1}, }, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: ` { "instance": "", @@ -180,7 +180,7 @@ func TestIam_UpdateBlockedProperties(t *testing.T) { Properties: []int64{10977166, 10977167}, }, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/123450000/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/123450000/blocked-properties", responseBody: ` { "instance": "", @@ -208,7 +208,7 @@ func TestIam_UpdateBlockedProperties(t *testing.T) { IdentityID: "1-ABCDE", }, responseStatus: http.StatusInternalServerError, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/groups/12345/blocked-properties", responseBody: ` { "type": "internal_error", diff --git a/pkg/iam/groups.go b/pkg/iam/groups.go index cc0d5b80..bfadee26 100644 --- a/pkg/iam/groups.go +++ b/pkg/iam/groups.go @@ -16,37 +16,37 @@ type ( Groups interface { // CreateGroup creates a new group within a parent group_id specified in the request // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-group + // See: https://techdocs.akamai.com/iam-api/reference/post-group CreateGroup(context.Context, GroupRequest) (*Group, error) // GetGroup returns a group's details // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-group + // See: https://techdocs.akamai.com/iam-api/reference/get-group GetGroup(context.Context, GetGroupRequest) (*Group, error) // ListAffectedUsers lists users who are affected when a group is moved // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-move-affected-users + // See: https://techdocs.akamai.com/iam-api/reference/get-move-affected-users ListAffectedUsers(context.Context, ListAffectedUsersRequest) ([]GroupUser, error) // ListGroups lists all groups in which you have a scope of admin for the current account and contract type // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-groups + // See: https://techdocs.akamai.com/iam-api/reference/get-groups ListGroups(context.Context, ListGroupsRequest) ([]Group, error) // RemoveGroup removes a group based on group_id. We can only delete a sub-group, and only if that sub-group doesn't include any users // - // See: https://techdocs.akamai.com/iam-user-admin/reference/delete-group + // See: https://techdocs.akamai.com/iam-api/reference/delete-group RemoveGroup(context.Context, RemoveGroupRequest) error // UpdateGroupName changes the name of the group // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-group + // See: https://techdocs.akamai.com/iam-api/reference/put-group UpdateGroupName(context.Context, GroupRequest) (*Group, error) - // MoveGroup Move a nested group under another group within the same parent hierarchy + // MoveGroup moves a nested group under another group within the same parent hierarchy // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-groups-move + // See: https://techdocs.akamai.com/iam-api/reference/post-groups-move MoveGroup(context.Context, MoveGroupRequest) error } @@ -143,39 +143,39 @@ var ( // Validate validates GetGroupRequest func (r GetGroupRequest) Validate() error { return validation.Errors{ - "groupID": validation.Validate(r.GroupID, validation.Required), + "GroupID": validation.Validate(r.GroupID, validation.Required), }.Filter() } // Validate validates GroupRequest func (r GroupRequest) Validate() error { return validation.Errors{ - "groupID": validation.Validate(r.GroupID, validation.Required), - "groupName": validation.Validate(r.GroupName, validation.Required), + "GroupID": validation.Validate(r.GroupID, validation.Required), + "GroupName": validation.Validate(r.GroupName, validation.Required), }.Filter() } // Validate validates MoveGroupRequest func (r MoveGroupRequest) Validate() error { return validation.Errors{ - "destinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), - "sourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), + "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), + "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), }.Filter() } // Validate validates ListAffectedUsersRequest func (r ListAffectedUsersRequest) Validate() error { return validation.Errors{ - "destinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), - "sourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), - "userType": validation.Validate(r.UserType, validation.In(LostAccessUsers, GainAccessUsers)), + "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), + "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), + "UserType": validation.Validate(r.UserType, validation.In(LostAccessUsers, GainAccessUsers)), }.Filter() } // Validate validates RemoveGroupRequest func (r RemoveGroupRequest) Validate() error { return validation.Errors{ - "groupID": validation.Validate(r.GroupID, validation.Required), + "GroupID": validation.Validate(r.GroupID, validation.Required), }.Filter() } @@ -187,7 +187,7 @@ func (i *iam) CreateGroup(ctx context.Context, params GroupRequest) (*Group, err return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/groups/%d", params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateGroup, err) } @@ -218,7 +218,7 @@ func (i *iam) GetGroup(ctx context.Context, params GetGroupRequest) (*Group, err return nil, fmt.Errorf("%s: %w:\n%s", ErrGetGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/groups/%d", params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetGroup, err) } @@ -253,7 +253,7 @@ func (i *iam) ListAffectedUsers(ctx context.Context, params ListAffectedUsersReq return nil, fmt.Errorf("%s: %w:\n%s", ErrListAffectedUsers, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/groups/move/%d/%d/affected-users", params.SourceGroupID, params.DestinationGroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/move/%d/%d/affected-users", params.SourceGroupID, params.DestinationGroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAffectedUsers, err) } @@ -286,7 +286,7 @@ func (i *iam) ListGroups(ctx context.Context, params ListGroupsRequest) ([]Group logger := i.Log(ctx) logger.Debug("ListGroups") - u, err := url.Parse("/identity-management/v2/user-admin/groups") + u, err := url.Parse("/identity-management/v3/user-admin/groups") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListGroups, err) } @@ -321,7 +321,7 @@ func (i *iam) RemoveGroup(ctx context.Context, params RemoveGroupRequest) error return fmt.Errorf("%s: %w:\n%s", ErrRemoveGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/groups/%d", params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveGroup, err) } @@ -351,7 +351,7 @@ func (i *iam) UpdateGroupName(ctx context.Context, params GroupRequest) (*Group, return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateGroupName, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/groups/%d", params.GroupID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateGroupName, err) } @@ -382,7 +382,7 @@ func (i *iam) MoveGroup(ctx context.Context, params MoveGroupRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrMoveGroup, ErrStructValidation, err) } - u, err := url.Parse("/identity-management/v2/user-admin/groups/move") + u, err := url.Parse("/identity-management/v3/user-admin/groups/move") if err != nil { return fmt.Errorf("%w: failed to parse url: %s", ErrMoveGroup, err) } diff --git a/pkg/iam/groups_test.go b/pkg/iam/groups_test.go index 20435775..749a8a54 100644 --- a/pkg/iam/groups_test.go +++ b/pkg/iam/groups_test.go @@ -38,7 +38,7 @@ func TestCreateGroup(t *testing.T) { "modifiedDate": "2012-04-28T00:00:00.000Z", "modifiedBy": "johndoe" }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", expectedRequestBody: `{"groupName":"Test Group"}`, expectedResponse: &Group{ GroupID: 98765, @@ -63,7 +63,7 @@ func TestCreateGroup(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -140,7 +140,7 @@ func TestMoveGroup(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "/identity-management/v2/user-admin/groups/move", r.URL.String()) + assert.Equal(t, "/identity-management/v3/user-admin/groups/move", r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) body, err := ioutil.ReadAll(r.Body) require.NoError(t, err) @@ -188,7 +188,7 @@ func TestGetGroup(t *testing.T) { "delete": true } }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345?actions=true", + expectedPath: "/identity-management/v3/user-admin/groups/12345?actions=true", expectedResponse: &Group{ GroupID: 12345, GroupName: "Top Level group", @@ -216,7 +216,7 @@ func TestGetGroup(t *testing.T) { "modifiedDate": "2012-04-28T00:00:00.000Z", "modifiedBy": "johndoe" }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345?actions=false", + expectedPath: "/identity-management/v3/user-admin/groups/12345?actions=false", expectedResponse: &Group{ GroupID: 12345, GroupName: "Top Level group", @@ -238,7 +238,7 @@ func TestGetGroup(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345?actions=false", + expectedPath: "/identity-management/v3/user-admin/groups/12345?actions=false", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -303,7 +303,7 @@ func TestListAffectedUsers(t *testing.T) { "lastLoginDate": "2022-02-22T17:06:50.000Z" } ]`, - expectedPath: "/identity-management/v2/user-admin/groups/move/12344/12345/affected-users?userType=gainAccess", + expectedPath: "/identity-management/v3/user-admin/groups/move/12344/12345/affected-users?userType=gainAccess", expectedResponse: []GroupUser{ { IdentityID: "test-identity", @@ -330,7 +330,7 @@ func TestListAffectedUsers(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups/move/12344/12345/affected-users?userType=gainAccess", + expectedPath: "/identity-management/v3/user-admin/groups/move/12344/12345/affected-users?userType=gainAccess", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -412,7 +412,7 @@ func TestListGroups(t *testing.T) { } } ]`, - expectedPath: "/identity-management/v2/user-admin/groups?actions=true", + expectedPath: "/identity-management/v3/user-admin/groups?actions=true", expectedResponse: []Group{ { GroupID: 12345, @@ -444,7 +444,7 @@ func TestListGroups(t *testing.T) { "modifiedBy": "johndoe" } ]`, - expectedPath: "/identity-management/v2/user-admin/groups?actions=false", + expectedPath: "/identity-management/v3/user-admin/groups?actions=false", expectedResponse: []Group{ { GroupID: 12345, @@ -468,7 +468,7 @@ func TestListGroups(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups?actions=true", + expectedPath: "/identity-management/v3/user-admin/groups?actions=true", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -515,7 +515,7 @@ func TestRemoveGroup(t *testing.T) { GroupID: 12345, }, responseStatus: http.StatusNoContent, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", }, "500 internal server error": { params: RemoveGroupRequest{ @@ -529,7 +529,7 @@ func TestRemoveGroup(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -550,7 +550,7 @@ func TestRemoveGroup(t *testing.T) { "title": "Forbidden", "type": "/useradmin-api/error-types/1001" }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", withError: &Error{ Instance: "", StatusCode: http.StatusForbidden, @@ -612,7 +612,7 @@ func TestUpdateGroupName(t *testing.T) { "modifiedDate": "2012-04-28T00:00:00.000Z", "modifiedBy": "johndoe" }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", expectedRequestBody: `{"groupName":"New Group Name"}`, expectedResponse: &Group{ GroupID: 12345, @@ -637,7 +637,7 @@ func TestUpdateGroupName(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/groups/12345", + expectedPath: "/identity-management/v3/user-admin/groups/12345", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index e3eee488..bc98a425 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -2,7 +2,10 @@ package iam import ( + "bytes" + "encoding/json" "errors" + "io" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" ) @@ -49,3 +52,11 @@ func Client(sess session.Session, opts ...Option) IAM { } return p } + +func convertStructToReqBody(srcStruct interface{}) (io.Reader, error) { + reqBody, err := json.Marshal(srcStruct) + if err != nil { + return nil, err + } + return bytes.NewBuffer(reqBody), nil +} diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index d175ad9a..d4797906 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -311,6 +311,18 @@ func (m *Mock) UpdateTFA(ctx context.Context, request UpdateTFARequest) error { return args.Error(0) } +func (m *Mock) UpdateMFA(ctx context.Context, request UpdateMFARequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} + +func (m *Mock) ResetMFA(ctx context.Context, request ResetMFARequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} + func (m *Mock) ResetUserPassword(ctx context.Context, request ResetUserPasswordRequest) (*ResetUserPasswordResponse, error) { args := m.Called(ctx, request) diff --git a/pkg/iam/roles.go b/pkg/iam/roles.go index e1e52e36..c7b05cfb 100644 --- a/pkg/iam/roles.go +++ b/pkg/iam/roles.go @@ -16,32 +16,32 @@ type ( Roles interface { // CreateRole creates a custom role // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-role + // See: https://techdocs.akamai.com/iam-api/reference/post-role CreateRole(context.Context, CreateRoleRequest) (*Role, error) // GetRole gets details for a specific role // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-role + // See: https://techdocs.akamai.com/iam-api/reference/get-role GetRole(context.Context, GetRoleRequest) (*Role, error) // UpdateRole adds or removes permissions from a role and updates other parameters // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-role + // See: https://techdocs.akamai.com/iam-api/reference/put-role UpdateRole(context.Context, UpdateRoleRequest) (*Role, error) // DeleteRole deletes a role. This operation is only allowed if the role isn't assigned to any users. // - // See: https://techdocs.akamai.com/iam-user-admin/reference/delete-role + // See: https://techdocs.akamai.com/iam-api/reference/delete-role DeleteRole(context.Context, DeleteRoleRequest) error // ListRoles lists roles for the current account and contract type // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-roles + // See: https://techdocs.akamai.com/iam-api/reference/get-roles ListRoles(context.Context, ListRolesRequest) ([]Role, error) // ListGrantableRoles lists which grantable roles can be included in a new custom role or added to an existing custom role // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-grantable-roles + // See: https://techdocs.akamai.com/iam-api/reference/get-grantable-roles ListGrantableRoles(context.Context) ([]RoleGrantedRole, error) } @@ -191,7 +191,7 @@ func (i *iam) CreateRole(ctx context.Context, params CreateRoleRequest) (*Role, return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateRole, ErrStructValidation, err) } - uri, err := url.Parse("/identity-management/v2/user-admin/roles") + uri, err := url.Parse("/identity-management/v3/user-admin/roles") if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrCreateRole, err) } @@ -222,7 +222,7 @@ func (i *iam) GetRole(ctx context.Context, params GetRoleRequest) (*Role, error) return nil, fmt.Errorf("%s: %w:\n%s", ErrGetRole, ErrStructValidation, err) } - uri, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/roles/%d", params.ID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/roles/%d", params.ID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetRole, err) } @@ -260,7 +260,7 @@ func (i *iam) UpdateRole(ctx context.Context, params UpdateRoleRequest) (*Role, return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateRole, ErrStructValidation, err) } - uri, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/roles/%d", params.ID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/roles/%d", params.ID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrUpdateRole, err) } @@ -291,7 +291,7 @@ func (i *iam) DeleteRole(ctx context.Context, params DeleteRoleRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrDeleteRole, ErrStructValidation, err) } - uri, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/roles/%d", params.ID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/roles/%d", params.ID)) if err != nil { return fmt.Errorf("%w: failed to parse url: %s", ErrDeleteRole, err) } @@ -317,7 +317,7 @@ func (i *iam) ListRoles(ctx context.Context, params ListRolesRequest) ([]Role, e logger := i.Log(ctx) logger.Debug("ListRoles") - u, err := url.Parse("/identity-management/v2/user-admin/roles") + u, err := url.Parse("/identity-management/v3/user-admin/roles") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListRoles, err) } @@ -354,7 +354,7 @@ func (i *iam) ListGrantableRoles(ctx context.Context) ([]RoleGrantedRole, error) logger := i.Log(ctx) logger.Debug("ListGrantableRoles") - uri, err := url.Parse("/identity-management/v2/user-admin/roles/grantable-roles") + uri, err := url.Parse("/identity-management/v3/user-admin/roles/grantable-roles") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListGrantableRoles, err) } diff --git a/pkg/iam/roles_test.go b/pkg/iam/roles_test.go index 1a451d3b..6716ebde 100644 --- a/pkg/iam/roles_test.go +++ b/pkg/iam/roles_test.go @@ -52,7 +52,7 @@ func TestIAM_CreateRole(t *testing.T) { } ] }`, - expectedPath: "/identity-management/v2/user-admin/roles", + expectedPath: "/identity-management/v3/user-admin/roles", expectedRequestBody: `{"roleName":"Terraform admin","roleDescription":"Admin granted role for tests","grantedRoles":[{"grantedRoleId":12345}]}`, expectedResponse: &Role{ RoleID: 123456, @@ -90,7 +90,7 @@ func TestIAM_CreateRole(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles", + expectedPath: "/identity-management/v3/user-admin/roles", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -190,7 +190,7 @@ func TestIAM_GetRole(t *testing.T) { } ] }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456?actions=true&grantedRoles=true&users=true", + expectedPath: "/identity-management/v3/user-admin/roles/123456?actions=true&grantedRoles=true&users=true", expectedResponse: &Role{ RoleID: 123456, RoleName: "Terraform admin updated", @@ -250,7 +250,7 @@ func TestIAM_GetRole(t *testing.T) { "modifiedDate": "2022-04-11T10:59:30.000Z", "modifiedBy": "jBond" }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", + expectedPath: "/identity-management/v3/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", expectedResponse: &Role{ RoleID: 123456, RoleName: "Terraform admin updated", @@ -265,7 +265,7 @@ func TestIAM_GetRole(t *testing.T) { "404 Not found": { params: GetRoleRequest{ID: 123456}, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v2/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", + expectedPath: "/identity-management/v3/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", responseBody: ` { "instance": "", @@ -293,7 +293,7 @@ func TestIAM_GetRole(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", + expectedPath: "/identity-management/v3/user-admin/roles/123456?actions=false&grantedRoles=false&users=false", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -378,7 +378,7 @@ func TestIAM_UpdateRole(t *testing.T) { } ] }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456", + expectedPath: "/identity-management/v3/user-admin/roles/123456", expectedRequestBody: `{"roleName":"Terraform admin updated","grantedRoles":[{"grantedRoleId":54321},{"grantedRoleId":12345}]}`, expectedResponse: &Role{ RoleID: 123456, @@ -422,7 +422,7 @@ func TestIAM_UpdateRole(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456", + expectedPath: "/identity-management/v3/user-admin/roles/123456", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -471,12 +471,12 @@ func TestIAM_DeleteRole(t *testing.T) { "204 Deleted": { params: DeleteRoleRequest{ID: 123456}, responseStatus: http.StatusNoContent, - expectedPath: "/identity-management/v2/user-admin/roles/123456", + expectedPath: "/identity-management/v3/user-admin/roles/123456", }, "404 Not found": { params: DeleteRoleRequest{ID: 123456}, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v2/user-admin/roles/123456", + expectedPath: "/identity-management/v3/user-admin/roles/123456", responseBody: ` { "instance": "", @@ -504,7 +504,7 @@ func TestIAM_DeleteRole(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles/123456", + expectedPath: "/identity-management/v3/user-admin/roles/123456", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -566,7 +566,7 @@ func TestIAM_ListRoles(t *testing.T) { } } ]`, - expectedPath: "/identity-management/v2/user-admin/roles?actions=true&ignoreContext=false&users=false", + expectedPath: "/identity-management/v3/user-admin/roles?actions=true&ignoreContext=false&users=false", expectedResponse: []Role{ { RoleID: 123456, @@ -596,7 +596,7 @@ func TestIAM_ListRoles(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles?actions=true&ignoreContext=false&users=false", + expectedPath: "/identity-management/v3/user-admin/roles?actions=true&ignoreContext=false&users=false", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", @@ -651,7 +651,7 @@ func TestIAM_ListGrantableRoles(t *testing.T) { "grantedRoleDescription": "second role description" } ]`, - expectedPath: "/identity-management/v2/user-admin/roles/grantable-roles", + expectedPath: "/identity-management/v3/user-admin/roles/grantable-roles", expectedResponse: []RoleGrantedRole{ { RoleID: 123456, @@ -674,7 +674,7 @@ func TestIAM_ListGrantableRoles(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/roles/grantable-roles", + expectedPath: "/identity-management/v3/user-admin/roles/grantable-roles", withError: &Error{ Type: "internal_error", Title: "Internal Server Error", diff --git a/pkg/iam/support.go b/pkg/iam/support.go index b195d045..4c6cc6dc 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -19,37 +19,37 @@ type ( // ListProducts lists products a user can subscribe to and receive notifications for on the account // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-notification-products + // See: https://techdocs.akamai.com/iam-api/reference/get-common-notification-products ListProducts(context.Context) ([]string, error) // ListStates lists U.S. states or Canadian provinces // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-states + // See: https://techdocs.akamai.com/iam-api/reference/get-common-states ListStates(context.Context, ListStatesRequest) ([]string, error) // ListTimeoutPolicies lists all the possible session timeout policies // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-timeout-policies + // See: https://techdocs.akamai.com/iam-api/reference/get-common-timeout-policies ListTimeoutPolicies(context.Context) ([]TimeoutPolicy, error) // SupportedContactTypes lists supported contact types // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-contact-types + // See: https://techdocs.akamai.com/iam-api/reference/get-common-contact-types SupportedContactTypes(context.Context) ([]string, error) // SupportedCountries lists supported countries // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-countries + // See: https://techdocs.akamai.com/iam-api/reference/get-common-countries SupportedCountries(context.Context) ([]string, error) // SupportedLanguages lists supported languages // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-languages + // See: https://techdocs.akamai.com/iam-api/reference/get-common-languages SupportedLanguages(context.Context) ([]string, error) // SupportedTimezones lists supported timezones // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-common-timezones + // See: https://techdocs.akamai.com/iam-api/reference/get-common-timezones SupportedTimezones(context.Context) ([]Timezone, error) } @@ -115,7 +115,7 @@ var ( // Validate validates ListStatesRequest func (r ListStatesRequest) Validate() error { return validation.Errors{ - "country": validation.Validate(r.Country, validation.Required), + "Country": validation.Validate(r.Country, validation.Required), }.Filter() } @@ -147,7 +147,7 @@ func (i *iam) ListProducts(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("ListProducts") - getURL := "/identity-management/v2/user-admin/common/notification-products" + getURL := "/identity-management/v3/user-admin/common/notification-products" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -175,7 +175,7 @@ func (i *iam) ListStates(ctx context.Context, params ListStatesRequest) ([]strin return nil, fmt.Errorf("%s: %w:\n%s", ErrListStates, ErrStructValidation, err) } - getURL := fmt.Sprintf("/identity-management/v2/user-admin/common/countries/%s/states", params.Country) + getURL := fmt.Sprintf("/identity-management/v3/user-admin/common/countries/%s/states", params.Country) req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -199,7 +199,7 @@ func (i *iam) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) logger := i.Log(ctx) logger.Debug("ListTimeoutPolicies") - getURL := "/identity-management/v2/user-admin/common/timeout-policies" + getURL := "/identity-management/v3/user-admin/common/timeout-policies" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -223,7 +223,7 @@ func (i *iam) SupportedContactTypes(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedContactTypes") - getURL := "/identity-management/v2/user-admin/common/contact-types" + getURL := "/identity-management/v3/user-admin/common/contact-types" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -247,7 +247,7 @@ func (i *iam) SupportedCountries(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedCountries") - getURL := "/identity-management/v2/user-admin/common/countries" + getURL := "/identity-management/v3/user-admin/common/countries" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -271,7 +271,7 @@ func (i *iam) SupportedLanguages(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedLanguages") - getURL := "/identity-management/v2/user-admin/common/supported-languages" + getURL := "/identity-management/v3/user-admin/common/supported-languages" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { @@ -295,7 +295,7 @@ func (i *iam) SupportedTimezones(ctx context.Context) ([]Timezone, error) { logger := i.Log(ctx) logger.Debug("SupportedTimezones") - getURL := "/identity-management/v2/user-admin/common/timezones" + getURL := "/identity-management/v3/user-admin/common/timezones" req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) if err != nil { diff --git a/pkg/iam/support_test.go b/pkg/iam/support_test.go index d2245e94..3f2b601b 100644 --- a/pkg/iam/support_test.go +++ b/pkg/iam/support_test.go @@ -106,7 +106,7 @@ func TestIAM_SupportedCountries(t *testing.T) { "Greenland", "Grenada" ]`, - expectedPath: "/identity-management/v2/user-admin/common/countries", + expectedPath: "/identity-management/v3/user-admin/common/countries", expectedResponse: []string{"Greece", "Greenland", "Grenada"}, }, "500 internal server error": { @@ -118,7 +118,7 @@ func TestIAM_SupportedCountries(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/countries", + expectedPath: "/identity-management/v3/user-admin/common/countries", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -171,7 +171,7 @@ func TestIAM_SupportedTimezones(t *testing.T) { "posix": "Asia/Rangoon" } ]`, - expectedPath: "/identity-management/v2/user-admin/common/timezones", + expectedPath: "/identity-management/v3/user-admin/common/timezones", expectedResponse: []Timezone{ { Timezone: "Asia/Rangoon", @@ -190,7 +190,7 @@ func TestIAM_SupportedTimezones(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/timezones", + expectedPath: "/identity-management/v3/user-admin/common/timezones", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -239,7 +239,7 @@ func TestIAM_SupportedContactTypes(t *testing.T) { "Billing", "Security" ]`, - expectedPath: "/identity-management/v2/user-admin/common/contact-types", + expectedPath: "/identity-management/v3/user-admin/common/contact-types", expectedResponse: []string{"Billing", "Security"}, }, "500 internal server error": { @@ -251,7 +251,7 @@ func TestIAM_SupportedContactTypes(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/contact-types", + expectedPath: "/identity-management/v3/user-admin/common/contact-types", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -300,7 +300,7 @@ func TestIAM_SupportedLanguages(t *testing.T) { "Deutsch", "English" ]`, - expectedPath: "/identity-management/v2/user-admin/common/supported-languages", + expectedPath: "/identity-management/v3/user-admin/common/supported-languages", expectedResponse: []string{"Deutsch", "English"}, }, "500 internal server error": { @@ -312,7 +312,7 @@ func TestIAM_SupportedLanguages(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/supported-languages", + expectedPath: "/identity-management/v3/user-admin/common/supported-languages", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -361,7 +361,7 @@ func TestIAM_ListProducts(t *testing.T) { "EdgeComputing for Java", "Streaming" ]`, - expectedPath: "/identity-management/v2/user-admin/common/notification-products", + expectedPath: "/identity-management/v3/user-admin/common/notification-products", expectedResponse: []string{"EdgeComputing for Java", "Streaming"}, }, "500 internal server error": { @@ -373,7 +373,7 @@ func TestIAM_ListProducts(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/notification-products", + expectedPath: "/identity-management/v3/user-admin/common/notification-products", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -428,7 +428,7 @@ func TestIAM_ListTimeoutPolicies(t *testing.T) { "value": 1800 } ]`, - expectedPath: "/identity-management/v2/user-admin/common/timeout-policies", + expectedPath: "/identity-management/v3/user-admin/common/timeout-policies", expectedResponse: []TimeoutPolicy{ { Name: "after15Minutes", @@ -449,7 +449,7 @@ func TestIAM_ListTimeoutPolicies(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/timeout-policies", + expectedPath: "/identity-management/v3/user-admin/common/timeout-policies", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -502,7 +502,7 @@ func TestIAM_ListStates(t *testing.T) { "AB", "BC" ]`, - expectedPath: "/identity-management/v2/user-admin/common/countries/canada/states", + expectedPath: "/identity-management/v3/user-admin/common/countries/canada/states", expectedResponse: []string{"AB", "BC"}, }, "500 internal server error": { @@ -517,7 +517,7 @@ func TestIAM_ListStates(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/common/countries/canada/states", + expectedPath: "/identity-management/v3/user-admin/common/countries/canada/states", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", diff --git a/pkg/iam/user.go b/pkg/iam/user.go index dff3d74b..c0908378 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -24,7 +24,7 @@ type ( // GetUser gets a specific user's profile // - // See: https://techdocs.akamai.com/iam-api/reference/get-ui-identity + // See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identity GetUser(context.Context, GetUserRequest) (*User, error) // ListUsers returns a list of users who have access on this account @@ -34,7 +34,7 @@ type ( // RemoveUser removes a user identity // - // See: https://techdocs.akamai.com/iam-user-admin/reference/delete-ui-identity + // See: https://techdocs.akamai.com/iam-api/reference/delete-ui-identity RemoveUser(context.Context, RemoveUserRequest) error // UpdateUserAuthGrants edits what groups a user has access to, and how the user can interact with the objects in those groups @@ -44,7 +44,7 @@ type ( // UpdateUserInfo updates a user's information // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-basic-info + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-basic-info UpdateUserInfo(context.Context, UpdateUserInfoRequest) (*UserBasicInfo, error) // UpdateUserNotifications subscribes or un-subscribes user to product notification emails @@ -55,7 +55,18 @@ type ( // UpdateTFA updates a user's two-factor authentication setting and can reset tfa // // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-tfa + /** @deprecated */ UpdateTFA(context.Context, UpdateTFARequest) error + + // UpdateMFA updates a user's profile authentication method + // + // See: https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication + UpdateMFA(context.Context, UpdateMFARequest) error + + // ResetMFA resets a user's profile authentication method + // + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication + ResetMFA(context.Context, ResetMFARequest) error } // CreateUserRequest contains the request parameters for the create user endpoint @@ -221,6 +232,17 @@ type ( // Authentication is a type of additional authentication Authentication string + + // UpdateMFARequest contains the request body of the mfa user endpoint + UpdateMFARequest struct { + IdentityID string + Value Authentication + } + + // ResetMFARequest contains the request parameters of the rest mfa endpoint + ResetMFARequest struct { + IdentityID string + } ) const ( @@ -262,6 +284,12 @@ var ( // ErrUpdateTFA is returned when UpdateTFA fails ErrUpdateTFA = errors.New("update user's two-factor authentication") + + // ErrUpdateMFA is returned when UpdateMFA fails + ErrUpdateMFA = errors.New("update user's authentication method") + + // ErrResetMFA is returned when ResetMFA fails + ErrResetMFA = errors.New("reset user's authentication method") ) // Validate performs validation on AuthGrant @@ -275,12 +303,12 @@ func (r AuthGrant) Validate() error { // Validate validates CreateUserRequest func (r CreateUserRequest) Validate() error { return validation.Errors{ - "country": validation.Validate(r.Country, validation.Required), - "email": validation.Validate(r.Email, validation.Required, is.EmailFormat), - "firstName": validation.Validate(r.FirstName, validation.Required), - "lastName": validation.Validate(r.LastName, validation.Required), - "authGrants": validation.Validate(r.AuthGrants, validation.Required), - "notifications": validation.Validate(r.Notifications, validation.Required), + "Country": validation.Validate(r.Country, validation.Required), + "Email": validation.Validate(r.Email, validation.Required, is.EmailFormat), + "FirstName": validation.Validate(r.FirstName, validation.Required), + "LastName": validation.Validate(r.LastName, validation.Required), + "AuthGrants": validation.Validate(r.AuthGrants, validation.Required), + "Notifications": validation.Validate(r.Notifications, validation.Required), }.Filter() } @@ -294,13 +322,13 @@ func (r GetUserRequest) Validate() error { // Validate validates UpdateUserInfoRequest func (r UpdateUserInfoRequest) Validate() error { return validation.Errors{ - "uiIdentity": validation.Validate(r.IdentityID, validation.Required), - "firstName": validation.Validate(r.User.FirstName, validation.Required), - "lastName": validation.Validate(r.User.LastName, validation.Required), - "country": validation.Validate(r.User.Country, validation.Required), - "timeZone": validation.Validate(r.User.TimeZone, validation.Required), - "preferredLanguage": validation.Validate(r.User.PreferredLanguage, validation.Required), - "sessionTimeOut": validation.Validate(r.User.SessionTimeOut, validation.Required), + "IdentityID": validation.Validate(r.IdentityID, validation.Required), + "FirstName": validation.Validate(r.User.FirstName, validation.Required), + "LastName": validation.Validate(r.User.LastName, validation.Required), + "Country": validation.Validate(r.User.Country, validation.Required), + "TimeZone": validation.Validate(r.User.TimeZone, validation.Required), + "PreferredLanguage": validation.Validate(r.User.PreferredLanguage, validation.Required), + "SessionTimeOut": validation.Validate(r.User.SessionTimeOut, validation.Required), }.Filter() } @@ -335,6 +363,14 @@ func (r UpdateTFARequest) Validate() error { }.Filter() } +// Validate validates UpdateMFARequest +func (r UpdateMFARequest) Validate() error { + return validation.Errors{ + "Value": validation.Validate(r.Value, validation.Required, validation.In(MFAAuthentication, TFAAuthentication, NoneAuthentication). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'TFA', 'MFA' or 'NONE'", r.Value))), + }.Filter() +} + func (i *iam) CreateUser(ctx context.Context, params CreateUserRequest) (*User, error) { if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateUser, ErrStructValidation, err) @@ -373,7 +409,7 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) return nil, fmt.Errorf("%s: %w:\n%s", ErrGetUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } @@ -440,7 +476,7 @@ func (i *iam) RemoveUser(ctx context.Context, params RemoveUserRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrRemoveUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveUser, err) } @@ -496,7 +532,7 @@ func (i *iam) UpdateUserInfo(ctx context.Context, params UpdateUserInfoRequest) return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserInfo, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/basic-info", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/basic-info", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserInfo, err) } @@ -577,3 +613,59 @@ func (i *iam) UpdateTFA(ctx context.Context, params UpdateTFARequest) error { return nil } + +func (i *iam) UpdateMFA(ctx context.Context, params UpdateMFARequest) error { + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w:\n%s", ErrUpdateMFA, ErrStructValidation, err) + } + + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication", params.IdentityID)) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) + } + + reqBody, err := convertStructToReqBody(params.Value) + if err != nil { + return fmt.Errorf("failed to generate request body: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), reqBody) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrUpdateMFA, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrUpdateMFA, i.Error(resp)) + } + + return nil +} + +func (i *iam) ResetMFA(ctx context.Context, params ResetMFARequest) error { + + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication/reset", params.IdentityID)) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrResetMFA, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrResetMFA, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrResetMFA, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrResetMFA, i.Error(resp)) + } + + return nil +} diff --git a/pkg/iam/user_lock.go b/pkg/iam/user_lock.go index 04a62201..3028bbb3 100644 --- a/pkg/iam/user_lock.go +++ b/pkg/iam/user_lock.go @@ -13,14 +13,14 @@ import ( type ( // UserLock is the IAM user lock/unlock API interface UserLock interface { - // LockUser lock the user + // LockUser locks the user // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-ui-identity-lock + // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-lock LockUser(context.Context, LockUserRequest) error - // UnlockUser release the lock on a user's account + // UnlockUser releases the lock on a user's account // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-ui-identity-unlock + // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-unlock UnlockUser(context.Context, UnlockUserRequest) error } @@ -62,7 +62,7 @@ func (i *iam) LockUser(ctx context.Context, params LockUserRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrLockUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/lock", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/lock", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrLockUser, err) } @@ -89,7 +89,7 @@ func (i *iam) UnlockUser(ctx context.Context, params UnlockUserRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrUnlockUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/unlock", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/unlock", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUnlockUser, err) } diff --git a/pkg/iam/user_lock_test.go b/pkg/iam/user_lock_test.go index 099a1244..fd6194c1 100644 --- a/pkg/iam/user_lock_test.go +++ b/pkg/iam/user_lock_test.go @@ -25,7 +25,7 @@ func TestIAM_LockUser(t *testing.T) { }, responseStatus: http.StatusOK, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/lock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/lock", }, "204 No Content": { params: LockUserRequest{ @@ -33,7 +33,7 @@ func TestIAM_LockUser(t *testing.T) { }, responseStatus: http.StatusNoContent, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/lock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/lock", }, "404 Not Found": { params: LockUserRequest{ @@ -48,7 +48,7 @@ func TestIAM_LockUser(t *testing.T) { "title": "User not found", "type": "/useradmin-api/error-types/1100" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/X1-ABCDE/lock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/X1-ABCDE/lock", withError: func(t *testing.T, err error) { want := &Error{ Instance: "", @@ -73,7 +73,7 @@ func TestIAM_LockUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/lock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/lock", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -120,7 +120,7 @@ func TestIAM_UnlockUser(t *testing.T) { }, responseStatus: http.StatusOK, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/unlock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/unlock", }, "204 No Content": { params: UnlockUserRequest{ @@ -128,7 +128,7 @@ func TestIAM_UnlockUser(t *testing.T) { }, responseStatus: http.StatusNoContent, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/unlock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/unlock", }, "404 Not Found": { params: UnlockUserRequest{ @@ -143,7 +143,7 @@ func TestIAM_UnlockUser(t *testing.T) { "title": "User not found", "type": "/useradmin-api/error-types/1100" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/X1-ABCDE/unlock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/X1-ABCDE/unlock", withError: func(t *testing.T, err error) { want := &Error{ Instance: "", @@ -168,7 +168,7 @@ func TestIAM_UnlockUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/unlock", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/unlock", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", diff --git a/pkg/iam/user_password.go b/pkg/iam/user_password.go index a5f44633..0fb4d5c2 100644 --- a/pkg/iam/user_password.go +++ b/pkg/iam/user_password.go @@ -18,12 +18,12 @@ type ( // If you send the email with the password directly to the user, the response for this operation doesn't include that password. // If you don't send the password to the user through email, the password is included in the response. // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-reset-password + // See: https://techdocs.akamai.com/iam-api/reference/post-reset-password ResetUserPassword(context.Context, ResetUserPasswordRequest) (*ResetUserPasswordResponse, error) // SetUserPassword sets a specific password for a user // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-set-password + // See: https://techdocs.akamai.com/iam-api/reference/post-set-password SetUserPassword(context.Context, SetUserPasswordRequest) error } @@ -73,7 +73,7 @@ func (i *iam) ResetUserPassword(ctx context.Context, params ResetUserPasswordReq return nil, fmt.Errorf("%s: %w:\n%s", ErrResetUserPassword, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/reset-password", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/reset-password", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrResetUserPassword, err) } @@ -105,7 +105,7 @@ func (i *iam) SetUserPassword(ctx context.Context, params SetUserPasswordRequest return fmt.Errorf("%s: %w:\n%s", ErrSetUserPassword, ErrStructValidation, err) } - u := fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/set-password", params.IdentityID) + u := fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/set-password", params.IdentityID) req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil) if err != nil { diff --git a/pkg/iam/user_password_test.go b/pkg/iam/user_password_test.go index 37975419..da5e4b77 100644 --- a/pkg/iam/user_password_test.go +++ b/pkg/iam/user_password_test.go @@ -33,7 +33,7 @@ func TestIAM_ResetUserPassword(t *testing.T) { expectedResponse: ResetUserPasswordResponse{ NewPassword: "K8QVa7Q2", }, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=false", }, "204 No Content": { params: ResetUserPasswordRequest{ @@ -42,7 +42,7 @@ func TestIAM_ResetUserPassword(t *testing.T) { }, responseStatus: http.StatusNoContent, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=true", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=true", }, "404 Not Found": { params: ResetUserPasswordRequest{ @@ -57,7 +57,7 @@ func TestIAM_ResetUserPassword(t *testing.T) { "title": "User not found", "type": "/useradmin-api/error-types/1100" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/X1-ABCDE/reset-password?sendEmail=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/X1-ABCDE/reset-password?sendEmail=false", withError: func(t *testing.T, err error) { want := &Error{ Instance: "", @@ -82,7 +82,7 @@ func TestIAM_ResetUserPassword(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/reset-password?sendEmail=false", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -133,7 +133,7 @@ func TestIAM_SetUserPassword(t *testing.T) { responseStatus: http.StatusNoContent, responseBody: "", expectedRequestBody: `{"newPassword":"newpwd"}`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/set-password", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/set-password", }, "400 Bad Request - same password": { params: SetUserPasswordRequest{ @@ -148,7 +148,7 @@ func TestIAM_SetUserPassword(t *testing.T) { "title": "Validation Exception", "type": "/useradmin-api/error-types/1508" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/X1-ABCDE/set-password", + expectedPath: "/identity-management/v3/user-admin/ui-identities/X1-ABCDE/set-password", withError: func(t *testing.T, err error) { want := &Error{ Instance: "", @@ -175,7 +175,7 @@ func TestIAM_SetUserPassword(t *testing.T) { "title": "User not found", "type": "/useradmin-api/error-types/1100" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/X1-ABCDE/set-password", + expectedPath: "/identity-management/v3/user-admin/ui-identities/X1-ABCDE/set-password", withError: func(t *testing.T, err error) { want := &Error{ Instance: "", @@ -201,7 +201,7 @@ func TestIAM_SetUserPassword(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/set-password", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/set-password", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index f8c0b0a5..629c8638 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -152,7 +152,7 @@ func TestIAM_GetUser(t *testing.T) { "state": "CA", "country": "USA" }`, - expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", expectedResponse: &User{ IdentityID: "A-BC-1234567", UserBasicInfo: UserBasicInfo{ @@ -177,7 +177,7 @@ func TestIAM_GetUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -470,7 +470,7 @@ func TestIAM_UpdateUserInfo(t *testing.T) { "timeZone": "GMT", "additionalAuthentication": "NONE" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/basic-info", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/basic-info", expectedResponse: &UserBasicInfo{ FirstName: "John", LastName: "Doe", @@ -509,7 +509,7 @@ func TestIAM_UpdateUserInfo(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE/basic-info", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/basic-info", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -788,7 +788,7 @@ func TestIAM_RemoveUser(t *testing.T) { }, responseStatus: http.StatusOK, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE", }, "204 No Content": { params: RemoveUserRequest{ @@ -796,7 +796,7 @@ func TestIAM_RemoveUser(t *testing.T) { }, responseStatus: http.StatusNoContent, responseBody: "", - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE", }, "500 internal server error": { params: RemoveUserRequest{ @@ -810,7 +810,7 @@ func TestIAM_RemoveUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/1-ABCDE", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -905,3 +905,127 @@ func TestIAM_UpdateTFA(t *testing.T) { }) } } + +func TestIAM_UpdateMFA(t *testing.T) { + tests := map[string]struct { + params UpdateMFARequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 No Content": { + params: UpdateMFARequest{ + IdentityID: "1-ABCDE", + Value: MFAAuthentication, + }, + responseStatus: http.StatusNoContent, + responseBody: "", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/additionalAuthentication", + }, + "500 internal server error": { + params: UpdateMFARequest{ + IdentityID: "1-ABCDE", + Value: MFAAuthentication, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +}`, + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/additionalAuthentication", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + err := client.UpdateMFA(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestIAM_ResetMFA(t *testing.T) { + tests := map[string]struct { + params ResetMFARequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 No Content": { + params: ResetMFARequest{ + IdentityID: "1-ABCDE", + }, + responseStatus: http.StatusNoContent, + responseBody: "", + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/additionalAuthentication/reset", + }, + "500 internal server error": { + params: ResetMFARequest{ + IdentityID: "1-ABCDE", + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +}`, + expectedPath: "/identity-management/v3/user-admin/ui-identities/1-ABCDE/additionalAuthentication/reset", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + err := client.ResetMFA(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} From 4176fa9ad175b5582ee3366b2e3cb79d870ab188 Mon Sep 17 00:00:00 2001 From: Wojciech Zagrajczuk Date: Mon, 22 Jul 2024 13:35:30 +0000 Subject: [PATCH 17/34] DXE-4001 CIDR blocks --- CHANGELOG.md | 35 ++ pkg/iam/cidr.go | 355 +++++++++++++++++++ pkg/iam/cidr_test.go | 822 +++++++++++++++++++++++++++++++++++++++++++ pkg/iam/iam.go | 1 + pkg/iam/mocks.go | 52 +++ 5 files changed, 1265 insertions(+) create mode 100644 pkg/iam/cidr.go create mode 100644 pkg/iam/cidr_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb03692..2df685a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -428,6 +428,41 @@ + + + + + + + + + + +* IAM + * Add support for new methods: + * [ListCIDRBlocks](https://techdocs.akamai.com/iam-api/reference/get-allowlist) + * [CreateCIDRBlock](https://techdocs.akamai.com/iam-api/reference/post-allowlist) + * [GetCIDRBlock](https://techdocs.akamai.com/iam-api/reference/get-allowlist-cidrblockid) + * [UpdateCIDRBlock](https://techdocs.akamai.com/iam-api/reference/put-allowlist-cidrblockid) + * [DeleteCIDRBlock](https://techdocs.akamai.com/iam-api/reference/delete-allowlist-cidrblockid) + * [ValidateCIDRBlock](https://techdocs.akamai.com/iam-api/reference/get-allowlist-validate) + + + + + + + + + + + + + + + + + diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go new file mode 100644 index 00000000..3a42c935 --- /dev/null +++ b/pkg/iam/cidr.go @@ -0,0 +1,355 @@ +package iam + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // CIDR is an interface for managing Classless Inter-Domain Routing (CIDR) blocks + CIDR interface { + // ListCIDRBlocks lists all CIDR blocks on selected account's allowlist + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist + ListCIDRBlocks(context.Context, ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) + + // CreateCIDRBlock adds CIDR blocks to your account's allowlist + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist + CreateCIDRBlock(context.Context, CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) + + // GetCIDRBlock retrieves a CIDR block's details + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-cidrblockid + GetCIDRBlock(context.Context, GetCIDRBlockRequest) (*GetCIDRBlockResponse, error) + + // UpdateCIDRBlock modifies an existing CIDR block + // + // See: https://techdocs.akamai.com/iam-api/reference/put-allowlist-cidrblockid + UpdateCIDRBlock(context.Context, UpdateCIDRBlockRequest) (*UpdateCIDRBlockResponse, error) + + // DeleteCIDRBlock deletes an existing CIDR block from the IP allowlist + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-allowlist-cidrblockid + DeleteCIDRBlock(context.Context, DeleteCIDRBlockRequest) error + + // ValidateCIDRBlock checks the format of CIDR block + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-validate + ValidateCIDRBlock(context.Context, ValidateCIDRBlockRequest) error + } + + // ListCIDRBlocksRequest contains the request parameters for the ListCIDRBlocks endpoint + ListCIDRBlocksRequest struct { + Actions bool + } + + // ListCIDRBlocksResponse describes the response of the ListCIDRBlocks endpoint + ListCIDRBlocksResponse []CIDRBlock + + // CIDRBlock represents a CIDR block + CIDRBlock struct { + Actions *CIDRActions `json:"actions"` + CIDRBlock string `json:"cidrBlock"` + CIDRBlockID int64 `json:"cidrBlockId"` + Comments string `json:"comments"` + CreatedBy string `json:"createdBy"` + CreatedDate string `json:"createdDate"` + Enabled bool `json:"enabled"` + ModifiedBy string `json:"modifiedBy"` + ModifiedDate string `json:"modifiedDate"` + } + + // CIDRActions specifies activities available for the CIDR block + CIDRActions struct { + Delete bool `json:"delete"` + Edit bool `json:"edit"` + } + + // CreateCIDRBlockRequest contains the request parameters for the CreateCIDRBlock endpoint + CreateCIDRBlockRequest struct { + CIDRBlock string `json:"cidrBlock"` + Comments string `json:"comments,omitempty"` + Enabled bool `json:"enabled"` + } + + // CreateCIDRBlockResponse describes the response of the CreateCIDRBlock endpoint + CreateCIDRBlockResponse CIDRBlock + + // GetCIDRBlockRequest contains the request parameters for the GetCIDRBlock endpoint + GetCIDRBlockRequest struct { + CIDRBlockID int64 + Actions bool + } + + // GetCIDRBlockResponse describes the response of the GetCIDRBlock endpoint + GetCIDRBlockResponse CIDRBlock + + // UpdateCIDRBlockRequest contains the request parameters for the UpdateCIDRBlock endpoint + UpdateCIDRBlockRequest struct { + CIDRBlockID int64 + Body UpdateCIDRBlockBody + } + + // UpdateCIDRBlockBody contains the request body to be used in UpdateCIDRBlock endpoint + UpdateCIDRBlockBody struct { + CIDRBlock string `json:"cidrBlock"` + Comments string `json:"comments,omitempty"` + Enabled bool `json:"enabled"` + } + + // UpdateCIDRBlockResponse describes the response of the UpdateCIDRBlock endpoint + UpdateCIDRBlockResponse CIDRBlock + + // DeleteCIDRBlockRequest contains the request parameters for the DeleteCIDRBlock endpoint + DeleteCIDRBlockRequest struct { + CIDRBlockID int64 + } + + // ValidateCIDRBlockRequest contains the request parameters for the ValidateCIDRBlock endpoint + ValidateCIDRBlockRequest struct { + CIDRBlock string + } +) + +// Validate performs validation on CreateCIDRBlockRequest +func (r CreateCIDRBlockRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + }) +} + +// Validate performs validation on GetCIDRBlockRequest +func (r GetCIDRBlockRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), + }) +} + +// Validate performs validation on UpdateCIDRBlockRequest +func (r UpdateCIDRBlockRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), + "Body": validation.Validate(r.Body, validation.Required), + }) +} + +// Validate performs validation on UpdateCIDRBlockBody +func (r UpdateCIDRBlockBody) Validate() error { + return validation.Errors{ + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + }.Filter() +} + +// Validate performs validation on DeleteCIDRBlockRequest +func (r DeleteCIDRBlockRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), + }) +} + +// Validate performs validation on ValidateCIDRBlockRequest +func (r ValidateCIDRBlockRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + }) +} + +var ( + // ErrListCIDRBlocks is returned when ListCIDRBlocks fails + ErrListCIDRBlocks = errors.New("list CIDR blocks") + // ErrCreateCIDRBlock is returned when CreateCIDRBlock fails + ErrCreateCIDRBlock = errors.New("create CIDR block") + // ErrGetCIDRBlock is returned when GetCIDRBlock fails + ErrGetCIDRBlock = errors.New("get CIDR block") + // ErrUpdateCIDRBlock is returned when UpdateCIDRBlock fails + ErrUpdateCIDRBlock = errors.New("update CIDR block") + // ErrDeleteCIDRBlock is returned when DeleteCIDRBlock fails + ErrDeleteCIDRBlock = errors.New("delete CIDR block") + // ErrValidateCIDRBlock is returned when ValidateCIDRBlock fails + ErrValidateCIDRBlock = errors.New("validate CIDR block") +) + +func (i *iam) ListCIDRBlocks(ctx context.Context, params ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListCIDRBlocks") + + uri, err := url.Parse("/identity-management/v3/user-admin/ip-acl/allowlist") + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListCIDRBlocks, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListCIDRBlocks, err) + } + + var result ListCIDRBlocksResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListCIDRBlocks, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListCIDRBlocks, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) CreateCIDRBlock(ctx context.Context, params CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) { + logger := i.Log(ctx) + logger.Debug("CreateCIDRBlock") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrCreateCIDRBlock, ErrStructValidation, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/identity-management/v3/user-admin/ip-acl/allowlist", nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateCIDRBlock, err) + } + + var result CreateCIDRBlockResponse + resp, err := i.Exec(req, &result, params) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrCreateCIDRBlock, err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, fmt.Errorf("%s: %w", ErrCreateCIDRBlock, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) GetCIDRBlock(ctx context.Context, params GetCIDRBlockRequest) (*GetCIDRBlockResponse, error) { + logger := i.Log(ctx) + logger.Debug("GetCIDRBlock") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetCIDRBlock, ErrStructValidation, err) + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ip-acl/allowlist/%d", params.CIDRBlockID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetCIDRBlock, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetCIDRBlock, err) + } + + var result GetCIDRBlockResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrGetCIDRBlock, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrGetCIDRBlock, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) UpdateCIDRBlock(ctx context.Context, params UpdateCIDRBlockRequest) (*UpdateCIDRBlockResponse, error) { + logger := i.Log(ctx) + logger.Debug("UpdateCIDRBlock") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateCIDRBlock, ErrStructValidation, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, fmt.Sprintf("/identity-management/v3/user-admin/ip-acl/allowlist/%d", params.CIDRBlockID), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateCIDRBlock, err) + } + + var result UpdateCIDRBlockResponse + resp, err := i.Exec(req, &result, params.Body) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateCIDRBlock, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrUpdateCIDRBlock, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) DeleteCIDRBlock(ctx context.Context, params DeleteCIDRBlockRequest) error { + logger := i.Log(ctx) + logger.Debug("DeleteCIDRBlock") + + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrDeleteCIDRBlock, ErrStructValidation, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, fmt.Sprintf("/identity-management/v3/user-admin/ip-acl/allowlist/%d", params.CIDRBlockID), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDeleteCIDRBlock, err) + } + + resp, err := i.Exec(req, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDeleteCIDRBlock, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDeleteCIDRBlock, i.Error(resp)) + } + + return nil +} + +func (i *iam) ValidateCIDRBlock(ctx context.Context, params ValidateCIDRBlockRequest) error { + logger := i.Log(ctx) + logger.Debug("ValidateCIDRBlock") + + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrValidateCIDRBlock, ErrStructValidation, err) + } + + uri, err := url.Parse("/identity-management/v3/user-admin/ip-acl/allowlist/validate") + if err != nil { + return fmt.Errorf("%w: failed to parse url: %s", ErrValidateCIDRBlock, err) + } + + q := uri.Query() + q.Add("cidrblock", params.CIDRBlock) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrValidateCIDRBlock, err) + } + + resp, err := i.Exec(req, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrValidateCIDRBlock, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrValidateCIDRBlock, i.Error(resp)) + } + + return nil +} diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go new file mode 100644 index 00000000..54738b01 --- /dev/null +++ b/pkg/iam/cidr_test.go @@ -0,0 +1,822 @@ +package iam + +import ( + "context" + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestListCIDRBlocks(t *testing.T) { + tests := map[string]struct { + params ListCIDRBlocksRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse *ListCIDRBlocksResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListCIDRBlocksRequest{}, + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "cidrBlockId": 1, + "enabled": true, + "comments": "abc", + "cidrBlock": "1.2.3.4/8", + "createdDate": "2024-06-17T08:46:41.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-17T08:46:41.000Z", + "modifiedBy": "johndoe" + }, + { + "cidrBlockId": 2, + "enabled": false, + "comments": null, + "cidrBlock": "2.4.8.16/32", + "createdDate": "2024-06-25T06:14:36.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-25T06:14:36.000Z", + "modifiedBy": "johndoe" + } +]`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist?actions=false", + expectedResponse: &ListCIDRBlocksResponse{ + { + CIDRBlockID: 1, + Enabled: true, + Comments: "abc", + CIDRBlock: "1.2.3.4/8", + CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + { + CIDRBlockID: 2, + Enabled: false, + Comments: "", + CIDRBlock: "2.4.8.16/32", + CreatedDate: "2024-06-25T06:14:36.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-25T06:14:36.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + }, + }, + "200 with actions": { + params: ListCIDRBlocksRequest{Actions: true}, + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "cidrBlockId": 1, + "enabled": true, + "comments": "abc", + "cidrBlock": "1.2.3.4/8", + "createdDate": "2024-06-17T08:46:41.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-17T08:46:41.000Z", + "modifiedBy": "johndoe", + "actions": { + "edit": true, + "delete": true + } + }, + { + "cidrBlockId": 2, + "enabled": false, + "comments": null, + "cidrBlock": "2.4.8.16/32", + "createdDate": "2024-06-25T06:14:36.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-25T06:14:36.000Z", + "modifiedBy": "johndoe", + "actions": { + "edit": true, + "delete": true + } + } +]`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist?actions=true", + expectedResponse: &ListCIDRBlocksResponse{ + { + CIDRBlockID: 1, + Enabled: true, + Comments: "abc", + CIDRBlock: "1.2.3.4/8", + CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedBy: "johndoe", + Actions: &CIDRActions{ + Edit: true, + Delete: true, + }, + }, + { + CIDRBlockID: 2, + Enabled: false, + Comments: "", + CIDRBlock: "2.4.8.16/32", + CreatedDate: "2024-06-25T06:14:36.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-25T06:14:36.000Z", + ModifiedBy: "johndoe", + Actions: &CIDRActions{ + Edit: true, + Delete: true, + }, + }, + }, + }, + "500 internal server error": { + params: ListCIDRBlocksRequest{}, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +} +`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist?actions=false", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListCIDRBlocks(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestCreateCIDRBlock(t *testing.T) { + tests := map[string]struct { + params CreateCIDRBlockRequest + responseStatus int + responseBody string + expectedPath string + expectedRequestBody string + expectedResponse *CreateCIDRBlockResponse + withError func(*testing.T, error) + }{ + "201 created": { + params: CreateCIDRBlockRequest{ + CIDRBlock: "1.2.3.4/32", + Comments: "abc", + Enabled: true, + }, + responseStatus: http.StatusCreated, + responseBody: ` +{ + "cidrBlockId": 1234, + "enabled": true, + "comments": "abc", + "cidrBlock": "1.2.3.4/32", + "createdDate": "2024-07-15T13:53:49.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-07-15T13:53:49.000Z", + "modifiedBy": "johndoe" +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist", + expectedRequestBody: `{"cidrBlock":"1.2.3.4/32","comments":"abc","enabled":true}`, + expectedResponse: &CreateCIDRBlockResponse{ + CIDRBlockID: 1234, + Enabled: true, + Comments: "abc", + CIDRBlock: "1.2.3.4/32", + CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-07-15T13:53:49.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + }, + "201 without comment": { + params: CreateCIDRBlockRequest{ + CIDRBlock: "1.2.3.4/32", + Enabled: true, + }, + responseStatus: http.StatusCreated, + responseBody: ` +{ + "cidrBlockId": 1234, + "enabled": true, + "comments": null, + "cidrBlock": "1.2.3.4/32", + "createdDate": "2024-07-15T13:53:49.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-07-15T13:53:49.000Z", + "modifiedBy": "johndoe" +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist", + expectedRequestBody: `{"cidrBlock":"1.2.3.4/32","enabled":true}`, + expectedResponse: &CreateCIDRBlockResponse{ + CIDRBlockID: 1234, + Enabled: true, + Comments: "", + CIDRBlock: "1.2.3.4/32", + CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-07-15T13:53:49.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + }, + "missing required parameters": { + params: CreateCIDRBlockRequest{}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "create CIDR block: struct validation: CIDRBlock: cannot be blank") + }, + }, + "403 - incorrect cidrblock": { + params: CreateCIDRBlockRequest{ + CIDRBlock: "1.2.3.4:32", + Comments: "abc", + Enabled: true, + }, + responseStatus: http.StatusForbidden, + responseBody: ` +{ + "type": "/ip-acl/error-types/1013", + "httpStatus": 403, + "title": "CIDR format not correct", + "detail": "invalid cidrblock/ip", + "instance": "", + "errors": [] +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist", + expectedRequestBody: `{"cidrBlock":"1.2.3.4:32","comments":"abc","enabled":true}`, + withError: func(t *testing.T, e error) { + err := Error{ + Type: "/ip-acl/error-types/1013", + HTTPStatus: http.StatusForbidden, + Title: "CIDR format not correct", + Detail: "invalid cidrblock/ip", + StatusCode: http.StatusForbidden, + Instance: "", + Errors: json.RawMessage("[]"), + } + assert.Equal(t, true, err.Is(e)) + }, + }, + "500 internal server error": { + params: CreateCIDRBlockRequest{ + CIDRBlock: "1.2.3.4/32", + Comments: "abc", + Enabled: true, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +} +`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + if len(test.expectedRequestBody) > 0 { + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + assert.Equal(t, test.expectedRequestBody, string(body)) + } + })) + client := mockAPIClient(t, mockServer) + result, err := client.CreateCIDRBlock(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestGetCIDRBlock(t *testing.T) { + tests := map[string]struct { + params GetCIDRBlockRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse *GetCIDRBlockResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: GetCIDRBlockRequest{CIDRBlockID: 1}, + responseStatus: http.StatusOK, + responseBody: ` +{ + "cidrBlockId": 1, + "enabled": true, + "comments": "abc", + "cidrBlock": "1.2.3.4/8", + "createdDate": "2024-06-17T08:46:41.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-17T08:46:41.000Z", + "modifiedBy": "johndoe" +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1?actions=false", + expectedResponse: &GetCIDRBlockResponse{ + CIDRBlockID: 1, + Enabled: true, + Comments: "abc", + CIDRBlock: "1.2.3.4/8", + CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + }, + "200 with actions": { + params: GetCIDRBlockRequest{CIDRBlockID: 1, Actions: true}, + responseStatus: http.StatusOK, + responseBody: ` +{ + "cidrBlockId": 1, + "enabled": true, + "comments": "abc", + "cidrBlock": "1.2.3.4/8", + "createdDate": "2024-06-17T08:46:41.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-06-17T08:46:41.000Z", + "modifiedBy": "johndoe", + "actions": { + "edit": true, + "delete": true + } +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1?actions=true", + expectedResponse: &GetCIDRBlockResponse{ + CIDRBlockID: 1, + Enabled: true, + Comments: "abc", + CIDRBlock: "1.2.3.4/8", + CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedBy: "johndoe", + Actions: &CIDRActions{ + Edit: true, + Delete: true, + }, + }, + }, + "missing required parameters": { + params: GetCIDRBlockRequest{}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "get CIDR block: struct validation: CIDRBlockID: cannot be blank") + }, + }, + "incorrect parameters": { + params: GetCIDRBlockRequest{CIDRBlockID: -1}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "get CIDR block: struct validation: CIDRBlockID: must be no less than 1") + }, + }, + "404 no such block": { + params: GetCIDRBlockRequest{CIDRBlockID: 9000}, + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/ip-acl/error-types/1010", + "httpStatus": 404, + "title": "no data found", + "detail": "", + "instance": "", + "errors": [] +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/9000?actions=false", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "/ip-acl/error-types/1010", + HTTPStatus: http.StatusNotFound, + Title: "no data found", + Detail: "", + StatusCode: http.StatusNotFound, + Instance: "", + Errors: json.RawMessage("[]"), + } + assert.Equal(t, true, err.Is(e)) + }, + }, + "500 internal server error": { + params: GetCIDRBlockRequest{CIDRBlockID: 1}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1?actions=false", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + result, err := client.GetCIDRBlock(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestUpdateCIDRBlock(t *testing.T) { + tests := map[string]struct { + params UpdateCIDRBlockRequest + responseStatus int + responseBody string + expectedPath string + expectedRequestBody string + expectedResponse *UpdateCIDRBlockResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: UpdateCIDRBlockRequest{ + CIDRBlockID: 1, + Body: UpdateCIDRBlockBody{ + CIDRBlock: "1.2.3.4/32", + Comments: "abc - updated", + Enabled: false, + }, + }, + responseStatus: http.StatusOK, + responseBody: ` +{ + "cidrBlockId": 1234, + "enabled": false, + "comments": "abc - updated", + "cidrBlock": "1.2.3.4/32", + "createdDate": "2024-07-15T13:53:49.000Z", + "createdBy": "johndoe", + "modifiedDate": "2024-07-16T13:53:49.000Z", + "modifiedBy": "johndoe" +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1", + expectedRequestBody: `{"cidrBlock":"1.2.3.4/32","comments":"abc - updated","enabled":false}`, + expectedResponse: &UpdateCIDRBlockResponse{ + CIDRBlockID: 1234, + Enabled: false, + Comments: "abc - updated", + CIDRBlock: "1.2.3.4/32", + CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedBy: "johndoe", + ModifiedDate: "2024-07-16T13:53:49.000Z", + ModifiedBy: "johndoe", + Actions: nil, + }, + }, + "missing required parameters": { + params: UpdateCIDRBlockRequest{}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "update CIDR block: struct validation: CIDRBlock: cannot be blank\nCIDRBlockID: cannot be blank") + }, + }, + "invalid required parameters": { + params: UpdateCIDRBlockRequest{ + CIDRBlockID: -1, + Body: UpdateCIDRBlockBody{ + CIDRBlock: "1.2.3.4/32", + Comments: "abc - updated", + Enabled: false, + }, + }, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "update CIDR block: struct validation: CIDRBlockID: must be no less than 1") + }, + }, + "500 internal server error": { + params: UpdateCIDRBlockRequest{ + CIDRBlockID: 1, + Body: UpdateCIDRBlockBody{ + CIDRBlock: "1.2.3.4/32", + Comments: "abc - updated", + Enabled: false, + }, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + if len(test.expectedRequestBody) > 0 { + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + assert.Equal(t, test.expectedRequestBody, string(body)) + } + })) + client := mockAPIClient(t, mockServer) + result, err := client.UpdateCIDRBlock(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestDeleteCIDRBlocks(t *testing.T) { + tests := map[string]struct { + params DeleteCIDRBlockRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 No content": { + params: DeleteCIDRBlockRequest{CIDRBlockID: 1}, + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1", + }, + "missing required parameters": { + params: DeleteCIDRBlockRequest{}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "delete CIDR block: struct validation: CIDRBlockID: cannot be blank") + }, + }, + "incorrect parameters": { + params: DeleteCIDRBlockRequest{CIDRBlockID: -1}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "delete CIDR block: struct validation: CIDRBlockID: must be no less than 1") + }, + }, + "404 no such block": { + params: DeleteCIDRBlockRequest{CIDRBlockID: 9000}, + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/ip-acl/error-types/1010", + "httpStatus": 404, + "title": "no data found", + "detail": "", + "instance": "", + "errors": [] +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/9000", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "/ip-acl/error-types/1010", + HTTPStatus: http.StatusNotFound, + Title: "no data found", + Detail: "", + StatusCode: http.StatusNotFound, + Instance: "", + Errors: json.RawMessage("[]"), + } + assert.Equal(t, true, err.Is(e)) + }, + }, + "500 internal server error": { + params: DeleteCIDRBlockRequest{CIDRBlockID: 1}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/1", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodDelete, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + err := client.DeleteCIDRBlock(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestValidateCIDRBlocks(t *testing.T) { + tests := map[string]struct { + params ValidateCIDRBlockRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 No content": { + params: ValidateCIDRBlockRequest{CIDRBlock: "1.2.3.4/32"}, + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/validate?cidrblock=1.2.3.4%2F32", + }, + "missing required parameters": { + params: ValidateCIDRBlockRequest{}, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "validate CIDR block: struct validation: CIDRBlock: cannot be blank") + }, + }, + "400 invalid": { + params: ValidateCIDRBlockRequest{CIDRBlock: "abc"}, + responseStatus: http.StatusBadRequest, + responseBody: ` +{ + "type": "/ip-acl/error-types/1013", + "httpStatus": 400, + "title": "CIDR format not correct", + "detail": "invalid cidr format", + "instance": "", + "errors": [] +}`, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/validate?cidrblock=abc", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "/ip-acl/error-types/1013", + HTTPStatus: http.StatusBadRequest, + Title: "CIDR format not correct", + Detail: "invalid cidr format", + StatusCode: http.StatusBadRequest, + Instance: "", + Errors: json.RawMessage("[]"), + } + assert.Equal(t, true, err.Is(e)) + }, + }, + "500 internal server error": { + params: ValidateCIDRBlockRequest{CIDRBlock: "1.2.3.4/32"}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/validate?cidrblock=1.2.3.4%2F32", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + err := client.ValidateCIDRBlock(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index bc98a425..19b2d50f 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -19,6 +19,7 @@ type ( // IAM is the IAM api interface IAM interface { BlockedProperties + CIDR Groups Helper IPAllowlist diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index d4797906..326832d6 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -416,3 +416,55 @@ func (m *Mock) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodes return args.Get(0).(ListAllowedCPCodesResponse), args.Error(1) } + +func (m *Mock) ListCIDRBlocks(ctx context.Context, request ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*ListCIDRBlocksResponse), args.Error(1) +} + +func (m *Mock) CreateCIDRBlock(ctx context.Context, request CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*CreateCIDRBlockResponse), args.Error(1) +} + +func (m *Mock) GetCIDRBlock(ctx context.Context, request GetCIDRBlockRequest) (*GetCIDRBlockResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*GetCIDRBlockResponse), args.Error(1) +} + +func (m *Mock) UpdateCIDRBlock(ctx context.Context, request UpdateCIDRBlockRequest) (*UpdateCIDRBlockResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*UpdateCIDRBlockResponse), args.Error(1) +} + +func (m *Mock) DeleteCIDRBlock(ctx context.Context, request DeleteCIDRBlockRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} + +func (m *Mock) ValidateCIDRBlock(ctx context.Context, request ValidateCIDRBlockRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} From 21f2bc62a3f980d4b9d4fca46c4db148e4fc7d18 Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Mon, 22 Jul 2024 13:53:34 +0000 Subject: [PATCH 18/34] DXE-3997 Add support for properties interface --- CHANGELOG.md | 6 +- pkg/iam/mocks.go | 20 +++ pkg/iam/properties.go | 137 ++++++++++++++++++ pkg/iam/properties_test.go | 280 +++++++++++++++++++++++++++++++++++++ 4 files changed, 442 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2df685a9..d55b2d42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -398,7 +398,11 @@ * Added Helper APIs * [ListAllowedCPCodes](https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes) - + +* IAM + * Added new methods: + * [ListUsersForProperty](https://techdocs.akamai.com/iam-api/reference/get-property-users) + * [BlockUsers](https://techdocs.akamai.com/iam-api/reference/put-property-users-block) diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 326832d6..5e60b3e2 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -349,6 +349,16 @@ func (m *Mock) ListProperties(ctx context.Context, request ListPropertiesRequest return args.Get(0).(*ListPropertiesResponse), args.Error(1) } +func (m *Mock) ListUsersForProperty(ctx context.Context, request ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*ListUsersForPropertyResponse), args.Error(1) +} + func (m *Mock) GetProperty(ctx context.Context, request GetPropertyRequest) (*GetPropertyResponse, error) { args := m.Called(ctx, request) @@ -468,3 +478,13 @@ func (m *Mock) ValidateCIDRBlock(ctx context.Context, request ValidateCIDRBlockR return args.Error(0) } + +func (m *Mock) BlockUsers(ctx context.Context, request BlockUsersRequest) (*BlockUsersResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*BlockUsersResponse), args.Error(1) +} diff --git a/pkg/iam/properties.go b/pkg/iam/properties.go index 415108c8..6360ae5f 100644 --- a/pkg/iam/properties.go +++ b/pkg/iam/properties.go @@ -21,6 +21,11 @@ type ( // See: https://techdocs.akamai.com/iam-api/reference/get-properties ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) + // ListUsersForProperty lists users who can access a property. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-property-users + ListUsersForProperty(context.Context, ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) + // GetProperty lists a property's details. // // See: https://techdocs.akamai.com/iam-api/reference/get-property @@ -35,6 +40,11 @@ type ( // Mainly to be used to map (IAM) Property ID to (PAPI) Property ID // To finish the mapping, please use papi.MapPropertyNameToID MapPropertyIDToName(context.Context, MapPropertyIDToNameRequest) (*string, error) + + // BlockUsers blocks the users on a property. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-property-users-block + BlockUsers(context.Context, BlockUsersRequest) (*BlockUsersResponse, error) } // ListPropertiesRequest contains the request parameters for the list properties operation. @@ -43,6 +53,12 @@ type ( Actions bool } + // ListUsersForPropertyRequest contains the request parameters for the ListUsersForProperty operation. + ListUsersForPropertyRequest struct { + PropertyID int64 + UserType string + } + // GetPropertyRequest contains the request parameters for the get property operation. GetPropertyRequest struct { PropertyID int64 @@ -52,9 +68,18 @@ type ( // MapPropertyNameToIDRequest is the argument for MapPropertyNameToID MapPropertyNameToIDRequest string + // BlockUsersRequest contains the request parameters for the BlockUsers operation. + BlockUsersRequest struct { + PropertyID int64 + BodyParams BlockUsersReqBody + } + // ListPropertiesResponse holds the response data from ListProperties. ListPropertiesResponse []Property + // ListUsersForPropertyResponse holds the response data from ListUsersForProperty. + ListUsersForPropertyResponse []UsersForProperty + // GetPropertyResponse holds the response data from GetProperty. GetPropertyResponse struct { ARLConfigFile string `json:"arlConfigFile"` @@ -68,6 +93,9 @@ type ( PropertyName string `json:"propertyName"` } + // BlockUsersResponse holds the response data from BlockUsers. + BlockUsersResponse []UsersForProperty + // MovePropertyRequest contains the request parameters for the MoveProperty operation. MovePropertyRequest struct { PropertyID int64 @@ -80,6 +108,14 @@ type ( SourceGroupID int64 `json:"sourceGroupId"` } + // BlockUsersReqBody hold the request body parameters for BlockUsers operation. + BlockUsersReqBody []BlockUserItem + + // BlockUserItem contains body parameters for the BlockUsers operation. + BlockUserItem struct { + UIIdentityID string `json:"uiIdentityId"` + } + // Property holds the property details. Property struct { PropertyID int64 `json:"propertyId"` @@ -100,8 +136,25 @@ type ( PropertyID int64 GroupID int64 } + + // UsersForProperty holds details about the users accessing the property. + UsersForProperty struct { + FirstName string `json:"firstName"` + IsBlocked bool `json:"isBlocked"` + LastName string `json:"lastName"` + UIIdentityID string `json:"uiIdentityId"` + UIUserName string `json:"uiUserName"` + } ) +// Validate validates ListUsersForPropertyRequest +func (r ListUsersForPropertyRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "PropertyID": validation.Validate(r.PropertyID, validation.Required), + "UserType": validation.Validate(r.UserType, validation.In(LostAccessUsers, GainAccessUsers)), + }) +} + // Validate validates GetPropertyRequest func (r GetPropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ @@ -134,9 +187,26 @@ func (r MovePropertyReqBody) Validate() error { }) } +// Validate validates BlockUsersRequest +func (r BlockUsersRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "PropertyID": validation.Validate(r.PropertyID, validation.Required), + "BodyParams": validation.Validate(r.BodyParams, validation.Required), + }) +} + +// Validate validates BlockUsersReqBody +func (r BlockUserItem) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "UIIdentityID": validation.Validate(r.UIIdentityID, validation.Required), + }) +} + var ( // ErrListProperties is returned when ListProperties fails ErrListProperties = errors.New("list properties") + // ErrListUsersForProperty is returned when ListUsersForProperty fails + ErrListUsersForProperty = errors.New("list users for property") // ErrGetProperty is returned when GetProperty fails ErrGetProperty = errors.New("get property") // ErrMoveProperty is returned when MoveProperty fails @@ -147,6 +217,8 @@ var ( ErrMapPropertyNameToID = errors.New("map property by name") // ErrNoProperty is returned when MapPropertyNameToID did not find given property ErrNoProperty = errors.New("no such property") + // ErrBlockUsers is returned when BlockUsers fails + ErrBlockUsers = errors.New("block users") ) func (i *iam) ListProperties(ctx context.Context, params ListPropertiesRequest) (*ListPropertiesResponse, error) { @@ -183,6 +255,43 @@ func (i *iam) ListProperties(ctx context.Context, params ListPropertiesRequest) return &result, nil } +func (i *iam) ListUsersForProperty(ctx context.Context, params ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListUsersForProperty") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrListUsersForProperty, ErrStructValidation, err) + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/properties/%d/users", params.PropertyID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListUsersForProperty, err) + } + + if params.UserType != "" { + q := uri.Query() + q.Add("userType", params.UserType) + uri.RawQuery = q.Encode() + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListUsersForProperty, err) + } + + var result ListUsersForPropertyResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListUsersForProperty, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListUsersForProperty, i.Error(resp)) + } + + return &result, nil +} + func (i *iam) GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) { logger := i.Log(ctx) logger.Debug("GetProperty") @@ -287,3 +396,31 @@ func (i *iam) MapPropertyNameToID(ctx context.Context, name MapPropertyNameToIDR return nil, fmt.Errorf("%w: %s", ErrNoProperty, name) } + +func (i *iam) BlockUsers(ctx context.Context, params BlockUsersRequest) (*BlockUsersResponse, error) { + logger := i.Log(ctx) + logger.Debug("BlockUsers") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrBlockUsers, ErrStructValidation, err) + } + + uri := fmt.Sprintf("/identity-management/v3/user-admin/properties/%d/users/block", params.PropertyID) + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrBlockUsers, err) + } + + var result BlockUsersResponse + resp, err := i.Exec(req, &result, params.BodyParams) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrBlockUsers, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrBlockUsers, i.Error(resp)) + } + + return &result, nil +} diff --git a/pkg/iam/properties_test.go b/pkg/iam/properties_test.go index a0a130e1..1df753a3 100644 --- a/pkg/iam/properties_test.go +++ b/pkg/iam/properties_test.go @@ -147,6 +147,111 @@ func TestListProperties(t *testing.T) { } } +func TestListUserForProperty(t *testing.T) { + tests := map[string]struct { + params ListUsersForPropertyRequest + responseStatus int + expectedPath string + responseBody string + expectedResponse *ListUsersForPropertyResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListUsersForPropertyRequest{ + PropertyID: 1, + }, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/user-admin/properties/1/users", + responseBody: ` +[ + { + "firstName": "John", + "isBlocked": true, + "lastName": "Doe", + "uiIdentityId": "A-test-1234", + "uiUserName": "jdoe" + }, + { + "firstName": "Jan", + "isBlocked": false, + "lastName": "Kowalski", + "uiIdentityId": "A-test-12345", + "uiUserName": "jkowalski" + } +] +`, + expectedResponse: &ListUsersForPropertyResponse{ + { + FirstName: "John", + IsBlocked: true, + LastName: "Doe", + UIIdentityID: "A-test-1234", + UIUserName: "jdoe", + }, + { + FirstName: "Jan", + IsBlocked: false, + LastName: "Kowalski", + UIIdentityID: "A-test-12345", + UIUserName: "jkowalski", + }, + }, + }, + "validation errors": { + params: ListUsersForPropertyRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "list users for property: struct validation:\nPropertyID: cannot be blank", err.Error()) + }, + }, + "404 not found": { + params: ListUsersForPropertyRequest{ + PropertyID: 1, + UserType: GainAccessUsers, + }, + responseStatus: http.StatusNotFound, + expectedPath: "/identity-management/v3/user-admin/properties/1/users?userType=gainAccess", + responseBody: ` +{ + "instance": "", + "httpStatus": 404, + "detail": "", + "title": "Property not found", + "type": "/useradmin-api/error-types/1806" +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "/useradmin-api/error-types/1806", + Title: "Property not found", + StatusCode: http.StatusNotFound, + HTTPStatus: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + users, err := client.ListUsersForProperty(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, test.expectedResponse, users) + }) + } +} + func TestGetProperty(t *testing.T) { tests := map[string]struct { params GetPropertyRequest @@ -415,3 +520,178 @@ func TestMapPropertyIDToName(t *testing.T) { }) } } + +func TestBlockUsers(t *testing.T) { + tests := map[string]struct { + params BlockUsersRequest + expectedPath string + expectedRequestBody string + responseStatus int + responseBody string + expectedResponse *BlockUsersResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: BlockUsersRequest{ + PropertyID: 1, + BodyParams: BlockUsersReqBody{ + BlockUserItem{ + UIIdentityID: "A-test-1234", + }, + BlockUserItem{ + UIIdentityID: "A-test-12345", + }, + }, + }, + expectedRequestBody: ` +[ + { + "uiIdentityId": "A-test-1234" + }, + { + "uiIdentityId": "A-test-12345" + } +]`, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/user-admin/properties/1/users/block", + responseBody: ` +[ + { + "firstName": "John", + "isBlocked": true, + "lastName": "Doe", + "uiIdentityId": "A-test-1234", + "uiUserName": "jdoe" + }, + { + "firstName": "Jan", + "isBlocked": true, + "lastName": "Kowalski", + "uiIdentityId": "A-test-12345", + "uiUserName": "jkowalski" + } +] +`, + expectedResponse: &BlockUsersResponse{ + { + FirstName: "John", + IsBlocked: true, + LastName: "Doe", + UIIdentityID: "A-test-1234", + UIUserName: "jdoe", + }, + { + FirstName: "Jan", + IsBlocked: true, + LastName: "Kowalski", + UIIdentityID: "A-test-12345", + UIUserName: "jkowalski", + }, + }, + }, + "validation errors - no params": { + params: BlockUsersRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "block users: struct validation: BodyParams: cannot be blank\nPropertyID: cannot be blank", err.Error()) + }, + }, + "validation errors - empty body": { + params: BlockUsersRequest{ + PropertyID: 1, + BodyParams: BlockUsersReqBody{}, + }, + withError: func(t *testing.T, err error) { + assert.Equal(t, "block users: struct validation: BodyParams: cannot be blank", err.Error()) + }, + }, + "404 invalid identity": { + params: BlockUsersRequest{ + PropertyID: 1, + BodyParams: BlockUsersReqBody{ + BlockUserItem{ + UIIdentityID: "test", + }, + }, + }, + responseStatus: http.StatusNotFound, + expectedPath: "/identity-management/v3/user-admin/properties/1/users/block", + responseBody: ` +{ + "instance": "", + "httpStatus": 404, + "detail": "", + "title": "Identities [test] are not valid.", + "type": "/useradmin-api/error-types/1100" +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "/useradmin-api/error-types/1100", + Title: "Identities [test] are not valid.", + Detail: "", + HTTPStatus: http.StatusNotFound, + StatusCode: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "404 not found": { + params: BlockUsersRequest{ + PropertyID: 2, + BodyParams: BlockUsersReqBody{ + BlockUserItem{ + UIIdentityID: "A-test-1234", + }, + }, + }, + responseStatus: http.StatusNotFound, + expectedPath: "/identity-management/v3/user-admin/properties/2/users/block", + responseBody: ` +{ + "instance": "", + "httpStatus": 404, + "detail": "", + "title": "Property not found", + "type": "/useradmin-api/error-types/1806" +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "/useradmin-api/error-types/1806", + Title: "Property not found", + Detail: "", + HTTPStatus: http.StatusNotFound, + StatusCode: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + if test.expectedRequestBody != "" { + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + assert.JSONEq(t, test.expectedRequestBody, string(body)) + } + w.WriteHeader(test.responseStatus) + if test.responseBody != "" { + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + } + })) + client := mockAPIClient(t, mockServer) + users, err := client.BlockUsers(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, test.expectedResponse, users) + }) + } +} From fd7390d6e7a7e803f5a57fd16227f7c99c6ce810 Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Tue, 23 Jul 2024 09:51:34 +0000 Subject: [PATCH 19/34] DXE-4007 Add support for API Client Lock and Listing Account Switch Keys --- CHANGELOG.md | 7 + pkg/iam/api_clients.go | 138 ++++++++++++++++ pkg/iam/api_clients_test.go | 308 ++++++++++++++++++++++++++++++++++++ pkg/iam/iam.go | 1 + pkg/iam/mocks.go | 30 ++++ pkg/iam/support.go | 61 +++++++ pkg/iam/support_test.go | 190 ++++++++++++++++++++++ 7 files changed, 735 insertions(+) create mode 100644 pkg/iam/api_clients.go create mode 100644 pkg/iam/api_clients_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d55b2d42..9acd6bd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -420,6 +420,13 @@ +* IAM + * Added new methods: + * ListAccountSwitchKeys based on [ListAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys) and [ListYourAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys) + * LockAPIClient based on [LockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client) and [LockYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self) + * [UnlockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client) + + diff --git a/pkg/iam/api_clients.go b/pkg/iam/api_clients.go new file mode 100644 index 00000000..2c227fde --- /dev/null +++ b/pkg/iam/api_clients.go @@ -0,0 +1,138 @@ +package iam + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // APIClients is the IAM API clients interface + APIClients interface { + // LockAPIClient locks an API client based on `ClientID` parameter. If `ClientID` is not provided, it locks your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-lock-api-client, https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self + LockAPIClient(ctx context.Context, params LockAPIClientRequest) (*LockAPIClientResponse, error) + + // UnlockAPIClient unlocks an API client + // + // See: https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client + UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) + } + + // LockAPIClientRequest contains the request parameters for the LockAPIClient operation + LockAPIClientRequest struct { + ClientID string + } + + // UnlockAPIClientRequest contains the request parameters for the UnlockAPIClient endpoint + UnlockAPIClientRequest struct { + ClientID string + } + + // LockAPIClientResponse holds the response data from LockAPIClient + LockAPIClientResponse APIClient + + // UnlockAPIClientResponse holds the response data from UnlockAPIClient + UnlockAPIClientResponse APIClient + + // APIClient contains information about the API client + APIClient struct { + AccessToken string `json:"accessToken"` + ActiveCredentialCount int64 `json:"activeCredentialCount"` + AllowAccountSwitch bool `json:"allowAccountSwitch"` + AuthorizedUsers []string `json:"authorizedUsers"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientID string `json:"clientId"` + ClientName string `json:"clientName"` + ClientType string `json:"clientType"` + CreatedBy string `json:"createdBy"` + CreatedDate time.Time `json:"createdDate"` + IsLocked bool `json:"isLocked"` + NotificationEmails []string `json:"notificationEmails"` + ServiceConsumerToken string `json:"serviceConsumerToken"` + } +) + +// Validate validates UnlockAPIClientRequest +func (r UnlockAPIClientRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "ClientID": validation.Validate(r.ClientID, validation.Required), + }) +} + +var ( + // ErrLockAPIClient is returned when LockAPIClient fails + ErrLockAPIClient = errors.New("lock api client") + // ErrUnlockAPIClient is returned when UnlockAPIClient fails + ErrUnlockAPIClient = errors.New("unlock api client") +) + +func (i *iam) LockAPIClient(ctx context.Context, params LockAPIClientRequest) (*LockAPIClientResponse, error) { + logger := i.Log(ctx) + logger.Debug("LockAPIClient") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/lock", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrLockAPIClient, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrLockAPIClient, err) + } + + var result LockAPIClientResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrLockAPIClient, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrLockAPIClient, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) { + logger := i.Log(ctx) + logger.Debug("UnlockAPIClient") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrUnlockAPIClient, ErrStructValidation, err) + } + + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/unlock", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrUnlockAPIClient, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrUnlockAPIClient, err) + } + + var result UnlockAPIClientResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrUnlockAPIClient, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrUnlockAPIClient, i.Error(resp)) + } + + return &result, nil +} diff --git a/pkg/iam/api_clients_test.go b/pkg/iam/api_clients_test.go new file mode 100644 index 00000000..4bac1b13 --- /dev/null +++ b/pkg/iam/api_clients_test.go @@ -0,0 +1,308 @@ +package iam + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/stretchr/testify/require" + "github.com/tj/assert" +) + +func TestIAM_LockAPIClient(t *testing.T) { + tests := map[string]struct { + params LockAPIClientRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *LockAPIClientResponse + withError func(*testing.T, error) + }{ + "200 OK with specified client": { + params: LockAPIClientRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/lock", + responseStatus: http.StatusOK, + responseBody: ` +{ + "accessToken": "test_token1234", + "activeCredentialCount": 1, + "allowAccountSwitch": false, + "authorizedUsers": [ + "jdoe" + ], + "clientDescription": "Test", + "clientId": "abcd1234", + "clientName": "test", + "clientType": "CLIENT", + "createdBy": "jdoe", + "createdDate": "2022-05-13T20:04:35.000Z", + "isLocked": true, + "notificationEmails": [ + "jdoe@example.com" + ], + "serviceConsumerToken": "test_token12345" +}`, + expectedResponse: &LockAPIClientResponse{ + AccessToken: "test_token1234", + ActiveCredentialCount: 1, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"jdoe"}, + CanAutoCreateCredential: false, + ClientDescription: "Test", + ClientID: "abcd1234", + ClientName: "test", + ClientType: "CLIENT", + CreatedBy: "jdoe", + CreatedDate: test.NewTimeFromString(t, "2022-05-13T20:04:35.000Z"), + IsLocked: true, + NotificationEmails: []string{"jdoe@example.com"}, + ServiceConsumerToken: "test_token12345", + }, + }, + "200 OK - self": { + params: LockAPIClientRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/lock", + responseStatus: http.StatusOK, + responseBody: ` +{ + "accessToken": "test_token1234", + "activeCredentialCount": 1, + "allowAccountSwitch": false, + "authorizedUsers": [ + "jdoe" + ], + "clientDescription": "Test", + "clientId": "abcd1234", + "clientName": "test", + "clientType": "CLIENT", + "createdBy": "jdoe", + "createdDate": "2022-05-13T20:04:35.000Z", + "isLocked": true, + "notificationEmails": [ + "jdoe@example.com" + ], + "serviceConsumerToken": "test_token12345" +}`, + expectedResponse: &LockAPIClientResponse{ + AccessToken: "test_token1234", + ActiveCredentialCount: 1, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"jdoe"}, + CanAutoCreateCredential: false, + ClientDescription: "Test", + ClientID: "abcd1234", + ClientName: "test", + ClientType: "CLIENT", + CreatedBy: "jdoe", + CreatedDate: test.NewTimeFromString(t, "2022-05-13T20:04:35.000Z"), + IsLocked: true, + NotificationEmails: []string{"jdoe@example.com"}, + ServiceConsumerToken: "test_token12345", + }, + }, + "404 Not Found": { + params: LockAPIClientRequest{ + ClientID: "test12344", + }, + expectedPath: "/identity-management/v3/api-clients/test12344/lock", + responseStatus: http.StatusNotFound, + responseBody: ` + { + "instance": "", + "httpStatus": 404, + "detail": "", + "title": "invalid open identity", + "type": "/identity-management/error-types/2" + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Instance: "", + HTTPStatus: http.StatusNotFound, + Detail: "", + Title: "invalid open identity", + Type: "/identity-management/error-types/2", + StatusCode: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: LockAPIClientRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/lock", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.LockAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestIAM_UnlockAPIClient(t *testing.T) { + tests := map[string]struct { + params UnlockAPIClientRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *UnlockAPIClientResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: UnlockAPIClientRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/unlock", + responseStatus: http.StatusOK, + responseBody: ` +{ + "accessToken": "test_token1234", + "activeCredentialCount": 1, + "allowAccountSwitch": false, + "authorizedUsers": [ + "jdoe" + ], + "clientDescription": "Test", + "clientId": "abcd1234", + "clientName": "test", + "clientType": "CLIENT", + "createdBy": "jdoe", + "createdDate": "2022-05-13T20:04:35.000Z", + "isLocked": true, + "notificationEmails": [ + "jdoe@example.com" + ], + "serviceConsumerToken": "test_token12345" +}`, + expectedResponse: &UnlockAPIClientResponse{ + AccessToken: "test_token1234", + ActiveCredentialCount: 1, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"jdoe"}, + CanAutoCreateCredential: false, + ClientDescription: "Test", + ClientID: "abcd1234", + ClientName: "test", + ClientType: "CLIENT", + CreatedBy: "jdoe", + CreatedDate: test.NewTimeFromString(t, "2022-05-13T20:04:35.000Z"), + IsLocked: true, + NotificationEmails: []string{"jdoe@example.com"}, + ServiceConsumerToken: "test_token12345", + }, + }, + "validation errors": { + params: UnlockAPIClientRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "unlock api client: struct validation:\nClientID: cannot be blank", err.Error()) + }, + }, + "404 Not Found": { + params: UnlockAPIClientRequest{ + ClientID: "test12344", + }, + expectedPath: "/identity-management/v3/api-clients/test12344/unlock", + responseStatus: http.StatusNotFound, + responseBody: ` + { + "instance": "", + "httpStatus": 404, + "detail": "", + "title": "invalid open identity", + "type": "/identity-management/error-types/2" + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Instance: "", + HTTPStatus: http.StatusNotFound, + Detail: "", + Title: "invalid open identity", + Type: "/identity-management/error-types/2", + StatusCode: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: UnlockAPIClientRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/unlock", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.UnlockAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index 19b2d50f..3852fc66 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -18,6 +18,7 @@ var ( type ( // IAM is the IAM api interface IAM interface { + APIClients BlockedProperties CIDR Groups diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 5e60b3e2..32cce541 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -104,6 +104,16 @@ func (m *Mock) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) return args.Get(0).([]TimeoutPolicy), args.Error(1) } +func (m *Mock) ListAccountSwitchKeys(ctx context.Context, request ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*ListAccountSwitchKeysResponse), args.Error(1) +} + func (m *Mock) ListStates(ctx context.Context, request ListStatesRequest) ([]string, error) { args := m.Called(ctx, request) @@ -395,6 +405,26 @@ func (m *Mock) MapPropertyNameToID(ctx context.Context, request MapPropertyNameT return args.Get(0).(*int64), args.Error(1) } +func (m *Mock) LockAPIClient(ctx context.Context, request LockAPIClientRequest) (*LockAPIClientResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*LockAPIClientResponse), args.Error(1) +} + +func (m *Mock) UnlockAPIClient(ctx context.Context, request UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*UnlockAPIClientResponse), args.Error(1) +} + func (m *Mock) DisableIPAllowlist(ctx context.Context) error { args := m.Called(ctx) diff --git a/pkg/iam/support.go b/pkg/iam/support.go index 4c6cc6dc..aa16e4cb 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "net/url" validation "github.com/go-ozzo/ozzo-validation/v4" ) @@ -32,6 +33,11 @@ type ( // See: https://techdocs.akamai.com/iam-api/reference/get-common-timeout-policies ListTimeoutPolicies(context.Context) ([]TimeoutPolicy, error) + // ListAccountSwitchKeys lists account switch keys available for a specific API client. If `ClientID` is not provided, it lists account switch keys available for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys, https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys + ListAccountSwitchKeys(context.Context, ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) + // SupportedContactTypes lists supported contact types // // See: https://techdocs.akamai.com/iam-api/reference/get-common-contact-types @@ -77,6 +83,21 @@ type ( Country string } + // ListAccountSwitchKeysRequest contains the request parameters for the ListAccountSwitchKeys endpoint + ListAccountSwitchKeysRequest struct { + ClientID string + Search string + } + + // ListAccountSwitchKeysResponse holds the response data from ListAccountSwitchKeys + ListAccountSwitchKeysResponse []AccountSwitchKey + + // AccountSwitchKey contains information about account switch key + AccountSwitchKey struct { + AccountName string `json:"accountName"` + AccountSwitchKey string `json:"accountSwitchKey"` + } + // Timezone contains the response of the list supported timezones endpoint Timezone struct { Description string `json:"description"` @@ -99,6 +120,9 @@ var ( // ErrListTimeoutPolicies is returned when ListTimeoutPolicies fails ErrListTimeoutPolicies = errors.New("list timeout policies") + // ErrListAccountSwitchKeys is returned when ListAccountSwitchKeys fails + ErrListAccountSwitchKeys = errors.New("list account switch keys") + // ErrSupportedContactTypes is returned when SupportedContactTypes fails ErrSupportedContactTypes = errors.New("supported contact types") @@ -219,6 +243,43 @@ func (i *iam) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) return rval, nil } +func (i *iam) ListAccountSwitchKeys(ctx context.Context, params ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAccountSwitchKeys") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/account-switch-keys", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListAccountSwitchKeys, err) + } + + if params.Search != "" { + q := uri.Query() + q.Add("search", params.Search) + uri.RawQuery = q.Encode() + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAccountSwitchKeys, err) + } + + var result ListAccountSwitchKeysResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListAccountSwitchKeys, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListAccountSwitchKeys, i.Error(resp)) + } + + return &result, nil +} + func (i *iam) SupportedContactTypes(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedContactTypes") diff --git a/pkg/iam/support_test.go b/pkg/iam/support_test.go index 3f2b601b..e624abbd 100644 --- a/pkg/iam/support_test.go +++ b/pkg/iam/support_test.go @@ -557,3 +557,193 @@ func TestIAM_ListStates(t *testing.T) { }) } } + +func TestIAM_ListAccountSwitchKeys(t *testing.T) { + tests := map[string]struct { + params ListAccountSwitchKeysRequest + responseStatus int + expectedPath string + responseBody string + expectedResponse *ListAccountSwitchKeysResponse + withError func(*testing.T, error) + }{ + "200 OK with specified client": { + params: ListAccountSwitchKeysRequest{ + ClientID: "test1234", + }, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/api-clients/test1234/account-switch-keys", + responseBody: ` +[ + { + "accountName": "Test Name A", + "accountSwitchKey": "ABC-123" + }, + { + "accountName": "Test Name A", + "accountSwitchKey": "ABCD-1234" + }, + { + "accountName": "Test Name B", + "accountSwitchKey": "ABCDE-12345" + } +] +`, + expectedResponse: &ListAccountSwitchKeysResponse{ + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABC-123", + }, + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABCD-1234", + }, + AccountSwitchKey{ + AccountName: "Test Name B", + AccountSwitchKey: "ABCDE-12345", + }, + }, + }, + "200 OK without specified client": { + params: ListAccountSwitchKeysRequest{}, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/api-clients/self/account-switch-keys", + responseBody: ` +[ + { + "accountName": "Test Name A", + "accountSwitchKey": "ABC-123" + }, + { + "accountName": "Test Name A", + "accountSwitchKey": "ABCD-1234" + }, + { + "accountName": "Test Name B", + "accountSwitchKey": "ABCDE-12345" + } +] +`, + expectedResponse: &ListAccountSwitchKeysResponse{ + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABC-123", + }, + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABCD-1234", + }, + AccountSwitchKey{ + AccountName: "Test Name B", + AccountSwitchKey: "ABCDE-12345", + }, + }, + }, + "200 OK - no account switch keys": { + params: ListAccountSwitchKeysRequest{ + ClientID: "test1234", + }, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/api-clients/test1234/account-switch-keys", + responseBody: `[]`, + expectedResponse: &ListAccountSwitchKeysResponse{}, + }, + "200 OK with query param": { + params: ListAccountSwitchKeysRequest{ + ClientID: "test1234", + Search: "Name A", + }, + responseStatus: http.StatusOK, + expectedPath: "/identity-management/v3/api-clients/test1234/account-switch-keys?search=Name+A", + responseBody: ` +[ + { + "accountName": "Test Name A", + "accountSwitchKey": "ABC-123" + }, + { + "accountName": "Test Name A", + "accountSwitchKey": "ABCD-1234" + } +] +`, + expectedResponse: &ListAccountSwitchKeysResponse{ + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABC-123", + }, + AccountSwitchKey{ + AccountName: "Test Name A", + AccountSwitchKey: "ABCD-1234", + }, + }, + }, + "404 not found": { + params: ListAccountSwitchKeysRequest{ + ClientID: "test12344", + }, + responseStatus: http.StatusNotFound, + expectedPath: "/identity-management/v3/api-clients/test12344/account-switch-keys", + responseBody: ` +{ + "instances": "", + "type": "/identity-management/error-types/2", + "status": 404, + "title": "invalid open identity", + "detail": "" +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "/identity-management/error-types/2", + Title: "invalid open identity", + StatusCode: http.StatusNotFound, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: ListAccountSwitchKeysRequest{ + ClientID: "test12344", + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +}`, + expectedPath: "/identity-management/v3/api-clients/test12344/account-switch-keys", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + users, err := client.ListAccountSwitchKeys(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, test.expectedResponse, users) + }) + } +} From d48f133233ca2f9bc92b3a76c6e3cf4685d166cd Mon Sep 17 00:00:00 2001 From: rbhatved Date: Tue, 23 Jul 2024 16:08:40 +0530 Subject: [PATCH 20/34] DXE-3994 Fixed bug with UpdateMFA --- pkg/iam/user.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pkg/iam/user.go b/pkg/iam/user.go index c0908378..e5a59913 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -624,17 +624,12 @@ func (i *iam) UpdateMFA(ctx context.Context, params UpdateMFARequest) error { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) } - reqBody, err := convertStructToReqBody(params.Value) - if err != nil { - return fmt.Errorf("failed to generate request body: %w", err) - } - - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), reqBody) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) } - resp, err := i.Exec(req, nil, nil) + resp, err := i.Exec(req, nil, params.Value) if err != nil { return fmt.Errorf("%w: request failed: %s", ErrUpdateMFA, err) } From 2e9f75b57665d623afcfe65ddddd3f15246ffbbe Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Wed, 24 Jul 2024 07:32:15 +0000 Subject: [PATCH 21/34] DXE-4061 Align User interface to changes in V3 API --- CHANGELOG.md | 8 ++- pkg/iam/user.go | 27 +++++----- pkg/iam/user_test.go | 115 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 119 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9acd6bd7..eb300c84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,13 @@ - +* IAM + * Changed `Notifications` to pointer type in following structures: + * `CreateUserRequest` + * `UpdateUserNotificationsRequest` + * Added `UsertStatus`, `AccountID` to the `User` structure + * Added required field `AdditionalAuthentication` to the `CreateUserRequest` + * Made `Notifications` required in `UpdateUserNotifications` method diff --git a/pkg/iam/user.go b/pkg/iam/user.go index e5a59913..833c3c59 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -6,7 +6,6 @@ import ( "fmt" "net/http" "net/url" - "path" "strconv" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" @@ -73,7 +72,7 @@ type ( CreateUserRequest struct { UserBasicInfo AuthGrants []AuthGrantRequest `json:"authGrants,omitempty"` - Notifications UserNotifications `json:"notifications,omitempty"` + Notifications *UserNotifications `json:"notifications,omitempty"` SendEmail bool `json:"-"` } @@ -101,7 +100,7 @@ type ( // UpdateUserNotificationsRequest contains the request parameters of the update user notifications endpoint UpdateUserNotificationsRequest struct { IdentityID string - Notifications UserNotifications + Notifications *UserNotifications } // UpdateUserAuthGrantsRequest contains the request parameters of the update user auth grants endpoint @@ -127,6 +126,8 @@ type ( AuthGrants []AuthGrant `json:"authGrants,omitempty"` Notifications UserNotifications `json:"notifications,omitempty"` Actions *UserActions `json:"actions,omitempty"` + UserStatus string `json:"userStatus"` + AccountID string `json:"accountId"` AdditionalAuthenticationConfigured bool `json:"additionalAuthenticationConfigured"` } @@ -303,12 +304,13 @@ func (r AuthGrant) Validate() error { // Validate validates CreateUserRequest func (r CreateUserRequest) Validate() error { return validation.Errors{ - "Country": validation.Validate(r.Country, validation.Required), - "Email": validation.Validate(r.Email, validation.Required, is.EmailFormat), - "FirstName": validation.Validate(r.FirstName, validation.Required), - "LastName": validation.Validate(r.LastName, validation.Required), - "AuthGrants": validation.Validate(r.AuthGrants, validation.Required), - "Notifications": validation.Validate(r.Notifications, validation.Required), + "Country": validation.Validate(r.Country, validation.Required), + "Email": validation.Validate(r.Email, validation.Required, is.EmailFormat), + "FirstName": validation.Validate(r.FirstName, validation.Required), + "LastName": validation.Validate(r.LastName, validation.Required), + "AuthGrants": validation.Validate(r.AuthGrants, validation.Required), + "Notifications": validation.Validate(r.Notifications), + "AdditionalAuthentication": validation.Validate(r.AdditionalAuthentication, validation.In(MFAAuthentication, TFAAuthentication, NoneAuthentication), validation.Required), }.Filter() } @@ -335,7 +337,8 @@ func (r UpdateUserInfoRequest) Validate() error { // Validate validates UpdateUserNotificationsRequest func (r UpdateUserNotificationsRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ - "IdentityID": validation.Validate(r.IdentityID, validation.Required), + "IdentityID": validation.Validate(r.IdentityID, validation.Required), + "Notifications": validation.Validate(r.Notifications, validation.Required), }) } @@ -376,7 +379,7 @@ func (i *iam) CreateUser(ctx context.Context, params CreateUserRequest) (*User, return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateUser, ErrStructValidation, err) } - u, err := url.Parse(path.Join("/identity-management/v2/user-admin", "ui-identities")) + u, err := url.Parse("/identity-management/v3/user-admin/ui-identities") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateUser, err) } @@ -409,7 +412,7 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) return nil, fmt.Errorf("%s: %w:\n%s", ErrGetUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s", params.IdentityID)) + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index 629c8638..fea6dfe5 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -34,10 +34,9 @@ func TestIAM_CreateUser(t *testing.T) { State: "CA", AdditionalAuthentication: NoneAuthentication, }, - AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, - Notifications: UserNotifications{}, + AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, }, - requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","additionalAuthentication":"NONE","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}],"notifications":{"enableEmailNotifications":false,"options":{"newUserNotification":false,"passwordExpiry":false,"proactive":null,"upgrade":null,"apiClientCredentialExpiryNotification":false}}}`, + requestBody: `{"firstName":"John","lastName":"Doe","email":"john.doe@mycompany.com","phone":"(123) 321-1234","jobTitle":"","tfaEnabled":false,"state":"CA","country":"USA","additionalAuthentication":"NONE","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}]}`, responseStatus: http.StatusCreated, responseBody: ` { @@ -51,7 +50,7 @@ func TestIAM_CreateUser(t *testing.T) { "additionalAuthenticationConfigured": false, "additionalAuthentication": "NONE" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities?sendEmail=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities?sendEmail=false", expectedResponse: &User{ IdentityID: "A-BC-1234567", UserBasicInfo: UserBasicInfo{ @@ -66,18 +65,88 @@ func TestIAM_CreateUser(t *testing.T) { AdditionalAuthenticationConfigured: false, }, }, + "201 OK - all fields": { + params: CreateUserRequest{ + UserBasicInfo: UserBasicInfo{ + FirstName: "John", + LastName: "Doe", + UserName: "UserName", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + TimeZone: "GMT+2", + JobTitle: "Title", + SecondaryEmail: "second@email.com", + MobilePhone: "123123123", + Address: "Address", + City: "City", + State: "CA", + ZipCode: "11-111", + Country: "USA", + ContactType: "Dev", + PreferredLanguage: "EN", + SessionTimeOut: ptr.To(1), + AdditionalAuthentication: MFAAuthentication, + }, + AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, + Notifications: &UserNotifications{ + EnableEmail: false, + Options: UserNotificationOptions{ + NewUser: false, + PasswordExpiry: false, + Proactive: []string{"Test1"}, + Upgrade: []string{"Test2"}, + APIClientCredentialExpiry: false, + }, + }, + SendEmail: true, + }, + requestBody: `{"firstName":"John","lastName":"Doe","uiUserName":"UserName","email":"john.doe@mycompany.com","phone":"(123) 321-1234","timeZone":"GMT+2","jobTitle":"Title","tfaEnabled":false,"secondaryEmail":"second@email.com","mobilePhone":"123123123","address":"Address","city":"City","state":"CA","zipCode":"11-111","country":"USA","contactType":"Dev","preferredLanguage":"EN","sessionTimeOut":1,"additionalAuthentication":"MFA","authGrants":[{"groupId":1,"isBlocked":false,"roleId":1}],"notifications":{"enableEmailNotifications":false,"options":{"newUserNotification":false,"passwordExpiry":false,"proactive":["Test1"],"upgrade":["Test2"],"apiClientCredentialExpiryNotification":false}}}`, + responseStatus: http.StatusCreated, + responseBody: ` +{ + "uiIdentityId": "A-BC-1234567", + "firstName": "John", + "lastName": "Doe", + "email": "john.doe@mycompany.com", + "phone": "(123) 321-1234", + "state": "CA", + "country": "USA", + "additionalAuthenticationConfigured": false, + "additionalAuthentication": "NONE" +}`, + expectedPath: "/identity-management/v3/user-admin/ui-identities?sendEmail=true", + expectedResponse: &User{ + IdentityID: "A-BC-1234567", + UserBasicInfo: UserBasicInfo{ + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + AdditionalAuthentication: NoneAuthentication, + }, + AdditionalAuthenticationConfigured: false, + }, + }, + "validation errors": { + params: CreateUserRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "create user: struct validation:\nAdditionalAuthentication: cannot be blank; AuthGrants: cannot be blank; Country: cannot be blank; Email: cannot be blank; FirstName: cannot be blank; LastName: cannot be blank.", err.Error()) + }, + }, "500 internal server error": { params: CreateUserRequest{ UserBasicInfo: UserBasicInfo{ - FirstName: "John", - LastName: "Doe", - Email: "john.doe@mycompany.com", - Phone: "(123) 321-1234", - Country: "USA", - State: "CA", + FirstName: "John", + LastName: "Doe", + Email: "john.doe@mycompany.com", + Phone: "(123) 321-1234", + Country: "USA", + State: "CA", + AdditionalAuthentication: TFAAuthentication, }, - AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, - Notifications: UserNotifications{}, + AuthGrants: []AuthGrantRequest{{GroupID: 1, RoleID: ptr.To(1)}}, }, responseStatus: http.StatusInternalServerError, responseBody: ` @@ -87,7 +156,7 @@ func TestIAM_CreateUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities?sendEmail=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities?sendEmail=false", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -150,9 +219,11 @@ func TestIAM_GetUser(t *testing.T) { "email": "john.doe@mycompany.com", "phone": "(123) 321-1234", "state": "CA", - "country": "USA" + "country": "USA", + "accountId": "sampleID", + "userStatus": "PENDING" }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", expectedResponse: &User{ IdentityID: "A-BC-1234567", UserBasicInfo: UserBasicInfo{ @@ -163,6 +234,8 @@ func TestIAM_GetUser(t *testing.T) { Country: "USA", State: "CA", }, + UserStatus: "PENDING", + AccountID: "sampleID", }, }, "500 internal server error": { @@ -177,7 +250,7 @@ func TestIAM_GetUser(t *testing.T) { "detail": "Error making request", "status": 500 }`, - expectedPath: "/identity-management/v2/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", + expectedPath: "/identity-management/v3/user-admin/ui-identities/A-BC-1234567?actions=false&authGrants=false¬ifications=false", withError: func(t *testing.T, err error) { want := &Error{ Type: "internal_error", @@ -563,7 +636,7 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { "200 OK": { params: UpdateUserNotificationsRequest{ IdentityID: "1-ABCDE", - Notifications: UserNotifications{ + Notifications: &UserNotifications{ EnableEmail: true, Options: UserNotificationOptions{ Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, @@ -605,10 +678,16 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { }, }, }, + "validation errors": { + params: UpdateUserNotificationsRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "update user notifications: struct validation:\nIdentityID: cannot be blank\nNotifications: cannot be blank", err.Error()) + }, + }, "500 internal server error": { params: UpdateUserNotificationsRequest{ IdentityID: "1-ABCDE", - Notifications: UserNotifications{ + Notifications: &UserNotifications{ EnableEmail: true, Options: UserNotificationOptions{ Upgrade: []string{"NetStorage", "Other Upgrade Notifications (Planned)"}, From 3ac81a866b31e0515196d6efb30deca1d34367d0 Mon Sep 17 00:00:00 2001 From: Michal Mazur Date: Wed, 24 Jul 2024 10:53:18 +0000 Subject: [PATCH 22/34] DXE-4004 add support for helper endpoints --- CHANGELOG.md | 5 + pkg/iam/helper.go | 210 +++++++++++++++++++- pkg/iam/helper_test.go | 423 ++++++++++++++++++++++++++++++++++++++++- pkg/iam/mocks.go | 30 +++ 4 files changed, 659 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb300c84..57f8590c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -404,6 +404,11 @@ * Added Helper APIs * [ListAllowedCPCodes](https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes) +* IAM + * Added Helper APIs + * [ListAuthorizedUsers](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users) + * [ListAllowedAPIs](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis) + * [ListAccessibleGroups](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access) * IAM * Added new methods: diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go index f2583cf7..5a5d952e 100644 --- a/pkg/iam/helper.go +++ b/pkg/iam/helper.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "net/http" + "net/url" + "strconv" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" @@ -17,6 +19,21 @@ type ( // // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes ListAllowedCPCodes(context.Context, ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) + + // ListAuthorizedUsers lists authorized API client users + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users + ListAuthorizedUsers(context.Context) (ListAuthorizedUsersResponse, error) + + // ListAllowedAPIs lists available APIs for a user + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis + ListAllowedAPIs(context.Context, ListAllowedAPIsRequest) (ListAllowedAPIsResponse, error) + + // ListAccessibleGroups lists groups available to a user + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access + ListAccessibleGroups(context.Context, ListAccessibleGroupsRequest) (ListAccessibleGroupsResponse, error) } // ListAllowedCPCodesRequest contains the request parameter for the list of allowed CP codes endpoint @@ -25,9 +42,21 @@ type ( ListAllowedCPCodesRequestBody } + // ListAllowedAPIsRequest contains the request parameters for the list of allowed APIs endpoint + ListAllowedAPIsRequest struct { + UserName string + ClientType ClientType + AllowAccountSwitch bool + } + + // ListAccessibleGroupsRequest contains the request parameter for the list of accessible groups endpoint + ListAccessibleGroupsRequest struct { + UserName string + } + // ListAllowedCPCodesRequestBody contains the filtering parameters for the list of allowed CP codes endpoint ListAllowedCPCodesRequestBody struct { - ClientType string `json:"clientType"` + ClientType ClientType `json:"clientType"` Groups []AllowedCPCodesGroup `json:"groups"` } @@ -51,11 +80,78 @@ type ( Name string `json:"name"` Value int `json:"value"` } + + // ListAuthorizedUsersResponse contains the response for the list of authorized users endpoint + ListAuthorizedUsersResponse []AuthorizedUser + + // AuthorizedUser contains the details about the authorized user + AuthorizedUser struct { + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + Username string `json:"username"` + Email string `json:"email"` + UIIdentityID string `json:"uiIdentityId"` + } + + // ListAccessibleGroupsResponse contains the response for the list of accessible groups endpoint + ListAccessibleGroupsResponse []AccessibleGroup + + // AccessibleGroup contains the details about accessible group + AccessibleGroup struct { + GroupID int64 `json:"groupId"` + RoleID int64 `json:"roleId"` + GroupName string `json:"groupName"` + RoleName string `json:"roleName"` + IsBlocked bool `json:"isBlocked"` + RoleDescription string `json:"roleDescription"` + SubGroups []AccessibleSubGroup `json:"subGroups"` + } + + // AccessibleSubGroup contains the details about subgroup + AccessibleSubGroup struct { + GroupID int64 `json:"groupId"` + GroupName string `json:"groupName"` + ParentGroupID int64 `json:"parentGroupId"` + SubGroups []AccessibleSubGroup `json:"subGroups"` + } + + // ListAllowedAPIsResponse contains the response for the list of allowed APIs endpoint + ListAllowedAPIsResponse []AllowedAPI + + // AllowedAPI contains the details about the API + AllowedAPI struct { + AccessLevels []string `json:"accessLevels"` + APIID int64 `json:"apiId"` + APIName string `json:"apiName"` + Description string `json:"description"` + DocumentationURL string `json:"documentationUrl"` + Endpoint string `json:"endpoint"` + HasAccess bool `json:"hasAccess"` + ServiceProviderID int64 `json:"serviceProviderId"` + } + + // ClientType represents the type of the client + ClientType string +) + +const ( + // UserClientType is the `USER_CLIENT` client type + UserClientType ClientType = "USER_CLIENT" + // ServiceAccountClientType is the `SERVICE_ACCOUNT` client type + ServiceAccountClientType ClientType = "SERVICE_ACCOUNT" + // ClientClientType is the `CLIENT` client type + ClientClientType ClientType = "CLIENT" ) var ( // ErrListAllowedCPCodes is returned when ListAllowedCPCodes fails ErrListAllowedCPCodes = errors.New("list allowed CP codes") + // ErrListAuthorizedUsers is returned when ListAuthorizedUsers fails + ErrListAuthorizedUsers = errors.New("list authorized users") + // ErrListAllowedAPIs is returned when ListAllowedAPIs fails + ErrListAllowedAPIs = errors.New("list allowed APIs") + // ErrAccessibleGroups is returned when ListAccessibleGroups fails + ErrAccessibleGroups = errors.New("list accessible groups") ) // Validate validates ListAllowedCPCodesRequest @@ -69,11 +165,26 @@ func (r ListAllowedCPCodesRequest) Validate() error { // Validate validates ListAllowedCPCodesRequestBody func (r ListAllowedCPCodesRequestBody) Validate() error { return validation.Errors{ - "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In("CLIENT", "USER_CLIENT", "SERVICE_ACCOUNT").Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'", r.ClientType))), - "Groups": validation.Validate(r.Groups, validation.Required.When(r.ClientType == "SERVICE_ACCOUNT")), + "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType, ServiceAccountClientType).Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'", r.ClientType))), + "Groups": validation.Validate(r.Groups, validation.Required.When(r.ClientType == ServiceAccountClientType)), }.Filter() } +// Validate validates ListAllowedAPIsRequest +func (r ListAllowedAPIsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "UserName": validation.Validate(r.UserName, validation.Required), + "ClientType": validation.Validate(r.ClientType, validation.In(ClientClientType, UserClientType, ServiceAccountClientType).Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'", r.ClientType))), + }) +} + +// Validate validates ListAccessibleGroupsRequest +func (r ListAccessibleGroupsRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "UserName": validation.Validate(r.UserName, validation.Required), + }) +} + func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) { logger := i.Log(ctx) logger.Debug("ListAllowedCPCodes") @@ -82,9 +193,9 @@ func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesR return nil, fmt.Errorf("%s: %w:\n%s", ErrListAllowedCPCodes, ErrStructValidation, err) } - url := fmt.Sprintf("/identity-management/v3/users/%s/allowed-cpcodes", params.UserName) + u := fmt.Sprintf("/identity-management/v3/users/%s/allowed-cpcodes", params.UserName) - req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedCPCodes, err) } @@ -101,3 +212,92 @@ func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesR return result, nil } + +func (i *iam) ListAuthorizedUsers(ctx context.Context) (ListAuthorizedUsersResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAuthorizedUsers") + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/identity-management/v3/users", nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAuthorizedUsers, err) + } + + var result ListAuthorizedUsersResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListAuthorizedUsers, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListAuthorizedUsers, i.Error(resp)) + } + + return result, nil +} + +func (i *iam) ListAllowedAPIs(ctx context.Context, params ListAllowedAPIsRequest) (ListAllowedAPIsResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAllowedAPIs") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrListAllowedAPIs, ErrStructValidation, err) + } + + u, err := url.Parse(fmt.Sprintf("/identity-management/v3/users/%s/allowed-apis", params.UserName)) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedAPIs, err) + } + + q := u.Query() + if params.ClientType != "" { + q.Add("clientType", string(params.ClientType)) + + } + q.Add("allowAccountSwitch", strconv.FormatBool(params.AllowAccountSwitch)) + u.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedAPIs, err) + } + + var result ListAllowedAPIsResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListAllowedAPIs, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListAllowedAPIs, i.Error(resp)) + } + + return result, nil +} + +func (i *iam) ListAccessibleGroups(ctx context.Context, params ListAccessibleGroupsRequest) (ListAccessibleGroupsResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAccessibleGroups") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrAccessibleGroups, ErrStructValidation, err) + } + + u := fmt.Sprintf("/identity-management/v3/users/%s/group-access", params.UserName) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrAccessibleGroups, err) + } + + var result ListAccessibleGroupsResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrAccessibleGroups, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrAccessibleGroups, i.Error(resp)) + } + + return result, nil +} diff --git a/pkg/iam/helper_test.go b/pkg/iam/helper_test.go index b51063d9..97c21045 100644 --- a/pkg/iam/helper_test.go +++ b/pkg/iam/helper_test.go @@ -24,7 +24,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { params: ListAllowedCPCodesRequest{ UserName: "jsmith", ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ - ClientType: "CLIENT", + ClientType: ClientClientType, }, }, responseStatus: http.StatusOK, @@ -70,7 +70,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { params: ListAllowedCPCodesRequest{ UserName: "jsmith", ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ - ClientType: "SERVICE_ACCOUNT", + ClientType: ServiceAccountClientType, Groups: []AllowedCPCodesGroup{ { GroupID: 1, @@ -121,7 +121,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { params: ListAllowedCPCodesRequest{ UserName: "jsmith", ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ - ClientType: "CLIENT", + ClientType: ClientClientType, }, }, responseStatus: http.StatusInternalServerError, @@ -155,7 +155,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { params: ListAllowedCPCodesRequest{ UserName: "jsmith", ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ - ClientType: "SERVICE_ACCOUNT", + ClientType: ServiceAccountClientType, }, }, withError: func(t *testing.T, err error) { @@ -186,3 +186,418 @@ func TestIAMListAllowedCPCodes(t *testing.T) { }) } } + +func TestIAMListAuthorizedUsers(t *testing.T) { + tests := map[string]struct { + responseStatus int + responseBody string + expectedPath string + expectedResponse ListAuthorizedUsersResponse + withError func(*testing.T, error) + }{ + "200 OK": { + responseStatus: http.StatusOK, + responseBody: `[ + { + "username": "test.example.user", + "firstName": "Edd", + "lastName": "Example", + "email": "test_example@akamai.com", + "uiIdentityId": "X-YZ-1111111" + }, + { + "username": "test.example.user2", + "firstName": "Fred", + "lastName": "Example2", + "email": "test_example2@akamai.com", + "uiIdentityId": "X-YZ-2222222" + }, + { + "username": "test.example.user3", + "firstName": "Ted", + "lastName": "Example3", + "email": "test_example3@akamai.com", + "uiIdentityId": "X-YZ-3333333" + } +]`, + expectedPath: "/identity-management/v3/users", + expectedResponse: ListAuthorizedUsersResponse{ + { + Username: "test.example.user", + FirstName: "Edd", + LastName: "Example", + Email: "test_example@akamai.com", + UIIdentityID: "X-YZ-1111111", + }, + { + Username: "test.example.user2", + FirstName: "Fred", + LastName: "Example2", + Email: "test_example2@akamai.com", + UIIdentityID: "X-YZ-2222222", + }, + { + Username: "test.example.user3", + FirstName: "Ted", + LastName: "Example3", + Email: "test_example3@akamai.com", + UIIdentityID: "X-YZ-3333333", + }, + }, + }, + "500 internal server error": { + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/users", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListAuthorizedUsers(context.Background()) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestIAMListAllowedAPIs(t *testing.T) { + tests := map[string]struct { + params ListAllowedAPIsRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse ListAllowedAPIsResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListAllowedAPIsRequest{ + UserName: "jsmith", + }, + responseStatus: http.StatusOK, + responseBody: `[ + { + "apiId": 1111, + "serviceProviderId": 1, + "apiName": "Test API Name", + "description": "Test API Name", + "endPoint": "/test-api-name/", + "documentationUrl": "https://example.akamai.com/", + "accessLevels": [ + "READ-WRITE", + "READ-ONLY" + ], + "hasAccess": false + }, + { + "apiId": 2222, + "serviceProviderId": 1, + "apiName": "Example API Name", + "description": "Example API Name", + "endPoint": "/example-api-name/", + "documentationUrl": "https://example2.akamai.com/", + "accessLevels": [ + "READ-WRITE", + "READ-ONLY" + ], + "hasAccess": false + }, + { + "apiId": 3333, + "serviceProviderId": 1, + "apiName": "Best API Name", + "description": "Best API Name", + "endPoint": "/best-api-name/", + "documentationUrl": "https://example3.akamai.com/", + "accessLevels": [ + "READ-WRITE", + "READ-ONLY" + ], + "hasAccess": false + } +]`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-apis?allowAccountSwitch=false", + expectedResponse: ListAllowedAPIsResponse{ + { + APIID: 1111, + ServiceProviderID: 1, + APIName: "Test API Name", + Description: "Test API Name", + Endpoint: "/test-api-name/", + DocumentationURL: "https://example.akamai.com/", + AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + HasAccess: false, + }, + { + APIID: 2222, + ServiceProviderID: 1, + APIName: "Example API Name", + Description: "Example API Name", + Endpoint: "/example-api-name/", + DocumentationURL: "https://example2.akamai.com/", + AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + HasAccess: false, + }, + { + APIID: 3333, + ServiceProviderID: 1, + APIName: "Best API Name", + Description: "Best API Name", + Endpoint: "/best-api-name/", + DocumentationURL: "https://example3.akamai.com/", + AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + HasAccess: false, + }, + }, + }, + "200 OK with query params": { + params: ListAllowedAPIsRequest{ + UserName: "jsmith", + ClientType: UserClientType, + AllowAccountSwitch: true, + }, + responseStatus: http.StatusOK, + responseBody: `[ + { + "apiId": 1111, + "serviceProviderId": 1, + "apiName": "Test API Name", + "description": "Test API Name", + "endPoint": "/test-api-name/", + "documentationUrl": "https://example.akamai.com/", + "accessLevels": [ + "READ-WRITE", + "READ-ONLY" + ], + "hasAccess": false + } +]`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-apis?allowAccountSwitch=true&clientType=USER_CLIENT", + expectedResponse: ListAllowedAPIsResponse{ + { + APIID: 1111, + ServiceProviderID: 1, + APIName: "Test API Name", + Description: "Test API Name", + Endpoint: "/test-api-name/", + DocumentationURL: "https://example.akamai.com/", + AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + HasAccess: false, + }, + }, + }, + "500 internal server error": { + params: ListAllowedAPIsRequest{ + UserName: "jsmith", + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/users/jsmith/allowed-apis?allowAccountSwitch=false", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "missing user name": { + params: ListAllowedAPIsRequest{}, + withError: func(t *testing.T, err error) { + want := ErrStructValidation + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + assert.Contains(t, err.Error(), "list allowed APIs: struct validation:\nUserName: cannot be blank") + }, + }, + "wrong client type": { + params: ListAllowedAPIsRequest{ + UserName: "jsmith", + ClientType: "Test", + }, + withError: func(t *testing.T, err error) { + want := ErrStructValidation + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + assert.Contains(t, err.Error(), "list allowed APIs: struct validation:\nClientType: value 'Test' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'") + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListAllowedAPIs(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestIAMAccessibleGroups(t *testing.T) { + tests := map[string]struct { + params ListAccessibleGroupsRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse ListAccessibleGroupsResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListAccessibleGroupsRequest{ + UserName: "jsmith", + }, + responseStatus: http.StatusOK, + responseBody: `[ + { + "groupId": 1111, + "groupName": "TestGroupName", + "roleId": 123123, + "roleName": "Test Role Name", + "roleDescription": "Test Role Description", + "isBlocked": false, + "subGroups": [ + { + "groupId": 3333, + "groupName": "TestSubGroupName", + "parentGroupId": 1111, + "subGroups": [] + } + ] + }, + { + "groupId": 2222, + "groupName": "TestGroupName2", + "roleId": 321321, + "roleName": "Test Role Name 2", + "roleDescription": "Test Role Description 2", + "isBlocked": false, + "subGroups": [] + } +]`, + expectedPath: "/identity-management/v3/users/jsmith/group-access", + expectedResponse: ListAccessibleGroupsResponse{ + { + GroupID: 1111, + RoleID: 123123, + GroupName: "TestGroupName", + RoleName: "Test Role Name", + IsBlocked: false, + RoleDescription: "Test Role Description", + SubGroups: []AccessibleSubGroup{ + { + GroupID: 3333, + GroupName: "TestSubGroupName", + ParentGroupID: 1111, + SubGroups: []AccessibleSubGroup{}, + }, + }, + }, + { + GroupID: 2222, + RoleID: 321321, + GroupName: "TestGroupName2", + RoleName: "Test Role Name 2", + IsBlocked: false, + RoleDescription: "Test Role Description 2", + SubGroups: []AccessibleSubGroup{}, + }, + }, + }, + "500 internal server error": { + params: ListAccessibleGroupsRequest{ + UserName: "jsmith", + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + expectedPath: "/identity-management/v3/users/jsmith/group-access", + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "missing user name": { + params: ListAccessibleGroupsRequest{}, + withError: func(t *testing.T, err error) { + want := ErrStructValidation + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + assert.Contains(t, err.Error(), "list accessible groups: struct validation:\nUserName: cannot be blank") + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListAccessibleGroups(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 32cce541..76a4d9a7 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -518,3 +518,33 @@ func (m *Mock) BlockUsers(ctx context.Context, request BlockUsersRequest) (*Bloc return args.Get(0).(*BlockUsersResponse), args.Error(1) } + +func (m *Mock) ListAuthorizedUsers(ctx context.Context) (ListAuthorizedUsersResponse, error) { + args := m.Called(ctx) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListAuthorizedUsersResponse), args.Error(1) +} + +func (m *Mock) ListAllowedAPIs(ctx context.Context, request ListAllowedAPIsRequest) (ListAllowedAPIsResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListAllowedAPIsResponse), args.Error(1) +} + +func (m *Mock) ListAccessibleGroups(ctx context.Context, request ListAccessibleGroupsRequest) (ListAccessibleGroupsResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListAccessibleGroupsResponse), args.Error(1) +} From 6746701a6931ef9ecb6f2de878af393980a86db4 Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Mon, 5 Aug 2024 09:08:54 +0000 Subject: [PATCH 23/34] DXE-4009 Add IAM API clients credentials methods --- CHANGELOG.md | 11 +- internal/test/test.go | 5 +- pkg/iam/api_clients_credentials.go | 458 +++++++++++ pkg/iam/api_clients_credentials_test.go | 998 ++++++++++++++++++++++++ pkg/iam/iam.go | 1 + pkg/iam/mocks.go | 58 ++ 6 files changed, 1529 insertions(+), 2 deletions(-) create mode 100644 pkg/iam/api_clients_credentials.go create mode 100644 pkg/iam/api_clients_credentials_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f8590c..3fce14f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,7 +71,16 @@ - +* IAM + * Added API Clients Credentials methods + * [CreateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credentials) and [CreateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credentials) + * [GetYourCredential](https://techdocs.akamai.com/iam-api/reference/get-self-credential) and [GetCredential](https://techdocs.akamai.com/iam-api/reference/get-client-credential) + * [UpdateYourCredential](https://techdocs.akamai.com/iam-api/reference/put-self-credential) and [UpdateCredential](https://techdocs.akamai.com/iam-api/reference/put-client-credential) + * [DeleteYourCredential](https://techdocs.akamai.com/iam-api/reference/delete-self-credential) and [DeleteCredential](https://techdocs.akamai.com/iam-api/reference/delete-client-credential) + * [ListYourCredentials](https://techdocs.akamai.com/iam-api/reference/get-self-credentials) and [ListCredentials](https://techdocs.akamai.com/iam-api/reference/get-client-credentials) + * [DeactivateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate) and [DeactivateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate) + * [DeactivateYourCredentials](https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate) and [DeactivateCredentials](https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate) + diff --git a/internal/test/test.go b/internal/test/test.go index 7c8210fb..f091865f 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -9,7 +9,10 @@ import ( ) // NewTimeFromString returns a time value parsed from a string -// in the RFC3339Nano format +// in the RFC3339Nano format. Note that it cuts off trailing zeros in the milliseconds part, which +// might cause issues in IAM endpoints which do not accept the time format without the milliseconds part. +// +// Example: if "2025-10-11T23:06:59.000Z" is used, the actual value that will be sent is "2025-10-11T23:06:59Z". func NewTimeFromString(t *testing.T, s string) time.Time { parsedTime, err := time.Parse(time.RFC3339Nano, s) require.NoError(t, err) diff --git a/pkg/iam/api_clients_credentials.go b/pkg/iam/api_clients_credentials.go new file mode 100644 index 00000000..9503344d --- /dev/null +++ b/pkg/iam/api_clients_credentials.go @@ -0,0 +1,458 @@ +package iam + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +type ( + // APIClientsCredentials is the IAM API clients credentials interface + APIClientsCredentials interface { + // CreateCredential creates a new credential for the API client. If `ClientID` is not provided, it creates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials, https://techdocs.akamai.com/iam-api/reference/post-client-credentials + CreateCredential(context.Context, CreateCredentialRequest) (*CreateCredentialResponse, error) + + // ListCredentials lists credentials for an API client. If `ClientID` is not provided, it lists credentials for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-self-credentials, https://techdocs.akamai.com/iam-api/reference/get-client-credentials + ListCredentials(context.Context, ListCredentialsRequest) (ListCredentialsResponse, error) + + // GetCredential returns details about a specific credential for an API client. If `ClientID` is not provided, it gets credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-self-credential, https://techdocs.akamai.com/iam-api/reference/get-client-credential + GetCredential(context.Context, GetCredentialRequest) (*GetCredentialResponse, error) + + // UpdateCredential updates a specific credential for an API client. If `ClientID` is not provided, it updates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-self-credential, https://techdocs.akamai.com/iam-api/reference/put-client-credential + UpdateCredential(context.Context, UpdateCredentialRequest) (*UpdateCredentialResponse, error) + + // DeleteCredential deletes a specific credential from an API client. If `ClientID` is not provided, it deletes credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-self-credential, https://techdocs.akamai.com/iam-api/reference/delete-client-credential + DeleteCredential(context.Context, DeleteCredentialRequest) error + + // DeactivateCredential deactivates a specific credential for an API client. If `ClientID` is not provided, it deactivates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate + DeactivateCredential(context.Context, DeactivateCredentialRequest) error + + // DeactivateCredentials deactivates all credentials for a specific API client. If `ClientID` is not provided, it deactivates all credentials for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate + DeactivateCredentials(context.Context, DeactivateCredentialsRequest) error + } + + // CreateCredentialRequest contains request parameters for CreateCredential operation + CreateCredentialRequest struct { + ClientID string + } + + // ListCredentialsRequest contains request parameters for ListCredentials operation + ListCredentialsRequest struct { + ClientID string + Actions bool + } + + // GetCredentialRequest contains request parameters for GetCredentials operation + GetCredentialRequest struct { + CredentialID int64 + ClientID string + Actions bool + } + + // UpdateCredentialRequest contains request parameters for UpdateCredential operation + UpdateCredentialRequest struct { + CredentialID int64 + ClientID string + RequestBody UpdateCredentialRequestBody + } + + // UpdateCredentialRequestBody contains request body parameters for UpdateCredential operation + UpdateCredentialRequestBody struct { + Description string `json:"description,omitempty"` + ExpiresOn time.Time `json:"expiresOn"` + Status CredentialStatus `json:"status"` + } + + // DeleteCredentialRequest contains request parameters for DeleteCredential operation + DeleteCredentialRequest struct { + CredentialID int64 + ClientID string + } + + // DeactivateCredentialRequest contains request parameters for DeactivateCredential operation + DeactivateCredentialRequest struct { + CredentialID int64 + ClientID string + } + + // DeactivateCredentialsRequest contains request parameters for DeactivateCredentials operation + DeactivateCredentialsRequest struct { + ClientID string + } + + // CreateCredentialResponse holds response from CreateCredentials operation + CreateCredentialResponse struct { + ClientSecret string `json:"clientSecret"` + ClientToken string `json:"clientToken"` + CreatedOn time.Time `json:"createdOn"` + CredentialID int64 `json:"credentialId"` + Description string `json:"description"` + ExpiresOn time.Time `json:"expiresOn"` + Status CredentialStatus `json:"status"` + } + + // ListCredentialsResponse holds response from ListCredentials operation + ListCredentialsResponse []Credential + + // Credential represents single credential information + Credential struct { + ClientToken string `json:"clientToken"` + CreatedOn time.Time `json:"createdOn"` + CredentialID int64 `json:"credentialId"` + Description string `json:"description"` + ExpiresOn time.Time `json:"expiresOn"` + Status CredentialStatus `json:"status"` + MaxAllowedExpiry time.Time `json:"maxAllowedExpiry"` + Actions *CredentialActions `json:"actions"` + } + + // CredentialActions describes the actions that can be performed on the credential + CredentialActions struct { + Deactivate bool `json:"deactivate"` + Delete bool `json:"delete"` + Activate bool `json:"activate"` + EditDescription bool `json:"editDescription"` + EditExpiration bool `json:"editExpiration"` + } + + // GetCredentialResponse holds response from GetCredential operation + GetCredentialResponse Credential + + // UpdateCredentialResponse holds response from UpdateCredential operation + UpdateCredentialResponse struct { + Status CredentialStatus `json:"status"` + ExpiresOn time.Time `json:"expiresOn"` + Description *string `json:"description"` + } + + // CredentialStatus represents the status of the credential + CredentialStatus string +) + +const ( + // CredentialActive represents active credential + CredentialActive CredentialStatus = "ACTIVE" + // CredentialInactive represents inactive credential + CredentialInactive CredentialStatus = "INACTIVE" + // CredentialDeleted represents deleted credential + CredentialDeleted CredentialStatus = "DELETED" +) + +// Validate validates GetCredentialRequest +func (r GetCredentialRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CredentialID": validation.Validate(r.CredentialID, validation.Required), + }) +} + +// Validate validates UpdateCredentialRequest +func (r UpdateCredentialRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CredentialID": validation.Validate(r.CredentialID, validation.Required), + "RequestBody": validation.Validate(r.RequestBody, validation.Required), + }) +} + +// Validate validates UpdateCredentialRequestBody +func (r UpdateCredentialRequestBody) Validate() error { + return validation.Errors{ + "ExpiresOn": validation.Validate(r.ExpiresOn, validation.Required), + "Status": validation.Validate(r.Status, validation.Required, validation.In(CredentialActive, CredentialInactive)), + }.Filter() +} + +// Validate validates DeleteCredentialRequest +func (r DeleteCredentialRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CredentialID": validation.Validate(r.CredentialID, validation.Required), + }) +} + +// Validate validates DeactivateCredentialRequest +func (r DeactivateCredentialRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "CredentialID": validation.Validate(r.CredentialID, validation.Required), + }) +} + +var ( + // ErrCreateCredential is returned when CreateCredential fails + ErrCreateCredential = errors.New("create credential") + // ErrListCredentials is returned when ListCredentials fails + ErrListCredentials = errors.New("list credentials") + // ErrGetCredential is returned when GetCredential fails + ErrGetCredential = errors.New("get credential") + // ErrUpdateCredential is returned when UpdateCredential fails + ErrUpdateCredential = errors.New("update credential") + // ErrDeleteCredential is returned when DeleteCredential fails + ErrDeleteCredential = errors.New("delete credential") + // ErrDeactivateCredential is returned when DeactivateCredential fails + ErrDeactivateCredential = errors.New("deactivate credential") + // ErrDeactivateCredentials is returned when DeactivateCredentials fails + ErrDeactivateCredentials = errors.New("deactivate credentials") +) + +func (i *iam) CreateCredential(ctx context.Context, params CreateCredentialRequest) (*CreateCredentialResponse, error) { + logger := i.Log(ctx) + logger.Debug("create credential") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrCreateCredential, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateCredential, err) + } + + var result CreateCredentialResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrCreateCredential, err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, fmt.Errorf("%s: %w", ErrCreateCredential, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) ListCredentials(ctx context.Context, params ListCredentialsRequest) (ListCredentialsResponse, error) { + logger := i.Log(ctx) + logger.Debug("list credentials") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListCredentials, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListCredentials, err) + } + + var result ListCredentialsResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListCredentials, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListCredentials, i.Error(resp)) + } + + return result, nil +} + +func (i *iam) GetCredential(ctx context.Context, params GetCredentialRequest) (*GetCredentialResponse, error) { + logger := i.Log(ctx) + logger.Debug("get credential") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrGetCredential, ErrStructValidation, err) + } + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/%d", params.ClientID, params.CredentialID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetCredential, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetCredential, err) + } + + var result GetCredentialResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrGetCredential, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrGetCredential, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) UpdateCredential(ctx context.Context, params UpdateCredentialRequest) (*UpdateCredentialResponse, error) { + logger := i.Log(ctx) + logger.Debug("update credential") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w: %s", ErrUpdateCredential, ErrStructValidation, err) + } + + if params.ClientID == "" { + params.ClientID = "self" + } + + // Because API does not accept date without providing milliseconds, if there are no millisecond add a small duration to allow the request to + // be processed. Only applicable when no milliseconds are provided, or they are equal to zero. Ticket for tracking: IDM-3347. + if params.RequestBody.ExpiresOn.Nanosecond() == 0 { + params.RequestBody.ExpiresOn = params.RequestBody.ExpiresOn.Add(time.Nanosecond) + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/%d", params.ClientID, params.CredentialID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to parse url: %s", ErrUpdateCredential, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateCredential, err) + } + + var result UpdateCredentialResponse + resp, err := i.Exec(req, &result, params.RequestBody) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateCredential, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrUpdateCredential, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) DeleteCredential(ctx context.Context, params DeleteCredentialRequest) error { + logger := i.Log(ctx) + logger.Debug("delete credential") + + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrDeleteCredential, ErrStructValidation, err) + } + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/%d", params.ClientID, params.CredentialID)) + if err != nil { + return fmt.Errorf("%w: failed to parse url: %s", ErrDeleteCredential, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDeleteCredential, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDeleteCredential, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDeleteCredential, i.Error(resp)) + } + + return nil +} + +func (i *iam) DeactivateCredential(ctx context.Context, params DeactivateCredentialRequest) error { + logger := i.Log(ctx) + logger.Debug("deactivate credential") + + if err := params.Validate(); err != nil { + return fmt.Errorf("%s: %w: %s", ErrDeactivateCredential, ErrStructValidation, err) + } + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/%d/deactivate", params.ClientID, params.CredentialID)) + if err != nil { + return fmt.Errorf("%w: failed to parse url: %s", ErrDeactivateCredential, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDeactivateCredential, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDeactivateCredential, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDeactivateCredential, i.Error(resp)) + } + + return nil +} + +func (i *iam) DeactivateCredentials(ctx context.Context, params DeactivateCredentialsRequest) error { + logger := i.Log(ctx) + logger.Debug("deactivate credentials") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/deactivate", params.ClientID)) + if err != nil { + return fmt.Errorf("%w: failed to parse url: %s", ErrDeactivateCredentials, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDeactivateCredentials, err) + } + + resp, err := i.Exec(req, nil, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDeactivateCredentials, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDeactivateCredentials, i.Error(resp)) + } + + return nil +} diff --git a/pkg/iam/api_clients_credentials_test.go b/pkg/iam/api_clients_credentials_test.go new file mode 100644 index 00000000..05106c1b --- /dev/null +++ b/pkg/iam/api_clients_credentials_test.go @@ -0,0 +1,998 @@ +package iam + +import ( + "context" + "encoding/json" + "errors" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/terraform-provider-akamai/v6/pkg/common/ptr" + "github.com/stretchr/testify/require" + "github.com/tj/assert" +) + +func TestCreateCredential(t *testing.T) { + tests := map[string]struct { + params CreateCredentialRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *CreateCredentialResponse + withError func(*testing.T, error) + }{ + "201 Created with specified client": { + params: CreateCredentialRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials", + responseStatus: http.StatusCreated, + responseBody: ` +{ + "credentialId": 123, + "clientToken": "test-token", + "clientSecret": "test-secret", + "createdOn": "2024-07-25T11:02:28.000Z", + "expiresOn": "2026-07-25T11:02:28.000Z", + "status": "ACTIVE", + "description": "" +} +`, + expectedResponse: &CreateCredentialResponse{ + ClientSecret: "test-secret", + ClientToken: "test-token", + CreatedOn: test.NewTimeFromString(t, "2024-07-25T11:02:28.000Z"), + CredentialID: 123, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-07-25T11:02:28.000Z"), + Status: CredentialActive, + }, + }, + "200 OK - self": { + params: CreateCredentialRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials", + responseStatus: http.StatusCreated, + responseBody: ` +{ + "credentialId": 123, + "clientToken": "test-token", + "clientSecret": "test-secret", + "createdOn": "2024-07-25T11:02:28.000Z", + "expiresOn": "2026-07-25T11:02:28.000Z", + "status": "ACTIVE", + "description": "" +} +`, + expectedResponse: &CreateCredentialResponse{ + ClientSecret: "test-secret", + ClientToken: "test-token", + CreatedOn: test.NewTimeFromString(t, "2024-07-25T11:02:28.000Z"), + CredentialID: 123, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-07-25T11:02:28.000Z"), + Status: CredentialActive, + }, + }, + "404 Not Found": { + params: CreateCredentialRequest{ + ClientID: "test12344", + }, + expectedPath: "/identity-management/v3/api-clients/test12344/credentials", + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/identity-management/error-types/2", + "status": 404, + "title": "invalid open identity", + "detail": "", + "instance": "", + "errors": [] +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "invalid open identity", + Type: "/identity-management/error-types/2", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: CreateCredentialRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.CreateCredential(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestListCredentials(t *testing.T) { + tests := map[string]struct { + params ListCredentialsRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse ListCredentialsResponse + withError func(*testing.T, error) + }{ + "200 OK with specified client": { + params: ListCredentialsRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials?actions=false", + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "credentialId": 1, + "clientToken": "test-token1", + "status": "ACTIVE", + "createdOn": "2024-05-14T11:10:25.000Z", + "description": "", + "expiresOn": "2026-05-14T11:10:25.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z" + }, + { + "credentialId": 2, + "clientToken": "test-token2", + "status": "DELETED", + "createdOn": "2024-05-28T06:53:36.000Z", + "description": "deactivate for deletion", + "expiresOn": "2025-10-11T23:06:59.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z" + }, + { + "credentialId": 3, + "clientToken": "test-token3", + "status": "ACTIVE", + "createdOn": "2024-07-25T11:02:28.000Z", + "description": "", + "expiresOn": "2026-07-25T11:02:28.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z" + } +] +`, + expectedResponse: ListCredentialsResponse{ + { + ClientToken: "test-token1", + CreatedOn: test.NewTimeFromString(t, "2024-05-14T11:10:25.000Z"), + CredentialID: 1, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + }, + { + ClientToken: "test-token2", + CreatedOn: test.NewTimeFromString(t, "2024-05-28T06:53:36.000Z"), + CredentialID: 2, + Description: "deactivate for deletion", + ExpiresOn: test.NewTimeFromString(t, "2025-10-11T23:06:59.000Z"), + Status: CredentialDeleted, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + }, + { + ClientToken: "test-token3", + CreatedOn: test.NewTimeFromString(t, "2024-07-25T11:02:28.000Z"), + CredentialID: 3, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-07-25T11:02:28.000Z"), + Status: CredentialActive, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + }, + }, + }, + "200 OK - self and actions query param": { + params: ListCredentialsRequest{ + Actions: true, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials?actions=true", + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "credentialId": 1, + "clientToken": "test-token1", + "status": "ACTIVE", + "createdOn": "2024-05-14T11:10:25.000Z", + "description": "", + "expiresOn": "2026-05-14T11:10:25.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z", + "actions": { + "deactivate": true, + "delete": true, + "activate": true, + "editDescription": true, + "editExpiration": true + } + } +] +`, + expectedResponse: ListCredentialsResponse{ + { + ClientToken: "test-token1", + CreatedOn: test.NewTimeFromString(t, "2024-05-14T11:10:25.000Z"), + CredentialID: 1, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + Actions: &CredentialActions{ + Deactivate: true, + Delete: true, + Activate: true, + EditDescription: true, + EditExpiration: true, + }, + }, + }, + }, + "404 Not Found": { + params: ListCredentialsRequest{ + ClientID: "test12344", + }, + expectedPath: "/identity-management/v3/api-clients/test12344/credentials?actions=false", + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/identity-management/error-types/2", + "status": 404, + "title": "invalid open identity", + "detail": "", + "instance": "", + "errors": [] +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "invalid open identity", + Type: "/identity-management/error-types/2", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: ListCredentialsRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials?actions=false", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.ListCredentials(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestGetCredential(t *testing.T) { + tests := map[string]struct { + params GetCredentialRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *GetCredentialResponse + withError func(*testing.T, error) + }{ + "200 OK with specified client": { + params: GetCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123?actions=false", + responseStatus: http.StatusOK, + responseBody: ` +{ + "credentialId": 1, + "clientToken": "test-token1", + "status": "ACTIVE", + "createdOn": "2024-05-14T11:10:25.000Z", + "description": "", + "expiresOn": "2026-05-14T11:10:25.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z" +} +`, + expectedResponse: &GetCredentialResponse{ + ClientToken: "test-token1", + CreatedOn: test.NewTimeFromString(t, "2024-05-14T11:10:25.000Z"), + CredentialID: 1, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + }, + }, + "200 OK - self with actions query param": { + params: GetCredentialRequest{ + CredentialID: 123, + Actions: true, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123?actions=true", + responseStatus: http.StatusOK, + responseBody: ` +{ + "credentialId": 1, + "clientToken": "test-token1", + "status": "ACTIVE", + "createdOn": "2024-05-14T11:10:25.000Z", + "description": "", + "expiresOn": "2026-05-14T11:10:25.000Z", + "maxAllowedExpiry": "2026-07-25T11:09:30.658Z", + "actions": { + "deactivate": true, + "delete": true, + "activate": true, + "editDescription": true, + "editExpiration": false + } +} +`, + expectedResponse: &GetCredentialResponse{ + ClientToken: "test-token1", + CreatedOn: test.NewTimeFromString(t, "2024-05-14T11:10:25.000Z"), + CredentialID: 1, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + MaxAllowedExpiry: test.NewTimeFromString(t, "2026-07-25T11:09:30.658Z"), + Actions: &CredentialActions{ + Deactivate: true, + Delete: true, + Activate: true, + EditDescription: true, + EditExpiration: false, + }, + }, + }, + "validation errors": { + params: GetCredentialRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "get credential: struct validation: CredentialID: cannot be blank", err.Error()) + }, + }, + "404 Not Found": { + params: GetCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123?actions=false", + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/identity-management/error-types/25", + "status": 404, + "title": "ERROR_NO_CREDENTIAL", + "detail": "", + "instance": "", + "errors": [] +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "ERROR_NO_CREDENTIAL", + Type: "/identity-management/error-types/25", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: GetCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123?actions=false", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.GetCredential(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestUpdateCredential(t *testing.T) { + tests := map[string]struct { + params UpdateCredentialRequest + responseStatus int + responseBody string + expectedPath string + expectedRequestBody string + expectedResponse *UpdateCredentialResponse + withError func(*testing.T, error) + }{ + "200 OK with zeros as milliseconds - add nanosecond to the request": { + params: UpdateCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + }, + }, + expectedRequestBody: ` +{ + "expiresOn": "2026-05-14T11:10:25.000000001Z", + "status": "ACTIVE" +} +`, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123", + responseStatus: http.StatusOK, + responseBody: ` +{ + "status": "ACTIVE", + "expiresOn": "2026-05-14T11:10:25.000Z" +} +`, + expectedResponse: &UpdateCredentialResponse{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + }, + }, + "200 OK with no milliseconds provided - add nanosecond to the request": { + params: UpdateCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25Z"), + Status: CredentialActive, + }, + }, + expectedRequestBody: ` +{ + "expiresOn": "2026-05-14T11:10:25.000000001Z", + "status": "ACTIVE" +} +`, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123", + responseStatus: http.StatusOK, + responseBody: ` +{ + "status": "ACTIVE", + "expiresOn": "2026-05-14T11:10:25.000Z" +} +`, + expectedResponse: &UpdateCredentialResponse{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + }, + }, + "200 OK with specified client, without description": { + params: UpdateCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.123Z"), + Status: CredentialActive, + }, + }, + expectedRequestBody: ` +{ + "expiresOn": "2026-05-14T11:10:25.123Z", + "status": "ACTIVE" +} +`, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123", + responseStatus: http.StatusOK, + responseBody: ` +{ + "status": "ACTIVE", + "expiresOn": "2026-05-14T11:10:25.000Z" +} +`, + expectedResponse: &UpdateCredentialResponse{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + }, + }, + "200 OK without specified client, with description": { + params: UpdateCredentialRequest{ + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.123Z"), + Status: CredentialInactive, + Description: "test description", + }, + }, + expectedRequestBody: ` +{ + "description": "test description", + "expiresOn": "2026-05-14T11:10:25.123Z", + "status": "INACTIVE" +} +`, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusOK, + responseBody: ` +{ + "status": "INACTIVE", + "expiresOn": "2026-05-14T11:10:25.000Z", + "description": "test description" +} +`, + expectedResponse: &UpdateCredentialResponse{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialInactive, + Description: ptr.To("test description"), + }, + }, + "validation errors": { + params: UpdateCredentialRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "update credential: struct validation: CredentialID: cannot be blank\nExpiresOn: cannot be blank\nStatus: cannot be blank", err.Error()) + }, + }, + "404 Not Found": { + params: UpdateCredentialRequest{ + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: "ACTIVE", + }, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusNotFound, + responseBody: ` + { + "type": "/identity-management/error-types/25", + "status": 404, + "title": "ERROR_NO_CREDENTIAL", + "detail": "", + "instance": "", + "errors": [] + } + `, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "ERROR_NO_CREDENTIAL", + Type: "/identity-management/error-types/25", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: UpdateCredentialRequest{ + CredentialID: 123, + RequestBody: UpdateCredentialRequestBody{ + ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), + Status: CredentialActive, + }, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + if test.expectedRequestBody != "" { + body, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.JSONEq(t, test.expectedRequestBody, string(body)) + } + })) + client := mockAPIClient(t, mockServer) + response, err := client.UpdateCredential(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestDeleteCredential(t *testing.T) { + tests := map[string]struct { + params DeleteCredentialRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 with specified client": { + params: DeleteCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123", + responseStatus: http.StatusNoContent, + }, + "204 without specified client": { + params: DeleteCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusNoContent, + }, + "validation errors": { + params: DeleteCredentialRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "delete credential: struct validation: CredentialID: cannot be blank", err.Error()) + }, + }, + "404 Not Found": { + params: DeleteCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusNotFound, + responseBody: ` + { + "type": "/identity-management/error-types/25", + "status": 404, + "title": "ERROR_NO_CREDENTIAL", + "detail": "", + "instance": "", + "errors": [] + } + `, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "ERROR_NO_CREDENTIAL", + Type: "/identity-management/error-types/25", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: DeleteCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodDelete, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + err := client.DeleteCredential(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestDeactivateCredential(t *testing.T) { + tests := map[string]struct { + params DeactivateCredentialRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 with specified client": { + params: DeactivateCredentialRequest{ + ClientID: "test1234", + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/123/deactivate", + responseStatus: http.StatusNoContent, + }, + "204 without specified client": { + params: DeactivateCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123/deactivate", + responseStatus: http.StatusNoContent, + }, + "validation errors": { + params: DeactivateCredentialRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "deactivate credential: struct validation: CredentialID: cannot be blank", err.Error()) + }, + }, + "404 Not Found": { + params: DeactivateCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123/deactivate", + responseStatus: http.StatusNotFound, + responseBody: ` + { + "type": "/identity-management/error-types/25", + "status": 404, + "title": "ERROR_NO_CREDENTIAL", + "detail": "", + "instance": "", + "errors": [] + } + `, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "ERROR_NO_CREDENTIAL", + Type: "/identity-management/error-types/25", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: DeactivateCredentialRequest{ + CredentialID: 123, + }, + expectedPath: "/identity-management/v3/api-clients/self/credentials/123/deactivate", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + err := client.DeactivateCredential(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestDeactivateCredentials(t *testing.T) { + tests := map[string]struct { + params DeactivateCredentialsRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 with specified client": { + params: DeactivateCredentialsRequest{ + ClientID: "test1234", + }, + expectedPath: "/identity-management/v3/api-clients/test1234/credentials/deactivate", + responseStatus: http.StatusNoContent, + }, + "204 without specified client": { + params: DeactivateCredentialsRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials/deactivate", + responseStatus: http.StatusNoContent, + }, + "404 Not Found": { + params: DeactivateCredentialsRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials/deactivate", + responseStatus: http.StatusNotFound, + responseBody: ` +{ + "type": "/identity-management/error-types/2", + "status": 404, + "title": "invalid open identity", + "detail": "", + "instance": "", + "errors": [] +} +`, + withError: func(t *testing.T, err error) { + want := &Error{ + Title: "invalid open identity", + Type: "/identity-management/error-types/2", + StatusCode: http.StatusNotFound, + Errors: json.RawMessage("[]"), + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + "500 internal server error": { + params: DeactivateCredentialsRequest{}, + expectedPath: "/identity-management/v3/api-clients/self/credentials/deactivate", + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + }`, + withError: func(t *testing.T, err error) { + want := &Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + err := client.DeactivateCredentials(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index 3852fc66..b660f7d5 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -19,6 +19,7 @@ type ( // IAM is the IAM api interface IAM interface { APIClients + APIClientsCredentials BlockedProperties CIDR Groups diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 76a4d9a7..2f7d129f 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -548,3 +548,61 @@ func (m *Mock) ListAccessibleGroups(ctx context.Context, request ListAccessibleG return args.Get(0).(ListAccessibleGroupsResponse), args.Error(1) } + +func (m *Mock) CreateCredential(ctx context.Context, request CreateCredentialRequest) (*CreateCredentialResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*CreateCredentialResponse), args.Error(1) +} + +func (m *Mock) ListCredentials(ctx context.Context, request ListCredentialsRequest) (ListCredentialsResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListCredentialsResponse), args.Error(1) +} + +func (m *Mock) GetCredential(ctx context.Context, request GetCredentialRequest) (*GetCredentialResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*GetCredentialResponse), args.Error(1) +} + +func (m *Mock) UpdateCredential(ctx context.Context, request UpdateCredentialRequest) (*UpdateCredentialResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*UpdateCredentialResponse), args.Error(1) +} + +func (m *Mock) DeleteCredential(ctx context.Context, request DeleteCredentialRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} + +func (m *Mock) DeactivateCredential(ctx context.Context, request DeactivateCredentialRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} + +func (m *Mock) DeactivateCredentials(ctx context.Context, request DeactivateCredentialsRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} From 6e4d77d67ebd9c1ff30d8f9f9f7c797cb19c2bda Mon Sep 17 00:00:00 2001 From: Filip Antkowiak Date: Tue, 6 Aug 2024 09:43:18 +0000 Subject: [PATCH 24/34] DXE-4066 Modify dates to use time.Time in IAM --- CHANGELOG.md | 15 +++++++++++++++ pkg/iam/cidr.go | 5 +++-- pkg/iam/cidr_test.go | 37 +++++++++++++++++++------------------ pkg/iam/groups.go | 19 ++++++++++--------- pkg/iam/groups_test.go | 27 ++++++++++++++------------- pkg/iam/roles.go | 17 +++++++++-------- pkg/iam/roles_test.go | 25 +++++++++++++------------ pkg/iam/user.go | 7 ++++--- pkg/iam/user_test.go | 13 +++++++------ 9 files changed, 94 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fce14f3..47033549 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,21 @@ +* IAM + * Improved date handling to use `time.Time` instead of `string` + * Changed fields in following structures: + * `Users` + * `LastLoginDate` changed type from `string` to `time.Time` + * `PasswordExpiryDate` changed type from `string` to `time.Time` + * `UserListItem` + * `LastLoginDate` changed type from `string` to `time.Time` + * `Role` + * `CreatedDate` changed type from `string` to `time.Time` + * `ModifiedDate` changed type from `string` to `time.Time` + * `RoleUser` + * `LastLoginDate` changed type from `string` to `time.Time` + * `GroupUser` + * `LastLoginDate` changed type from `string` to `time.Time` diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index 3a42c935..bf4755e3 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" @@ -61,10 +62,10 @@ type ( CIDRBlockID int64 `json:"cidrBlockId"` Comments string `json:"comments"` CreatedBy string `json:"createdBy"` - CreatedDate string `json:"createdDate"` + CreatedDate time.Time `json:"createdDate"` Enabled bool `json:"enabled"` ModifiedBy string `json:"modifiedBy"` - ModifiedDate string `json:"modifiedDate"` + ModifiedDate time.Time `json:"modifiedDate"` } // CIDRActions specifies activities available for the CIDR block diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index 54738b01..cb702279 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -9,6 +9,7 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -55,9 +56,9 @@ func TestListCIDRBlocks(t *testing.T) { Enabled: true, Comments: "abc", CIDRBlock: "1.2.3.4/8", - CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), ModifiedBy: "johndoe", Actions: nil, }, @@ -66,9 +67,9 @@ func TestListCIDRBlocks(t *testing.T) { Enabled: false, Comments: "", CIDRBlock: "2.4.8.16/32", - CreatedDate: "2024-06-25T06:14:36.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-25T06:14:36.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), ModifiedBy: "johndoe", Actions: nil, }, @@ -115,9 +116,9 @@ func TestListCIDRBlocks(t *testing.T) { Enabled: true, Comments: "abc", CIDRBlock: "1.2.3.4/8", - CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), ModifiedBy: "johndoe", Actions: &CIDRActions{ Edit: true, @@ -129,9 +130,9 @@ func TestListCIDRBlocks(t *testing.T) { Enabled: false, Comments: "", CIDRBlock: "2.4.8.16/32", - CreatedDate: "2024-06-25T06:14:36.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-25T06:14:36.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), ModifiedBy: "johndoe", Actions: &CIDRActions{ Edit: true, @@ -221,9 +222,9 @@ func TestCreateCIDRBlock(t *testing.T) { Enabled: true, Comments: "abc", CIDRBlock: "1.2.3.4/32", - CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-07-15T13:53:49.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), ModifiedBy: "johndoe", Actions: nil, }, @@ -252,9 +253,9 @@ func TestCreateCIDRBlock(t *testing.T) { Enabled: true, Comments: "", CIDRBlock: "1.2.3.4/32", - CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-07-15T13:53:49.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), ModifiedBy: "johndoe", Actions: nil, }, @@ -381,9 +382,9 @@ func TestGetCIDRBlock(t *testing.T) { Enabled: true, Comments: "abc", CIDRBlock: "1.2.3.4/8", - CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), ModifiedBy: "johndoe", Actions: nil, }, @@ -412,9 +413,9 @@ func TestGetCIDRBlock(t *testing.T) { Enabled: true, Comments: "abc", CIDRBlock: "1.2.3.4/8", - CreatedDate: "2024-06-17T08:46:41.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-06-17T08:46:41.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), ModifiedBy: "johndoe", Actions: &CIDRActions{ Edit: true, @@ -546,9 +547,9 @@ func TestUpdateCIDRBlock(t *testing.T) { Enabled: false, Comments: "abc - updated", CIDRBlock: "1.2.3.4/32", - CreatedDate: "2024-07-15T13:53:49.000Z", + CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2024-07-16T13:53:49.000Z", + ModifiedDate: test.NewTimeFromString(t, "2024-07-16T13:53:49.000Z"), ModifiedBy: "johndoe", Actions: nil, }, diff --git a/pkg/iam/groups.go b/pkg/iam/groups.go index bfadee26..dc5cc29a 100644 --- a/pkg/iam/groups.go +++ b/pkg/iam/groups.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "time" validation "github.com/go-ozzo/ozzo-validation/v4" ) @@ -60,11 +61,11 @@ type ( Group struct { Actions *GroupActions `json:"actions,omitempty"` CreatedBy string `json:"createdBy"` - CreatedDate string `json:"createdDate"` + CreatedDate time.Time `json:"createdDate"` GroupID int64 `json:"groupId"` GroupName string `json:"groupName"` ModifiedBy string `json:"modifiedBy"` - ModifiedDate string `json:"modifiedDate"` + ModifiedDate time.Time `json:"modifiedDate"` ParentGroupID int64 `json:"parentGroupId"` SubGroups []Group `json:"subGroups,omitempty"` } @@ -77,13 +78,13 @@ type ( // GroupUser describes the response of the list affected users endpoint GroupUser struct { - AccountID string `json:"accountId"` - Email string `json:"email"` - FirstName string `json:"firstName"` - IdentityID string `json:"uiIdentityId"` - LastLoginDate string `json:"lastLoginDate"` - LastName string `json:"lastName"` - UserName string `json:"uiUserName"` + AccountID string `json:"accountId"` + Email string `json:"email"` + FirstName string `json:"firstName"` + IdentityID string `json:"uiIdentityId"` + LastLoginDate time.Time `json:"lastLoginDate"` + LastName string `json:"lastName"` + UserName string `json:"uiUserName"` } // GroupRequest describes the request and body parameters for creating new group or updating a group name endpoint diff --git a/pkg/iam/groups_test.go b/pkg/iam/groups_test.go index 749a8a54..8f5d648c 100644 --- a/pkg/iam/groups_test.go +++ b/pkg/iam/groups_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -44,9 +45,9 @@ func TestCreateGroup(t *testing.T) { GroupID: 98765, GroupName: "Test Group", ParentGroupID: 12345, - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", }, }, @@ -192,9 +193,9 @@ func TestGetGroup(t *testing.T) { expectedResponse: &Group{ GroupID: 12345, GroupName: "Top Level group", - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", Actions: &GroupActions{ Edit: true, @@ -220,9 +221,9 @@ func TestGetGroup(t *testing.T) { expectedResponse: &Group{ GroupID: 12345, GroupName: "Top Level group", - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", }, }, @@ -312,7 +313,7 @@ func TestListAffectedUsers(t *testing.T) { AccountID: "test-account", Email: "john.doe@mycompany.com", UserName: "john.doe@mycompany.com", - LastLoginDate: "2022-02-22T17:06:50.000Z", + LastLoginDate: test.NewTimeFromString(t, "2022-02-22T17:06:50.000Z"), }, }, }, @@ -417,9 +418,9 @@ func TestListGroups(t *testing.T) { { GroupID: 12345, GroupName: "Top Level group", - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", Actions: &GroupActions{ Edit: true, @@ -449,9 +450,9 @@ func TestListGroups(t *testing.T) { { GroupID: 12345, GroupName: "Top Level group", - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", }, }, @@ -618,9 +619,9 @@ func TestUpdateGroupName(t *testing.T) { GroupID: 12345, GroupName: "New Group Name", ParentGroupID: 12344, - CreatedDate: "2012-04-28T00:00:00.000Z", + CreatedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), CreatedBy: "johndoe", - ModifiedDate: "2012-04-28T00:00:00.000Z", + ModifiedDate: test.NewTimeFromString(t, "2012-04-28T00:00:00.000Z"), ModifiedBy: "johndoe", }, }, diff --git a/pkg/iam/roles.go b/pkg/iam/roles.go index c7b05cfb..c8c4924d 100644 --- a/pkg/iam/roles.go +++ b/pkg/iam/roles.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "time" validation "github.com/go-ozzo/ozzo-validation/v4" ) @@ -103,22 +104,22 @@ type ( // RoleUser user who shares the same role RoleUser struct { - AccountID string `json:"accountId"` - Email string `json:"email"` - FirstName string `json:"firstName"` - LastLoginDate string `json:"lastLoginDate"` - LastName string `json:"lastName"` - UIIdentityID string `json:"uiIdentityId"` + AccountID string `json:"accountId"` + Email string `json:"email"` + FirstName string `json:"firstName"` + LastLoginDate time.Time `json:"lastLoginDate"` + LastName string `json:"lastName"` + UIIdentityID string `json:"uiIdentityId"` } // Role encapsulates the response of the list roles endpoint Role struct { Actions *RoleAction `json:"actions,omitempty"` CreatedBy string `json:"createdBy"` - CreatedDate string `json:"createdDate"` + CreatedDate time.Time `json:"createdDate"` GrantedRoles []RoleGrantedRole `json:"grantedRoles,omitempty"` ModifiedBy string `json:"modifiedBy"` - ModifiedDate string `json:"modifiedDate"` + ModifiedDate time.Time `json:"modifiedDate"` RoleDescription string `json:"roleDescription"` RoleID int64 `json:"roleId"` RoleName string `json:"roleName"` diff --git a/pkg/iam/roles_test.go b/pkg/iam/roles_test.go index 6716ebde..00475b59 100644 --- a/pkg/iam/roles_test.go +++ b/pkg/iam/roles_test.go @@ -9,6 +9,7 @@ import ( "strconv" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/stretchr/testify/require" "github.com/tj/assert" ) @@ -59,9 +60,9 @@ func TestIAM_CreateRole(t *testing.T) { RoleName: "Terraform admin", RoleDescription: "Admin granted role for tests", RoleType: RoleTypeCustom, - CreatedDate: "2022-04-11T10:52:03.811Z", + CreatedDate: test.NewTimeFromString(t, "2022-04-11T10:52:03.811Z"), CreatedBy: "jBond", - ModifiedDate: "2022-04-11T10:52:03.811Z", + ModifiedDate: test.NewTimeFromString(t, "2022-04-11T10:52:03.811Z"), ModifiedBy: "jBond", Actions: &RoleAction{ Edit: true, @@ -196,9 +197,9 @@ func TestIAM_GetRole(t *testing.T) { RoleName: "Terraform admin updated", RoleDescription: "Admin granted role for tests", RoleType: RoleTypeCustom, - CreatedDate: "2022-04-11T10:52:03.000Z", + CreatedDate: test.NewTimeFromString(t, "2022-04-11T10:52:03.000Z"), CreatedBy: "jBond", - ModifiedDate: "2022-04-11T10:59:30.000Z", + ModifiedDate: test.NewTimeFromString(t, "2022-04-11T10:59:30.000Z"), ModifiedBy: "jBond", Actions: &RoleAction{ Edit: true, @@ -223,7 +224,7 @@ func TestIAM_GetRole(t *testing.T) { LastName: "Smith", AccountID: "ACCOUNT1", Email: "example@akamai.com", - LastLoginDate: "2016-02-17T18:46:42.000Z", + LastLoginDate: test.NewTimeFromString(t, "2016-02-17T18:46:42.000Z"), }, { UIIdentityID: "USER2", @@ -231,7 +232,7 @@ func TestIAM_GetRole(t *testing.T) { LastName: "Smith", AccountID: "ACCOUNT2", Email: "example1@akamai.com", - LastLoginDate: "2016-02-17T18:46:42.000Z", + LastLoginDate: test.NewTimeFromString(t, "2016-02-17T18:46:42.000Z"), }, }, }, @@ -256,9 +257,9 @@ func TestIAM_GetRole(t *testing.T) { RoleName: "Terraform admin updated", RoleDescription: "Admin granted role for tests", RoleType: RoleTypeCustom, - CreatedDate: "2022-04-11T10:52:03.000Z", + CreatedDate: test.NewTimeFromString(t, "2022-04-11T10:52:03.000Z"), CreatedBy: "jBond", - ModifiedDate: "2022-04-11T10:59:30.000Z", + ModifiedDate: test.NewTimeFromString(t, "2022-04-11T10:59:30.000Z"), ModifiedBy: "jBond", }, }, @@ -385,9 +386,9 @@ func TestIAM_UpdateRole(t *testing.T) { RoleName: "Terraform admin updated", RoleDescription: "Admin granted role for tests", RoleType: RoleTypeCustom, - CreatedDate: "2022-04-11T10:52:03.000Z", + CreatedDate: test.NewTimeFromString(t, "2022-04-11T10:52:03.000Z"), CreatedBy: "jBond", - ModifiedDate: "2022-04-11T10:59:30.000Z", + ModifiedDate: test.NewTimeFromString(t, "2022-04-11T10:59:30.000Z"), ModifiedBy: "jBond", Actions: &RoleAction{ Edit: true, @@ -573,9 +574,9 @@ func TestIAM_ListRoles(t *testing.T) { RoleName: "View Only", RoleDescription: "This role will allow you to view", RoleType: RoleTypeCustom, - CreatedDate: "2017-07-27T18:11:25.000Z", + CreatedDate: test.NewTimeFromString(t, "2017-07-27T18:11:25.000Z"), CreatedBy: "john.doe@mycompany.com", - ModifiedDate: "2017-07-27T18:11:25.000Z", + ModifiedDate: test.NewTimeFromString(t, "2017-07-27T18:11:25.000Z"), ModifiedBy: "john.doe@mycompany.com", Actions: &RoleAction{ Edit: true, diff --git a/pkg/iam/user.go b/pkg/iam/user.go index 833c3c59..c44b7b58 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" @@ -119,8 +120,8 @@ type ( UserBasicInfo IdentityID string `json:"uiIdentityId"` IsLocked bool `json:"isLocked"` - LastLoginDate string `json:"lastLoginDate,omitempty"` - PasswordExpiryDate string `json:"passwordExpiryDate,omitempty"` + LastLoginDate time.Time `json:"lastLoginDate,omitempty"` + PasswordExpiryDate time.Time `json:"passwordExpiryDate,omitempty"` TFAConfigured bool `json:"tfaConfigured"` EmailUpdatePending bool `json:"emailUpdatePending"` AuthGrants []AuthGrant `json:"authGrants,omitempty"` @@ -140,7 +141,7 @@ type ( TFAEnabled bool `json:"tfaEnabled"` IdentityID string `json:"uiIdentityId"` IsLocked bool `json:"isLocked"` - LastLoginDate string `json:"lastLoginDate,omitempty"` + LastLoginDate time.Time `json:"lastLoginDate,omitempty"` TFAConfigured bool `json:"tfaConfigured"` AccountID string `json:"accountId"` Actions *UserActions `json:"actions,omitempty"` diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index fea6dfe5..48ae507c 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "testing" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" @@ -309,7 +310,7 @@ func TestIam_ListUsers(t *testing.T) { "uiUserName": "johndoe", "email": "john.doe@mycompany.com", "accountId": "1-123A", - "lastLoginDate": "2016-01-13T17:53:57Z", + "lastLoginDate": "2016-01-13T17:53:57.000Z", "tfaEnabled": true, "tfaConfigured": true, "isLocked": false, @@ -348,7 +349,7 @@ func TestIam_ListUsers(t *testing.T) { Email: "john.doe@mycompany.com", AccountID: "1-123A", TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", + LastLoginDate: test.NewTimeFromString(t, "2016-01-13T17:53:57.000Z"), TFAConfigured: true, IsLocked: false, AdditionalAuthentication: TFAAuthentication, @@ -391,7 +392,7 @@ func TestIam_ListUsers(t *testing.T) { "uiUserName": "johndoe", "email": "john.doe@mycompany.com", "accountId": "1-123A", - "lastLoginDate": "2016-01-13T17:53:57Z", + "lastLoginDate": "2016-01-13T17:53:57.000Z", "tfaEnabled": true, "tfaConfigured": true, "isLocked": false, @@ -408,7 +409,7 @@ func TestIam_ListUsers(t *testing.T) { Email: "john.doe@mycompany.com", AccountID: "1-123A", TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", + LastLoginDate: test.NewTimeFromString(t, "2016-01-13T17:53:57.000Z"), TFAConfigured: true, IsLocked: false, AdditionalAuthenticationConfigured: true, @@ -427,7 +428,7 @@ func TestIam_ListUsers(t *testing.T) { "uiUserName": "johndoe", "email": "john.doe@mycompany.com", "accountId": "1-123A", - "lastLoginDate": "2016-01-13T17:53:57Z", + "lastLoginDate": "2016-01-13T17:53:57.000Z", "tfaEnabled": true, "tfaConfigured": true, "isLocked": false, @@ -444,7 +445,7 @@ func TestIam_ListUsers(t *testing.T) { Email: "john.doe@mycompany.com", AccountID: "1-123A", TFAEnabled: true, - LastLoginDate: "2016-01-13T17:53:57Z", + LastLoginDate: test.NewTimeFromString(t, "2016-01-13T17:53:57.000Z"), TFAConfigured: true, IsLocked: false, AdditionalAuthentication: TFAAuthentication, From c271ebd03b34ab6e32f7cc9c5ab5bd4902842751 Mon Sep 17 00:00:00 2001 From: Wojciech Zagrajczuk Date: Tue, 20 Aug 2024 13:14:11 +0000 Subject: [PATCH 25/34] DXE-4006 API Client endpoints --- CHANGELOG.md | 16 +- pkg/iam/api_clients.go | 508 ++++++ pkg/iam/api_clients_credentials_test.go | 2 +- pkg/iam/api_clients_test.go | 2062 +++++++++++++++++++++++ pkg/iam/helper.go | 16 +- pkg/iam/helper_test.go | 8 +- pkg/iam/mocks.go | 46 + 7 files changed, 2643 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47033549..31dee3a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -457,8 +457,8 @@ * IAM * Added new methods: - * ListAccountSwitchKeys based on [ListAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys) and [ListYourAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys) - * LockAPIClient based on [LockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client) and [LockYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self) + * `ListAccountSwitchKeys` based on [ListAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys) and [ListYourAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys) + * `LockAPIClient` based on [LockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client) and [LockYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self) * [UnlockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client) @@ -470,6 +470,18 @@ +* IAM + * Added new methods: + * [ListAPIClients](https://techdocs.akamai.com/iam-api/reference/get-api-clients) + * [CreateAPIClient](https://techdocs.akamai.com/iam-api/reference/post-api-clients) + * `GetAPIClient` based on [GetAPIClient](https://techdocs.akamai.com/iam-api/reference/get-api-client) and [GetYourAPIClient](https://techdocs.akamai.com/iam-api/reference/get-api-client-self) + * `UpdateAPIClient` based on [UpdateAPIClient](https://techdocs.akamai.com/iam-api/reference/put-api-clients) and [UpdateYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-api-clients-self) + * `DeleteAPIClient` based on [DeleteAPIClient](https://techdocs.akamai.com/iam-api/reference/delete-api-client) and [DeleteYourAPIClient](https://techdocs.akamai.com/iam-api/reference/delete-api-client-self) + + + + + diff --git a/pkg/iam/api_clients.go b/pkg/iam/api_clients.go index 2c227fde..000a3c84 100644 --- a/pkg/iam/api_clients.go +++ b/pkg/iam/api_clients.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "net/url" + "strconv" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" @@ -24,6 +25,32 @@ type ( // // See: https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) + + // ListAPIClients lists API clients an administrator can manage + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients + ListAPIClients(ctx context.Context, params ListAPIClientsRequest) (ListAPIClientsResponse, error) + + // GetAPIClient provides details about an API client. If `ClientID` is not provided, it returns details about your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-client and https://techdocs.akamai.com/iam-api/reference/get-api-client-self + GetAPIClient(ctx context.Context, params GetAPIClientRequest) (*GetAPIClientResponse, error) + + // CreateAPIClient creates a new API client. Optionally, it can automatically assign a credential for the client when creating it + // + // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients + CreateAPIClient(ctx context.Context, params CreateAPIClientRequest) (*CreateAPIClientResponse, error) + + // UpdateAPIClient updates an API client. If `ClientID` is not provided, it updates your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-api-clients and https://techdocs.akamai.com/iam-api/reference/put-api-clients-self + UpdateAPIClient(ctx context.Context, params UpdateAPIClientRequest) (*UpdateAPIClientResponse, error) + + // DeleteAPIClient permanently deletes the API client, breaking any API connections with the client. + // If `ClientID` is not provided, it deletes your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-api-client and https://techdocs.akamai.com/iam-api/reference/delete-api-client-self + DeleteAPIClient(ctx context.Context, params DeleteAPIClientRequest) error } // LockAPIClientRequest contains the request parameters for the LockAPIClient operation @@ -59,6 +86,249 @@ type ( NotificationEmails []string `json:"notificationEmails"` ServiceConsumerToken string `json:"serviceConsumerToken"` } + + // ListAPIClientsRequest contains the request parameters for the ListAPIClients endpoint + ListAPIClientsRequest struct { + Actions bool + } + + // ListAPIClientsResponse describes the response of the ListAPIClients endpoint + ListAPIClientsResponse []ListAPIClientsItem + + // ListAPIClientsItem represents information returned by the ListAPIClients endpoint for a single API client + ListAPIClientsItem struct { + AccessToken string `json:"accessToken"` + Actions *ListAPIClientsActions `json:"actions"` + ActiveCredentialCount int64 `json:"activeCredentialCount"` + AllowAccountSwitch bool `json:"allowAccountSwitch"` + AuthorizedUsers []string `json:"authorizedUsers"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientID string `json:"clientId"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + CreatedBy string `json:"createdBy"` + CreatedDate time.Time `json:"createdDate"` + IsLocked bool `json:"isLocked"` + NotificationEmails []string `json:"notificationEmails"` + ServiceConsumerToken string `json:"serviceConsumerToken"` + } + + // ListAPIClientsActions specifies activities available for the API client + ListAPIClientsActions struct { + Delete bool `json:"delete"` + DeactivateAll bool `json:"deactivateAll"` + Edit bool `json:"edit"` + Lock bool `json:"lock"` + Transfer bool `json:"transfer"` + Unlock bool `json:"unlock"` + } + + // GetAPIClientRequest contains the request parameters for the GetAPIClient endpoint + GetAPIClientRequest struct { + ClientID string + Actions bool + GroupAccess bool + APIAccess bool + Credentials bool + IPACL bool + } + + // CreateAPIClientResponse describes the response of the CreateAPIClient endpoint + CreateAPIClientResponse struct { + AccessToken string `json:"accessToken"` + Actions *APIClientActions `json:"actions"` + ActiveCredentialCount int64 `json:"activeCredentialCount"` + AllowAccountSwitch bool `json:"allowAccountSwitch"` + APIAccess APIAccess `json:"apiAccess"` + AuthorizedUsers []string `json:"authorizedUsers"` + BaseURL string `json:"baseURL"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientID string `json:"clientId"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + CreatedBy string `json:"createdBy"` + CreatedDate time.Time `json:"createdDate"` + Credentials []CreateAPIClientCredential `json:"credentials"` + GroupAccess GroupAccess `json:"groupAccess"` + IPACL IPACL `json:"ipAcl"` + IsLocked bool `json:"isLocked"` + NotificationEmails []string `json:"notificationEmails"` + PurgeOptions PurgeOptions `json:"purgeOptions"` + ServiceProviderID int64 `json:"serviceProviderId"` + } + + // GetAPIClientResponse describes the response of the GetAPIClient endpoint + GetAPIClientResponse struct { + AccessToken string `json:"accessToken"` + Actions *APIClientActions `json:"actions"` + ActiveCredentialCount int64 `json:"activeCredentialCount"` + AllowAccountSwitch bool `json:"allowAccountSwitch"` + APIAccess APIAccess `json:"apiAccess"` + AuthorizedUsers []string `json:"authorizedUsers"` + BaseURL string `json:"baseURL"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientID string `json:"clientId"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + CreatedBy string `json:"createdBy"` + CreatedDate time.Time `json:"createdDate"` + Credentials []APIClientCredential `json:"credentials"` + GroupAccess GroupAccess `json:"groupAccess"` + IPACL IPACL `json:"ipAcl"` + IsLocked bool `json:"isLocked"` + NotificationEmails []string `json:"notificationEmails"` + PurgeOptions PurgeOptions `json:"purgeOptions"` + ServiceProviderID int64 `json:"serviceProviderId"` + } + + // APIClientActions specifies activities available for the API client + APIClientActions struct { + Delete bool `json:"delete"` + DeactivateAll bool `json:"deactivateAll"` + Edit bool `json:"edit"` + EditAPIs bool `json:"editApis"` + EditAuth bool `json:"editAuth"` + EditGroups bool `json:"editGroups"` + EditIPAcl bool `json:"editIpAcl"` + EditSwitchAccount bool `json:"editSwitchAccount"` + Lock bool `json:"lock"` + Transfer bool `json:"transfer"` + Unlock bool `json:"unlock"` + } + + // APIAccess represents the APIs the API client can access + APIAccess struct { + AllAccessibleAPIs bool `json:"allAccessibleApis"` + APIs []API `json:"apis"` + } + + // API represents single Application Programming Interface (API) + API struct { + AccessLevel AccessLevel `json:"accessLevel"` + APIID int64 `json:"apiId"` + APIName string `json:"apiName"` + Description string `json:"description"` + DocumentationURL string `json:"documentationUrl"` + Endpoint string `json:"endPoint"` + } + + // APIClientCredential represents single Credential returned by APIClient interfaces + APIClientCredential struct { + Actions CredentialActions `json:"actions"` + ClientToken string `json:"clientToken"` + CreatedOn time.Time `json:"createdOn"` + CredentialID int64 `json:"credentialId"` + Description string `json:"description"` + ExpiresOn time.Time `json:"expiresOn"` + Status CredentialStatus `json:"status"` + } + + // CreateAPIClientCredential represents single Credential returned by CreateAPIClient method + CreateAPIClientCredential struct { + Actions CredentialActions `json:"actions"` + ClientToken string `json:"clientToken"` + ClientSecret string `json:"clientSecret"` + CreatedOn time.Time `json:"createdOn"` + CredentialID int64 `json:"credentialId"` + Description string `json:"description"` + ExpiresOn time.Time `json:"expiresOn"` + Status CredentialStatus `json:"status"` + } + + // GroupAccess specifies the API client's group access. + GroupAccess struct { + CloneAuthorizedUserGroups bool `json:"cloneAuthorizedUserGroups"` + Groups []ClientGroup `json:"groups"` + } + + // ClientGroup represents a group the API client can access. + ClientGroup struct { + GroupID int64 `json:"groupId"` + GroupName string `json:"groupName"` + IsBlocked bool `json:"isBlocked"` + ParentGroupID int64 `json:"parentGroupId"` + RoleDescription string `json:"roleDescription"` + RoleID int64 `json:"roleId"` + RoleName string `json:"roleName"` + Subgroups []ClientGroup `json:"subgroups"` + } + + // IPACL specifies the API client's IP list restriction + IPACL struct { + CIDR []string `json:"cidr"` + Enable bool `json:"enable"` + } + + //PurgeOptions specifies the API clients configuration for access to the Fast Purge API + PurgeOptions struct { + CanPurgeByCacheTag bool `json:"canPurgeByCacheTag"` + CanPurgeByCPCode bool `json:"canPurgeByCpcode"` + CPCodeAccess CPCodeAccess `json:"cpcodeAccess"` + } + + // CPCodeAccess represents the CP codes the API client can purge + CPCodeAccess struct { + AllCurrentAndNewCPCodes bool `json:"allCurrentAndNewCpcodes"` + CPCodes []int64 `json:"cpcodes"` + } + + // CreateAPIClientRequest contains the request parameters for the CreateAPIClient endpoint + CreateAPIClientRequest struct { + AllowAccountSwitch bool `json:"allowAccountSwitch"` + APIAccess APIAccess `json:"apiAccess"` + AuthorizedUsers []string `json:"authorizedUsers"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + CreateCredential bool `json:"createCredential"` + GroupAccess GroupAccess `json:"groupAccess"` + IPACL *IPACL `json:"ipAcl,omitempty"` + NotificationEmails []string `json:"notificationEmails"` + PurgeOptions *PurgeOptions `json:"purgeOptions,omitempty"` + } + + // UpdateAPIClientRequest contains the request parameters for the UpdateAPIClient endpoint + UpdateAPIClientRequest struct { + ClientID string + Body UpdateAPIClientBody + } + + // UpdateAPIClientBody represents body params for UpdateAPIClient + UpdateAPIClientBody struct { + AllowAccountSwitch bool `json:"allowAccountSwitch"` + APIAccess APIAccess `json:"apiAccess"` + AuthorizedUsers []string `json:"authorizedUsers"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + GroupAccess GroupAccess `json:"groupAccess"` + IPACL *IPACL `json:"ipAcl,omitempty"` + NotificationEmails []string `json:"notificationEmails"` + PurgeOptions *PurgeOptions `json:"purgeOptions,omitempty"` + } + + // UpdateAPIClientResponse describes the response of the UpdateAPIClientResponse endpoint + UpdateAPIClientResponse GetAPIClientResponse + + // DeleteAPIClientRequest contains the request parameters for the DeleteAPIClient endpoint + DeleteAPIClientRequest struct { + ClientID string + } + + // AccessLevel represents the access level for API + AccessLevel string +) + +const ( + // ReadWriteLevel is the `READ-WRITE` access level + ReadWriteLevel AccessLevel = "READ-WRITE" + // ReadOnlyLevel is the `READ-ONLY` access level + ReadOnlyLevel AccessLevel = "READ-ONLY" ) // Validate validates UnlockAPIClientRequest @@ -68,11 +338,97 @@ func (r UnlockAPIClientRequest) Validate() error { }) } +// Validate validates CreateAPIClientRequest +func (r CreateAPIClientRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "APIAccess": validation.Validate(r.APIAccess, validation.Required), + "AuthorizedUsers": validation.Validate(r.AuthorizedUsers, validation.Required, validation.Length(1, 0)), + "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType).Error( + fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'", r.ClientType))), + "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), + "PurgeOptions": validation.Validate(r.PurgeOptions), + }) +} + +// Validate validates APIAccess +func (a APIAccess) Validate() error { + return validation.Errors{ + "APIs": validation.Validate(a.APIs, validation.When(!a.AllAccessibleAPIs, validation.Required)), + }.Filter() +} + +// Validate validates API +func (a API) Validate() error { + return validation.Errors{ + "AccessLevel": validation.Validate(a.AccessLevel, validation.Required, validation.In(ReadOnlyLevel, ReadWriteLevel).Error( + fmt.Sprintf("value '%s' is invalid. Must be one of: 'READ-ONLY' or 'READ-WRITE'", a.AccessLevel))), + "APIID": validation.Validate(a.APIID, validation.Required), + }.Filter() +} + +// Validate validates GroupAccess +func (ga GroupAccess) Validate() error { + return validation.Errors{ + "Groups": validation.Validate(ga.Groups, validation.When(!ga.CloneAuthorizedUserGroups, validation.Required)), + }.Filter() +} + +// Validate validates ClientGroup +func (cg ClientGroup) Validate() error { + return validation.Errors{ + "GroupID": validation.Validate(cg.GroupID, validation.Required), + "RoleID": validation.Validate(cg.RoleID, validation.Required), + }.Filter() +} + +// Validate validates UpdateAPIClientRequest +func (r UpdateAPIClientRequest) Validate() error { + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Body": validation.Validate(r.Body, validation.Required), + }) +} + +// Validate validates UpdateAPIClientBody +func (r UpdateAPIClientBody) Validate() error { + return validation.Errors{ + "APIAccess": validation.Validate(r.APIAccess, validation.Required), + "AuthorizedUsers": validation.Validate(r.AuthorizedUsers, validation.Required, validation.Length(1, 0)), + "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType).Error( + fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'", r.ClientType))), + "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), + "PurgeOptions": validation.Validate(r.PurgeOptions), + }.Filter() +} + +// Validate validates PurgeOptions +func (po PurgeOptions) Validate() error { + return validation.Errors{ + "CPCodeAccess": validation.Validate(po.CPCodeAccess), + }.Filter() +} + +// Validate validates UpdateAPIClientBody +func (ca CPCodeAccess) Validate() error { + return validation.Errors{ + "CPCodes": validation.Validate(ca.CPCodes, validation.When(!ca.AllCurrentAndNewCPCodes, validation.NotNil)), + }.Filter() +} + var ( // ErrLockAPIClient is returned when LockAPIClient fails ErrLockAPIClient = errors.New("lock api client") // ErrUnlockAPIClient is returned when UnlockAPIClient fails ErrUnlockAPIClient = errors.New("unlock api client") + // ErrListAPIClients is returned when ListAPIClients fails + ErrListAPIClients = errors.New("list api clients") + // ErrGetAPIClient is returned when GetAPIClient fails + ErrGetAPIClient = errors.New("get api client") + // ErrCreateAPIClient is returned when CreateAPIClient fails + ErrCreateAPIClient = errors.New("create api client") + // ErrUpdateAPIClient is returned when UpdateAPIClient fails + ErrUpdateAPIClient = errors.New("update api client") + // ErrDeleteAPIClient is returned when DeleteAPIClient fails + ErrDeleteAPIClient = errors.New("delete api client") ) func (i *iam) LockAPIClient(ctx context.Context, params LockAPIClientRequest) (*LockAPIClientResponse, error) { @@ -136,3 +492,155 @@ func (i *iam) UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest return &result, nil } + +func (i *iam) ListAPIClients(ctx context.Context, params ListAPIClientsRequest) (ListAPIClientsResponse, error) { + logger := i.Log(ctx) + logger.Debug("ListAPIClients") + + uri, err := url.Parse("/identity-management/v3/api-clients") + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAPIClients, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAPIClients, err) + } + + var result ListAPIClientsResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrListAPIClients, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrListAPIClients, i.Error(resp)) + } + + return result, nil + +} + +func (i *iam) GetAPIClient(ctx context.Context, params GetAPIClientRequest) (*GetAPIClientResponse, error) { + logger := i.Log(ctx) + logger.Debug("GetAPIClient") + + if params.ClientID == "" { + params.ClientID = "self" + } + + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s", params.ClientID)) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAPIClient, err) + } + + q := uri.Query() + q.Add("actions", strconv.FormatBool(params.Actions)) + q.Add("groupAccess", strconv.FormatBool(params.GroupAccess)) + q.Add("apiAccess", strconv.FormatBool(params.APIAccess)) + q.Add("credentials", strconv.FormatBool(params.Credentials)) + q.Add("ipAcl", strconv.FormatBool(params.IPACL)) + uri.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAPIClient, err) + } + + var result GetAPIClientResponse + resp, err := i.Exec(req, &result) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrGetAPIClient, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrGetAPIClient, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) CreateAPIClient(ctx context.Context, params CreateAPIClientRequest) (*CreateAPIClientResponse, error) { + logger := i.Log(ctx) + logger.Debug("CreateAPIClient") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateAPIClient, ErrStructValidation, err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/identity-management/v3/api-clients", nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateAPIClient, err) + } + + var result CreateAPIClientResponse + resp, err := i.Exec(req, &result, params) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrCreateAPIClient, err) + } + + if resp.StatusCode != http.StatusCreated { + return nil, fmt.Errorf("%s: %w", ErrCreateAPIClient, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) UpdateAPIClient(ctx context.Context, params UpdateAPIClientRequest) (*UpdateAPIClientResponse, error) { + logger := i.Log(ctx) + logger.Debug("UpdateAPIClient") + + if err := params.Validate(); err != nil { + return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateAPIClient, ErrStructValidation, err) + } + + if params.ClientID == "" { + params.ClientID = "self" + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, fmt.Sprintf("/identity-management/v3/api-clients/%s", params.ClientID), nil) + if err != nil { + return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateAPIClient, err) + } + + var result UpdateAPIClientResponse + resp, err := i.Exec(req, &result, params.Body) + if err != nil { + return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateAPIClient, err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s: %w", ErrUpdateAPIClient, i.Error(resp)) + } + + return &result, nil +} + +func (i *iam) DeleteAPIClient(ctx context.Context, params DeleteAPIClientRequest) error { + logger := i.Log(ctx) + logger.Debug("DeleteAPIClient") + + if params.ClientID == "" { + params.ClientID = "self" + } + + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, fmt.Sprintf("/identity-management/v3/api-clients/%s", params.ClientID), nil) + if err != nil { + return fmt.Errorf("%w: failed to create request: %s", ErrDeleteAPIClient, err) + } + + resp, err := i.Exec(req, nil) + if err != nil { + return fmt.Errorf("%w: request failed: %s", ErrDeleteAPIClient, err) + } + + if resp.StatusCode != http.StatusNoContent { + return fmt.Errorf("%s: %w", ErrDeleteAPIClient, i.Error(resp)) + } + + return nil +} diff --git a/pkg/iam/api_clients_credentials_test.go b/pkg/iam/api_clients_credentials_test.go index 05106c1b..b962d874 100644 --- a/pkg/iam/api_clients_credentials_test.go +++ b/pkg/iam/api_clients_credentials_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/terraform-provider-akamai/v6/pkg/common/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/api_clients_test.go b/pkg/iam/api_clients_test.go index 4bac1b13..b52b1259 100644 --- a/pkg/iam/api_clients_test.go +++ b/pkg/iam/api_clients_test.go @@ -3,6 +3,7 @@ package iam import ( "context" "errors" + "io/ioutil" "net/http" "net/http/httptest" "testing" @@ -306,3 +307,2064 @@ func TestIAM_UnlockAPIClient(t *testing.T) { }) } } + +func TestListAPIClients(t *testing.T) { + tests := map[string]struct { + params ListAPIClientsRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse ListAPIClientsResponse + withError func(*testing.T, error) + }{ + "200 OK": { + params: ListAPIClientsRequest{}, + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "serviceConsumerToken": "akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1" + }, + { + "clientId": "hgfedcba87654321", + "clientName": "test_user_2", + "clientDescription": "test_user_2 description", + "clientType": "SERVICE_ACCOUNT", + "authorizedUsers": [ + "user2" + ], + "canAutoCreateCredential": true, + "notificationEmails": [ + "user2@example.com" + ], + "activeCredentialCount": 1, + "allowAccountSwitch": false, + "createdDate": "2023-07-03T15:04:01.000Z", + "createdBy": "admin", + "isLocked": false, + "accessToken": "akaa-8h7g6f5e8h7g6f5e-8h7g6f5e8h7g6f5e", + "serviceConsumerToken": "akaa-e5f6g7h8e5f6g7h8-e5f6g7h8e5f6g7h8" + } +]`, + expectedPath: "/identity-management/v3/api-clients?actions=false", + expectedResponse: ListAPIClientsResponse{ + { + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + ActiveCredentialCount: 0, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + NotificationEmails: []string{"user1@example.com"}, + ServiceConsumerToken: "akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1", + }, + { + AccessToken: "akaa-8h7g6f5e8h7g6f5e-8h7g6f5e8h7g6f5e", + ActiveCredentialCount: 1, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user2"}, + CanAutoCreateCredential: true, + ClientDescription: "test_user_2 description", + ClientID: "hgfedcba87654321", + ClientName: "test_user_2", + ClientType: ServiceAccountClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2023-07-03T15:04:01.000Z"), + IsLocked: false, + NotificationEmails: []string{"user2@example.com"}, + ServiceConsumerToken: "akaa-e5f6g7h8e5f6g7h8-e5f6g7h8e5f6g7h8", + }, + }, + }, + "200 with actions": { + params: ListAPIClientsRequest{Actions: true}, + responseStatus: http.StatusOK, + responseBody: ` +[ + { + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "serviceConsumerToken": "akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1", + "actions": { + "lock": false, + "unlock": false, + "edit": false, + "transfer": false, + "delete": false, + "deactivateAll": false + } + }, + { + "clientId": "hgfedcba87654321", + "clientName": "test_user_2", + "clientDescription": "test_user_2 description", + "clientType": "SERVICE_ACCOUNT", + "authorizedUsers": [ + "user2" + ], + "canAutoCreateCredential": true, + "notificationEmails": [ + "user2@example.com" + ], + "activeCredentialCount": 1, + "allowAccountSwitch": false, + "createdDate": "2023-07-03T15:04:01.000Z", + "createdBy": "admin", + "isLocked": false, + "accessToken": "akaa-8h7g6f5e8h7g6f5e-8h7g6f5e8h7g6f5e", + "serviceConsumerToken": "akaa-e5f6g7h8e5f6g7h8-e5f6g7h8e5f6g7h8", + "actions": { + "lock": true, + "unlock": true, + "edit": true, + "transfer": true, + "delete": true, + "deactivateAll": true + } + } +]`, + expectedPath: "/identity-management/v3/api-clients?actions=true", + expectedResponse: ListAPIClientsResponse{ + { + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + ActiveCredentialCount: 0, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + NotificationEmails: []string{"user1@example.com"}, + ServiceConsumerToken: "akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1", + Actions: &ListAPIClientsActions{ + Delete: false, + DeactivateAll: false, + Edit: false, + Lock: false, + Transfer: false, + Unlock: false, + }, + }, + { + AccessToken: "akaa-8h7g6f5e8h7g6f5e-8h7g6f5e8h7g6f5e", + ActiveCredentialCount: 1, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user2"}, + CanAutoCreateCredential: true, + ClientDescription: "test_user_2 description", + ClientID: "hgfedcba87654321", + ClientName: "test_user_2", + ClientType: ServiceAccountClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2023-07-03T15:04:01.000Z"), + IsLocked: false, + NotificationEmails: []string{"user2@example.com"}, + ServiceConsumerToken: "akaa-e5f6g7h8e5f6g7h8-e5f6g7h8e5f6g7h8", + Actions: &ListAPIClientsActions{ + Delete: true, + DeactivateAll: true, + Edit: true, + Lock: true, + Transfer: true, + Unlock: true, + }, + }, + }, + }, + "500 internal server error": { + params: ListAPIClientsRequest{}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/api-clients?actions=false", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + result, err := client.ListAPIClients(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestCreateAPIClient(t *testing.T) { + tests := map[string]struct { + params CreateAPIClientRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *CreateAPIClientResponse + expectedRequestBody string + withError func(*testing.T, error) + }{ + "201 Created with allAPI, cpCodes and clone group": { + params: CreateAPIClientRequest{ + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + }, + AuthorizedUsers: []string{"user1"}, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + }, + NotificationEmails: []string{"user1@example.com"}, + PurgeOptions: &PurgeOptions{ + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + }, + }, + }, + expectedPath: "/identity-management/v3/api-clients", + responseStatus: http.StatusCreated, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": true, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": false, + "canPurgeByCacheTag": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": [] + } + }, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "actions": { + "editGroups": true, + "editApis": true, + "lock": true, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": true, + "deactivateAll": false + } +}`, + expectedRequestBody: ` +{ + "allowAccountSwitch": false, + "apiAccess": { + "allAccessibleApis": true, + "apis": null + }, + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "clientDescription": "test_user_1 description", + "clientName": "test_user_1", + "clientType": "CLIENT", + "createCredential": false, + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": null + }, + "notificationEmails": [ + "user1@example.com" + ], + "purgeOptions": { + "canPurgeByCacheTag": false, + "canPurgeByCpcode": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": null + } + } +} +`, + expectedResponse: &CreateAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ActiveCredentialCount: 0, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + NotificationEmails: []string{"user1@example.com"}, + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCPCode: false, + CanPurgeByCacheTag: false, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + CPCodes: []int64{}, + }, + }, + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: true, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: true, + DeactivateAll: false, + }, + }, + }, + "201 Created with all fields and custom API and group": { + params: CreateAPIClientRequest{ + AllowAccountSwitch: true, + APIAccess: APIAccess{ + AllAccessibleAPIs: false, + APIs: []API{ + { + AccessLevel: ReadOnlyLevel, + APIID: 1, + }, + { + AccessLevel: ReadWriteLevel, + APIID: 2, + }, + }, + }, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: true, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreateCredential: true, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: false, + Groups: []ClientGroup{ + { + GroupID: 123, + RoleID: 1, + }, + }, + }, + IPACL: &IPACL{ + CIDR: []string{"1.2.3.4/32"}, + Enable: true, + }, + NotificationEmails: []string{"user1@example.com"}, + PurgeOptions: &PurgeOptions{ + CanPurgeByCacheTag: true, + CanPurgeByCPCode: true, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: false, + CPCodes: []int64{321}, + }, + }, + }, + expectedPath: "/identity-management/v3/api-clients", + responseStatus: http.StatusCreated, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": true, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 1, + "allowAccountSwitch": true, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "groupAccess": { + "cloneAuthorizedUserGroups": false, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": false, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": true, + "canPurgeByCacheTag": true, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": false, + "cpcodes": [321] + } + }, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "credentials": [ + { + "credentialId": 456, + "clientToken": "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + "clientSecret": "verysecretsecret", + "status": "ACTIVE", + "createdOn": "2023-01-03T07:44:08.000Z", + "description": "desc", + "expiresOn": "2025-01-03T07:44:08.000Z", + "actions": { + "deactivate": true, + "delete": false, + "activate": false, + "editDescription": true, + "editExpiration": true + } + } + ], + "actions": { + "editGroups": true, + "editApis": true, + "lock": true, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": true, + "deactivateAll": false + } +}`, + expectedRequestBody: ` +{ + "allowAccountSwitch": true, + "apiAccess": { + "allAccessibleApis": false, + "apis": [ + { + "accessLevel": "READ-ONLY", + "apiId": 1, + "apiName": "", + "description": "", + "documentationUrl": "", + "endPoint": "" + }, + { + "accessLevel": "READ-WRITE", + "apiId": 2, + "apiName": "", + "description": "", + "documentationUrl": "", + "endPoint": "" + } + ] + }, + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": true, + "clientDescription": "test_user_1 description", + "clientName": "test_user_1", + "clientType": "CLIENT", + "createCredential": true, + "groupAccess": { + "cloneAuthorizedUserGroups": false, + "groups": [ + { + "groupId": 123, + "groupName": "", + "isBlocked": false, + "parentGroupId": 0, + "roleDescription": "", + "roleId": 1, + "roleName": "", + "subgroups": null + } + ] + }, + "ipAcl": { + "cidr": [ + "1.2.3.4/32" + ], + "enable": true + }, + "notificationEmails": [ + "user1@example.com" + ], + "purgeOptions": { + "canPurgeByCacheTag": true, + "canPurgeByCpcode": true, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": false, + "cpcodes": [ + 321 + ] + } + } +} +`, + expectedResponse: &CreateAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + AllowAccountSwitch: true, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: true, + ActiveCredentialCount: 1, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: false, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + NotificationEmails: []string{"user1@example.com"}, + APIAccess: APIAccess{ + AllAccessibleAPIs: false, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCacheTag: true, + CanPurgeByCPCode: true, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: false, + CPCodes: []int64{321}, + }, + }, + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + Credentials: []CreateAPIClientCredential{ + { + Actions: CredentialActions{ + Deactivate: true, + Delete: false, + Activate: false, + EditDescription: true, + EditExpiration: true, + }, + ClientToken: "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + ClientSecret: "verysecretsecret", + CreatedOn: test.NewTimeFromString(t, "2023-01-03T07:44:08.000Z"), + CredentialID: 456, + Description: "desc", + ExpiresOn: test.NewTimeFromString(t, "2025-01-03T07:44:08.000Z"), + Status: CredentialActive, + }, + }, + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: true, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: true, + DeactivateAll: false, + }, + }, + }, + "validation errors": { + params: CreateAPIClientRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "create api client: struct validation:\nAPIs: cannot be blank\nAuthorizedUsers: cannot be blank\nClientType: cannot be blank\nGroups: cannot be blank", err.Error()) + }, + }, + "validation errors - internal validations": { + params: CreateAPIClientRequest{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "create api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) + }, + }, + "500 internal server error": { + params: CreateAPIClientRequest{ + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + }, + AuthorizedUsers: []string{"user1"}, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + }, + NotificationEmails: []string{"user1@example.com"}, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` +{ + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 +} +`, + expectedPath: "/identity-management/v3/api-clients", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPost, r.Method) + + if len(test.expectedRequestBody) > 0 { + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + assert.JSONEq(t, test.expectedRequestBody, string(body)) + } + + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.CreateAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestUpdateAPIClient(t *testing.T) { + tests := map[string]struct { + params UpdateAPIClientRequest + expectedPath string + responseStatus int + responseBody string + expectedResponse *UpdateAPIClientResponse + expectedRequestBody string + withError func(*testing.T, error) + }{ + "200 Updated self": { + params: UpdateAPIClientRequest{ + Body: UpdateAPIClientBody{ + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + }, + AuthorizedUsers: []string{"user1"}, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + }, + NotificationEmails: []string{"user1@example.com"}, + PurgeOptions: &PurgeOptions{ + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + }, + }, + }, + }, + expectedPath: "/identity-management/v3/api-clients/self", + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": true, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": false, + "canPurgeByCacheTag": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": [] + } + }, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "actions": { + "editGroups": true, + "editApis": true, + "lock": true, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": true, + "deactivateAll": false + } +}`, + expectedResponse: &UpdateAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ActiveCredentialCount: 0, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + NotificationEmails: []string{"user1@example.com"}, + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCPCode: false, + CanPurgeByCacheTag: false, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + CPCodes: []int64{}, + }, + }, + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: true, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: true, + DeactivateAll: false, + }, + }, + }, + "200 Updated with allAPI, cpCodes and clone group": { + params: UpdateAPIClientRequest{ + ClientID: "abcdefgh12345678", + Body: UpdateAPIClientBody{ + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + }, + AuthorizedUsers: []string{"user1"}, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + }, + NotificationEmails: []string{"user1@example.com"}, + PurgeOptions: &PurgeOptions{ + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + }, + }, + }, + }, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678", + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": true, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": false, + "canPurgeByCacheTag": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": [] + } + }, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "actions": { + "editGroups": true, + "editApis": true, + "lock": true, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": true, + "deactivateAll": false + } +}`, + expectedRequestBody: ` +{ + "allowAccountSwitch": false, + "apiAccess": { + "allAccessibleApis": true, + "apis": null + }, + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "clientDescription": "test_user_1 description", + "clientName": "test_user_1", + "clientType": "CLIENT", + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": null + }, + "notificationEmails": [ + "user1@example.com" + ], + "purgeOptions": { + "canPurgeByCacheTag": false, + "canPurgeByCpcode": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": null + } + } +} +`, + expectedResponse: &UpdateAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ActiveCredentialCount: 0, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + NotificationEmails: []string{"user1@example.com"}, + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCPCode: false, + CanPurgeByCacheTag: false, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + CPCodes: []int64{}, + }, + }, + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: true, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: true, + DeactivateAll: false, + }, + }, + }, + "200 Updated with all fields and custom API and group": { + params: UpdateAPIClientRequest{ + ClientID: "abcdefgh12345678", + Body: UpdateAPIClientBody{ + AllowAccountSwitch: true, + APIAccess: APIAccess{ + AllAccessibleAPIs: false, + APIs: []API{ + { + AccessLevel: ReadOnlyLevel, + APIID: 1, + }, + { + AccessLevel: ReadWriteLevel, + APIID: 2, + }, + }, + }, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: true, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: false, + Groups: []ClientGroup{ + { + GroupID: 123, + RoleID: 1, + }, + }, + }, + IPACL: &IPACL{ + CIDR: []string{"1.2.3.4/32"}, + Enable: true, + }, + NotificationEmails: []string{"user1@example.com"}, + PurgeOptions: &PurgeOptions{ + CanPurgeByCacheTag: true, + CanPurgeByCPCode: true, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: false, + CPCodes: []int64{321}, + }, + }, + }, + }, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678", + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": true, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 1, + "allowAccountSwitch": true, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "groupAccess": { + "cloneAuthorizedUserGroups": false, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": false, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": true, + "canPurgeByCacheTag": true, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": false, + "cpcodes": [321] + } + }, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "credentials": [ + { + "credentialId": 456, + "clientToken": "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + "status": "ACTIVE", + "createdOn": "2023-01-03T07:44:08.000Z", + "description": "desc", + "expiresOn": "2025-01-03T07:44:08.000Z", + "actions": { + "deactivate": true, + "delete": false, + "activate": false, + "editDescription": true, + "editExpiration": true + } + } + ], + "actions": { + "editGroups": true, + "editApis": true, + "lock": true, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": true, + "deactivateAll": false + } +}`, + expectedRequestBody: ` +{ + "allowAccountSwitch": true, + "apiAccess": { + "allAccessibleApis": false, + "apis": [ + { + "accessLevel": "READ-ONLY", + "apiId": 1, + "apiName": "", + "description": "", + "documentationUrl": "", + "endPoint": "" + }, + { + "accessLevel": "READ-WRITE", + "apiId": 2, + "apiName": "", + "description": "", + "documentationUrl": "", + "endPoint": "" + } + ] + }, + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": true, + "clientDescription": "test_user_1 description", + "clientName": "test_user_1", + "clientType": "CLIENT", + "groupAccess": { + "cloneAuthorizedUserGroups": false, + "groups": [ + { + "groupId": 123, + "groupName": "", + "isBlocked": false, + "parentGroupId": 0, + "roleDescription": "", + "roleId": 1, + "roleName": "", + "subgroups": null + } + ] + }, + "ipAcl": { + "cidr": [ + "1.2.3.4/32" + ], + "enable": true + }, + "notificationEmails": [ + "user1@example.com" + ], + "purgeOptions": { + "canPurgeByCacheTag": true, + "canPurgeByCpcode": true, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": false, + "cpcodes": [ + 321 + ] + } + } +} +`, + expectedResponse: &UpdateAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + AllowAccountSwitch: true, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: true, + ActiveCredentialCount: 1, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: false, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + NotificationEmails: []string{"user1@example.com"}, + APIAccess: APIAccess{ + AllAccessibleAPIs: false, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCacheTag: true, + CanPurgeByCPCode: true, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: false, + CPCodes: []int64{321}, + }, + }, + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + Credentials: []APIClientCredential{ + { + Actions: CredentialActions{ + Deactivate: true, + Delete: false, + Activate: false, + EditDescription: true, + EditExpiration: true, + }, + ClientToken: "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + CreatedOn: test.NewTimeFromString(t, "2023-01-03T07:44:08.000Z"), + CredentialID: 456, + Description: "desc", + ExpiresOn: test.NewTimeFromString(t, "2025-01-03T07:44:08.000Z"), + Status: CredentialActive, + }, + }, + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: true, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: true, + DeactivateAll: false, + }, + }, + }, + "validation errors": { + params: UpdateAPIClientRequest{}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "update api client: struct validation:\nAPIs: cannot be blank\nAuthorizedUsers: cannot be blank\nClientType: cannot be blank\nGroups: cannot be blank", err.Error()) + }, + }, + "validation errors - internal validations": { + params: UpdateAPIClientRequest{Body: UpdateAPIClientBody{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}}, + withError: func(t *testing.T, err error) { + assert.Equal(t, "update api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) + }, + }, + "500 internal server error": { + params: UpdateAPIClientRequest{ + Body: UpdateAPIClientBody{ + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + }, + AuthorizedUsers: []string{"user1"}, + ClientDescription: "test_user_1 description", + ClientName: "test_user_1", + ClientType: ClientClientType, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + }, + NotificationEmails: []string{"user1@example.com"}, + }, + }, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/api-clients/self", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodPut, r.Method) + + if len(test.expectedRequestBody) > 0 { + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + assert.JSONEq(t, test.expectedRequestBody, string(body)) + } + + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + })) + client := mockAPIClient(t, mockServer) + response, err := client.UpdateAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, response) + }) + } +} + +func TestGetAPIClient(t *testing.T) { + tests := map[string]struct { + params GetAPIClientRequest + responseStatus int + responseBody string + expectedPath string + expectedResponse *GetAPIClientResponse + withError func(*testing.T, error) + }{ + "200 OK - Self": { + params: GetAPIClientRequest{}, + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d" +} +`, + expectedPath: "/identity-management/v3/api-clients/self?actions=false&apiAccess=false&credentials=false&groupAccess=false&ipAcl=false", + expectedResponse: &GetAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + ActiveCredentialCount: 0, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + NotificationEmails: []string{"user1@example.com"}, + }, + }, + "200 OK - with clientID": { + params: GetAPIClientRequest{ClientID: "abcdefgh12345678"}, + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d" +} +`, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678?actions=false&apiAccess=false&credentials=false&groupAccess=false&ipAcl=false", + expectedResponse: &GetAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + ActiveCredentialCount: 0, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + NotificationEmails: []string{"user1@example.com"}, + }, + }, + "200 OK - with all query params and all fields": { + params: GetAPIClientRequest{ + ClientID: "abcdefgh12345678", + Actions: true, + GroupAccess: true, + APIAccess: true, + Credentials: true, + IPACL: true, + }, + responseStatus: http.StatusOK, + responseBody: ` +{ + "clientId": "abcdefgh12345678", + "clientName": "test_user_1", + "clientDescription": "test_user_1 description", + "clientType": "CLIENT", + "authorizedUsers": [ + "user1" + ], + "canAutoCreateCredential": false, + "notificationEmails": [ + "user1@example.com" + ], + "activeCredentialCount": 0, + "allowAccountSwitch": false, + "createdDate": "2024-07-16T23:01:50.000Z", + "createdBy": "admin", + "isLocked": false, + "baseURL": "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + "accessToken": "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + "groupAccess": { + "cloneAuthorizedUserGroups": true, + "groups": [ + { + "groupId": 123, + "groupName": "GroupName-G-R0UP", + "roleId": 1, + "roleName": "Admin", + "roleDescription": "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + "isBlocked": false, + "subGroups": [] + } + ] + }, + "apiAccess": { + "allAccessibleApis": true, + "apis": [ + { + "apiId": 1, + "apiName": "API Client Administration", + "description": "API Client Administration", + "endPoint": "/identity-management", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-ONLY" + }, + { + "apiId": 2, + "apiName": "CCU APIs", + "description": "Content control utility APIs", + "endPoint": "/ccu", + "documentationUrl": "https://developer.akamai.com", + "accessLevel": "READ-WRITE" + } + ] + }, + "purgeOptions": { + "canPurgeByCpcode": false, + "canPurgeByCacheTag": false, + "cpcodeAccess": { + "allCurrentAndNewCpcodes": true, + "cpcodes": [] + } + }, + "credentials": [ + { + "credentialId": 456, + "clientToken": "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + "status": "ACTIVE", + "createdOn": "2023-01-03T07:44:08.000Z", + "description": "desc", + "expiresOn": "2025-01-03T07:44:08.000Z", + "actions": { + "deactivate": true, + "delete": false, + "activate": false, + "editDescription": true, + "editExpiration": true + } + }, + { + "credentialId": 678, + "clientToken": "akaa-de90de90de90de90-de90de90de90de90", + "status": "INACTIVE", + "createdOn": "2023-01-03T07:44:08.000Z", + "description": "", + "expiresOn": "2025-01-03T07:44:08.000Z", + "actions": { + "deactivate": false, + "delete": false, + "activate": false, + "editDescription": false, + "editExpiration": false + } + }, + { + "credentialId": 789, + "clientToken": "akaa-gh34gh34gh34gh34-gh34gh34gh34gh34", + "status": "DELETED", + "createdOn": "2023-01-03T07:44:08.000Z", + "description": "", + "expiresOn": "2025-01-03T07:44:08.000Z", + "actions": { + "deactivate": false, + "delete": false, + "activate": false, + "editDescription": false, + "editExpiration": false + } + } + ], + "actions": { + "editGroups": true, + "editApis": true, + "lock": false, + "unlock": false, + "editAuth": true, + "edit": true, + "editSwitchAccount": false, + "transfer": true, + "editIpAcl": true, + "delete": false, + "deactivateAll": true + } +} +`, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678?actions=true&apiAccess=true&credentials=true&groupAccess=true&ipAcl=true", + expectedResponse: &GetAPIClientResponse{ + AccessToken: "akaa-1a2b3c4d1a2b3c4d-1a2b3c4d1a2b3c4d", + BaseURL: "https://akaa-d4c3b2a1d4c3b2a1-d4c3b2a1d4c3b2a1.luna-dev.akamaiapis.net", + ActiveCredentialCount: 0, + AllowAccountSwitch: false, + AuthorizedUsers: []string{"user1"}, + CanAutoCreateCredential: false, + ClientDescription: "test_user_1 description", + ClientID: "abcdefgh12345678", + ClientName: "test_user_1", + ClientType: ClientClientType, + CreatedBy: "admin", + CreatedDate: test.NewTimeFromString(t, "2024-07-16T23:01:50.000Z"), + IsLocked: false, + NotificationEmails: []string{"user1@example.com"}, + GroupAccess: GroupAccess{ + CloneAuthorizedUserGroups: true, + Groups: []ClientGroup{ + { + GroupID: 123, + GroupName: "GroupName-G-R0UP", + RoleID: 1, + RoleName: "Admin", + RoleDescription: "This role provides the maximum access to users. An Administrator can perform admin tasks such as creating users and groups; configuration-related tasks such as creating and editing configurations; publishing tasks", + Subgroups: []ClientGroup{}, + }, + }, + }, + APIAccess: APIAccess{ + AllAccessibleAPIs: true, + APIs: []API{ + { + APIID: 1, + APIName: "API Client Administration", + Description: "API Client Administration", + Endpoint: "/identity-management", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadOnlyLevel, + }, + { + APIID: 2, + APIName: "CCU APIs", + Description: "Content control utility APIs", + Endpoint: "/ccu", + DocumentationURL: "https://developer.akamai.com", + AccessLevel: ReadWriteLevel, + }, + }, + }, + PurgeOptions: PurgeOptions{ + CanPurgeByCPCode: false, + CanPurgeByCacheTag: false, + CPCodeAccess: CPCodeAccess{ + AllCurrentAndNewCPCodes: true, + CPCodes: []int64{}, + }, + }, + Credentials: []APIClientCredential{ + { + Actions: CredentialActions{ + Deactivate: true, + Delete: false, + Activate: false, + EditDescription: true, + EditExpiration: true, + }, + ClientToken: "akaa-bc78bc78bc78bc78-bc78bc78bc78bc78", + CreatedOn: test.NewTimeFromString(t, "2023-01-03T07:44:08.000Z"), + CredentialID: 456, + Description: "desc", + ExpiresOn: test.NewTimeFromString(t, "2025-01-03T07:44:08.000Z"), + Status: CredentialActive, + }, + { + Actions: CredentialActions{ + Deactivate: false, + Delete: false, + Activate: false, + EditDescription: false, + EditExpiration: false, + }, + ClientToken: "akaa-de90de90de90de90-de90de90de90de90", + CreatedOn: test.NewTimeFromString(t, "2023-01-03T07:44:08.000Z"), + CredentialID: 678, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2025-01-03T07:44:08.000Z"), + Status: CredentialInactive, + }, + { + Actions: CredentialActions{ + Deactivate: false, + Delete: false, + Activate: false, + EditDescription: false, + EditExpiration: false, + }, + ClientToken: "akaa-gh34gh34gh34gh34-gh34gh34gh34gh34", + CreatedOn: test.NewTimeFromString(t, "2023-01-03T07:44:08.000Z"), + CredentialID: 789, + Description: "", + ExpiresOn: test.NewTimeFromString(t, "2025-01-03T07:44:08.000Z"), + Status: CredentialDeleted, + }, + }, + Actions: &APIClientActions{ + EditGroups: true, + EditAPIs: true, + Lock: false, + Unlock: false, + EditAuth: true, + Edit: true, + EditSwitchAccount: false, + Transfer: true, + EditIPAcl: true, + Delete: false, + DeactivateAll: true, + }, + }, + }, + "500 internal server error": { + params: GetAPIClientRequest{}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/api-clients/self?actions=false&apiAccess=false&credentials=false&groupAccess=false&ipAcl=false", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + result, err := client.GetAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, test.expectedResponse, result) + }) + } +} + +func TestDeleteAPIClient(t *testing.T) { + tests := map[string]struct { + params DeleteAPIClientRequest + responseStatus int + responseBody string + expectedPath string + withError func(*testing.T, error) + }{ + "204 No content - self": { + params: DeleteAPIClientRequest{}, + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/api-clients/self", + }, + "204 No content - by ID": { + params: DeleteAPIClientRequest{ClientID: "abcdefgh12345678"}, + responseStatus: http.StatusNoContent, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678", + }, + "500 internal server error": { + params: DeleteAPIClientRequest{ClientID: "abcdefgh12345678"}, + responseStatus: http.StatusInternalServerError, + responseBody: ` + { + "type": "internal_error", + "title": "Internal Server Error", + "detail": "Error making request", + "status": 500 + } + `, + expectedPath: "/identity-management/v3/api-clients/abcdefgh12345678", + withError: func(t *testing.T, e error) { + err := Error{ + Type: "internal_error", + Title: "Internal Server Error", + Detail: "Error making request", + StatusCode: http.StatusInternalServerError, + } + assert.Equal(t, true, err.Is(e)) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, http.MethodDelete, r.Method) + w.WriteHeader(test.responseStatus) + _, err := w.Write([]byte(test.responseBody)) + assert.NoError(t, err) + + })) + client := mockAPIClient(t, mockServer) + err := client.DeleteAPIClient(context.Background(), test.params) + if test.withError != nil { + test.withError(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go index 5a5d952e..41b4b01c 100644 --- a/pkg/iam/helper.go +++ b/pkg/iam/helper.go @@ -120,14 +120,14 @@ type ( // AllowedAPI contains the details about the API AllowedAPI struct { - AccessLevels []string `json:"accessLevels"` - APIID int64 `json:"apiId"` - APIName string `json:"apiName"` - Description string `json:"description"` - DocumentationURL string `json:"documentationUrl"` - Endpoint string `json:"endpoint"` - HasAccess bool `json:"hasAccess"` - ServiceProviderID int64 `json:"serviceProviderId"` + AccessLevels []AccessLevel `json:"accessLevels"` + APIID int64 `json:"apiId"` + APIName string `json:"apiName"` + Description string `json:"description"` + DocumentationURL string `json:"documentationUrl"` + Endpoint string `json:"endpoint"` + HasAccess bool `json:"hasAccess"` + ServiceProviderID int64 `json:"serviceProviderId"` } // ClientType represents the type of the client diff --git a/pkg/iam/helper_test.go b/pkg/iam/helper_test.go index 97c21045..fd715965 100644 --- a/pkg/iam/helper_test.go +++ b/pkg/iam/helper_test.go @@ -352,7 +352,7 @@ func TestIAMListAllowedAPIs(t *testing.T) { Description: "Test API Name", Endpoint: "/test-api-name/", DocumentationURL: "https://example.akamai.com/", - AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + AccessLevels: []AccessLevel{ReadWriteLevel, ReadOnlyLevel}, HasAccess: false, }, { @@ -362,7 +362,7 @@ func TestIAMListAllowedAPIs(t *testing.T) { Description: "Example API Name", Endpoint: "/example-api-name/", DocumentationURL: "https://example2.akamai.com/", - AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + AccessLevels: []AccessLevel{ReadWriteLevel, ReadOnlyLevel}, HasAccess: false, }, { @@ -372,7 +372,7 @@ func TestIAMListAllowedAPIs(t *testing.T) { Description: "Best API Name", Endpoint: "/best-api-name/", DocumentationURL: "https://example3.akamai.com/", - AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + AccessLevels: []AccessLevel{ReadWriteLevel, ReadOnlyLevel}, HasAccess: false, }, }, @@ -408,7 +408,7 @@ func TestIAMListAllowedAPIs(t *testing.T) { Description: "Test API Name", Endpoint: "/test-api-name/", DocumentationURL: "https://example.akamai.com/", - AccessLevels: []string{"READ-WRITE", "READ-ONLY"}, + AccessLevels: []AccessLevel{ReadWriteLevel, ReadOnlyLevel}, HasAccess: false, }, }, diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 2f7d129f..0dec5a1d 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -606,3 +606,49 @@ func (m *Mock) DeactivateCredentials(ctx context.Context, request DeactivateCred return args.Error(0) } + +func (m *Mock) ListAPIClients(ctx context.Context, request ListAPIClientsRequest) (ListAPIClientsResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(ListAPIClientsResponse), args.Error(1) +} + +func (m *Mock) GetAPIClient(ctx context.Context, request GetAPIClientRequest) (*GetAPIClientResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*GetAPIClientResponse), args.Error(1) +} + +func (m *Mock) CreateAPIClient(ctx context.Context, request CreateAPIClientRequest) (*CreateAPIClientResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*CreateAPIClientResponse), args.Error(1) +} + +func (m *Mock) UpdateAPIClient(ctx context.Context, request UpdateAPIClientRequest) (*UpdateAPIClientResponse, error) { + args := m.Called(ctx, request) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*UpdateAPIClientResponse), args.Error(1) +} + +func (m *Mock) DeleteAPIClient(ctx context.Context, request DeleteAPIClientRequest) error { + args := m.Called(ctx, request) + + return args.Error(0) +} From 23c3c5986288f47ce0cbe3b7c8e56ceb600505d5 Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Thu, 22 Aug 2024 12:51:11 +0000 Subject: [PATCH 26/34] DXE-4037 Implement iam_account_switch_keys data source --- pkg/iam/mocks.go | 4 ++-- pkg/iam/support.go | 6 +++--- pkg/iam/support_test.go | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 0dec5a1d..9908576f 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -104,14 +104,14 @@ func (m *Mock) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) return args.Get(0).([]TimeoutPolicy), args.Error(1) } -func (m *Mock) ListAccountSwitchKeys(ctx context.Context, request ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) { +func (m *Mock) ListAccountSwitchKeys(ctx context.Context, request ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) { args := m.Called(ctx, request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ListAccountSwitchKeysResponse), args.Error(1) + return args.Get(0).(ListAccountSwitchKeysResponse), args.Error(1) } func (m *Mock) ListStates(ctx context.Context, request ListStatesRequest) ([]string, error) { diff --git a/pkg/iam/support.go b/pkg/iam/support.go index aa16e4cb..b2999592 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -36,7 +36,7 @@ type ( // ListAccountSwitchKeys lists account switch keys available for a specific API client. If `ClientID` is not provided, it lists account switch keys available for your API client. // // See: https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys, https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys - ListAccountSwitchKeys(context.Context, ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) + ListAccountSwitchKeys(context.Context, ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) // SupportedContactTypes lists supported contact types // @@ -243,7 +243,7 @@ func (i *iam) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) return rval, nil } -func (i *iam) ListAccountSwitchKeys(ctx context.Context, params ListAccountSwitchKeysRequest) (*ListAccountSwitchKeysResponse, error) { +func (i *iam) ListAccountSwitchKeys(ctx context.Context, params ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) { logger := i.Log(ctx) logger.Debug("ListAccountSwitchKeys") @@ -277,7 +277,7 @@ func (i *iam) ListAccountSwitchKeys(ctx context.Context, params ListAccountSwitc return nil, fmt.Errorf("%s: %w", ErrListAccountSwitchKeys, i.Error(resp)) } - return &result, nil + return result, nil } func (i *iam) SupportedContactTypes(ctx context.Context) ([]string, error) { diff --git a/pkg/iam/support_test.go b/pkg/iam/support_test.go index e624abbd..83da90d9 100644 --- a/pkg/iam/support_test.go +++ b/pkg/iam/support_test.go @@ -564,7 +564,7 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { responseStatus int expectedPath string responseBody string - expectedResponse *ListAccountSwitchKeysResponse + expectedResponse ListAccountSwitchKeysResponse withError func(*testing.T, error) }{ "200 OK with specified client": { @@ -589,7 +589,7 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { } ] `, - expectedResponse: &ListAccountSwitchKeysResponse{ + expectedResponse: ListAccountSwitchKeysResponse{ AccountSwitchKey{ AccountName: "Test Name A", AccountSwitchKey: "ABC-123", @@ -624,7 +624,7 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { } ] `, - expectedResponse: &ListAccountSwitchKeysResponse{ + expectedResponse: ListAccountSwitchKeysResponse{ AccountSwitchKey{ AccountName: "Test Name A", AccountSwitchKey: "ABC-123", @@ -646,7 +646,7 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { responseStatus: http.StatusOK, expectedPath: "/identity-management/v3/api-clients/test1234/account-switch-keys", responseBody: `[]`, - expectedResponse: &ListAccountSwitchKeysResponse{}, + expectedResponse: ListAccountSwitchKeysResponse{}, }, "200 OK with query param": { params: ListAccountSwitchKeysRequest{ @@ -667,7 +667,7 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { } ] `, - expectedResponse: &ListAccountSwitchKeysResponse{ + expectedResponse: ListAccountSwitchKeysResponse{ AccountSwitchKey{ AccountName: "Test Name A", AccountSwitchKey: "ABC-123", From e84b2d6c47de10777ba8a6d3ad6a1da68ea6291e Mon Sep 17 00:00:00 2001 From: Piotr Bartosik Date: Tue, 27 Aug 2024 06:44:11 +0000 Subject: [PATCH 27/34] DXE-4028 introduce enum PropertyUserType --- pkg/iam/properties.go | 26 +++++++++++++++++++++++--- pkg/iam/properties_test.go | 20 ++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/pkg/iam/properties.go b/pkg/iam/properties.go index 6360ae5f..1516cb9b 100644 --- a/pkg/iam/properties.go +++ b/pkg/iam/properties.go @@ -13,6 +13,26 @@ import ( validation "github.com/go-ozzo/ozzo-validation/v4" ) +// PropertyUserType filters property users based on their access to the property +type PropertyUserType string + +const ( + // PropertyUserTypeAll selects all property users + PropertyUserTypeAll PropertyUserType = "all" + // PropertyUserTypeAssigned selects users that have access to the property + PropertyUserTypeAssigned PropertyUserType = "assigned" + // PropertyUserTypeBlocked selects users whose access to the property is blocked + PropertyUserTypeBlocked PropertyUserType = "blocked" +) + +// Validate validates PropertyUserType +func (p PropertyUserType) Validate() error { + return validation.In(PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", + p, PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked)). + Validate(p) +} + type ( // Properties is the IAM properties API interface Properties interface { @@ -56,7 +76,7 @@ type ( // ListUsersForPropertyRequest contains the request parameters for the ListUsersForProperty operation. ListUsersForPropertyRequest struct { PropertyID int64 - UserType string + UserType PropertyUserType } // GetPropertyRequest contains the request parameters for the get property operation. @@ -151,7 +171,7 @@ type ( func (r ListUsersForPropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), - "UserType": validation.Validate(r.UserType, validation.In(LostAccessUsers, GainAccessUsers)), + "UserType": r.UserType.Validate(), }) } @@ -270,7 +290,7 @@ func (i *iam) ListUsersForProperty(ctx context.Context, params ListUsersForPrope if params.UserType != "" { q := uri.Query() - q.Add("userType", params.UserType) + q.Add("userType", string(params.UserType)) uri.RawQuery = q.Encode() } diff --git a/pkg/iam/properties_test.go b/pkg/iam/properties_test.go index 1df753a3..d97bb2a2 100644 --- a/pkg/iam/properties_test.go +++ b/pkg/iam/properties_test.go @@ -197,19 +197,31 @@ func TestListUserForProperty(t *testing.T) { }, }, }, - "validation errors": { + "validation errors - blank PropertyID": { params: ListUsersForPropertyRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "list users for property: struct validation:\nPropertyID: cannot be blank", err.Error()) + assert.Equal(t, "list users for property: struct validation:\n"+ + "PropertyID: cannot be blank", err.Error()) + }, + }, + "validation errors - bad UserType": { + params: ListUsersForPropertyRequest{ + PropertyID: 1, + UserType: "foo", + }, + withError: func(t *testing.T, err error) { + assert.Equal(t, "list users for property: struct validation:\n"+ + "UserType: value 'foo' is invalid. Must be one of: 'all', 'assigned' or 'blocked'", + err.Error()) }, }, "404 not found": { params: ListUsersForPropertyRequest{ PropertyID: 1, - UserType: GainAccessUsers, + UserType: PropertyUserTypeAssigned, }, responseStatus: http.StatusNotFound, - expectedPath: "/identity-management/v3/user-admin/properties/1/users?userType=gainAccess", + expectedPath: "/identity-management/v3/user-admin/properties/1/users?userType=assigned", responseBody: ` { "instance": "", From 3e4c35e67854041e895f0c8f7060e518105e39cc Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Mon, 9 Sep 2024 09:50:07 +0000 Subject: [PATCH 28/34] DXE-4150 Fix IAM request body naming --- pkg/iam/api_clients.go | 10 +++++----- pkg/iam/api_clients_credentials.go | 10 +++++----- pkg/iam/api_clients_credentials_test.go | 14 ++++++------- pkg/iam/api_clients_test.go | 10 +++++----- pkg/iam/cidr.go | 10 +++++----- pkg/iam/cidr_test.go | 6 +++--- pkg/iam/helper.go | 6 +++--- pkg/iam/helper_test.go | 8 ++++---- pkg/iam/properties.go | 26 ++++++++++++------------- pkg/iam/properties_test.go | 18 ++++++++--------- 10 files changed, 59 insertions(+), 59 deletions(-) diff --git a/pkg/iam/api_clients.go b/pkg/iam/api_clients.go index 000a3c84..45646ce5 100644 --- a/pkg/iam/api_clients.go +++ b/pkg/iam/api_clients.go @@ -294,11 +294,11 @@ type ( // UpdateAPIClientRequest contains the request parameters for the UpdateAPIClient endpoint UpdateAPIClientRequest struct { ClientID string - Body UpdateAPIClientBody + Body UpdateAPIClientRequestBody } - // UpdateAPIClientBody represents body params for UpdateAPIClient - UpdateAPIClientBody struct { + // UpdateAPIClientRequestBody represents body params for UpdateAPIClient + UpdateAPIClientRequestBody struct { AllowAccountSwitch bool `json:"allowAccountSwitch"` APIAccess APIAccess `json:"apiAccess"` AuthorizedUsers []string `json:"authorizedUsers"` @@ -388,8 +388,8 @@ func (r UpdateAPIClientRequest) Validate() error { }) } -// Validate validates UpdateAPIClientBody -func (r UpdateAPIClientBody) Validate() error { +// Validate validates UpdateAPIClientRequestBody +func (r UpdateAPIClientRequestBody) Validate() error { return validation.Errors{ "APIAccess": validation.Validate(r.APIAccess, validation.Required), "AuthorizedUsers": validation.Validate(r.AuthorizedUsers, validation.Required, validation.Length(1, 0)), diff --git a/pkg/iam/api_clients_credentials.go b/pkg/iam/api_clients_credentials.go index 9503344d..8475f9b0 100644 --- a/pkg/iam/api_clients_credentials.go +++ b/pkg/iam/api_clients_credentials.go @@ -74,7 +74,7 @@ type ( UpdateCredentialRequest struct { CredentialID int64 ClientID string - RequestBody UpdateCredentialRequestBody + Body UpdateCredentialRequestBody } // UpdateCredentialRequestBody contains request body parameters for UpdateCredential operation @@ -170,7 +170,7 @@ func (r GetCredentialRequest) Validate() error { func (r UpdateCredentialRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CredentialID": validation.Validate(r.CredentialID, validation.Required), - "RequestBody": validation.Validate(r.RequestBody, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } @@ -332,8 +332,8 @@ func (i *iam) UpdateCredential(ctx context.Context, params UpdateCredentialReque // Because API does not accept date without providing milliseconds, if there are no millisecond add a small duration to allow the request to // be processed. Only applicable when no milliseconds are provided, or they are equal to zero. Ticket for tracking: IDM-3347. - if params.RequestBody.ExpiresOn.Nanosecond() == 0 { - params.RequestBody.ExpiresOn = params.RequestBody.ExpiresOn.Add(time.Nanosecond) + if params.Body.ExpiresOn.Nanosecond() == 0 { + params.Body.ExpiresOn = params.Body.ExpiresOn.Add(time.Nanosecond) } uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/credentials/%d", params.ClientID, params.CredentialID)) @@ -347,7 +347,7 @@ func (i *iam) UpdateCredential(ctx context.Context, params UpdateCredentialReque } var result UpdateCredentialResponse - resp, err := i.Exec(req, &result, params.RequestBody) + resp, err := i.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateCredential, err) } diff --git a/pkg/iam/api_clients_credentials_test.go b/pkg/iam/api_clients_credentials_test.go index b962d874..40e1fa31 100644 --- a/pkg/iam/api_clients_credentials_test.go +++ b/pkg/iam/api_clients_credentials_test.go @@ -508,7 +508,7 @@ func TestUpdateCredential(t *testing.T) { params: UpdateCredentialRequest{ ClientID: "test1234", CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), Status: CredentialActive, }, @@ -536,7 +536,7 @@ func TestUpdateCredential(t *testing.T) { params: UpdateCredentialRequest{ ClientID: "test1234", CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25Z"), Status: CredentialActive, }, @@ -564,7 +564,7 @@ func TestUpdateCredential(t *testing.T) { params: UpdateCredentialRequest{ ClientID: "test1234", CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.123Z"), Status: CredentialActive, }, @@ -591,7 +591,7 @@ func TestUpdateCredential(t *testing.T) { "200 OK without specified client, with description": { params: UpdateCredentialRequest{ CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.123Z"), Status: CredentialInactive, Description: "test description", @@ -622,13 +622,13 @@ func TestUpdateCredential(t *testing.T) { "validation errors": { params: UpdateCredentialRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "update credential: struct validation: CredentialID: cannot be blank\nExpiresOn: cannot be blank\nStatus: cannot be blank", err.Error()) + assert.Equal(t, "update credential: struct validation: ExpiresOn: cannot be blank\nStatus: cannot be blank\nCredentialID: cannot be blank", err.Error()) }, }, "404 Not Found": { params: UpdateCredentialRequest{ CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), Status: "ACTIVE", }, @@ -658,7 +658,7 @@ func TestUpdateCredential(t *testing.T) { "500 internal server error": { params: UpdateCredentialRequest{ CredentialID: 123, - RequestBody: UpdateCredentialRequestBody{ + Body: UpdateCredentialRequestBody{ ExpiresOn: test.NewTimeFromString(t, "2026-05-14T11:10:25.000Z"), Status: CredentialActive, }, diff --git a/pkg/iam/api_clients_test.go b/pkg/iam/api_clients_test.go index b52b1259..5765f724 100644 --- a/pkg/iam/api_clients_test.go +++ b/pkg/iam/api_clients_test.go @@ -1159,7 +1159,7 @@ func TestUpdateAPIClient(t *testing.T) { }{ "200 Updated self": { params: UpdateAPIClientRequest{ - Body: UpdateAPIClientBody{ + Body: UpdateAPIClientRequestBody{ APIAccess: APIAccess{ AllAccessibleAPIs: true, }, @@ -1332,7 +1332,7 @@ func TestUpdateAPIClient(t *testing.T) { "200 Updated with allAPI, cpCodes and clone group": { params: UpdateAPIClientRequest{ ClientID: "abcdefgh12345678", - Body: UpdateAPIClientBody{ + Body: UpdateAPIClientRequestBody{ APIAccess: APIAccess{ AllAccessibleAPIs: true, }, @@ -1536,7 +1536,7 @@ func TestUpdateAPIClient(t *testing.T) { "200 Updated with all fields and custom API and group": { params: UpdateAPIClientRequest{ ClientID: "abcdefgh12345678", - Body: UpdateAPIClientBody{ + Body: UpdateAPIClientRequestBody{ AllowAccountSwitch: true, APIAccess: APIAccess{ AllAccessibleAPIs: false, @@ -1839,14 +1839,14 @@ func TestUpdateAPIClient(t *testing.T) { }, }, "validation errors - internal validations": { - params: UpdateAPIClientRequest{Body: UpdateAPIClientBody{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}}, + params: UpdateAPIClientRequest{Body: UpdateAPIClientRequestBody{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}}, withError: func(t *testing.T, err error) { assert.Equal(t, "update api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) }, }, "500 internal server error": { params: UpdateAPIClientRequest{ - Body: UpdateAPIClientBody{ + Body: UpdateAPIClientRequestBody{ APIAccess: APIAccess{ AllAccessibleAPIs: true, }, diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index bf4755e3..b63b3cba 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -96,11 +96,11 @@ type ( // UpdateCIDRBlockRequest contains the request parameters for the UpdateCIDRBlock endpoint UpdateCIDRBlockRequest struct { CIDRBlockID int64 - Body UpdateCIDRBlockBody + Body UpdateCIDRBlockRequestBody } - // UpdateCIDRBlockBody contains the request body to be used in UpdateCIDRBlock endpoint - UpdateCIDRBlockBody struct { + // UpdateCIDRBlockRequestBody contains the request body to be used in UpdateCIDRBlock endpoint + UpdateCIDRBlockRequestBody struct { CIDRBlock string `json:"cidrBlock"` Comments string `json:"comments,omitempty"` Enabled bool `json:"enabled"` @@ -142,8 +142,8 @@ func (r UpdateCIDRBlockRequest) Validate() error { }) } -// Validate performs validation on UpdateCIDRBlockBody -func (r UpdateCIDRBlockBody) Validate() error { +// Validate performs validation on UpdateCIDRBlockRequestBody +func (r UpdateCIDRBlockRequestBody) Validate() error { return validation.Errors{ "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), }.Filter() diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index cb702279..3375d766 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -522,7 +522,7 @@ func TestUpdateCIDRBlock(t *testing.T) { "200 OK": { params: UpdateCIDRBlockRequest{ CIDRBlockID: 1, - Body: UpdateCIDRBlockBody{ + Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", Comments: "abc - updated", Enabled: false, @@ -564,7 +564,7 @@ func TestUpdateCIDRBlock(t *testing.T) { "invalid required parameters": { params: UpdateCIDRBlockRequest{ CIDRBlockID: -1, - Body: UpdateCIDRBlockBody{ + Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", Comments: "abc - updated", Enabled: false, @@ -578,7 +578,7 @@ func TestUpdateCIDRBlock(t *testing.T) { "500 internal server error": { params: UpdateCIDRBlockRequest{ CIDRBlockID: 1, - Body: UpdateCIDRBlockBody{ + Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", Comments: "abc - updated", Enabled: false, diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go index 41b4b01c..530d20af 100644 --- a/pkg/iam/helper.go +++ b/pkg/iam/helper.go @@ -39,7 +39,7 @@ type ( // ListAllowedCPCodesRequest contains the request parameter for the list of allowed CP codes endpoint ListAllowedCPCodesRequest struct { UserName string - ListAllowedCPCodesRequestBody + Body ListAllowedCPCodesRequestBody } // ListAllowedAPIsRequest contains the request parameters for the list of allowed APIs endpoint @@ -158,7 +158,7 @@ var ( func (r ListAllowedCPCodesRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UserName": validation.Validate(r.UserName, validation.Required), - "Body": validation.Validate(r.ListAllowedCPCodesRequestBody, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } @@ -201,7 +201,7 @@ func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesR } var result ListAllowedCPCodesResponse - resp, err := i.Exec(req, &result, params.ListAllowedCPCodesRequestBody) + resp, err := i.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrListAllowedCPCodes, err) } diff --git a/pkg/iam/helper_test.go b/pkg/iam/helper_test.go index fd715965..13ec7d5f 100644 --- a/pkg/iam/helper_test.go +++ b/pkg/iam/helper_test.go @@ -23,7 +23,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { "200 OK": { params: ListAllowedCPCodesRequest{ UserName: "jsmith", - ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + Body: ListAllowedCPCodesRequestBody{ ClientType: ClientClientType, }, }, @@ -69,7 +69,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { "200 OK with groups": { params: ListAllowedCPCodesRequest{ UserName: "jsmith", - ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + Body: ListAllowedCPCodesRequestBody{ ClientType: ServiceAccountClientType, Groups: []AllowedCPCodesGroup{ { @@ -120,7 +120,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { "500 internal server error": { params: ListAllowedCPCodesRequest{ UserName: "jsmith", - ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + Body: ListAllowedCPCodesRequestBody{ ClientType: ClientClientType, }, }, @@ -154,7 +154,7 @@ func TestIAMListAllowedCPCodes(t *testing.T) { "group is required for client type SERVICE_ACCOUNT": { params: ListAllowedCPCodesRequest{ UserName: "jsmith", - ListAllowedCPCodesRequestBody: ListAllowedCPCodesRequestBody{ + Body: ListAllowedCPCodesRequestBody{ ClientType: ServiceAccountClientType, }, }, diff --git a/pkg/iam/properties.go b/pkg/iam/properties.go index 1516cb9b..1a94efa8 100644 --- a/pkg/iam/properties.go +++ b/pkg/iam/properties.go @@ -91,7 +91,7 @@ type ( // BlockUsersRequest contains the request parameters for the BlockUsers operation. BlockUsersRequest struct { PropertyID int64 - BodyParams BlockUsersReqBody + Body BlockUsersRequestBody } // ListPropertiesResponse holds the response data from ListProperties. @@ -119,17 +119,17 @@ type ( // MovePropertyRequest contains the request parameters for the MoveProperty operation. MovePropertyRequest struct { PropertyID int64 - BodyParams MovePropertyReqBody + Body MovePropertyRequestBody } - // MovePropertyReqBody contains body parameters for the MoveProperty operation. - MovePropertyReqBody struct { + // MovePropertyRequestBody contains body parameters for the MoveProperty operation. + MovePropertyRequestBody struct { DestinationGroupID int64 `json:"destinationGroupId"` SourceGroupID int64 `json:"sourceGroupId"` } - // BlockUsersReqBody hold the request body parameters for BlockUsers operation. - BlockUsersReqBody []BlockUserItem + // BlockUsersRequestBody hold the request body parameters for BlockUsers operation. + BlockUsersRequestBody []BlockUserItem // BlockUserItem contains body parameters for the BlockUsers operation. BlockUserItem struct { @@ -195,12 +195,12 @@ func (r MapPropertyIDToNameRequest) Validate() error { func (r MovePropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), - "BodyParams": validation.Validate(r.BodyParams, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } -// Validate validates MovePropertyReqBody -func (r MovePropertyReqBody) Validate() error { +// Validate validates MovePropertyRequestBody +func (r MovePropertyRequestBody) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), @@ -211,11 +211,11 @@ func (r MovePropertyReqBody) Validate() error { func (r BlockUsersRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), - "BodyParams": validation.Validate(r.BodyParams, validation.Required), + "Body": validation.Validate(r.Body, validation.Required), }) } -// Validate validates BlockUsersReqBody +// Validate validates BlockUserItem func (r BlockUserItem) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UIIdentityID": validation.Validate(r.UIIdentityID, validation.Required), @@ -362,7 +362,7 @@ func (i *iam) MoveProperty(ctx context.Context, params MovePropertyRequest) erro return fmt.Errorf("%w: failed to create request: %s", ErrMoveProperty, err) } - resp, err := i.Exec(req, nil, params.BodyParams) + resp, err := i.Exec(req, nil, params.Body) if err != nil { return fmt.Errorf("%w: request failed: %s", ErrMoveProperty, err) } @@ -433,7 +433,7 @@ func (i *iam) BlockUsers(ctx context.Context, params BlockUsersRequest) (*BlockU } var result BlockUsersResponse - resp, err := i.Exec(req, &result, params.BodyParams) + resp, err := i.Exec(req, &result, params.Body) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrBlockUsers, err) } diff --git a/pkg/iam/properties_test.go b/pkg/iam/properties_test.go index d97bb2a2..97acf35b 100644 --- a/pkg/iam/properties_test.go +++ b/pkg/iam/properties_test.go @@ -372,7 +372,7 @@ func TestMoveProperty(t *testing.T) { "204 OK": { params: MovePropertyRequest{ PropertyID: 1, - BodyParams: MovePropertyReqBody{ + Body: MovePropertyRequestBody{ DestinationGroupID: 22, SourceGroupID: 11, }, @@ -388,13 +388,13 @@ func TestMoveProperty(t *testing.T) { "validation errors": { params: MovePropertyRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "move property: struct validation: BodyParams: DestinationGroupID: cannot be blank\nSourceGroupID: cannot be blank\nPropertyID: cannot be blank", err.Error()) + assert.Equal(t, "move property: struct validation: Body: DestinationGroupID: cannot be blank\nSourceGroupID: cannot be blank\nPropertyID: cannot be blank", err.Error()) }, }, "400 not allowed": { params: MovePropertyRequest{ PropertyID: 1, - BodyParams: MovePropertyReqBody{ + Body: MovePropertyRequestBody{ DestinationGroupID: 22, SourceGroupID: 11, }, @@ -546,7 +546,7 @@ func TestBlockUsers(t *testing.T) { "200 OK": { params: BlockUsersRequest{ PropertyID: 1, - BodyParams: BlockUsersReqBody{ + Body: BlockUsersRequestBody{ BlockUserItem{ UIIdentityID: "A-test-1234", }, @@ -604,22 +604,22 @@ func TestBlockUsers(t *testing.T) { "validation errors - no params": { params: BlockUsersRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "block users: struct validation: BodyParams: cannot be blank\nPropertyID: cannot be blank", err.Error()) + assert.Equal(t, "block users: struct validation: Body: cannot be blank\nPropertyID: cannot be blank", err.Error()) }, }, "validation errors - empty body": { params: BlockUsersRequest{ PropertyID: 1, - BodyParams: BlockUsersReqBody{}, + Body: BlockUsersRequestBody{}, }, withError: func(t *testing.T, err error) { - assert.Equal(t, "block users: struct validation: BodyParams: cannot be blank", err.Error()) + assert.Equal(t, "block users: struct validation: Body: cannot be blank", err.Error()) }, }, "404 invalid identity": { params: BlockUsersRequest{ PropertyID: 1, - BodyParams: BlockUsersReqBody{ + Body: BlockUsersRequestBody{ BlockUserItem{ UIIdentityID: "test", }, @@ -650,7 +650,7 @@ func TestBlockUsers(t *testing.T) { "404 not found": { params: BlockUsersRequest{ PropertyID: 2, - BodyParams: BlockUsersReqBody{ + Body: BlockUsersRequestBody{ BlockUserItem{ UIIdentityID: "A-test-1234", }, From ccf95f6479d6d4c566133fba1cf2f4ce59aa4ff0 Mon Sep 17 00:00:00 2001 From: Jakub Bilski Date: Wed, 18 Sep 2024 09:42:10 +0000 Subject: [PATCH 29/34] DXE-4027 Implement iam_cidr_blocks resource Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/DXE-4027 to feature/sp-iam-extension --- pkg/iam/cidr.go | 20 ++++++++++---------- pkg/iam/cidr_test.go | 37 +++++++++++++++++++------------------ pkg/iam/mocks.go | 4 ++-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index b63b3cba..6004b1f0 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -19,7 +19,7 @@ type ( // ListCIDRBlocks lists all CIDR blocks on selected account's allowlist // // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist - ListCIDRBlocks(context.Context, ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) + ListCIDRBlocks(context.Context, ListCIDRBlocksRequest) (ListCIDRBlocksResponse, error) // CreateCIDRBlock adds CIDR blocks to your account's allowlist // @@ -60,7 +60,7 @@ type ( Actions *CIDRActions `json:"actions"` CIDRBlock string `json:"cidrBlock"` CIDRBlockID int64 `json:"cidrBlockId"` - Comments string `json:"comments"` + Comments *string `json:"comments"` CreatedBy string `json:"createdBy"` CreatedDate time.Time `json:"createdDate"` Enabled bool `json:"enabled"` @@ -76,9 +76,9 @@ type ( // CreateCIDRBlockRequest contains the request parameters for the CreateCIDRBlock endpoint CreateCIDRBlockRequest struct { - CIDRBlock string `json:"cidrBlock"` - Comments string `json:"comments,omitempty"` - Enabled bool `json:"enabled"` + CIDRBlock string `json:"cidrBlock"` + Comments *string `json:"comments,omitempty"` + Enabled bool `json:"enabled"` } // CreateCIDRBlockResponse describes the response of the CreateCIDRBlock endpoint @@ -101,9 +101,9 @@ type ( // UpdateCIDRBlockRequestBody contains the request body to be used in UpdateCIDRBlock endpoint UpdateCIDRBlockRequestBody struct { - CIDRBlock string `json:"cidrBlock"` - Comments string `json:"comments,omitempty"` - Enabled bool `json:"enabled"` + CIDRBlock string `json:"cidrBlock"` + Comments *string `json:"comments,omitempty"` + Enabled bool `json:"enabled"` } // UpdateCIDRBlockResponse describes the response of the UpdateCIDRBlock endpoint @@ -178,7 +178,7 @@ var ( ErrValidateCIDRBlock = errors.New("validate CIDR block") ) -func (i *iam) ListCIDRBlocks(ctx context.Context, params ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) { +func (i *iam) ListCIDRBlocks(ctx context.Context, params ListCIDRBlocksRequest) (ListCIDRBlocksResponse, error) { logger := i.Log(ctx) logger.Debug("ListCIDRBlocks") @@ -206,7 +206,7 @@ func (i *iam) ListCIDRBlocks(ctx context.Context, params ListCIDRBlocksRequest) return nil, fmt.Errorf("%s: %w", ErrListCIDRBlocks, i.Error(resp)) } - return &result, nil + return result, nil } func (i *iam) CreateCIDRBlock(ctx context.Context, params CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) { diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index 3375d766..8c16dada 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -20,7 +21,7 @@ func TestListCIDRBlocks(t *testing.T) { responseStatus int responseBody string expectedPath string - expectedResponse *ListCIDRBlocksResponse + expectedResponse ListCIDRBlocksResponse withError func(*testing.T, error) }{ "200 OK": { @@ -50,11 +51,11 @@ func TestListCIDRBlocks(t *testing.T) { } ]`, expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist?actions=false", - expectedResponse: &ListCIDRBlocksResponse{ + expectedResponse: ListCIDRBlocksResponse{ { CIDRBlockID: 1, Enabled: true, - Comments: "abc", + Comments: ptr.To("abc"), CIDRBlock: "1.2.3.4/8", CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", @@ -65,7 +66,7 @@ func TestListCIDRBlocks(t *testing.T) { { CIDRBlockID: 2, Enabled: false, - Comments: "", + Comments: nil, CIDRBlock: "2.4.8.16/32", CreatedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), CreatedBy: "johndoe", @@ -110,11 +111,11 @@ func TestListCIDRBlocks(t *testing.T) { } ]`, expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist?actions=true", - expectedResponse: &ListCIDRBlocksResponse{ + expectedResponse: ListCIDRBlocksResponse{ { CIDRBlockID: 1, Enabled: true, - Comments: "abc", + Comments: ptr.To("abc"), CIDRBlock: "1.2.3.4/8", CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", @@ -128,7 +129,7 @@ func TestListCIDRBlocks(t *testing.T) { { CIDRBlockID: 2, Enabled: false, - Comments: "", + Comments: nil, CIDRBlock: "2.4.8.16/32", CreatedDate: test.NewTimeFromString(t, "2024-06-25T06:14:36.000Z"), CreatedBy: "johndoe", @@ -200,7 +201,7 @@ func TestCreateCIDRBlock(t *testing.T) { "201 created": { params: CreateCIDRBlockRequest{ CIDRBlock: "1.2.3.4/32", - Comments: "abc", + Comments: ptr.To("abc"), Enabled: true, }, responseStatus: http.StatusCreated, @@ -220,7 +221,7 @@ func TestCreateCIDRBlock(t *testing.T) { expectedResponse: &CreateCIDRBlockResponse{ CIDRBlockID: 1234, Enabled: true, - Comments: "abc", + Comments: ptr.To("abc"), CIDRBlock: "1.2.3.4/32", CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", @@ -251,7 +252,7 @@ func TestCreateCIDRBlock(t *testing.T) { expectedResponse: &CreateCIDRBlockResponse{ CIDRBlockID: 1234, Enabled: true, - Comments: "", + Comments: nil, CIDRBlock: "1.2.3.4/32", CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", @@ -270,7 +271,7 @@ func TestCreateCIDRBlock(t *testing.T) { "403 - incorrect cidrblock": { params: CreateCIDRBlockRequest{ CIDRBlock: "1.2.3.4:32", - Comments: "abc", + Comments: ptr.To("abc"), Enabled: true, }, responseStatus: http.StatusForbidden, @@ -301,7 +302,7 @@ func TestCreateCIDRBlock(t *testing.T) { "500 internal server error": { params: CreateCIDRBlockRequest{ CIDRBlock: "1.2.3.4/32", - Comments: "abc", + Comments: ptr.To("abc"), Enabled: true, }, responseStatus: http.StatusInternalServerError, @@ -380,7 +381,7 @@ func TestGetCIDRBlock(t *testing.T) { expectedResponse: &GetCIDRBlockResponse{ CIDRBlockID: 1, Enabled: true, - Comments: "abc", + Comments: ptr.To("abc"), CIDRBlock: "1.2.3.4/8", CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", @@ -411,7 +412,7 @@ func TestGetCIDRBlock(t *testing.T) { expectedResponse: &GetCIDRBlockResponse{ CIDRBlockID: 1, Enabled: true, - Comments: "abc", + Comments: ptr.To("abc"), CIDRBlock: "1.2.3.4/8", CreatedDate: test.NewTimeFromString(t, "2024-06-17T08:46:41.000Z"), CreatedBy: "johndoe", @@ -524,7 +525,7 @@ func TestUpdateCIDRBlock(t *testing.T) { CIDRBlockID: 1, Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", - Comments: "abc - updated", + Comments: ptr.To("abc - updated"), Enabled: false, }, }, @@ -545,7 +546,7 @@ func TestUpdateCIDRBlock(t *testing.T) { expectedResponse: &UpdateCIDRBlockResponse{ CIDRBlockID: 1234, Enabled: false, - Comments: "abc - updated", + Comments: ptr.To("abc - updated"), CIDRBlock: "1.2.3.4/32", CreatedDate: test.NewTimeFromString(t, "2024-07-15T13:53:49.000Z"), CreatedBy: "johndoe", @@ -566,7 +567,7 @@ func TestUpdateCIDRBlock(t *testing.T) { CIDRBlockID: -1, Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", - Comments: "abc - updated", + Comments: ptr.To("abc - updated"), Enabled: false, }, }, @@ -580,7 +581,7 @@ func TestUpdateCIDRBlock(t *testing.T) { CIDRBlockID: 1, Body: UpdateCIDRBlockRequestBody{ CIDRBlock: "1.2.3.4/32", - Comments: "abc - updated", + Comments: ptr.To("abc - updated"), Enabled: false, }, }, diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 9908576f..88345019 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -457,14 +457,14 @@ func (m *Mock) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodes return args.Get(0).(ListAllowedCPCodesResponse), args.Error(1) } -func (m *Mock) ListCIDRBlocks(ctx context.Context, request ListCIDRBlocksRequest) (*ListCIDRBlocksResponse, error) { +func (m *Mock) ListCIDRBlocks(ctx context.Context, request ListCIDRBlocksRequest) (ListCIDRBlocksResponse, error) { args := m.Called(ctx, request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ListCIDRBlocksResponse), args.Error(1) + return args.Get(0).(ListCIDRBlocksResponse), args.Error(1) } func (m *Mock) CreateCIDRBlock(ctx context.Context, request CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) { From 17e5f7ddb22eef02745bf61f36560d8be3a6d85d Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Wed, 25 Sep 2024 06:10:17 +0000 Subject: [PATCH 30/34] DXE-4262 Validate CIDR addresses --- pkg/iam/cidr.go | 24 +++++++++++-- pkg/iam/cidr_test.go | 84 +++++++++++++++++--------------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index 6004b1f0..34e69c3a 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net" "net/http" "net/url" "strconv" @@ -120,10 +121,27 @@ type ( } ) +// validateCIDR validates the format of CIDRBlock +func validateCIDR() validation.Rule { + return validation.By(func(value interface{}) error { + stringVal, ok := value.(string) + if !ok { + return fmt.Errorf("expected type 'string', got: %T", value) + } + + _, _, err := net.ParseCIDR(stringVal) + if err != nil { + return err + } + + return nil + }) +} + // Validate performs validation on CreateCIDRBlockRequest func (r CreateCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ - "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), }) } @@ -145,7 +163,7 @@ func (r UpdateCIDRBlockRequest) Validate() error { // Validate performs validation on UpdateCIDRBlockRequestBody func (r UpdateCIDRBlockRequestBody) Validate() error { return validation.Errors{ - "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), }.Filter() } @@ -159,7 +177,7 @@ func (r DeleteCIDRBlockRequest) Validate() error { // Validate performs validation on ValidateCIDRBlockRequest func (r ValidateCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ - "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required), + "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), }) } diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index 8c16dada..b8a9918d 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -268,35 +268,22 @@ func TestCreateCIDRBlock(t *testing.T) { assert.Contains(t, err.Error(), "create CIDR block: struct validation: CIDRBlock: cannot be blank") }, }, - "403 - incorrect cidrblock": { + "validation error - incorrect IPv4 CIDR": { params: CreateCIDRBlockRequest{ - CIDRBlock: "1.2.3.4:32", - Comments: ptr.To("abc"), - Enabled: true, + CIDRBlock: "1.2.3.555/32", }, - responseStatus: http.StatusForbidden, - responseBody: ` -{ - "type": "/ip-acl/error-types/1013", - "httpStatus": 403, - "title": "CIDR format not correct", - "detail": "invalid cidrblock/ip", - "instance": "", - "errors": [] -}`, - expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist", - expectedRequestBody: `{"cidrBlock":"1.2.3.4:32","comments":"abc","enabled":true}`, - withError: func(t *testing.T, e error) { - err := Error{ - Type: "/ip-acl/error-types/1013", - HTTPStatus: http.StatusForbidden, - Title: "CIDR format not correct", - Detail: "invalid cidrblock/ip", - StatusCode: http.StatusForbidden, - Instance: "", - Errors: json.RawMessage("[]"), - } - assert.Equal(t, true, err.Is(e)) + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "create CIDR block: struct validation: CIDRBlock: invalid CIDR address: 1.2.3.555/32") + }, + }, + "validation error - incorrect IPv6 CIDR": { + params: CreateCIDRBlockRequest{ + CIDRBlock: "aa::wqert:1:0:ff/48", + }, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "create CIDR block: struct validation: CIDRBlock: invalid CIDR address: aa::wqert:1:0:ff/48") }, }, "500 internal server error": { @@ -576,6 +563,18 @@ func TestUpdateCIDRBlock(t *testing.T) { assert.Contains(t, err.Error(), "update CIDR block: struct validation: CIDRBlockID: must be no less than 1") }, }, + "validation error - invalid IP address": { + params: UpdateCIDRBlockRequest{ + CIDRBlockID: 1, + Body: UpdateCIDRBlockRequestBody{ + CIDRBlock: "1a.2.3.4/32", + }, + }, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "update CIDR block: struct validation: CIDRBlock: invalid CIDR address: 1a.2.3.4/32") + }, + }, "500 internal server error": { params: UpdateCIDRBlockRequest{ CIDRBlockID: 1, @@ -752,30 +751,13 @@ func TestValidateCIDRBlocks(t *testing.T) { assert.Contains(t, err.Error(), "validate CIDR block: struct validation: CIDRBlock: cannot be blank") }, }, - "400 invalid": { - params: ValidateCIDRBlockRequest{CIDRBlock: "abc"}, - responseStatus: http.StatusBadRequest, - responseBody: ` -{ - "type": "/ip-acl/error-types/1013", - "httpStatus": 400, - "title": "CIDR format not correct", - "detail": "invalid cidr format", - "instance": "", - "errors": [] -}`, - expectedPath: "/identity-management/v3/user-admin/ip-acl/allowlist/validate?cidrblock=abc", - withError: func(t *testing.T, e error) { - err := Error{ - Type: "/ip-acl/error-types/1013", - HTTPStatus: http.StatusBadRequest, - Title: "CIDR format not correct", - Detail: "invalid cidr format", - StatusCode: http.StatusBadRequest, - Instance: "", - Errors: json.RawMessage("[]"), - } - assert.Equal(t, true, err.Is(e)) + "validation error - invalid IP address": { + params: ValidateCIDRBlockRequest{ + CIDRBlock: "255.255.255.256/24", + }, + withError: func(t *testing.T, err error) { + assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err) + assert.Contains(t, err.Error(), "validate CIDR block: struct validation: CIDRBlock: invalid CIDR address: 255.255.255.256/24") }, }, "500 internal server error": { From 0d089e606834bcfed44d0af3ac3ed0939a83a7b6 Mon Sep 17 00:00:00 2001 From: Dawid Dzhafarov Date: Thu, 26 Sep 2024 10:54:00 +0000 Subject: [PATCH 31/34] DXE-4151 Verify IAM subprovider --- pkg/iam/api_clients.go | 180 ++++------ pkg/iam/api_clients_credentials.go | 122 +++---- pkg/iam/api_clients_credentials_test.go | 124 +++---- pkg/iam/api_clients_test.go | 140 ++++---- pkg/iam/blocked_properties.go | 42 +-- pkg/iam/blocked_properties_test.go | 36 +- pkg/iam/cidr.go | 85 ++--- pkg/iam/cidr_test.go | 118 +++---- pkg/iam/errors.go | 15 +- pkg/iam/errors_test.go | 22 +- pkg/iam/groups.go | 141 +++----- pkg/iam/groups_test.go | 138 ++++---- pkg/iam/helper.go | 99 +++--- pkg/iam/helper_test.go | 70 ++-- pkg/iam/iam.go | 415 ++++++++++++++++++++++-- pkg/iam/ip_allowlist.go | 29 +- pkg/iam/ip_allowlist_test.go | 48 +-- pkg/iam/mocks.go | 8 +- pkg/iam/properties.go | 145 ++++----- pkg/iam/properties_test.go | 130 ++++---- pkg/iam/roles.go | 106 +++--- pkg/iam/roles_test.go | 118 +++---- pkg/iam/support.go | 161 ++++----- pkg/iam/support_test.go | 130 ++++---- pkg/iam/user.go | 268 +++++++-------- pkg/iam/user_lock.go | 48 ++- pkg/iam/user_lock_test.go | 28 +- pkg/iam/user_password.go | 59 ++-- pkg/iam/user_password_test.go | 38 +-- pkg/iam/user_test.go | 168 +++++----- 30 files changed, 1629 insertions(+), 1602 deletions(-) diff --git a/pkg/iam/api_clients.go b/pkg/iam/api_clients.go index 45646ce5..81a2bd39 100644 --- a/pkg/iam/api_clients.go +++ b/pkg/iam/api_clients.go @@ -14,88 +14,49 @@ import ( ) type ( - // APIClients is the IAM API clients interface - APIClients interface { - // LockAPIClient locks an API client based on `ClientID` parameter. If `ClientID` is not provided, it locks your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/put-lock-api-client, https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self - LockAPIClient(ctx context.Context, params LockAPIClientRequest) (*LockAPIClientResponse, error) - - // UnlockAPIClient unlocks an API client - // - // See: https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client - UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) - - // ListAPIClients lists API clients an administrator can manage - // - // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients - ListAPIClients(ctx context.Context, params ListAPIClientsRequest) (ListAPIClientsResponse, error) - - // GetAPIClient provides details about an API client. If `ClientID` is not provided, it returns details about your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-api-client and https://techdocs.akamai.com/iam-api/reference/get-api-client-self - GetAPIClient(ctx context.Context, params GetAPIClientRequest) (*GetAPIClientResponse, error) - - // CreateAPIClient creates a new API client. Optionally, it can automatically assign a credential for the client when creating it - // - // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients - CreateAPIClient(ctx context.Context, params CreateAPIClientRequest) (*CreateAPIClientResponse, error) - - // UpdateAPIClient updates an API client. If `ClientID` is not provided, it updates your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/put-api-clients and https://techdocs.akamai.com/iam-api/reference/put-api-clients-self - UpdateAPIClient(ctx context.Context, params UpdateAPIClientRequest) (*UpdateAPIClientResponse, error) - - // DeleteAPIClient permanently deletes the API client, breaking any API connections with the client. - // If `ClientID` is not provided, it deletes your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-api-client and https://techdocs.akamai.com/iam-api/reference/delete-api-client-self - DeleteAPIClient(ctx context.Context, params DeleteAPIClientRequest) error - } - - // LockAPIClientRequest contains the request parameters for the LockAPIClient operation + // LockAPIClientRequest contains the request parameters for the LockAPIClient endpoint. LockAPIClientRequest struct { ClientID string } - // UnlockAPIClientRequest contains the request parameters for the UnlockAPIClient endpoint + // UnlockAPIClientRequest contains the request parameters for the UnlockAPIClient endpoint. UnlockAPIClientRequest struct { ClientID string } - // LockAPIClientResponse holds the response data from LockAPIClient + // LockAPIClientResponse holds the response data from LockAPIClient. LockAPIClientResponse APIClient - // UnlockAPIClientResponse holds the response data from UnlockAPIClient + // UnlockAPIClientResponse holds the response data from UnlockAPIClient. UnlockAPIClientResponse APIClient - // APIClient contains information about the API client + // APIClient contains information about the API client. APIClient struct { - AccessToken string `json:"accessToken"` - ActiveCredentialCount int64 `json:"activeCredentialCount"` - AllowAccountSwitch bool `json:"allowAccountSwitch"` - AuthorizedUsers []string `json:"authorizedUsers"` - CanAutoCreateCredential bool `json:"canAutoCreateCredential"` - ClientDescription string `json:"clientDescription"` - ClientID string `json:"clientId"` - ClientName string `json:"clientName"` - ClientType string `json:"clientType"` - CreatedBy string `json:"createdBy"` - CreatedDate time.Time `json:"createdDate"` - IsLocked bool `json:"isLocked"` - NotificationEmails []string `json:"notificationEmails"` - ServiceConsumerToken string `json:"serviceConsumerToken"` - } - - // ListAPIClientsRequest contains the request parameters for the ListAPIClients endpoint + AccessToken string `json:"accessToken"` + ActiveCredentialCount int64 `json:"activeCredentialCount"` + AllowAccountSwitch bool `json:"allowAccountSwitch"` + AuthorizedUsers []string `json:"authorizedUsers"` + CanAutoCreateCredential bool `json:"canAutoCreateCredential"` + ClientDescription string `json:"clientDescription"` + ClientID string `json:"clientId"` + ClientName string `json:"clientName"` + ClientType ClientType `json:"clientType"` + CreatedBy string `json:"createdBy"` + CreatedDate time.Time `json:"createdDate"` + IsLocked bool `json:"isLocked"` + NotificationEmails []string `json:"notificationEmails"` + ServiceConsumerToken string `json:"serviceConsumerToken"` + } + + // ListAPIClientsRequest contains the request parameters for the ListAPIClients endpoint. ListAPIClientsRequest struct { Actions bool } - // ListAPIClientsResponse describes the response of the ListAPIClients endpoint + // ListAPIClientsResponse describes the response of the ListAPIClients endpoint. ListAPIClientsResponse []ListAPIClientsItem - // ListAPIClientsItem represents information returned by the ListAPIClients endpoint for a single API client + // ListAPIClientsItem represents information returned by the ListAPIClients endpoint for a single API client. ListAPIClientsItem struct { AccessToken string `json:"accessToken"` Actions *ListAPIClientsActions `json:"actions"` @@ -114,7 +75,7 @@ type ( ServiceConsumerToken string `json:"serviceConsumerToken"` } - // ListAPIClientsActions specifies activities available for the API client + // ListAPIClientsActions specifies activities available for the API client. ListAPIClientsActions struct { Delete bool `json:"delete"` DeactivateAll bool `json:"deactivateAll"` @@ -124,7 +85,7 @@ type ( Unlock bool `json:"unlock"` } - // GetAPIClientRequest contains the request parameters for the GetAPIClient endpoint + // GetAPIClientRequest contains the request parameters for the GetAPIClient endpoint. GetAPIClientRequest struct { ClientID string Actions bool @@ -134,7 +95,7 @@ type ( IPACL bool } - // CreateAPIClientResponse describes the response of the CreateAPIClient endpoint + // CreateAPIClientResponse describes the response of the CreateAPIClient endpoint. CreateAPIClientResponse struct { AccessToken string `json:"accessToken"` Actions *APIClientActions `json:"actions"` @@ -159,7 +120,7 @@ type ( ServiceProviderID int64 `json:"serviceProviderId"` } - // GetAPIClientResponse describes the response of the GetAPIClient endpoint + // GetAPIClientResponse describes the response of the GetAPIClient endpoint. GetAPIClientResponse struct { AccessToken string `json:"accessToken"` Actions *APIClientActions `json:"actions"` @@ -184,7 +145,7 @@ type ( ServiceProviderID int64 `json:"serviceProviderId"` } - // APIClientActions specifies activities available for the API client + // APIClientActions specifies activities available for the API client. APIClientActions struct { Delete bool `json:"delete"` DeactivateAll bool `json:"deactivateAll"` @@ -199,13 +160,13 @@ type ( Unlock bool `json:"unlock"` } - // APIAccess represents the APIs the API client can access + // APIAccess represents the APIs the API client can access. APIAccess struct { AllAccessibleAPIs bool `json:"allAccessibleApis"` APIs []API `json:"apis"` } - // API represents single Application Programming Interface (API) + // API represents single Application Programming Interface (API). API struct { AccessLevel AccessLevel `json:"accessLevel"` APIID int64 `json:"apiId"` @@ -215,7 +176,7 @@ type ( Endpoint string `json:"endPoint"` } - // APIClientCredential represents single Credential returned by APIClient interfaces + // APIClientCredential represents single Credential returned by APIClient interfaces. APIClientCredential struct { Actions CredentialActions `json:"actions"` ClientToken string `json:"clientToken"` @@ -226,7 +187,7 @@ type ( Status CredentialStatus `json:"status"` } - // CreateAPIClientCredential represents single Credential returned by CreateAPIClient method + // CreateAPIClientCredential represents single Credential returned by CreateAPIClient endpoint. CreateAPIClientCredential struct { Actions CredentialActions `json:"actions"` ClientToken string `json:"clientToken"` @@ -256,26 +217,26 @@ type ( Subgroups []ClientGroup `json:"subgroups"` } - // IPACL specifies the API client's IP list restriction + // IPACL specifies the API client's IP list restriction. IPACL struct { CIDR []string `json:"cidr"` Enable bool `json:"enable"` } - //PurgeOptions specifies the API clients configuration for access to the Fast Purge API + // PurgeOptions specifies the API clients configuration for access to the Fast Purge API. PurgeOptions struct { CanPurgeByCacheTag bool `json:"canPurgeByCacheTag"` CanPurgeByCPCode bool `json:"canPurgeByCpcode"` CPCodeAccess CPCodeAccess `json:"cpcodeAccess"` } - // CPCodeAccess represents the CP codes the API client can purge + // CPCodeAccess represents the CP codes the API client can purge. CPCodeAccess struct { AllCurrentAndNewCPCodes bool `json:"allCurrentAndNewCpcodes"` CPCodes []int64 `json:"cpcodes"` } - // CreateAPIClientRequest contains the request parameters for the CreateAPIClient endpoint + // CreateAPIClientRequest contains the request parameters for the CreateAPIClient endpoint. CreateAPIClientRequest struct { AllowAccountSwitch bool `json:"allowAccountSwitch"` APIAccess APIAccess `json:"apiAccess"` @@ -291,13 +252,13 @@ type ( PurgeOptions *PurgeOptions `json:"purgeOptions,omitempty"` } - // UpdateAPIClientRequest contains the request parameters for the UpdateAPIClient endpoint + // UpdateAPIClientRequest contains the request parameters for the UpdateAPIClient endpoint. UpdateAPIClientRequest struct { ClientID string Body UpdateAPIClientRequestBody } - // UpdateAPIClientRequestBody represents body params for UpdateAPIClient + // UpdateAPIClientRequestBody represents body params for the UpdateAPIClient endpoint. UpdateAPIClientRequestBody struct { AllowAccountSwitch bool `json:"allowAccountSwitch"` APIAccess APIAccess `json:"apiAccess"` @@ -312,52 +273,51 @@ type ( PurgeOptions *PurgeOptions `json:"purgeOptions,omitempty"` } - // UpdateAPIClientResponse describes the response of the UpdateAPIClientResponse endpoint + // UpdateAPIClientResponse describes the response from the UpdateAPIClient endpoint. UpdateAPIClientResponse GetAPIClientResponse - // DeleteAPIClientRequest contains the request parameters for the DeleteAPIClient endpoint + // DeleteAPIClientRequest contains the request parameters for the DeleteAPIClient endpoint. DeleteAPIClientRequest struct { ClientID string } - // AccessLevel represents the access level for API + // AccessLevel represents the access level for API. AccessLevel string ) const ( - // ReadWriteLevel is the `READ-WRITE` access level + // ReadWriteLevel is the `READ-WRITE` access level. ReadWriteLevel AccessLevel = "READ-WRITE" - // ReadOnlyLevel is the `READ-ONLY` access level + // ReadOnlyLevel is the `READ-ONLY` access level. ReadOnlyLevel AccessLevel = "READ-ONLY" ) -// Validate validates UnlockAPIClientRequest +// Validate validates UnlockAPIClientRequest. func (r UnlockAPIClientRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "ClientID": validation.Validate(r.ClientID, validation.Required), }) } -// Validate validates CreateAPIClientRequest +// Validate validates CreateAPIClientRequest. func (r CreateAPIClientRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "APIAccess": validation.Validate(r.APIAccess, validation.Required), "AuthorizedUsers": validation.Validate(r.AuthorizedUsers, validation.Required, validation.Length(1, 0)), - "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType).Error( - fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'", r.ClientType))), - "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), - "PurgeOptions": validation.Validate(r.PurgeOptions), + "ClientType": validation.Validate(r.ClientType, validation.Required), + "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), + "PurgeOptions": validation.Validate(r.PurgeOptions), }) } -// Validate validates APIAccess +// Validate validates APIAccess. func (a APIAccess) Validate() error { return validation.Errors{ "APIs": validation.Validate(a.APIs, validation.When(!a.AllAccessibleAPIs, validation.Required)), }.Filter() } -// Validate validates API +// Validate validates API. func (a API) Validate() error { return validation.Errors{ "AccessLevel": validation.Validate(a.AccessLevel, validation.Required, validation.In(ReadOnlyLevel, ReadWriteLevel).Error( @@ -366,14 +326,14 @@ func (a API) Validate() error { }.Filter() } -// Validate validates GroupAccess +// Validate validates GroupAccess. func (ga GroupAccess) Validate() error { return validation.Errors{ "Groups": validation.Validate(ga.Groups, validation.When(!ga.CloneAuthorizedUserGroups, validation.Required)), }.Filter() } -// Validate validates ClientGroup +// Validate validates ClientGroup. func (cg ClientGroup) Validate() error { return validation.Errors{ "GroupID": validation.Validate(cg.GroupID, validation.Required), @@ -381,33 +341,33 @@ func (cg ClientGroup) Validate() error { }.Filter() } -// Validate validates UpdateAPIClientRequest +// Validate validates UpdateAPIClientRequest. func (r UpdateAPIClientRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "Body": validation.Validate(r.Body, validation.Required), }) } -// Validate validates UpdateAPIClientRequestBody +// Validate validates UpdateAPIClientRequestBody. func (r UpdateAPIClientRequestBody) Validate() error { return validation.Errors{ + "ClientName": validation.Validate(r.ClientName, validation.Required), "APIAccess": validation.Validate(r.APIAccess, validation.Required), "AuthorizedUsers": validation.Validate(r.AuthorizedUsers, validation.Required, validation.Length(1, 0)), - "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType).Error( - fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'", r.ClientType))), - "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), - "PurgeOptions": validation.Validate(r.PurgeOptions), + "ClientType": validation.Validate(r.ClientType, validation.Required), + "GroupAccess": validation.Validate(r.GroupAccess, validation.Required), + "PurgeOptions": validation.Validate(r.PurgeOptions), }.Filter() } -// Validate validates PurgeOptions +// Validate validates PurgeOptions. func (po PurgeOptions) Validate() error { return validation.Errors{ "CPCodeAccess": validation.Validate(po.CPCodeAccess), }.Filter() } -// Validate validates UpdateAPIClientBody +// Validate validates CPCodeAccess. func (ca CPCodeAccess) Validate() error { return validation.Errors{ "CPCodes": validation.Validate(ca.CPCodes, validation.When(!ca.AllCurrentAndNewCPCodes, validation.NotNil)), @@ -415,19 +375,19 @@ func (ca CPCodeAccess) Validate() error { } var ( - // ErrLockAPIClient is returned when LockAPIClient fails + // ErrLockAPIClient is returned when LockAPIClient fails. ErrLockAPIClient = errors.New("lock api client") - // ErrUnlockAPIClient is returned when UnlockAPIClient fails + // ErrUnlockAPIClient is returned when UnlockAPIClient fails. ErrUnlockAPIClient = errors.New("unlock api client") - // ErrListAPIClients is returned when ListAPIClients fails + // ErrListAPIClients is returned when ListAPIClients fails. ErrListAPIClients = errors.New("list api clients") - // ErrGetAPIClient is returned when GetAPIClient fails + // ErrGetAPIClient is returned when GetAPIClient fails. ErrGetAPIClient = errors.New("get api client") - // ErrCreateAPIClient is returned when CreateAPIClient fails + // ErrCreateAPIClient is returned when CreateAPIClient fails. ErrCreateAPIClient = errors.New("create api client") - // ErrUpdateAPIClient is returned when UpdateAPIClient fails + // ErrUpdateAPIClient is returned when UpdateAPIClient fails. ErrUpdateAPIClient = errors.New("update api client") - // ErrDeleteAPIClient is returned when DeleteAPIClient fails + // ErrDeleteAPIClient is returned when DeleteAPIClient fails. ErrDeleteAPIClient = errors.New("delete api client") ) @@ -470,12 +430,12 @@ func (i *iam) UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest return nil, fmt.Errorf("%s: %w:\n%s", ErrUnlockAPIClient, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/unlock", params.ClientID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/api-clients/%s/unlock", params.ClientID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUnlockAPIClient, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUnlockAPIClient, err) } diff --git a/pkg/iam/api_clients_credentials.go b/pkg/iam/api_clients_credentials.go index 8475f9b0..2386c652 100644 --- a/pkg/iam/api_clients_credentials.go +++ b/pkg/iam/api_clients_credentials.go @@ -14,94 +14,56 @@ import ( ) type ( - // APIClientsCredentials is the IAM API clients credentials interface - APIClientsCredentials interface { - // CreateCredential creates a new credential for the API client. If `ClientID` is not provided, it creates credential for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials, https://techdocs.akamai.com/iam-api/reference/post-client-credentials - CreateCredential(context.Context, CreateCredentialRequest) (*CreateCredentialResponse, error) - - // ListCredentials lists credentials for an API client. If `ClientID` is not provided, it lists credentials for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-self-credentials, https://techdocs.akamai.com/iam-api/reference/get-client-credentials - ListCredentials(context.Context, ListCredentialsRequest) (ListCredentialsResponse, error) - - // GetCredential returns details about a specific credential for an API client. If `ClientID` is not provided, it gets credential for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-self-credential, https://techdocs.akamai.com/iam-api/reference/get-client-credential - GetCredential(context.Context, GetCredentialRequest) (*GetCredentialResponse, error) - - // UpdateCredential updates a specific credential for an API client. If `ClientID` is not provided, it updates credential for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/put-self-credential, https://techdocs.akamai.com/iam-api/reference/put-client-credential - UpdateCredential(context.Context, UpdateCredentialRequest) (*UpdateCredentialResponse, error) - - // DeleteCredential deletes a specific credential from an API client. If `ClientID` is not provided, it deletes credential for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-self-credential, https://techdocs.akamai.com/iam-api/reference/delete-client-credential - DeleteCredential(context.Context, DeleteCredentialRequest) error - - // DeactivateCredential deactivates a specific credential for an API client. If `ClientID` is not provided, it deactivates credential for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate - DeactivateCredential(context.Context, DeactivateCredentialRequest) error - - // DeactivateCredentials deactivates all credentials for a specific API client. If `ClientID` is not provided, it deactivates all credentials for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate - DeactivateCredentials(context.Context, DeactivateCredentialsRequest) error - } - - // CreateCredentialRequest contains request parameters for CreateCredential operation + // CreateCredentialRequest contains request parameters for the CreateCredential endpoint. CreateCredentialRequest struct { ClientID string } - // ListCredentialsRequest contains request parameters for ListCredentials operation + // ListCredentialsRequest contains request parameters for the ListCredentials endpoint. ListCredentialsRequest struct { ClientID string Actions bool } - // GetCredentialRequest contains request parameters for GetCredentials operation + // GetCredentialRequest contains request parameters for the GetCredentials endpoint. GetCredentialRequest struct { CredentialID int64 ClientID string Actions bool } - // UpdateCredentialRequest contains request parameters for UpdateCredential operation + // UpdateCredentialRequest contains request parameters for the UpdateCredential endpoint. UpdateCredentialRequest struct { CredentialID int64 ClientID string Body UpdateCredentialRequestBody } - // UpdateCredentialRequestBody contains request body parameters for UpdateCredential operation + // UpdateCredentialRequestBody contains request body parameters for the UpdateCredential endpoint. UpdateCredentialRequestBody struct { Description string `json:"description,omitempty"` ExpiresOn time.Time `json:"expiresOn"` Status CredentialStatus `json:"status"` } - // DeleteCredentialRequest contains request parameters for DeleteCredential operation + // DeleteCredentialRequest contains request parameters for the DeleteCredential endpoint. DeleteCredentialRequest struct { CredentialID int64 ClientID string } - // DeactivateCredentialRequest contains request parameters for DeactivateCredential operation + // DeactivateCredentialRequest contains request parameters for the DeactivateCredential endpoint. DeactivateCredentialRequest struct { CredentialID int64 ClientID string } - // DeactivateCredentialsRequest contains request parameters for DeactivateCredentials operation + // DeactivateCredentialsRequest contains request parameters for the DeactivateCredentials endpoint. DeactivateCredentialsRequest struct { ClientID string } - // CreateCredentialResponse holds response from CreateCredentials operation + // CreateCredentialResponse holds response from the CreateCredentials endpoint. CreateCredentialResponse struct { ClientSecret string `json:"clientSecret"` ClientToken string `json:"clientToken"` @@ -112,10 +74,10 @@ type ( Status CredentialStatus `json:"status"` } - // ListCredentialsResponse holds response from ListCredentials operation + // ListCredentialsResponse holds response from the ListCredentials endpoint. ListCredentialsResponse []Credential - // Credential represents single credential information + // Credential represents single credential information. Credential struct { ClientToken string `json:"clientToken"` CreatedOn time.Time `json:"createdOn"` @@ -127,7 +89,7 @@ type ( Actions *CredentialActions `json:"actions"` } - // CredentialActions describes the actions that can be performed on the credential + // CredentialActions describes the actions that can be performed on the credential. CredentialActions struct { Deactivate bool `json:"deactivate"` Delete bool `json:"delete"` @@ -136,37 +98,45 @@ type ( EditExpiration bool `json:"editExpiration"` } - // GetCredentialResponse holds response from GetCredential operation + // GetCredentialResponse holds response from the GetCredential endpoint. GetCredentialResponse Credential - // UpdateCredentialResponse holds response from UpdateCredential operation + // UpdateCredentialResponse holds response from the UpdateCredential endpoint. UpdateCredentialResponse struct { Status CredentialStatus `json:"status"` ExpiresOn time.Time `json:"expiresOn"` Description *string `json:"description"` } - // CredentialStatus represents the status of the credential + // CredentialStatus represents the status of the credential. CredentialStatus string ) const ( - // CredentialActive represents active credential + // CredentialActive represents active credential. CredentialActive CredentialStatus = "ACTIVE" - // CredentialInactive represents inactive credential + // CredentialInactive represents inactive credential. CredentialInactive CredentialStatus = "INACTIVE" - // CredentialDeleted represents deleted credential + // CredentialDeleted represents deleted credential. CredentialDeleted CredentialStatus = "DELETED" ) -// Validate validates GetCredentialRequest +// Validate validates CredentialStatus. +func (c CredentialStatus) Validate() error { + return validation.In(CredentialActive, CredentialInactive, CredentialDeleted). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", + c, CredentialActive, CredentialInactive, CredentialDeleted)). + Validate(c) +} + +// Validate validates GetCredentialRequest. func (r GetCredentialRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CredentialID": validation.Validate(r.CredentialID, validation.Required), }) } -// Validate validates UpdateCredentialRequest +// Validate validates UpdateCredentialRequest. func (r UpdateCredentialRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CredentialID": validation.Validate(r.CredentialID, validation.Required), @@ -174,22 +144,22 @@ func (r UpdateCredentialRequest) Validate() error { }) } -// Validate validates UpdateCredentialRequestBody +// Validate validates UpdateCredentialRequestBody. func (r UpdateCredentialRequestBody) Validate() error { return validation.Errors{ "ExpiresOn": validation.Validate(r.ExpiresOn, validation.Required), - "Status": validation.Validate(r.Status, validation.Required, validation.In(CredentialActive, CredentialInactive)), + "Status": validation.Validate(r.Status, validation.Required), }.Filter() } -// Validate validates DeleteCredentialRequest +// Validate validates DeleteCredentialRequest. func (r DeleteCredentialRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CredentialID": validation.Validate(r.CredentialID, validation.Required), }) } -// Validate validates DeactivateCredentialRequest +// Validate validates DeactivateCredentialRequest. func (r DeactivateCredentialRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CredentialID": validation.Validate(r.CredentialID, validation.Required), @@ -197,25 +167,25 @@ func (r DeactivateCredentialRequest) Validate() error { } var ( - // ErrCreateCredential is returned when CreateCredential fails + // ErrCreateCredential is returned when CreateCredential fails. ErrCreateCredential = errors.New("create credential") - // ErrListCredentials is returned when ListCredentials fails + // ErrListCredentials is returned when ListCredentials fails. ErrListCredentials = errors.New("list credentials") - // ErrGetCredential is returned when GetCredential fails + // ErrGetCredential is returned when GetCredential fails. ErrGetCredential = errors.New("get credential") - // ErrUpdateCredential is returned when UpdateCredential fails + // ErrUpdateCredential is returned when UpdateCredential fails. ErrUpdateCredential = errors.New("update credential") - // ErrDeleteCredential is returned when DeleteCredential fails + // ErrDeleteCredential is returned when DeleteCredential fails. ErrDeleteCredential = errors.New("delete credential") - // ErrDeactivateCredential is returned when DeactivateCredential fails + // ErrDeactivateCredential is returned when DeactivateCredential fails. ErrDeactivateCredential = errors.New("deactivate credential") - // ErrDeactivateCredentials is returned when DeactivateCredentials fails + // ErrDeactivateCredentials is returned when DeactivateCredentials fails. ErrDeactivateCredentials = errors.New("deactivate credentials") ) func (i *iam) CreateCredential(ctx context.Context, params CreateCredentialRequest) (*CreateCredentialResponse, error) { logger := i.Log(ctx) - logger.Debug("create credential") + logger.Debug("CreateCredential") if params.ClientID == "" { params.ClientID = "self" @@ -246,7 +216,7 @@ func (i *iam) CreateCredential(ctx context.Context, params CreateCredentialReque func (i *iam) ListCredentials(ctx context.Context, params ListCredentialsRequest) (ListCredentialsResponse, error) { logger := i.Log(ctx) - logger.Debug("list credentials") + logger.Debug("ListCredentials") if params.ClientID == "" { params.ClientID = "self" @@ -281,7 +251,7 @@ func (i *iam) ListCredentials(ctx context.Context, params ListCredentialsRequest func (i *iam) GetCredential(ctx context.Context, params GetCredentialRequest) (*GetCredentialResponse, error) { logger := i.Log(ctx) - logger.Debug("get credential") + logger.Debug("GetCredential") if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w: %s", ErrGetCredential, ErrStructValidation, err) @@ -320,7 +290,7 @@ func (i *iam) GetCredential(ctx context.Context, params GetCredentialRequest) (* func (i *iam) UpdateCredential(ctx context.Context, params UpdateCredentialRequest) (*UpdateCredentialResponse, error) { logger := i.Log(ctx) - logger.Debug("update credential") + logger.Debug("UpdateCredential") if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w: %s", ErrUpdateCredential, ErrStructValidation, err) @@ -361,7 +331,7 @@ func (i *iam) UpdateCredential(ctx context.Context, params UpdateCredentialReque func (i *iam) DeleteCredential(ctx context.Context, params DeleteCredentialRequest) error { logger := i.Log(ctx) - logger.Debug("delete credential") + logger.Debug("DeleteCredential") if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w: %s", ErrDeleteCredential, ErrStructValidation, err) @@ -395,7 +365,7 @@ func (i *iam) DeleteCredential(ctx context.Context, params DeleteCredentialReque func (i *iam) DeactivateCredential(ctx context.Context, params DeactivateCredentialRequest) error { logger := i.Log(ctx) - logger.Debug("deactivate credential") + logger.Debug("DeactivateCredential") if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w: %s", ErrDeactivateCredential, ErrStructValidation, err) @@ -429,7 +399,7 @@ func (i *iam) DeactivateCredential(ctx context.Context, params DeactivateCredent func (i *iam) DeactivateCredentials(ctx context.Context, params DeactivateCredentialsRequest) error { logger := i.Log(ctx) - logger.Debug("deactivate credentials") + logger.Debug("DeactivateCredentials") if params.ClientID == "" { params.ClientID = "self" diff --git a/pkg/iam/api_clients_credentials_test.go b/pkg/iam/api_clients_credentials_test.go index 40e1fa31..ab4ebcbf 100644 --- a/pkg/iam/api_clients_credentials_test.go +++ b/pkg/iam/api_clients_credentials_test.go @@ -15,7 +15,7 @@ import ( "github.com/tj/assert" ) -func TestCreateCredential(t *testing.T) { +func TestIAM_CreateCredential(t *testing.T) { tests := map[string]struct { params CreateCredentialRequest expectedPath string @@ -125,28 +125,28 @@ func TestCreateCredential(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.CreateCredential(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.CreateCredential(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestListCredentials(t *testing.T) { +func TestIAM_ListCredentials(t *testing.T) { tests := map[string]struct { params ListCredentialsRequest expectedPath string @@ -316,28 +316,28 @@ func TestListCredentials(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.ListCredentials(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.ListCredentials(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestGetCredential(t *testing.T) { +func TestIAM_GetCredential(t *testing.T) { tests := map[string]struct { params GetCredentialRequest expectedPath string @@ -473,28 +473,28 @@ func TestGetCredential(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.GetCredential(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.GetCredential(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestUpdateCredential(t *testing.T) { +func TestIAM_UpdateCredential(t *testing.T) { tests := map[string]struct { params UpdateCredentialRequest responseStatus int @@ -684,33 +684,33 @@ func TestUpdateCredential(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if test.expectedRequestBody != "" { + if tc.expectedRequestBody != "" { body, err := io.ReadAll(r.Body) assert.NoError(t, err) - assert.JSONEq(t, test.expectedRequestBody, string(body)) + assert.JSONEq(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - response, err := client.UpdateCredential(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.UpdateCredential(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestDeleteCredential(t *testing.T) { +func TestIAM_DeleteCredential(t *testing.T) { tests := map[string]struct { params DeleteCredentialRequest responseStatus int @@ -790,19 +790,19 @@ func TestDeleteCredential(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeleteCredential(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.DeleteCredential(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -810,7 +810,7 @@ func TestDeleteCredential(t *testing.T) { } } -func TestDeactivateCredential(t *testing.T) { +func TestIAM_DeactivateCredential(t *testing.T) { tests := map[string]struct { params DeactivateCredentialRequest responseStatus int @@ -890,19 +890,19 @@ func TestDeactivateCredential(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeactivateCredential(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.DeactivateCredential(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -910,7 +910,7 @@ func TestDeactivateCredential(t *testing.T) { } } -func TestDeactivateCredentials(t *testing.T) { +func TestIAM_DeactivateCredentials(t *testing.T) { tests := map[string]struct { params DeactivateCredentialsRequest responseStatus int @@ -977,19 +977,19 @@ func TestDeactivateCredentials(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeactivateCredentials(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.DeactivateCredentials(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/iam/api_clients_test.go b/pkg/iam/api_clients_test.go index 5765f724..7a8432d1 100644 --- a/pkg/iam/api_clients_test.go +++ b/pkg/iam/api_clients_test.go @@ -3,7 +3,7 @@ package iam import ( "context" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -157,23 +157,23 @@ func TestIAM_LockAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.LockAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.LockAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } @@ -287,28 +287,28 @@ func TestIAM_UnlockAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.UnlockAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.UnlockAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestListAPIClients(t *testing.T) { +func TestIAM_ListAPIClients(t *testing.T) { tests := map[string]struct { params ListAPIClientsRequest responseStatus int @@ -537,29 +537,29 @@ func TestListAPIClients(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListAPIClients(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListAPIClients(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestCreateAPIClient(t *testing.T) { +func TestIAM_CreateAPIClient(t *testing.T) { tests := map[string]struct { params CreateAPIClientRequest expectedPath string @@ -1080,7 +1080,7 @@ func TestCreateAPIClient(t *testing.T) { "validation errors - internal validations": { params: CreateAPIClientRequest{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}, withError: func(t *testing.T, err error) { - assert.Equal(t, "create api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) + assert.Equal(t, "create api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT', 'SERVICE_ACCOUNT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) }, }, "500 internal server error": { @@ -1119,35 +1119,35 @@ func TestCreateAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.JSONEq(t, test.expectedRequestBody, string(body)) + assert.JSONEq(t, tc.expectedRequestBody, string(body)) } - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.CreateAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.CreateAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestUpdateAPIClient(t *testing.T) { +func TestIAM_UpdateAPIClient(t *testing.T) { tests := map[string]struct { params UpdateAPIClientRequest expectedPath string @@ -1835,13 +1835,13 @@ func TestUpdateAPIClient(t *testing.T) { "validation errors": { params: UpdateAPIClientRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "update api client: struct validation:\nAPIs: cannot be blank\nAuthorizedUsers: cannot be blank\nClientType: cannot be blank\nGroups: cannot be blank", err.Error()) + assert.Equal(t, "update api client: struct validation:\nAPIs: cannot be blank\nAuthorizedUsers: cannot be blank\nClientName: cannot be blank\nClientType: cannot be blank\nGroups: cannot be blank", err.Error()) }, }, "validation errors - internal validations": { params: UpdateAPIClientRequest{Body: UpdateAPIClientRequestBody{APIAccess: APIAccess{APIs: []API{{}}}, AuthorizedUsers: []string{"user1"}, ClientType: "abc", GroupAccess: GroupAccess{Groups: []ClientGroup{{}}}, PurgeOptions: &PurgeOptions{CPCodeAccess: CPCodeAccess{AllCurrentAndNewCPCodes: false, CPCodes: nil}}}}, withError: func(t *testing.T, err error) { - assert.Equal(t, "update api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) + assert.Equal(t, "update api client: struct validation:\nAPIs[0]: {\n\tAPIID: cannot be blank\n\tAccessLevel: cannot be blank\n}\nClientName: cannot be blank\nClientType: value 'abc' is invalid. Must be one of: 'CLIENT', 'SERVICE_ACCOUNT' or 'USER_CLIENT'\nGroups[0]: {\n\tGroupID: cannot be blank\n\tRoleID: cannot be blank\n}\nCPCodes: is required", err.Error()) }, }, "500 internal server error": { @@ -1882,35 +1882,35 @@ func TestUpdateAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.JSONEq(t, test.expectedRequestBody, string(body)) + assert.JSONEq(t, tc.expectedRequestBody, string(body)) } - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.UpdateAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.UpdateAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, response) + assert.Equal(t, tc.expectedResponse, response) }) } } -func TestGetAPIClient(t *testing.T) { +func TestIAM_GetAPIClient(t *testing.T) { tests := map[string]struct { params GetAPIClientRequest responseStatus int @@ -2284,29 +2284,29 @@ func TestGetAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.GetAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestDeleteAPIClient(t *testing.T) { +func TestIAM_DeleteAPIClient(t *testing.T) { tests := map[string]struct { params DeleteAPIClientRequest responseStatus int @@ -2348,20 +2348,20 @@ func TestDeleteAPIClient(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeleteAPIClient(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.DeleteAPIClient(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/iam/blocked_properties.go b/pkg/iam/blocked_properties.go index b03d17ff..e4a668cf 100644 --- a/pkg/iam/blocked_properties.go +++ b/pkg/iam/blocked_properties.go @@ -7,30 +7,18 @@ import ( "net/http" "net/url" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // BlockedProperties is the IAM user blocked properties API interface - BlockedProperties interface { - // ListBlockedProperties returns all properties a user doesn't have access to in a group - // - // See: https://techdocs.akamai.com/iam-api/reference/get-blocked-properties - ListBlockedProperties(context.Context, ListBlockedPropertiesRequest) ([]int64, error) - - // UpdateBlockedProperties removes or grants user access to properties - // - // See: https://techdocs.akamai.com/iam-api/reference/put-blocked-properties - UpdateBlockedProperties(context.Context, UpdateBlockedPropertiesRequest) ([]int64, error) - } - - // ListBlockedPropertiesRequest contains the request parameters for the list blocked properties endpoint + // ListBlockedPropertiesRequest contains the request parameters for the ListBlockedProperties endpoint. ListBlockedPropertiesRequest struct { IdentityID string GroupID int64 } - // UpdateBlockedPropertiesRequest contains the request parameters for the update blocked properties endpoint + // UpdateBlockedPropertiesRequest contains the request parameters for the UpdateBlockedProperties endpoint. UpdateBlockedPropertiesRequest struct { IdentityID string GroupID int64 @@ -39,27 +27,27 @@ type ( ) var ( - // ErrListBlockedProperties is returned when ListBlockedPropertiesRequest fails + // ErrListBlockedProperties is returned when ListBlockedPropertiesRequest fails. ErrListBlockedProperties = errors.New("list blocked properties") - // ErrUpdateBlockedProperties is returned when UpdateBlockedPropertiesRequest fails + // ErrUpdateBlockedProperties is returned when UpdateBlockedPropertiesRequest fails. ErrUpdateBlockedProperties = errors.New("update blocked properties") ) -// Validate validates ListBlockedPropertiesRequest +// Validate validates ListBlockedPropertiesRequest. func (r ListBlockedPropertiesRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), "GroupID": validation.Validate(r.GroupID, validation.Required), - }.Filter() + }) } -// Validate validates UpdateBlockedPropertiesRequest +// Validate validates UpdateBlockedPropertiesRequest. func (r UpdateBlockedPropertiesRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), "GroupID": validation.Validate(r.GroupID, validation.Required), - }.Filter() + }) } func (i *iam) ListBlockedProperties(ctx context.Context, params ListBlockedPropertiesRequest) ([]int64, error) { @@ -67,12 +55,12 @@ func (i *iam) ListBlockedProperties(ctx context.Context, params ListBlockedPrope return nil, fmt.Errorf("%s: %w:\n%s", ErrListBlockedProperties, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListBlockedProperties, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListBlockedProperties, err) } @@ -95,12 +83,12 @@ func (i *iam) UpdateBlockedProperties(ctx context.Context, params UpdateBlockedP return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateBlockedProperties, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/groups/%d/blocked-properties", params.IdentityID, params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to parse url: %s", ErrUpdateBlockedProperties, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateBlockedProperties, err) } diff --git a/pkg/iam/blocked_properties_test.go b/pkg/iam/blocked_properties_test.go index eaebd305..cf243d91 100644 --- a/pkg/iam/blocked_properties_test.go +++ b/pkg/iam/blocked_properties_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestIam_ListBlockedProperties(t *testing.T) { +func TestIAM_ListBlockedProperties(t *testing.T) { tests := map[string]struct { params ListBlockedPropertiesRequest responseStatus int @@ -99,28 +99,28 @@ func TestIam_ListBlockedProperties(t *testing.T) { }, }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.ListBlockedProperties(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.ListBlockedProperties(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } -func TestIam_UpdateBlockedProperties(t *testing.T) { +func TestIAM_UpdateBlockedProperties(t *testing.T) { tests := map[string]struct { params UpdateBlockedPropertiesRequest responseStatus int @@ -227,23 +227,23 @@ func TestIam_UpdateBlockedProperties(t *testing.T) { }, }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.UpdateBlockedProperties(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.UpdateBlockedProperties(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index 34e69c3a..c1848db6 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -15,48 +15,15 @@ import ( ) type ( - // CIDR is an interface for managing Classless Inter-Domain Routing (CIDR) blocks - CIDR interface { - // ListCIDRBlocks lists all CIDR blocks on selected account's allowlist - // - // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist - ListCIDRBlocks(context.Context, ListCIDRBlocksRequest) (ListCIDRBlocksResponse, error) - - // CreateCIDRBlock adds CIDR blocks to your account's allowlist - // - // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist - CreateCIDRBlock(context.Context, CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) - - // GetCIDRBlock retrieves a CIDR block's details - // - // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-cidrblockid - GetCIDRBlock(context.Context, GetCIDRBlockRequest) (*GetCIDRBlockResponse, error) - - // UpdateCIDRBlock modifies an existing CIDR block - // - // See: https://techdocs.akamai.com/iam-api/reference/put-allowlist-cidrblockid - UpdateCIDRBlock(context.Context, UpdateCIDRBlockRequest) (*UpdateCIDRBlockResponse, error) - - // DeleteCIDRBlock deletes an existing CIDR block from the IP allowlist - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-allowlist-cidrblockid - DeleteCIDRBlock(context.Context, DeleteCIDRBlockRequest) error - - // ValidateCIDRBlock checks the format of CIDR block - // - // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-validate - ValidateCIDRBlock(context.Context, ValidateCIDRBlockRequest) error - } - - // ListCIDRBlocksRequest contains the request parameters for the ListCIDRBlocks endpoint + // ListCIDRBlocksRequest contains the request parameters for the ListCIDRBlocks endpoint. ListCIDRBlocksRequest struct { Actions bool } - // ListCIDRBlocksResponse describes the response of the ListCIDRBlocks endpoint + // ListCIDRBlocksResponse describes the response from the ListCIDRBlocks endpoint. ListCIDRBlocksResponse []CIDRBlock - // CIDRBlock represents a CIDR block + // CIDRBlock represents a CIDR block. CIDRBlock struct { Actions *CIDRActions `json:"actions"` CIDRBlock string `json:"cidrBlock"` @@ -69,59 +36,59 @@ type ( ModifiedDate time.Time `json:"modifiedDate"` } - // CIDRActions specifies activities available for the CIDR block + // CIDRActions specifies activities available for the CIDR block. CIDRActions struct { Delete bool `json:"delete"` Edit bool `json:"edit"` } - // CreateCIDRBlockRequest contains the request parameters for the CreateCIDRBlock endpoint + // CreateCIDRBlockRequest contains the request parameters for the CreateCIDRBlock endpoint. CreateCIDRBlockRequest struct { CIDRBlock string `json:"cidrBlock"` Comments *string `json:"comments,omitempty"` Enabled bool `json:"enabled"` } - // CreateCIDRBlockResponse describes the response of the CreateCIDRBlock endpoint + // CreateCIDRBlockResponse describes the response from the CreateCIDRBlock endpoint. CreateCIDRBlockResponse CIDRBlock - // GetCIDRBlockRequest contains the request parameters for the GetCIDRBlock endpoint + // GetCIDRBlockRequest contains the request parameters for the GetCIDRBlock endpoint. GetCIDRBlockRequest struct { CIDRBlockID int64 Actions bool } - // GetCIDRBlockResponse describes the response of the GetCIDRBlock endpoint + // GetCIDRBlockResponse describes the response from the GetCIDRBlock endpoint. GetCIDRBlockResponse CIDRBlock - // UpdateCIDRBlockRequest contains the request parameters for the UpdateCIDRBlock endpoint + // UpdateCIDRBlockRequest contains the request parameters for the UpdateCIDRBlock endpoint. UpdateCIDRBlockRequest struct { CIDRBlockID int64 Body UpdateCIDRBlockRequestBody } - // UpdateCIDRBlockRequestBody contains the request body to be used in UpdateCIDRBlock endpoint + // UpdateCIDRBlockRequestBody contains the request body to be used in the UpdateCIDRBlock endpoint. UpdateCIDRBlockRequestBody struct { CIDRBlock string `json:"cidrBlock"` Comments *string `json:"comments,omitempty"` Enabled bool `json:"enabled"` } - // UpdateCIDRBlockResponse describes the response of the UpdateCIDRBlock endpoint + // UpdateCIDRBlockResponse describes the response of the UpdateCIDRBlock endpoint. UpdateCIDRBlockResponse CIDRBlock - // DeleteCIDRBlockRequest contains the request parameters for the DeleteCIDRBlock endpoint + // DeleteCIDRBlockRequest contains the request parameters for the DeleteCIDRBlock endpoint. DeleteCIDRBlockRequest struct { CIDRBlockID int64 } - // ValidateCIDRBlockRequest contains the request parameters for the ValidateCIDRBlock endpoint + // ValidateCIDRBlockRequest contains the request parameters for the ValidateCIDRBlock endpoint. ValidateCIDRBlockRequest struct { CIDRBlock string } ) -// validateCIDR validates the format of CIDRBlock +// validateCIDR validates the format of CIDRBlock. func validateCIDR() validation.Rule { return validation.By(func(value interface{}) error { stringVal, ok := value.(string) @@ -138,21 +105,21 @@ func validateCIDR() validation.Rule { }) } -// Validate performs validation on CreateCIDRBlockRequest +// Validate validates validation on CreateCIDRBlockRequest. func (r CreateCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), }) } -// Validate performs validation on GetCIDRBlockRequest +// Validate validates validation on GetCIDRBlockRequest. func (r GetCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), }) } -// Validate performs validation on UpdateCIDRBlockRequest +// Validate validates validation on UpdateCIDRBlockRequest. func (r UpdateCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), @@ -160,21 +127,21 @@ func (r UpdateCIDRBlockRequest) Validate() error { }) } -// Validate performs validation on UpdateCIDRBlockRequestBody +// Validate validates validation on UpdateCIDRBlockRequestBody. func (r UpdateCIDRBlockRequestBody) Validate() error { return validation.Errors{ "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), }.Filter() } -// Validate performs validation on DeleteCIDRBlockRequest +// Validate validates validation on DeleteCIDRBlockRequest. func (r DeleteCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CIDRBlockID": validation.Validate(r.CIDRBlockID, validation.Required, validation.Min(1)), }) } -// Validate performs validation on ValidateCIDRBlockRequest +// Validate validates validation on ValidateCIDRBlockRequest. func (r ValidateCIDRBlockRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "CIDRBlock": validation.Validate(r.CIDRBlock, validation.Required, validateCIDR()), @@ -182,17 +149,17 @@ func (r ValidateCIDRBlockRequest) Validate() error { } var ( - // ErrListCIDRBlocks is returned when ListCIDRBlocks fails + // ErrListCIDRBlocks is returned when ListCIDRBlocks fails. ErrListCIDRBlocks = errors.New("list CIDR blocks") - // ErrCreateCIDRBlock is returned when CreateCIDRBlock fails + // ErrCreateCIDRBlock is returned when CreateCIDRBlock fails. ErrCreateCIDRBlock = errors.New("create CIDR block") - // ErrGetCIDRBlock is returned when GetCIDRBlock fails + // ErrGetCIDRBlock is returned when GetCIDRBlock fails. ErrGetCIDRBlock = errors.New("get CIDR block") - // ErrUpdateCIDRBlock is returned when UpdateCIDRBlock fails + // ErrUpdateCIDRBlock is returned when UpdateCIDRBlock fails. ErrUpdateCIDRBlock = errors.New("update CIDR block") - // ErrDeleteCIDRBlock is returned when DeleteCIDRBlock fails + // ErrDeleteCIDRBlock is returned when DeleteCIDRBlock fails. ErrDeleteCIDRBlock = errors.New("delete CIDR block") - // ErrValidateCIDRBlock is returned when ValidateCIDRBlock fails + // ErrValidateCIDRBlock is returned when ValidateCIDRBlock fails. ErrValidateCIDRBlock = errors.New("validate CIDR block") ) diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index b8a9918d..cd2e0fcf 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestListCIDRBlocks(t *testing.T) { +func TestIAM_ListCIDRBlocks(t *testing.T) { tests := map[string]struct { params ListCIDRBlocksRequest responseStatus int @@ -166,29 +166,29 @@ func TestListCIDRBlocks(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListCIDRBlocks(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListCIDRBlocks(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestCreateCIDRBlock(t *testing.T) { +func TestIAM_CreateCIDRBlock(t *testing.T) { tests := map[string]struct { params CreateCIDRBlockRequest responseStatus int @@ -314,34 +314,34 @@ func TestCreateCIDRBlock(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.CreateCIDRBlock(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.CreateCIDRBlock(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestGetCIDRBlock(t *testing.T) { +func TestIAM_GetCIDRBlock(t *testing.T) { tests := map[string]struct { params GetCIDRBlockRequest responseStatus int @@ -475,29 +475,29 @@ func TestGetCIDRBlock(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetCIDRBlock(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.GetCIDRBlock(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestUpdateCIDRBlock(t *testing.T) { +func TestIAM_UpdateCIDRBlock(t *testing.T) { tests := map[string]struct { params UpdateCIDRBlockRequest responseStatus int @@ -606,34 +606,34 @@ func TestUpdateCIDRBlock(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateCIDRBlock(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.UpdateCIDRBlock(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestDeleteCIDRBlocks(t *testing.T) { +func TestIAM_DeleteCIDRBlock(t *testing.T) { tests := map[string]struct { params DeleteCIDRBlockRequest responseStatus int @@ -710,20 +710,20 @@ func TestDeleteCIDRBlocks(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeleteCIDRBlock(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.DeleteCIDRBlock(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -731,7 +731,7 @@ func TestDeleteCIDRBlocks(t *testing.T) { } } -func TestValidateCIDRBlocks(t *testing.T) { +func TestIAM_ValidateCIDRBlock(t *testing.T) { tests := map[string]struct { params ValidateCIDRBlockRequest responseStatus int @@ -784,20 +784,20 @@ func TestValidateCIDRBlocks(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.ValidateCIDRBlock(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.ValidateCIDRBlock(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/iam/errors.go b/pkg/iam/errors.go index b2563e96..846ea39b 100644 --- a/pkg/iam/errors.go +++ b/pkg/iam/errors.go @@ -4,14 +4,14 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" ) type ( - // Error is an IAM error interface + // Error is an IAM error interface. Error struct { Type string `json:"type"` Title string `json:"title"` @@ -26,18 +26,13 @@ type ( } ) -var ( - // ErrInputValidation is returned when the input parameters failed validation - ErrInputValidation = errors.New("input validation error") -) - -// Error parses an error from the response +// Error parses an error from the response. func (i *iam) Error(r *http.Response) error { var e Error var body []byte - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { i.Log(r.Request.Context()).Errorf("reading error response body: %s", err) e.StatusCode = r.StatusCode @@ -65,7 +60,7 @@ func (e *Error) Error() string { return fmt.Sprintf("API error: \n%s", msg) } -// Is handles error comparisons +// Is handles error comparisons. func (e *Error) Is(target error) bool { var t *Error if !errors.As(target, &t) { diff --git a/pkg/iam/errors_test.go b/pkg/iam/errors_test.go index b1e435b7..48b227aa 100644 --- a/pkg/iam/errors_test.go +++ b/pkg/iam/errors_test.go @@ -2,7 +2,7 @@ package iam import ( "context" - "io/ioutil" + "io" "net/http" "strings" "testing" @@ -31,7 +31,7 @@ func TestNewError(t *testing.T) { response: &http.Response{ Status: "Internal Server Error", StatusCode: http.StatusInternalServerError, - Body: ioutil.NopCloser(strings.NewReader( + Body: io.NopCloser(strings.NewReader( `{"type":"a","title":"b","detail":"c"}`), ), Request: req, @@ -47,7 +47,7 @@ func TestNewError(t *testing.T) { response: &http.Response{ Status: "Internal Server Error", StatusCode: http.StatusInternalServerError, - Body: ioutil.NopCloser(strings.NewReader( + Body: io.NopCloser(strings.NewReader( `test`), ), Request: req, @@ -59,10 +59,10 @@ func TestNewError(t *testing.T) { }, }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { - res := Client(sess).(*iam).Error(test.response) - assert.Equal(t, test.expected, res) + res := Client(sess).(*iam).Error(tc.response) + assert.Equal(t, tc.expected, res) }) } } @@ -83,7 +83,7 @@ func TestJsonErrorUnmarshalling(t *testing.T) { Request: req, Status: "OK", StatusCode: http.StatusServiceUnavailable, - Body: ioutil.NopCloser(strings.NewReader(`......`))}, + Body: io.NopCloser(strings.NewReader(`......`))}, expected: &Error{ Type: "", StatusCode: http.StatusServiceUnavailable, @@ -96,7 +96,7 @@ func TestJsonErrorUnmarshalling(t *testing.T) { Request: req, Status: "OK", StatusCode: http.StatusServiceUnavailable, - Body: ioutil.NopCloser(strings.NewReader("Your request did not succeed as this operation has reached the limit for your account. Please try after 2024-01-16T15:20:55.945Z"))}, + Body: io.NopCloser(strings.NewReader("Your request did not succeed as this operation has reached the limit for your account. Please try after 2024-01-16T15:20:55.945Z"))}, expected: &Error{ Type: "", StatusCode: http.StatusServiceUnavailable, @@ -109,7 +109,7 @@ func TestJsonErrorUnmarshalling(t *testing.T) { Request: req, Status: "OK", StatusCode: http.StatusServiceUnavailable, - Body: ioutil.NopCloser(strings.NewReader(``))}, + Body: io.NopCloser(strings.NewReader(``))}, expected: &Error{ Type: "", Title: "Failed to unmarshal error body. IAM API failed. Check details for more information.", @@ -119,13 +119,13 @@ func TestJsonErrorUnmarshalling(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { sess, _ := session.New() i := iam{ Session: sess, } - assert.Equal(t, test.expected, i.Error(test.input)) + assert.Equal(t, tc.expected, i.Error(tc.input)) }) } } diff --git a/pkg/iam/groups.go b/pkg/iam/groups.go index dc5cc29a..fc3c34fb 100644 --- a/pkg/iam/groups.go +++ b/pkg/iam/groups.go @@ -9,55 +9,18 @@ import ( "strconv" "time" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // Groups is the IAM group API interface - Groups interface { - // CreateGroup creates a new group within a parent group_id specified in the request - // - // See: https://techdocs.akamai.com/iam-api/reference/post-group - CreateGroup(context.Context, GroupRequest) (*Group, error) - - // GetGroup returns a group's details - // - // See: https://techdocs.akamai.com/iam-api/reference/get-group - GetGroup(context.Context, GetGroupRequest) (*Group, error) - - // ListAffectedUsers lists users who are affected when a group is moved - // - // See: https://techdocs.akamai.com/iam-api/reference/get-move-affected-users - ListAffectedUsers(context.Context, ListAffectedUsersRequest) ([]GroupUser, error) - - // ListGroups lists all groups in which you have a scope of admin for the current account and contract type - // - // See: https://techdocs.akamai.com/iam-api/reference/get-groups - ListGroups(context.Context, ListGroupsRequest) ([]Group, error) - - // RemoveGroup removes a group based on group_id. We can only delete a sub-group, and only if that sub-group doesn't include any users - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-group - RemoveGroup(context.Context, RemoveGroupRequest) error - - // UpdateGroupName changes the name of the group - // - // See: https://techdocs.akamai.com/iam-api/reference/put-group - UpdateGroupName(context.Context, GroupRequest) (*Group, error) - - // MoveGroup moves a nested group under another group within the same parent hierarchy - // - // See: https://techdocs.akamai.com/iam-api/reference/post-groups-move - MoveGroup(context.Context, MoveGroupRequest) error - } - - // GetGroupRequest describes the request parameters of the get group endpoint + // GetGroupRequest describes the request parameters for the GetGroup endpoint. GetGroupRequest struct { GroupID int64 Actions bool } - // Group describes the response of the list groups endpoint + // Group describes the response from the ListGroups endpoint. Group struct { Actions *GroupActions `json:"actions,omitempty"` CreatedBy string `json:"createdBy"` @@ -70,13 +33,13 @@ type ( SubGroups []Group `json:"subGroups,omitempty"` } - // GroupActions encapsulates permissions available to the user for this group + // GroupActions encapsulates permissions available to the user for this group. GroupActions struct { Delete bool `json:"delete"` Edit bool `json:"edit"` } - // GroupUser describes the response of the list affected users endpoint + // GroupUser describes the response from the ListAffectedUsers endpoint. GroupUser struct { AccountID string `json:"accountId"` Email string `json:"email"` @@ -87,68 +50,68 @@ type ( UserName string `json:"uiUserName"` } - // GroupRequest describes the request and body parameters for creating new group or updating a group name endpoint + // GroupRequest describes the request and body parameters for creating new group or updating a group name endpoint. GroupRequest struct { GroupID int64 `json:"-"` GroupName string `json:"groupName"` } - // MoveGroupRequest describes the request body to move a group under another group + // MoveGroupRequest describes the request body for the MoveGroup endpoint. MoveGroupRequest struct { SourceGroupID int64 `json:"sourceGroupId"` DestinationGroupID int64 `json:"destinationGroupId"` } - // ListAffectedUsersRequest describes the request and body parameters of the list affected users endpoint + // ListAffectedUsersRequest describes the request and body parameters of the ListAffectedUsers endpoint. ListAffectedUsersRequest struct { DestinationGroupID int64 SourceGroupID int64 UserType string } - // ListGroupsRequest describes the request parameters of the list groups endpoint + // ListGroupsRequest describes the request parameters of the ListGroups endpoint. ListGroupsRequest struct { Actions bool } - // RemoveGroupRequest describes the request parameter for removing a group + // RemoveGroupRequest describes the request parameter for the RemoveGroup endpoint. RemoveGroupRequest struct { GroupID int64 } ) const ( - // LostAccessUsers with a userType of lostAccess lose their access to the source group + // LostAccessUsers with a userType of lostAccess lose their access to the source group. LostAccessUsers = "lostAccess" - // GainAccessUsers with a userType of gainAccess gain their access to the source group + // GainAccessUsers with a userType of gainAccess gain their access to the source group. GainAccessUsers = "gainAccess" ) var ( - // ErrCreateGroup is returned when CreateGroup fails + // ErrCreateGroup is returned when CreateGroup fails. ErrCreateGroup = errors.New("create group") - // ErrGetGroup is returned when GetGroup fails + // ErrGetGroup is returned when GetGroup fails. ErrGetGroup = errors.New("get group") - // ErrListAffectedUsers is returned when ListAffectedUsers fails + // ErrListAffectedUsers is returned when ListAffectedUsers fails. ErrListAffectedUsers = errors.New("list affected users") - // ErrListGroups is returned when ListGroups fails + // ErrListGroups is returned when ListGroups fails. ErrListGroups = errors.New("list groups") - // ErrUpdateGroupName is returned when UpdateGroupName fails + // ErrUpdateGroupName is returned when UpdateGroupName fails. ErrUpdateGroupName = errors.New("update group name") - // ErrRemoveGroup is returned when RemoveGroup fails + // ErrRemoveGroup is returned when RemoveGroup fails. ErrRemoveGroup = errors.New("remove group") - // ErrMoveGroup is returned when MoveGroup fails + // ErrMoveGroup is returned when MoveGroup fails. ErrMoveGroup = errors.New("move group") ) -// Validate validates GetGroupRequest +// Validate validates GetGroupRequest. func (r GetGroupRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "GroupID": validation.Validate(r.GroupID, validation.Required), - }.Filter() + }) } -// Validate validates GroupRequest +// Validate validates GroupRequest. func (r GroupRequest) Validate() error { return validation.Errors{ "GroupID": validation.Validate(r.GroupID, validation.Required), @@ -156,28 +119,28 @@ func (r GroupRequest) Validate() error { }.Filter() } -// Validate validates MoveGroupRequest +// Validate validates MoveGroupRequest. func (r MoveGroupRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), - }.Filter() + }) } -// Validate validates ListAffectedUsersRequest +// Validate validates ListAffectedUsersRequest. func (r ListAffectedUsersRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), "UserType": validation.Validate(r.UserType, validation.In(LostAccessUsers, GainAccessUsers)), - }.Filter() + }) } -// Validate validates RemoveGroupRequest +// Validate validates RemoveGroupRequest. func (r RemoveGroupRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "GroupID": validation.Validate(r.GroupID, validation.Required), - }.Filter() + }) } func (i *iam) CreateGroup(ctx context.Context, params GroupRequest) (*Group, error) { @@ -188,12 +151,12 @@ func (i *iam) CreateGroup(ctx context.Context, params GroupRequest) (*Group, err return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateGroup, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateGroup, err) } @@ -219,16 +182,16 @@ func (i *iam) GetGroup(ctx context.Context, params GetGroupRequest) (*Group, err return nil, fmt.Errorf("%s: %w:\n%s", ErrGetGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetGroup, err) } - q := u.Query() + q := uri.Query() q.Add("actions", strconv.FormatBool(params.Actions)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetGroup, err) } @@ -254,18 +217,18 @@ func (i *iam) ListAffectedUsers(ctx context.Context, params ListAffectedUsersReq return nil, fmt.Errorf("%s: %w:\n%s", ErrListAffectedUsers, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/move/%d/%d/affected-users", params.SourceGroupID, params.DestinationGroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/move/%d/%d/affected-users", params.SourceGroupID, params.DestinationGroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAffectedUsers, err) } if params.UserType != "" { - q := u.Query() + q := uri.Query() q.Add("userType", params.UserType) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAffectedUsers, err) } @@ -287,16 +250,16 @@ func (i *iam) ListGroups(ctx context.Context, params ListGroupsRequest) ([]Group logger := i.Log(ctx) logger.Debug("ListGroups") - u, err := url.Parse("/identity-management/v3/user-admin/groups") + uri, err := url.Parse("/identity-management/v3/user-admin/groups") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListGroups, err) } - q := u.Query() + q := uri.Query() q.Add("actions", strconv.FormatBool(params.Actions)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListGroups, err) } @@ -322,12 +285,12 @@ func (i *iam) RemoveGroup(ctx context.Context, params RemoveGroupRequest) error return fmt.Errorf("%s: %w:\n%s", ErrRemoveGroup, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveGroup, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodDelete, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveGroup, err) } @@ -352,12 +315,12 @@ func (i *iam) UpdateGroupName(ctx context.Context, params GroupRequest) (*Group, return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateGroupName, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/groups/%d", params.GroupID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateGroupName, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateGroupName, err) } @@ -383,12 +346,12 @@ func (i *iam) MoveGroup(ctx context.Context, params MoveGroupRequest) error { return fmt.Errorf("%s: %w:\n%s", ErrMoveGroup, ErrStructValidation, err) } - u, err := url.Parse("/identity-management/v3/user-admin/groups/move") + uri, err := url.Parse("/identity-management/v3/user-admin/groups/move") if err != nil { return fmt.Errorf("%w: failed to parse url: %s", ErrMoveGroup, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrMoveGroup, err) } diff --git a/pkg/iam/groups_test.go b/pkg/iam/groups_test.go index 8f5d648c..ef3753e2 100644 --- a/pkg/iam/groups_test.go +++ b/pkg/iam/groups_test.go @@ -3,7 +3,7 @@ package iam import ( "context" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -13,7 +13,7 @@ import ( "github.com/tj/assert" ) -func TestCreateGroup(t *testing.T) { +func TestIAM_CreateGroup(t *testing.T) { tests := map[string]struct { params GroupRequest responseStatus int @@ -86,34 +86,34 @@ func TestCreateGroup(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.CreateGroup(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + result, err := client.CreateGroup(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestMoveGroup(t *testing.T) { +func TestIAM_MoveGroup(t *testing.T) { tests := map[string]struct { params MoveGroupRequest expectedRequestBody string @@ -138,22 +138,22 @@ func TestMoveGroup(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/identity-management/v3/user-admin/groups/move", r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) - w.WriteHeader(test.responseStatus) - _, err = w.Write([]byte(test.responseBody)) + assert.Equal(t, tc.expectedRequestBody, string(body)) + w.WriteHeader(tc.responseStatus) + _, err = w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.MoveGroup(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + err := client.MoveGroup(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) @@ -161,7 +161,7 @@ func TestMoveGroup(t *testing.T) { } } -func TestGetGroup(t *testing.T) { +func TestIAM_GetGroup(t *testing.T) { tests := map[string]struct { params GetGroupRequest responseStatus int @@ -255,28 +255,28 @@ func TestGetGroup(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetGroup(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + result, err := client.GetGroup(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestListAffectedUsers(t *testing.T) { +func TestIAM_ListAffectedUsers(t *testing.T) { tests := map[string]struct { params ListAffectedUsersRequest responseStatus int @@ -363,28 +363,28 @@ func TestListAffectedUsers(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListAffectedUsers(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + result, err := client.ListAffectedUsers(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestListGroups(t *testing.T) { +func TestIAM_ListGroups(t *testing.T) { tests := map[string]struct { params ListGroupsRequest responseStatus int @@ -482,28 +482,28 @@ func TestListGroups(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListGroups(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListGroups(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestRemoveGroup(t *testing.T) { +func TestIAM_RemoveGroup(t *testing.T) { tests := map[string]struct { params RemoveGroupRequest responseStatus int @@ -567,19 +567,19 @@ func TestRemoveGroup(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.RemoveGroup(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + err := client.RemoveGroup(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) @@ -587,7 +587,7 @@ func TestRemoveGroup(t *testing.T) { } } -func TestUpdateGroupName(t *testing.T) { +func TestIAM_UpdateGroupName(t *testing.T) { tests := map[string]struct { params GroupRequest responseStatus int @@ -660,29 +660,29 @@ func TestUpdateGroupName(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateGroupName(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) + result, err := client.UpdateGroupName(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go index 530d20af..6a3ca671 100644 --- a/pkg/iam/helper.go +++ b/pkg/iam/helper.go @@ -13,54 +13,31 @@ import ( ) type ( - // Helper is a list of IAM helper API interfaces - Helper interface { - // ListAllowedCPCodes lists available CP codes for a user - // - // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes - ListAllowedCPCodes(context.Context, ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) - - // ListAuthorizedUsers lists authorized API client users - // - // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users - ListAuthorizedUsers(context.Context) (ListAuthorizedUsersResponse, error) - - // ListAllowedAPIs lists available APIs for a user - // - // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis - ListAllowedAPIs(context.Context, ListAllowedAPIsRequest) (ListAllowedAPIsResponse, error) - - // ListAccessibleGroups lists groups available to a user - // - // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access - ListAccessibleGroups(context.Context, ListAccessibleGroupsRequest) (ListAccessibleGroupsResponse, error) - } - - // ListAllowedCPCodesRequest contains the request parameter for the list of allowed CP codes endpoint + // ListAllowedCPCodesRequest contains the request parameters for the ListAllowedCPCodes endpoint. ListAllowedCPCodesRequest struct { UserName string Body ListAllowedCPCodesRequestBody } - // ListAllowedAPIsRequest contains the request parameters for the list of allowed APIs endpoint + // ListAllowedAPIsRequest contains the request parameters for the ListAllowedAPIs endpoint. ListAllowedAPIsRequest struct { UserName string ClientType ClientType AllowAccountSwitch bool } - // ListAccessibleGroupsRequest contains the request parameter for the list of accessible groups endpoint + // ListAccessibleGroupsRequest contains the request parameter for the ListAccessibleGroups endpoint. ListAccessibleGroupsRequest struct { UserName string } - // ListAllowedCPCodesRequestBody contains the filtering parameters for the list of allowed CP codes endpoint + // ListAllowedCPCodesRequestBody contains the filtering parameters for the ListAllowedCPCodes endpoint. ListAllowedCPCodesRequestBody struct { ClientType ClientType `json:"clientType"` Groups []AllowedCPCodesGroup `json:"groups"` } - // AllowedCPCodesGroup contains the group parameters for the list of allowed CP codes endpoint + // AllowedCPCodesGroup contains the group parameters for the ListAllowedCPCodes endpoint. AllowedCPCodesGroup struct { GroupID int64 `json:"groupId,omitempty"` RoleID int64 `json:"roleId,omitempty"` @@ -72,19 +49,19 @@ type ( SubGroups []AllowedCPCodesGroup `json:"subGroups,omitempty"` } - // ListAllowedCPCodesResponse contains response for the list of allowed CP codes endpoint + // ListAllowedCPCodesResponse contains response for the ListAllowedCPCodes endpoint. ListAllowedCPCodesResponse []ListAllowedCPCodesResponseItem - // ListAllowedCPCodesResponseItem contains single item of the response for allowed CP codes endpoint + // ListAllowedCPCodesResponseItem contains single item of the response from the ListAllowedCPCodes endpoint. ListAllowedCPCodesResponseItem struct { Name string `json:"name"` Value int `json:"value"` } - // ListAuthorizedUsersResponse contains the response for the list of authorized users endpoint + // ListAuthorizedUsersResponse contains the response from the ListAuthorizedUsers endpoint. ListAuthorizedUsersResponse []AuthorizedUser - // AuthorizedUser contains the details about the authorized user + // AuthorizedUser contains the details about the authorized user. AuthorizedUser struct { FirstName string `json:"firstName"` LastName string `json:"lastName"` @@ -93,10 +70,10 @@ type ( UIIdentityID string `json:"uiIdentityId"` } - // ListAccessibleGroupsResponse contains the response for the list of accessible groups endpoint + // ListAccessibleGroupsResponse contains the response from the ListAccessibleGroups endpoint. ListAccessibleGroupsResponse []AccessibleGroup - // AccessibleGroup contains the details about accessible group + // AccessibleGroup contains the details about accessible group. AccessibleGroup struct { GroupID int64 `json:"groupId"` RoleID int64 `json:"roleId"` @@ -107,7 +84,7 @@ type ( SubGroups []AccessibleSubGroup `json:"subGroups"` } - // AccessibleSubGroup contains the details about subgroup + // AccessibleSubGroup contains the details about subgroup. AccessibleSubGroup struct { GroupID int64 `json:"groupId"` GroupName string `json:"groupName"` @@ -115,10 +92,10 @@ type ( SubGroups []AccessibleSubGroup `json:"subGroups"` } - // ListAllowedAPIsResponse contains the response for the list of allowed APIs endpoint + // ListAllowedAPIsResponse contains the response from the ListAllowedAPIs endpoint. ListAllowedAPIsResponse []AllowedAPI - // AllowedAPI contains the details about the API + // AllowedAPI contains the details about the API. AllowedAPI struct { AccessLevels []AccessLevel `json:"accessLevels"` APIID int64 `json:"apiId"` @@ -130,31 +107,39 @@ type ( ServiceProviderID int64 `json:"serviceProviderId"` } - // ClientType represents the type of the client + // ClientType represents the type of the client. ClientType string ) const ( - // UserClientType is the `USER_CLIENT` client type + // UserClientType is the `USER_CLIENT` client type. UserClientType ClientType = "USER_CLIENT" - // ServiceAccountClientType is the `SERVICE_ACCOUNT` client type + // ServiceAccountClientType is the `SERVICE_ACCOUNT` client type. ServiceAccountClientType ClientType = "SERVICE_ACCOUNT" - // ClientClientType is the `CLIENT` client type + // ClientClientType is the `CLIENT` client type. ClientClientType ClientType = "CLIENT" ) var ( - // ErrListAllowedCPCodes is returned when ListAllowedCPCodes fails + // ErrListAllowedCPCodes is returned when ListAllowedCPCodes fails. ErrListAllowedCPCodes = errors.New("list allowed CP codes") - // ErrListAuthorizedUsers is returned when ListAuthorizedUsers fails + // ErrListAuthorizedUsers is returned when ListAuthorizedUsers fails. ErrListAuthorizedUsers = errors.New("list authorized users") - // ErrListAllowedAPIs is returned when ListAllowedAPIs fails + // ErrListAllowedAPIs is returned when ListAllowedAPIs fails. ErrListAllowedAPIs = errors.New("list allowed APIs") - // ErrAccessibleGroups is returned when ListAccessibleGroups fails + // ErrAccessibleGroups is returned when ListAccessibleGroups fails. ErrAccessibleGroups = errors.New("list accessible groups") ) -// Validate validates ListAllowedCPCodesRequest +// Validate validates ClientType. +func (c ClientType) Validate() error { + return validation.In(ClientClientType, ServiceAccountClientType, UserClientType). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", + c, ClientClientType, ServiceAccountClientType, UserClientType)). + Validate(c) +} + +// Validate validates ListAllowedCPCodesRequest. func (r ListAllowedCPCodesRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UserName": validation.Validate(r.UserName, validation.Required), @@ -162,7 +147,7 @@ func (r ListAllowedCPCodesRequest) Validate() error { }) } -// Validate validates ListAllowedCPCodesRequestBody +// Validate validates ListAllowedCPCodesRequestBody. func (r ListAllowedCPCodesRequestBody) Validate() error { return validation.Errors{ "ClientType": validation.Validate(r.ClientType, validation.Required, validation.In(ClientClientType, UserClientType, ServiceAccountClientType).Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'CLIENT' or 'USER_CLIENT' or 'SERVICE_ACCOUNT'", r.ClientType))), @@ -170,7 +155,7 @@ func (r ListAllowedCPCodesRequestBody) Validate() error { }.Filter() } -// Validate validates ListAllowedAPIsRequest +// Validate validates ListAllowedAPIsRequest. func (r ListAllowedAPIsRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UserName": validation.Validate(r.UserName, validation.Required), @@ -178,7 +163,7 @@ func (r ListAllowedAPIsRequest) Validate() error { }) } -// Validate validates ListAccessibleGroupsRequest +// Validate validates ListAccessibleGroupsRequest. func (r ListAccessibleGroupsRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UserName": validation.Validate(r.UserName, validation.Required), @@ -193,9 +178,9 @@ func (i *iam) ListAllowedCPCodes(ctx context.Context, params ListAllowedCPCodesR return nil, fmt.Errorf("%s: %w:\n%s", ErrListAllowedCPCodes, ErrStructValidation, err) } - u := fmt.Sprintf("/identity-management/v3/users/%s/allowed-cpcodes", params.UserName) + uri := fmt.Sprintf("/identity-management/v3/users/%s/allowed-cpcodes", params.UserName) - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedCPCodes, err) } @@ -243,20 +228,20 @@ func (i *iam) ListAllowedAPIs(ctx context.Context, params ListAllowedAPIsRequest return nil, fmt.Errorf("%s: %w:\n%s", ErrListAllowedAPIs, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/users/%s/allowed-apis", params.UserName)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/users/%s/allowed-apis", params.UserName)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedAPIs, err) } - q := u.Query() + q := uri.Query() if params.ClientType != "" { q.Add("clientType", string(params.ClientType)) } q.Add("allowAccountSwitch", strconv.FormatBool(params.AllowAccountSwitch)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListAllowedAPIs, err) } @@ -282,9 +267,9 @@ func (i *iam) ListAccessibleGroups(ctx context.Context, params ListAccessibleGro return nil, fmt.Errorf("%s: %w:\n%s", ErrAccessibleGroups, ErrStructValidation, err) } - u := fmt.Sprintf("/identity-management/v3/users/%s/group-access", params.UserName) + uri := fmt.Sprintf("/identity-management/v3/users/%s/group-access", params.UserName) - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrAccessibleGroups, err) } diff --git a/pkg/iam/helper_test.go b/pkg/iam/helper_test.go index 13ec7d5f..4384e6b7 100644 --- a/pkg/iam/helper_test.go +++ b/pkg/iam/helper_test.go @@ -11,7 +11,7 @@ import ( "github.com/tj/assert" ) -func TestIAMListAllowedCPCodes(t *testing.T) { +func TestIAM_ListAllowedCPCodes(t *testing.T) { tests := map[string]struct { params ListAllowedCPCodesRequest responseStatus int @@ -166,28 +166,28 @@ func TestIAMListAllowedCPCodes(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListAllowedCPCodes(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListAllowedCPCodes(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestIAMListAuthorizedUsers(t *testing.T) { +func TestIAM_ListAuthorizedUsers(t *testing.T) { tests := map[string]struct { responseStatus int responseBody string @@ -267,28 +267,28 @@ func TestIAMListAuthorizedUsers(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.ListAuthorizedUsers(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestIAMListAllowedAPIs(t *testing.T) { +func TestIAM_ListAllowedAPIs(t *testing.T) { tests := map[string]struct { params ListAllowedAPIsRequest responseStatus int @@ -457,28 +457,28 @@ func TestIAMListAllowedAPIs(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListAllowedAPIs(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListAllowedAPIs(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestIAMAccessibleGroups(t *testing.T) { +func TestIAM_AccessibleGroups(t *testing.T) { tests := map[string]struct { params ListAccessibleGroupsRequest responseStatus int @@ -581,23 +581,23 @@ func TestIAMAccessibleGroups(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListAccessibleGroups(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListAccessibleGroups(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index b660f7d5..401e14de 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -2,10 +2,8 @@ package iam import ( - "bytes" - "encoding/json" + "context" "errors" - "io" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" ) @@ -18,33 +16,404 @@ var ( type ( // IAM is the IAM api interface IAM interface { - APIClients - APIClientsCredentials - BlockedProperties - CIDR - Groups - Helper - IPAllowlist - Properties - Roles - Support - UserLock - UserPassword - Users + + // API Clients + + // LockAPIClient locks an API client based on `ClientID` parameter. If `ClientID` is not provided, it locks your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-lock-api-client, https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self + LockAPIClient(ctx context.Context, params LockAPIClientRequest) (*LockAPIClientResponse, error) + + // UnlockAPIClient unlocks an API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client + UnlockAPIClient(ctx context.Context, params UnlockAPIClientRequest) (*UnlockAPIClientResponse, error) + + // ListAPIClients lists API clients an administrator can manage. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients + ListAPIClients(ctx context.Context, params ListAPIClientsRequest) (ListAPIClientsResponse, error) + + // GetAPIClient provides details about an API client. If `ClientID` is not provided, it returns details about your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-client and https://techdocs.akamai.com/iam-api/reference/get-api-client-self + GetAPIClient(ctx context.Context, params GetAPIClientRequest) (*GetAPIClientResponse, error) + + // CreateAPIClient creates a new API client. Optionally, it can automatically assign a credential for the client when creating it. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients + CreateAPIClient(ctx context.Context, params CreateAPIClientRequest) (*CreateAPIClientResponse, error) + + // UpdateAPIClient updates an API client. If `ClientID` is not provided, it updates your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-api-clients and https://techdocs.akamai.com/iam-api/reference/put-api-clients-self + UpdateAPIClient(ctx context.Context, params UpdateAPIClientRequest) (*UpdateAPIClientResponse, error) + + // DeleteAPIClient permanently deletes the API client, breaking any API connections with the client. + // If `ClientID` is not provided, it deletes your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-api-client and https://techdocs.akamai.com/iam-api/reference/delete-api-client-self + DeleteAPIClient(ctx context.Context, params DeleteAPIClientRequest) error + + // API Client Credentials + + // CreateCredential creates a new credential for the API client. If `ClientID` is not provided, it creates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials, https://techdocs.akamai.com/iam-api/reference/post-client-credentials + CreateCredential(context.Context, CreateCredentialRequest) (*CreateCredentialResponse, error) + + // ListCredentials lists credentials for an API client. If `ClientID` is not provided, it lists credentials for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-self-credentials, https://techdocs.akamai.com/iam-api/reference/get-client-credentials + ListCredentials(context.Context, ListCredentialsRequest) (ListCredentialsResponse, error) + + // GetCredential returns details about a specific credential for an API client. If `ClientID` is not provided, it gets credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-self-credential, https://techdocs.akamai.com/iam-api/reference/get-client-credential + GetCredential(context.Context, GetCredentialRequest) (*GetCredentialResponse, error) + + // UpdateCredential updates a specific credential for an API client. If `ClientID` is not provided, it updates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-self-credential, https://techdocs.akamai.com/iam-api/reference/put-client-credential + UpdateCredential(context.Context, UpdateCredentialRequest) (*UpdateCredentialResponse, error) + + // DeleteCredential deletes a specific credential from an API client. If `ClientID` is not provided, it deletes credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-self-credential, https://techdocs.akamai.com/iam-api/reference/delete-client-credential + DeleteCredential(context.Context, DeleteCredentialRequest) error + + // DeactivateCredential deactivates a specific credential for an API client. If `ClientID` is not provided, it deactivates credential for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate + DeactivateCredential(context.Context, DeactivateCredentialRequest) error + + // DeactivateCredentials deactivates all credentials for a specific API client. If `ClientID` is not provided, it deactivates all credentials for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate, https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate + DeactivateCredentials(context.Context, DeactivateCredentialsRequest) error + + // Blocked Properties + + // ListBlockedProperties returns all properties a user doesn't have access to in a group. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-blocked-properties + ListBlockedProperties(context.Context, ListBlockedPropertiesRequest) ([]int64, error) + + // UpdateBlockedProperties removes or grants user access to properties. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-blocked-properties + UpdateBlockedProperties(context.Context, UpdateBlockedPropertiesRequest) ([]int64, error) + + // CIDR Blocks + + // ListCIDRBlocks lists all CIDR blocks on selected account's allowlist. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist + ListCIDRBlocks(context.Context, ListCIDRBlocksRequest) (ListCIDRBlocksResponse, error) + + // CreateCIDRBlock adds CIDR blocks to your account's allowlist. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist + CreateCIDRBlock(context.Context, CreateCIDRBlockRequest) (*CreateCIDRBlockResponse, error) + + // GetCIDRBlock retrieves a CIDR block's details. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-cidrblockid + GetCIDRBlock(context.Context, GetCIDRBlockRequest) (*GetCIDRBlockResponse, error) + + // UpdateCIDRBlock modifies an existing CIDR block. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-allowlist-cidrblockid + UpdateCIDRBlock(context.Context, UpdateCIDRBlockRequest) (*UpdateCIDRBlockResponse, error) + + // DeleteCIDRBlock deletes an existing CIDR block from the IP allowlist. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-allowlist-cidrblockid + DeleteCIDRBlock(context.Context, DeleteCIDRBlockRequest) error + + // ValidateCIDRBlock checks the format of CIDR block. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-validate + ValidateCIDRBlock(context.Context, ValidateCIDRBlockRequest) error + + // Groups + + // CreateGroup creates a new group within a parent group_id specified in the request. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-group + CreateGroup(context.Context, GroupRequest) (*Group, error) + + // GetGroup returns a group's details. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-group + GetGroup(context.Context, GetGroupRequest) (*Group, error) + + // ListAffectedUsers lists users who are affected when a group is moved. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-move-affected-users + ListAffectedUsers(context.Context, ListAffectedUsersRequest) ([]GroupUser, error) + + // ListGroups lists all groups in which you have a scope of admin for the current account and contract type. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-groups + ListGroups(context.Context, ListGroupsRequest) ([]Group, error) + + // RemoveGroup removes a group based on group_id. We can only delete a sub-group, and only if that sub-group doesn't include any users. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-group + RemoveGroup(context.Context, RemoveGroupRequest) error + + // UpdateGroupName changes the name of the group. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-group + UpdateGroupName(context.Context, GroupRequest) (*Group, error) + + // MoveGroup moves a nested group under another group within the same parent hierarchy. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-groups-move + MoveGroup(context.Context, MoveGroupRequest) error + + // Helpers + + // ListAllowedCPCodes lists available CP codes for a user. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes + ListAllowedCPCodes(context.Context, ListAllowedCPCodesRequest) (ListAllowedCPCodesResponse, error) + + // ListAuthorizedUsers lists authorized API client users. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users + ListAuthorizedUsers(context.Context) (ListAuthorizedUsersResponse, error) + + // ListAllowedAPIs lists available APIs for a user. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis + ListAllowedAPIs(context.Context, ListAllowedAPIsRequest) (ListAllowedAPIsResponse, error) + + // ListAccessibleGroups lists groups available to a user. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access + ListAccessibleGroups(context.Context, ListAccessibleGroupsRequest) (ListAccessibleGroupsResponse, error) + + // IP Allowlist + + // DisableIPAllowlist disables IP allowlist on your account. After you disable IP allowlist, + // users can access Control Center regardless of their IP address or who assigns it. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable + DisableIPAllowlist(context.Context) error + + // EnableIPAllowlist enables IP allowlist on your account. Before you enable IP allowlist, + // add at least one IP address to allow access to Control Center. + // The allowlist can't be empty with IP allowlist enabled. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable + EnableIPAllowlist(context.Context) error + + // GetIPAllowlistStatus indicates whether IP allowlist is enabled or disabled on your account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-status + GetIPAllowlistStatus(context.Context) (*GetIPAllowlistStatusResponse, error) + + // Properties + + // ListProperties lists the properties for the current account or other managed accounts using the accountSwitchKey parameter. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-properties + ListProperties(context.Context, ListPropertiesRequest) (ListPropertiesResponse, error) + + // ListUsersForProperty lists users who can access a property. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-property-users + ListUsersForProperty(context.Context, ListUsersForPropertyRequest) (ListUsersForPropertyResponse, error) + + // GetProperty lists a property's details. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-property + GetProperty(context.Context, GetPropertyRequest) (*GetPropertyResponse, error) + + // MoveProperty moves a property from one group to another group. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-property + MoveProperty(context.Context, MovePropertyRequest) error + + // MapPropertyIDToName returns property name for given (IAM) property ID + // Mainly to be used to map (IAM) Property ID to (PAPI) Property ID + // To finish the mapping, please use papi.MapPropertyNameToID + MapPropertyIDToName(context.Context, MapPropertyIDToNameRequest) (*string, error) + + // BlockUsers blocks the users on a property. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-property-users-block + BlockUsers(context.Context, BlockUsersRequest) (*BlockUsersResponse, error) + + // Roles + + // CreateRole creates a custom role. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-role + CreateRole(context.Context, CreateRoleRequest) (*Role, error) + + // GetRole gets details for a specific role. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-role + GetRole(context.Context, GetRoleRequest) (*Role, error) + + // UpdateRole adds or removes permissions from a role and updates other parameters. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-role + UpdateRole(context.Context, UpdateRoleRequest) (*Role, error) + + // DeleteRole deletes a role. This operation is only allowed if the role isn't assigned to any users. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-role + DeleteRole(context.Context, DeleteRoleRequest) error + + // ListRoles lists roles for the current account and contract type. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-roles + ListRoles(context.Context, ListRolesRequest) ([]Role, error) + + // ListGrantableRoles lists which grantable roles can be included in a new custom role or added to an existing custom role. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-grantable-roles + ListGrantableRoles(context.Context) ([]RoleGrantedRole, error) + + // Support + + // GetPasswordPolicy gets the password policy for the account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-password-policy + GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) + + // ListProducts lists products a user can subscribe to and receive notifications for on the account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-notification-products + ListProducts(context.Context) ([]string, error) + + // ListStates lists U.S. states or Canadian provinces. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-states + ListStates(context.Context, ListStatesRequest) ([]string, error) + + // ListTimeoutPolicies lists all the possible session timeout policies. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-timeout-policies + ListTimeoutPolicies(context.Context) ([]TimeoutPolicy, error) + + // ListAccountSwitchKeys lists account switch keys available for a specific API client. If `ClientID` is not provided, it lists account switch keys available for your API client. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys, https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys + ListAccountSwitchKeys(context.Context, ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) + + // SupportedContactTypes lists supported contact types. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-contact-types + SupportedContactTypes(context.Context) ([]string, error) + + // SupportedCountries lists supported countries. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-countries + SupportedCountries(context.Context) ([]string, error) + + // SupportedLanguages lists supported languages. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-languages + SupportedLanguages(context.Context) ([]string, error) + + // SupportedTimezones lists supported timezones. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-common-timezones + SupportedTimezones(context.Context) ([]Timezone, error) + + // Users + + // LockUser locks the user. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-lock + LockUser(context.Context, LockUserRequest) error + + // UnlockUser releases the lock on a user's account. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-unlock + UnlockUser(context.Context, UnlockUserRequest) error + + // ResetUserPassword optionally sends a one-time use password to the user. + // If you send the email with the password directly to the user, the response for this operation doesn't include that password. + // If you don't send the password to the user through email, the password is included in the response. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-reset-password + ResetUserPassword(context.Context, ResetUserPasswordRequest) (*ResetUserPasswordResponse, error) + + // SetUserPassword sets a specific password for a user. + // + // See: https://techdocs.akamai.com/iam-api/reference/post-set-password + SetUserPassword(context.Context, SetUserPasswordRequest) error + + // CreateUser creates a user in the account specified in your own API client credentials or clone an existing user's role assignments. + // + // See: https://techdocs.akamai.com/iam-user-admin/reference/post-ui-identity + CreateUser(context.Context, CreateUserRequest) (*User, error) + + // GetUser gets a specific user's profile. + // + // See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identity + GetUser(context.Context, GetUserRequest) (*User, error) + + // ListUsers returns a list of users who have access on this account. + // + // See: https://techdocs.akamai.com/iam-api/reference/get-ui-identities + ListUsers(context.Context, ListUsersRequest) ([]UserListItem, error) + + // RemoveUser removes a user identity. + // + // See: https://techdocs.akamai.com/iam-api/reference/delete-ui-identity + RemoveUser(context.Context, RemoveUserRequest) error + + // UpdateUserAuthGrants edits what groups a user has access to, and how the user can interact with the objects in those groups. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-uiidentity-auth-grants + UpdateUserAuthGrants(context.Context, UpdateUserAuthGrantsRequest) ([]AuthGrant, error) + + // UpdateUserInfo updates a user's information. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-basic-info + UpdateUserInfo(context.Context, UpdateUserInfoRequest) (*UserBasicInfo, error) + + // UpdateUserNotifications subscribes or un-subscribes user to product notification emails. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-notifications + UpdateUserNotifications(context.Context, UpdateUserNotificationsRequest) (*UserNotifications, error) + + // UpdateTFA updates a user's two-factor authentication setting and can reset tfa. + // + // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-tfa + /** @deprecated */ + UpdateTFA(context.Context, UpdateTFARequest) error + + // UpdateMFA updates a user's profile authentication method. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication + UpdateMFA(context.Context, UpdateMFARequest) error + + // ResetMFA resets a user's profile authentication method. + // + // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication + ResetMFA(context.Context, ResetMFARequest) error } iam struct { session.Session } - // Option defines a IAM option + // Option defines a IAM option. Option func(*iam) - // ClientFunc is an IAM client new method, this can be used for mocking + // ClientFunc is an IAM client new method, this can be used for mocking. ClientFunc func(sess session.Session, opts ...Option) IAM ) -// Client returns a new IAM Client instance with the specified controller +// Client returns a new IAM Client instance with the specified controller. func Client(sess session.Session, opts ...Option) IAM { p := &iam{ Session: sess, @@ -55,11 +424,3 @@ func Client(sess session.Session, opts ...Option) IAM { } return p } - -func convertStructToReqBody(srcStruct interface{}) (io.Reader, error) { - reqBody, err := json.Marshal(srcStruct) - if err != nil { - return nil, err - } - return bytes.NewBuffer(reqBody), nil -} diff --git a/pkg/iam/ip_allowlist.go b/pkg/iam/ip_allowlist.go index 282e5972..264d2dd0 100644 --- a/pkg/iam/ip_allowlist.go +++ b/pkg/iam/ip_allowlist.go @@ -8,39 +8,18 @@ import ( ) type ( - // IPAllowlist is the IAM IP allowlist API interface - IPAllowlist interface { - // DisableIPAllowlist disables IP allowlist on your account. After you disable IP allowlist, - // users can access Control Center regardless of their IP address or who assigns it. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable - DisableIPAllowlist(context.Context) error - - // EnableIPAllowlist enables IP allowlist on your account. Before you enable IP allowlist, - // add at least one IP address to allow access to Control Center. - // The allowlist can't be empty with IP allowlist enabled. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable - EnableIPAllowlist(context.Context) error - - // GetIPAllowlistStatus indicates whether IP allowlist is enabled or disabled on your account. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-allowlist-status - GetIPAllowlistStatus(context.Context) (*GetIPAllowlistStatusResponse, error) - } - - // GetIPAllowlistStatusResponse contains response from GetIPAllowlistStatus operation + // GetIPAllowlistStatusResponse contains response from the GetIPAllowlistStatus endpoint. GetIPAllowlistStatusResponse struct { Enabled bool `json:"enabled"` } ) var ( - // ErrDisableIPAllowlist is returned when DisableIPAllowlist fails + // ErrDisableIPAllowlist is returned when DisableIPAllowlist fails. ErrDisableIPAllowlist = errors.New("disable ip allowlist") - // ErrEnableIPAllowlist is returned when EnableIPAllowlist fails + // ErrEnableIPAllowlist is returned when EnableIPAllowlist fails. ErrEnableIPAllowlist = errors.New("enable ip allowlist") - // ErrGetIPAllowlistStatus is returned when GetIPAllowlistStatus fails + // ErrGetIPAllowlistStatus is returned when GetIPAllowlistStatus fails. ErrGetIPAllowlistStatus = errors.New("get ip allowlist status") ) diff --git a/pkg/iam/ip_allowlist_test.go b/pkg/iam/ip_allowlist_test.go index 4e8a0c95..5e08435a 100644 --- a/pkg/iam/ip_allowlist_test.go +++ b/pkg/iam/ip_allowlist_test.go @@ -10,7 +10,7 @@ import ( "github.com/tj/assert" ) -func TestDisableIPAllowlist(t *testing.T) { +func TestIAM_DisableIPAllowlist(t *testing.T) { tests := map[string]struct { responseStatus int expectedPath string @@ -43,21 +43,21 @@ func TestDisableIPAllowlist(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - if test.responseBody != "" { - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + if tc.responseBody != "" { + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) } })) client := mockAPIClient(t, mockServer) err := client.DisableIPAllowlist(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -65,7 +65,7 @@ func TestDisableIPAllowlist(t *testing.T) { } } -func TestEnableIPAllowlist(t *testing.T) { +func TestIAM_EnableIPAllowlist(t *testing.T) { tests := map[string]struct { responseStatus int expectedPath string @@ -98,21 +98,21 @@ func TestEnableIPAllowlist(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - if test.responseBody != "" { - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + if tc.responseBody != "" { + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) } })) client := mockAPIClient(t, mockServer) err := client.EnableIPAllowlist(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -120,7 +120,7 @@ func TestEnableIPAllowlist(t *testing.T) { } } -func TestGetIPAllowlistStatus(t *testing.T) { +func TestIAM_GetIPAllowlistStatus(t *testing.T) { tests := map[string]struct { responseStatus int responseBody string @@ -173,23 +173,23 @@ func TestGetIPAllowlistStatus(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.GetIPAllowlistStatus(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } diff --git a/pkg/iam/mocks.go b/pkg/iam/mocks.go index 88345019..b93dbfe1 100644 --- a/pkg/iam/mocks.go +++ b/pkg/iam/mocks.go @@ -349,24 +349,24 @@ func (m *Mock) SetUserPassword(ctx context.Context, request SetUserPasswordReque return args.Error(0) } -func (m *Mock) ListProperties(ctx context.Context, request ListPropertiesRequest) (*ListPropertiesResponse, error) { +func (m *Mock) ListProperties(ctx context.Context, request ListPropertiesRequest) (ListPropertiesResponse, error) { args := m.Called(ctx, request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ListPropertiesResponse), args.Error(1) + return args.Get(0).(ListPropertiesResponse), args.Error(1) } -func (m *Mock) ListUsersForProperty(ctx context.Context, request ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) { +func (m *Mock) ListUsersForProperty(ctx context.Context, request ListUsersForPropertyRequest) (ListUsersForPropertyResponse, error) { args := m.Called(ctx, request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*ListUsersForPropertyResponse), args.Error(1) + return args.Get(0).(ListUsersForPropertyResponse), args.Error(1) } func (m *Mock) GetProperty(ctx context.Context, request GetPropertyRequest) (*GetPropertyResponse, error) { diff --git a/pkg/iam/properties.go b/pkg/iam/properties.go index 1a94efa8..2ccc7f4d 100644 --- a/pkg/iam/properties.go +++ b/pkg/iam/properties.go @@ -13,94 +13,41 @@ import ( validation "github.com/go-ozzo/ozzo-validation/v4" ) -// PropertyUserType filters property users based on their access to the property -type PropertyUserType string - -const ( - // PropertyUserTypeAll selects all property users - PropertyUserTypeAll PropertyUserType = "all" - // PropertyUserTypeAssigned selects users that have access to the property - PropertyUserTypeAssigned PropertyUserType = "assigned" - // PropertyUserTypeBlocked selects users whose access to the property is blocked - PropertyUserTypeBlocked PropertyUserType = "blocked" -) - -// Validate validates PropertyUserType -func (p PropertyUserType) Validate() error { - return validation.In(PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked). - Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", - p, PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked)). - Validate(p) -} - type ( - // Properties is the IAM properties API interface - Properties interface { - // ListProperties lists the properties for the current account or other managed accounts using the accountSwitchKey parameter. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-properties - ListProperties(context.Context, ListPropertiesRequest) (*ListPropertiesResponse, error) - - // ListUsersForProperty lists users who can access a property. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-property-users - ListUsersForProperty(context.Context, ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) - - // GetProperty lists a property's details. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-property - GetProperty(context.Context, GetPropertyRequest) (*GetPropertyResponse, error) - - // MoveProperty moves a property from one group to another group. - // - // See: https://techdocs.akamai.com/iam-api/reference/put-property - MoveProperty(context.Context, MovePropertyRequest) error - - // MapPropertyIDToName returns property name for given (IAM) property ID - // Mainly to be used to map (IAM) Property ID to (PAPI) Property ID - // To finish the mapping, please use papi.MapPropertyNameToID - MapPropertyIDToName(context.Context, MapPropertyIDToNameRequest) (*string, error) - - // BlockUsers blocks the users on a property. - // - // See: https://techdocs.akamai.com/iam-api/reference/put-property-users-block - BlockUsers(context.Context, BlockUsersRequest) (*BlockUsersResponse, error) - } - - // ListPropertiesRequest contains the request parameters for the list properties operation. + // ListPropertiesRequest contains the request parameters for the ListProperties endpoint. ListPropertiesRequest struct { GroupID int64 Actions bool } - // ListUsersForPropertyRequest contains the request parameters for the ListUsersForProperty operation. + // ListUsersForPropertyRequest contains the request parameters for the ListUsersForProperty endpoint. ListUsersForPropertyRequest struct { PropertyID int64 UserType PropertyUserType } - // GetPropertyRequest contains the request parameters for the get property operation. + // GetPropertyRequest contains the request parameters for the GetProperty endpoint. GetPropertyRequest struct { PropertyID int64 GroupID int64 } - // MapPropertyNameToIDRequest is the argument for MapPropertyNameToID + // MapPropertyNameToIDRequest is the argument for MapPropertyNameToID. MapPropertyNameToIDRequest string - // BlockUsersRequest contains the request parameters for the BlockUsers operation. + // BlockUsersRequest contains the request parameters for the BlockUsers endpoint. BlockUsersRequest struct { PropertyID int64 Body BlockUsersRequestBody } - // ListPropertiesResponse holds the response data from ListProperties. + // ListPropertiesResponse holds the response data from the ListProperties endpoint. ListPropertiesResponse []Property - // ListUsersForPropertyResponse holds the response data from ListUsersForProperty. + // ListUsersForPropertyResponse holds the response data from the ListUsersForProperty endpoint. ListUsersForPropertyResponse []UsersForProperty - // GetPropertyResponse holds the response data from GetProperty. + // GetPropertyResponse holds the response data from the GetProperty endpoint. GetPropertyResponse struct { ARLConfigFile string `json:"arlConfigFile"` CreatedBy string `json:"createdBy"` @@ -113,25 +60,25 @@ type ( PropertyName string `json:"propertyName"` } - // BlockUsersResponse holds the response data from BlockUsers. + // BlockUsersResponse holds the response data from the BlockUsers endpoint. BlockUsersResponse []UsersForProperty - // MovePropertyRequest contains the request parameters for the MoveProperty operation. + // MovePropertyRequest contains the request parameters for the MoveProperty endpoint. MovePropertyRequest struct { PropertyID int64 Body MovePropertyRequestBody } - // MovePropertyRequestBody contains body parameters for the MoveProperty operation. + // MovePropertyRequestBody contains body parameters for the MoveProperty endpoint. MovePropertyRequestBody struct { DestinationGroupID int64 `json:"destinationGroupId"` SourceGroupID int64 `json:"sourceGroupId"` } - // BlockUsersRequestBody hold the request body parameters for BlockUsers operation. + // BlockUsersRequestBody hold the request body parameters for the BlockUsers endpoint. BlockUsersRequestBody []BlockUserItem - // BlockUserItem contains body parameters for the BlockUsers operation. + // BlockUserItem contains body parameters for the BlockUsers endpoint. BlockUserItem struct { UIIdentityID string `json:"uiIdentityId"` } @@ -151,7 +98,7 @@ type ( Move bool `json:"move"` } - // MapPropertyIDToNameRequest is the argument for MapPropertyIDToName + // MapPropertyIDToNameRequest is the argument for MapPropertyIDToName. MapPropertyIDToNameRequest struct { PropertyID int64 GroupID int64 @@ -165,9 +112,29 @@ type ( UIIdentityID string `json:"uiIdentityId"` UIUserName string `json:"uiUserName"` } + + // PropertyUserType filters property users based on their access to the property. + PropertyUserType string +) + +const ( + // PropertyUserTypeAll selects all property users. + PropertyUserTypeAll PropertyUserType = "all" + // PropertyUserTypeAssigned selects users that have access to the property. + PropertyUserTypeAssigned PropertyUserType = "assigned" + // PropertyUserTypeBlocked selects users whose access to the property is blocked. + PropertyUserTypeBlocked PropertyUserType = "blocked" ) -// Validate validates ListUsersForPropertyRequest +// Validate validates PropertyUserType. +func (p PropertyUserType) Validate() error { + return validation.In(PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", + p, PropertyUserTypeAll, PropertyUserTypeAssigned, PropertyUserTypeBlocked)). + Validate(p) +} + +// Validate validates ListUsersForPropertyRequest. func (r ListUsersForPropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), @@ -175,7 +142,7 @@ func (r ListUsersForPropertyRequest) Validate() error { }) } -// Validate validates GetPropertyRequest +// Validate validates GetPropertyRequest. func (r GetPropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), @@ -183,7 +150,7 @@ func (r GetPropertyRequest) Validate() error { }) } -// Validate validates MapPropertyIDToNameRequest +// Validate validates MapPropertyIDToNameRequest. func (r MapPropertyIDToNameRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), @@ -191,7 +158,7 @@ func (r MapPropertyIDToNameRequest) Validate() error { }) } -// Validate validates MovePropertyRequest +// Validate validates MovePropertyRequest. func (r MovePropertyRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), @@ -199,15 +166,15 @@ func (r MovePropertyRequest) Validate() error { }) } -// Validate validates MovePropertyRequestBody +// Validate validates MovePropertyRequestBody. func (r MovePropertyRequestBody) Validate() error { - return edgegriderr.ParseValidationErrors(validation.Errors{ + return validation.Errors{ "DestinationGroupID": validation.Validate(r.DestinationGroupID, validation.Required), "SourceGroupID": validation.Validate(r.SourceGroupID, validation.Required), - }) + }.Filter() } -// Validate validates BlockUsersRequest +// Validate validates BlockUsersRequest. func (r BlockUsersRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "PropertyID": validation.Validate(r.PropertyID, validation.Required), @@ -215,7 +182,7 @@ func (r BlockUsersRequest) Validate() error { }) } -// Validate validates BlockUserItem +// Validate validates BlockUserItem. func (r BlockUserItem) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "UIIdentityID": validation.Validate(r.UIIdentityID, validation.Required), @@ -223,25 +190,25 @@ func (r BlockUserItem) Validate() error { } var ( - // ErrListProperties is returned when ListProperties fails + // ErrListProperties is returned when ListProperties fails. ErrListProperties = errors.New("list properties") - // ErrListUsersForProperty is returned when ListUsersForProperty fails + // ErrListUsersForProperty is returned when ListUsersForProperty fails. ErrListUsersForProperty = errors.New("list users for property") - // ErrGetProperty is returned when GetProperty fails + // ErrGetProperty is returned when GetProperty fails. ErrGetProperty = errors.New("get property") - // ErrMoveProperty is returned when MoveProperty fails + // ErrMoveProperty is returned when MoveProperty fails. ErrMoveProperty = errors.New("move property") - // ErrMapPropertyIDToName is returned when MapPropertyIDToName fails + // ErrMapPropertyIDToName is returned when MapPropertyIDToName fails. ErrMapPropertyIDToName = errors.New("map property by id") - // ErrMapPropertyNameToID is returned when MapPropertyNameToID fails + // ErrMapPropertyNameToID is returned when MapPropertyNameToID fails. ErrMapPropertyNameToID = errors.New("map property by name") - // ErrNoProperty is returned when MapPropertyNameToID did not find given property + // ErrNoProperty is returned when MapPropertyNameToID did not find given property. ErrNoProperty = errors.New("no such property") - // ErrBlockUsers is returned when BlockUsers fails + // ErrBlockUsers is returned when BlockUsers fails. ErrBlockUsers = errors.New("block users") ) -func (i *iam) ListProperties(ctx context.Context, params ListPropertiesRequest) (*ListPropertiesResponse, error) { +func (i *iam) ListProperties(ctx context.Context, params ListPropertiesRequest) (ListPropertiesResponse, error) { logger := i.Log(ctx) logger.Debug("ListProperties") @@ -272,10 +239,10 @@ func (i *iam) ListProperties(ctx context.Context, params ListPropertiesRequest) return nil, fmt.Errorf("%s: %w", ErrListProperties, i.Error(resp)) } - return &result, nil + return result, nil } -func (i *iam) ListUsersForProperty(ctx context.Context, params ListUsersForPropertyRequest) (*ListUsersForPropertyResponse, error) { +func (i *iam) ListUsersForProperty(ctx context.Context, params ListUsersForPropertyRequest) (ListUsersForPropertyResponse, error) { logger := i.Log(ctx) logger.Debug("ListUsersForProperty") @@ -309,7 +276,7 @@ func (i *iam) ListUsersForProperty(ctx context.Context, params ListUsersForPrope return nil, fmt.Errorf("%s: %w", ErrListUsersForProperty, i.Error(resp)) } - return &result, nil + return result, nil } func (i *iam) GetProperty(ctx context.Context, params GetPropertyRequest) (*GetPropertyResponse, error) { @@ -408,7 +375,7 @@ func (i *iam) MapPropertyNameToID(ctx context.Context, name MapPropertyNameToIDR return nil, fmt.Errorf("%w: request failed: %s", ErrMapPropertyNameToID, err) } - for _, property := range *properties { + for _, property := range properties { if property.PropertyName == string(name) { return &property.PropertyID, nil } diff --git a/pkg/iam/properties_test.go b/pkg/iam/properties_test.go index 97acf35b..b6483240 100644 --- a/pkg/iam/properties_test.go +++ b/pkg/iam/properties_test.go @@ -14,13 +14,13 @@ import ( "github.com/stretchr/testify/require" ) -func TestListProperties(t *testing.T) { +func TestIAM_ListProperties(t *testing.T) { tests := map[string]struct { params ListPropertiesRequest responseStatus int expectedPath string responseBody string - expectedResponse *ListPropertiesResponse + expectedResponse ListPropertiesResponse withError func(*testing.T, error) }{ "200 OK - no query params": { @@ -45,7 +45,7 @@ func TestListProperties(t *testing.T) { } ] `, - expectedResponse: &ListPropertiesResponse{ + expectedResponse: ListPropertiesResponse{ { PropertyID: 1, PropertyName: "property1", @@ -83,7 +83,7 @@ func TestListProperties(t *testing.T) { } ] `, - expectedResponse: &ListPropertiesResponse{ + expectedResponse: ListPropertiesResponse{ { PropertyID: 1, PropertyName: "property1", @@ -101,7 +101,7 @@ func TestListProperties(t *testing.T) { responseStatus: http.StatusOK, expectedPath: "/identity-management/v3/user-admin/properties?actions=false", responseBody: `[]`, - expectedResponse: &ListPropertiesResponse{}, + expectedResponse: ListPropertiesResponse{}, }, "500 internal server error": { params: ListPropertiesRequest{}, @@ -126,34 +126,34 @@ func TestListProperties(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.ListProperties(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.ListProperties(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } -func TestListUserForProperty(t *testing.T) { +func TestIAM_ListUserForProperty(t *testing.T) { tests := map[string]struct { params ListUsersForPropertyRequest responseStatus int expectedPath string responseBody string - expectedResponse *ListUsersForPropertyResponse + expectedResponse ListUsersForPropertyResponse withError func(*testing.T, error) }{ "200 OK": { @@ -180,7 +180,7 @@ func TestListUserForProperty(t *testing.T) { } ] `, - expectedResponse: &ListUsersForPropertyResponse{ + expectedResponse: ListUsersForPropertyResponse{ { FirstName: "John", IsBlocked: true, @@ -243,28 +243,28 @@ func TestListUserForProperty(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.ListUsersForProperty(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.ListUsersForProperty(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } -func TestGetProperty(t *testing.T) { +func TestIAM_GetProperty(t *testing.T) { tests := map[string]struct { params GetPropertyRequest responseStatus int @@ -339,28 +339,28 @@ func TestGetProperty(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.GetProperty(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.GetProperty(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } -func TestMoveProperty(t *testing.T) { +func TestIAM_MoveProperty(t *testing.T) { tests := map[string]struct { params MovePropertyRequest expectedPath string @@ -388,7 +388,7 @@ func TestMoveProperty(t *testing.T) { "validation errors": { params: MovePropertyRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "move property: struct validation: Body: DestinationGroupID: cannot be blank\nSourceGroupID: cannot be blank\nPropertyID: cannot be blank", err.Error()) + assert.Equal(t, "move property: struct validation: DestinationGroupID: cannot be blank\nSourceGroupID: cannot be blank\nPropertyID: cannot be blank", err.Error()) }, }, "400 not allowed": { @@ -423,26 +423,26 @@ func TestMoveProperty(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - if test.expectedRequestBody != "" { + if tc.expectedRequestBody != "" { body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.JSONEq(t, test.expectedRequestBody, string(body)) + assert.JSONEq(t, tc.expectedRequestBody, string(body)) } - w.WriteHeader(test.responseStatus) - if test.responseBody != "" { - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + if tc.responseBody != "" { + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) } })) client := mockAPIClient(t, mockServer) - err := client.MoveProperty(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.MoveProperty(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) @@ -450,7 +450,7 @@ func TestMoveProperty(t *testing.T) { } } -func TestMapPropertyIDToName(t *testing.T) { +func TestIAM_MapPropertyIDToName(t *testing.T) { tests := map[string]struct { params MapPropertyIDToNameRequest responseStatus int @@ -513,27 +513,27 @@ func TestMapPropertyIDToName(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.MapPropertyIDToName(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.MapPropertyIDToName(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } -func TestBlockUsers(t *testing.T) { +func TestIAM_BlockUsers(t *testing.T) { tests := map[string]struct { params BlockUsersRequest expectedPath string @@ -680,30 +680,30 @@ func TestBlockUsers(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - if test.expectedRequestBody != "" { + if tc.expectedRequestBody != "" { body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.JSONEq(t, test.expectedRequestBody, string(body)) + assert.JSONEq(t, tc.expectedRequestBody, string(body)) } - w.WriteHeader(test.responseStatus) - if test.responseBody != "" { - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + if tc.responseBody != "" { + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) } })) client := mockAPIClient(t, mockServer) - users, err := client.BlockUsers(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.BlockUsers(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } diff --git a/pkg/iam/roles.go b/pkg/iam/roles.go index c8c4924d..0c7a0b77 100644 --- a/pkg/iam/roles.go +++ b/pkg/iam/roles.go @@ -9,59 +9,27 @@ import ( "strconv" "time" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // Roles is the IAM role API interface - Roles interface { - // CreateRole creates a custom role - // - // See: https://techdocs.akamai.com/iam-api/reference/post-role - CreateRole(context.Context, CreateRoleRequest) (*Role, error) - - // GetRole gets details for a specific role - // - // See: https://techdocs.akamai.com/iam-api/reference/get-role - GetRole(context.Context, GetRoleRequest) (*Role, error) - - // UpdateRole adds or removes permissions from a role and updates other parameters - // - // See: https://techdocs.akamai.com/iam-api/reference/put-role - UpdateRole(context.Context, UpdateRoleRequest) (*Role, error) - - // DeleteRole deletes a role. This operation is only allowed if the role isn't assigned to any users. - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-role - DeleteRole(context.Context, DeleteRoleRequest) error - - // ListRoles lists roles for the current account and contract type - // - // See: https://techdocs.akamai.com/iam-api/reference/get-roles - ListRoles(context.Context, ListRolesRequest) ([]Role, error) - - // ListGrantableRoles lists which grantable roles can be included in a new custom role or added to an existing custom role - // - // See: https://techdocs.akamai.com/iam-api/reference/get-grantable-roles - ListGrantableRoles(context.Context) ([]RoleGrantedRole, error) - } - - // RoleRequest describes request parameters of the create and update role endpoint + // RoleRequest describes request parameters for the CreateRole and UpdateRole endpoints. RoleRequest struct { Name string `json:"roleName,omitempty"` Description string `json:"roleDescription,omitempty"` GrantedRoles []GrantedRoleID `json:"grantedRoles,omitempty"` } - // CreateRoleRequest describes the request parameters of the create role endpoint + // CreateRoleRequest describes the request parameters for the CreateRole endpoint. CreateRoleRequest RoleRequest - // GrantedRoleID describes a unique identifier for a granted role + // GrantedRoleID describes a unique identifier for a granted role. GrantedRoleID struct { ID int64 `json:"grantedRoleId"` } - // GetRoleRequest describes the request parameters of the get role endpoint + // GetRoleRequest describes the request parameters for the GetRole endpoint. GetRoleRequest struct { ID int64 Actions bool @@ -69,19 +37,19 @@ type ( Users bool } - // UpdateRoleRequest describes the request parameters of the update role endpoint. + // UpdateRoleRequest describes the request parameters for the UpdateRole endpoint. // It works as patch request. You need to provide only fields which you want to update. UpdateRoleRequest struct { ID int64 RoleRequest } - // DeleteRoleRequest describes the request parameters of the delete role endpoint + // DeleteRoleRequest describes the request parameters for the DeleteRole endpoint. DeleteRoleRequest struct { ID int64 } - // ListRolesRequest describes the request parameters of the list roles endpoint + // ListRolesRequest describes the request parameters for the ListRoles endpoint. ListRolesRequest struct { GroupID *int64 Actions bool @@ -89,20 +57,20 @@ type ( Users bool } - // RoleAction encapsulates permissions available to the user for this role + // RoleAction encapsulates permissions available to the user for this role. RoleAction struct { Delete bool `json:"delete"` Edit bool `json:"edit"` } - // RoleGrantedRole is a list of granted roles, giving the user access to objects in a group + // RoleGrantedRole is a list of granted roles, giving the user access to objects in a group. RoleGrantedRole struct { Description string `json:"grantedRoleDescription,omitempty"` RoleID int64 `json:"grantedRoleId"` RoleName string `json:"grantedRoleName"` } - // RoleUser user who shares the same role + // RoleUser user who shares the same role. RoleUser struct { AccountID string `json:"accountId"` Email string `json:"email"` @@ -112,7 +80,7 @@ type ( UIIdentityID string `json:"uiIdentityId"` } - // Role encapsulates the response of the list roles endpoint + // Role encapsulates the response from the ListRoles endpoint. Role struct { Actions *RoleAction `json:"actions,omitempty"` CreatedBy string `json:"createdBy"` @@ -127,60 +95,60 @@ type ( RoleType RoleType `json:"type"` } - // RoleType is an enum of role types + // RoleType is an enum of role types. RoleType string ) -// Validate validates CreateRoleRequest +// Validate validates CreateRoleRequest. func (r CreateRoleRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "Name": validation.Validate(r.Name, validation.Required), "Description": validation.Validate(r.Description, validation.Required), "GrantedRoles": validation.Validate(r.GrantedRoles, validation.Required), - }.Filter() + }) } -// Validate validates GetRoleRequest +// Validate validates GetRoleRequest. func (r GetRoleRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "ID": validation.Validate(r.ID, validation.Required), - }.Filter() + }) } -// Validate validates UpdateRoleRequest +// Validate validates UpdateRoleRequest. func (r UpdateRoleRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "ID": validation.Validate(r.ID, validation.Required), - }.Filter() + }) } -// Validate validates DeleteRoleRequest +// Validate validates DeleteRoleRequest. func (r DeleteRoleRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "ID": validation.Validate(r.ID, validation.Required), - }.Filter() + }) } var ( - // RoleTypeStandard is a standard type provided by Akamai + // RoleTypeStandard is a standard type provided by Akamai. RoleTypeStandard RoleType = "standard" - // RoleTypeCustom is a custom role provided by the account + // RoleTypeCustom is a custom role provided by the account. RoleTypeCustom RoleType = "custom" ) var ( - // ErrCreateRole is returned when CreateRole fails + // ErrCreateRole is returned when CreateRole fails. ErrCreateRole = errors.New("create a role") - // ErrGetRole is returned when GetRole fails + // ErrGetRole is returned when GetRole fails. ErrGetRole = errors.New("get a role") - // ErrUpdateRole is returned when UpdateRole fails + // ErrUpdateRole is returned when UpdateRole fails. ErrUpdateRole = errors.New("update a role") - // ErrDeleteRole is returned when DeleteRole fails + // ErrDeleteRole is returned when DeleteRole fails. ErrDeleteRole = errors.New("delete a role") - // ErrListRoles is returned when ListRoles fails + // ErrListRoles is returned when ListRoles fails. ErrListRoles = errors.New("list roles") - // ErrListGrantableRoles is returned when ListGrantableRoles fails + // ErrListGrantableRoles is returned when ListGrantableRoles fails. ErrListGrantableRoles = errors.New("list grantable roles") ) @@ -318,11 +286,11 @@ func (i *iam) ListRoles(ctx context.Context, params ListRolesRequest) ([]Role, e logger := i.Log(ctx) logger.Debug("ListRoles") - u, err := url.Parse("/identity-management/v3/user-admin/roles") + uri, err := url.Parse("/identity-management/v3/user-admin/roles") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListRoles, err) } - q := u.Query() + q := uri.Query() q.Add("actions", strconv.FormatBool(params.Actions)) q.Add("ignoreContext", strconv.FormatBool(params.IgnoreContext)) q.Add("users", strconv.FormatBool(params.Users)) @@ -331,9 +299,9 @@ func (i *iam) ListRoles(ctx context.Context, params ListRolesRequest) ([]Role, e q.Add("groupId", strconv.FormatInt(*params.GroupID, 10)) } - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListRoles, err) } diff --git a/pkg/iam/roles_test.go b/pkg/iam/roles_test.go index 00475b59..c1fab76c 100644 --- a/pkg/iam/roles_test.go +++ b/pkg/iam/roles_test.go @@ -3,7 +3,7 @@ package iam import ( "context" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "strconv" @@ -101,30 +101,30 @@ func TestIAM_CreateRole(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.CreateRole(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + result, err := client.CreateRole(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -304,24 +304,24 @@ func TestIAM_GetRole(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetRole(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + result, err := client.GetRole(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -433,30 +433,30 @@ func TestIAM_UpdateRole(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateRole(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + result, err := client.UpdateRole(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -515,20 +515,20 @@ func TestIAM_DeleteRole(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.DeleteRole(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + err := client.DeleteRole(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) @@ -607,24 +607,24 @@ func TestIAM_ListRoles(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListRoles(context.Background(), test.params) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + result, err := client.ListRoles(context.Background(), tc.params) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -685,24 +685,24 @@ func TestIAM_ListGrantableRoles(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.ListGrantableRoles(context.Background()) - if test.withError != nil { - assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) - assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10)) + if tc.withError != nil { + assert.True(t, errors.Is(err, tc.withError), "want: %s; got: %s", tc.withError, err) + assert.Contains(t, err.Error(), strconv.FormatInt(int64(tc.responseStatus), 10)) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } diff --git a/pkg/iam/support.go b/pkg/iam/support.go index b2999592..89bd9f16 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -7,59 +7,12 @@ import ( "net/http" "net/url" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // Support is a list of IAM supported objects API interfaces - Support interface { - // GetPasswordPolicy gets the password policy for the account. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-password-policy - GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) - - // ListProducts lists products a user can subscribe to and receive notifications for on the account - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-notification-products - ListProducts(context.Context) ([]string, error) - - // ListStates lists U.S. states or Canadian provinces - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-states - ListStates(context.Context, ListStatesRequest) ([]string, error) - - // ListTimeoutPolicies lists all the possible session timeout policies - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-timeout-policies - ListTimeoutPolicies(context.Context) ([]TimeoutPolicy, error) - - // ListAccountSwitchKeys lists account switch keys available for a specific API client. If `ClientID` is not provided, it lists account switch keys available for your API client. - // - // See: https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys, https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys - ListAccountSwitchKeys(context.Context, ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) - - // SupportedContactTypes lists supported contact types - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-contact-types - SupportedContactTypes(context.Context) ([]string, error) - - // SupportedCountries lists supported countries - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-countries - SupportedCountries(context.Context) ([]string, error) - - // SupportedLanguages lists supported languages - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-languages - SupportedLanguages(context.Context) ([]string, error) - - // SupportedTimezones lists supported timezones - // - // See: https://techdocs.akamai.com/iam-api/reference/get-common-timezones - SupportedTimezones(context.Context) ([]Timezone, error) - } - - // GetPasswordPolicyResponse holds the response data from GetPasswordPolicy. + // GetPasswordPolicyResponse holds the response data from the GetPasswordPolicy endpoint. GetPasswordPolicyResponse struct { CaseDiff int64 `json:"caseDif"` MaxRepeating int64 `json:"maxRepeating"` @@ -72,33 +25,33 @@ type ( RotateFrequency int64 `json:"rotateFrequency"` } - // TimeoutPolicy encapsulates the response of the list timeout policies endpoint + // TimeoutPolicy encapsulates the response from the ListTimeoutPolicies endpoint. TimeoutPolicy struct { Name string `json:"name"` Value int64 `json:"value"` } - // ListStatesRequest contains the country request parameter for the list states endpoint + // ListStatesRequest contains the country request parameter for the ListStates endpoint. ListStatesRequest struct { Country string } - // ListAccountSwitchKeysRequest contains the request parameters for the ListAccountSwitchKeys endpoint + // ListAccountSwitchKeysRequest contains the request parameters for the ListAccountSwitchKeys endpoint. ListAccountSwitchKeysRequest struct { ClientID string Search string } - // ListAccountSwitchKeysResponse holds the response data from ListAccountSwitchKeys + // ListAccountSwitchKeysResponse holds the response data from the ListAccountSwitchKeys endpoint. ListAccountSwitchKeysResponse []AccountSwitchKey - // AccountSwitchKey contains information about account switch key + // AccountSwitchKey contains information about account switch key. AccountSwitchKey struct { AccountName string `json:"accountName"` AccountSwitchKey string `json:"accountSwitchKey"` } - // Timezone contains the response of the list supported timezones endpoint + // Timezone contains the response from the ListSupportedTimezones endpoint. Timezone struct { Description string `json:"description"` Offset string `json:"offset"` @@ -108,48 +61,48 @@ type ( ) var ( - // ErrGetPasswordPolicy is returned when GetPasswordPolicy fails + // ErrGetPasswordPolicy is returned when GetPasswordPolicy fails. ErrGetPasswordPolicy = errors.New("get password policy") - // ErrListProducts is returned when ListProducts fails + // ErrListProducts is returned when ListProducts fails. ErrListProducts = errors.New("list products") - // ErrListStates is returned when ListStates fails + // ErrListStates is returned when ListStates fails. ErrListStates = errors.New("list states") - // ErrListTimeoutPolicies is returned when ListTimeoutPolicies fails + // ErrListTimeoutPolicies is returned when ListTimeoutPolicies fails. ErrListTimeoutPolicies = errors.New("list timeout policies") - // ErrListAccountSwitchKeys is returned when ListAccountSwitchKeys fails + // ErrListAccountSwitchKeys is returned when ListAccountSwitchKeys fails. ErrListAccountSwitchKeys = errors.New("list account switch keys") - // ErrSupportedContactTypes is returned when SupportedContactTypes fails + // ErrSupportedContactTypes is returned when SupportedContactTypes fails. ErrSupportedContactTypes = errors.New("supported contact types") - // ErrSupportedCountries is returned when SupportedCountries fails + // ErrSupportedCountries is returned when SupportedCountries fails. ErrSupportedCountries = errors.New("supported countries") - // ErrSupportedLanguages is returned when SupportedLanguages fails + // ErrSupportedLanguages is returned when SupportedLanguages fails. ErrSupportedLanguages = errors.New("supported languages") - // ErrSupportedTimezones is returned when SupportedTimezones fails + // ErrSupportedTimezones is returned when SupportedTimezones fails. ErrSupportedTimezones = errors.New("supported timezones") ) -// Validate validates ListStatesRequest +// Validate validates ListStatesRequest. func (r ListStatesRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "Country": validation.Validate(r.Country, validation.Required), - }.Filter() + }) } func (i *iam) GetPasswordPolicy(ctx context.Context) (*GetPasswordPolicyResponse, error) { logger := i.Log(ctx) logger.Debug("GetPasswordPolicy") - getURL := "/identity-management/v3/user-admin/common/password-policy" + uri := "/identity-management/v3/user-admin/common/password-policy" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPasswordPolicy, err) } @@ -171,15 +124,15 @@ func (i *iam) ListProducts(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("ListProducts") - getURL := "/identity-management/v3/user-admin/common/notification-products" + uri := "/identity-management/v3/user-admin/common/notification-products" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListProducts, err) } - var rval []string - resp, err := i.Exec(req, &rval) + var result []string + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrListProducts, err) } @@ -188,7 +141,7 @@ func (i *iam) ListProducts(ctx context.Context) ([]string, error) { return nil, fmt.Errorf("%s: %w", ErrListProducts, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) ListStates(ctx context.Context, params ListStatesRequest) ([]string, error) { @@ -199,15 +152,15 @@ func (i *iam) ListStates(ctx context.Context, params ListStatesRequest) ([]strin return nil, fmt.Errorf("%s: %w:\n%s", ErrListStates, ErrStructValidation, err) } - getURL := fmt.Sprintf("/identity-management/v3/user-admin/common/countries/%s/states", params.Country) + uri := fmt.Sprintf("/identity-management/v3/user-admin/common/countries/%s/states", params.Country) - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListStates, err) } - var rval []string - resp, err := i.Exec(req, &rval) + var result []string + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrListStates, err) } @@ -216,22 +169,22 @@ func (i *iam) ListStates(ctx context.Context, params ListStatesRequest) ([]strin return nil, fmt.Errorf("%s: %w", ErrListStates, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) { logger := i.Log(ctx) logger.Debug("ListTimeoutPolicies") - getURL := "/identity-management/v3/user-admin/common/timeout-policies" + uri := "/identity-management/v3/user-admin/common/timeout-policies" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrListTimeoutPolicies, err) } - var rval []TimeoutPolicy - resp, err := i.Exec(req, &rval) + var result []TimeoutPolicy + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrListTimeoutPolicies, err) } @@ -240,7 +193,7 @@ func (i *iam) ListTimeoutPolicies(ctx context.Context) ([]TimeoutPolicy, error) return nil, fmt.Errorf("%s: %w", ErrListTimeoutPolicies, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) ListAccountSwitchKeys(ctx context.Context, params ListAccountSwitchKeysRequest) (ListAccountSwitchKeysResponse, error) { @@ -284,15 +237,15 @@ func (i *iam) SupportedContactTypes(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedContactTypes") - getURL := "/identity-management/v3/user-admin/common/contact-types" + uri := "/identity-management/v3/user-admin/common/contact-types" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrSupportedContactTypes, err) } - var rval []string - resp, err := i.Exec(req, &rval) + var result []string + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrSupportedContactTypes, err) } @@ -301,22 +254,22 @@ func (i *iam) SupportedContactTypes(ctx context.Context) ([]string, error) { return nil, fmt.Errorf("%s: %w", ErrSupportedContactTypes, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) SupportedCountries(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedCountries") - getURL := "/identity-management/v3/user-admin/common/countries" + uri := "/identity-management/v3/user-admin/common/countries" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrSupportedCountries, err) } - var rval []string - resp, err := i.Exec(req, &rval) + var result []string + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrSupportedCountries, err) } @@ -325,22 +278,22 @@ func (i *iam) SupportedCountries(ctx context.Context) ([]string, error) { return nil, fmt.Errorf("%s: %w", ErrSupportedCountries, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) SupportedLanguages(ctx context.Context) ([]string, error) { logger := i.Log(ctx) logger.Debug("SupportedLanguages") - getURL := "/identity-management/v3/user-admin/common/supported-languages" + uri := "/identity-management/v3/user-admin/common/supported-languages" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrSupportedLanguages, err) } - var rval []string - resp, err := i.Exec(req, &rval) + var result []string + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrSupportedLanguages, err) } @@ -349,22 +302,22 @@ func (i *iam) SupportedLanguages(ctx context.Context) ([]string, error) { return nil, fmt.Errorf("%s: %w", ErrSupportedLanguages, i.Error(resp)) } - return rval, nil + return result, nil } func (i *iam) SupportedTimezones(ctx context.Context) ([]Timezone, error) { logger := i.Log(ctx) logger.Debug("SupportedTimezones") - getURL := "/identity-management/v3/user-admin/common/timezones" + uri := "/identity-management/v3/user-admin/common/timezones" - req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrSupportedTimezones, err) } - var rval []Timezone - resp, err := i.Exec(req, &rval) + var result []Timezone + resp, err := i.Exec(req, &result) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrSupportedTimezones, err) } @@ -373,5 +326,5 @@ func (i *iam) SupportedTimezones(ctx context.Context) ([]Timezone, error) { return nil, fmt.Errorf("%s: %w", ErrSupportedTimezones, i.Error(resp)) } - return rval, nil + return result, nil } diff --git a/pkg/iam/support_test.go b/pkg/iam/support_test.go index 83da90d9..75cbb54f 100644 --- a/pkg/iam/support_test.go +++ b/pkg/iam/support_test.go @@ -69,23 +69,23 @@ func TestIAM_GetPasswordPolicy(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.GetPasswordPolicy(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -131,23 +131,23 @@ func TestIAM_SupportedCountries(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.SupportedCountries(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -203,23 +203,23 @@ func TestIAM_SupportedTimezones(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.SupportedTimezones(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -264,23 +264,23 @@ func TestIAM_SupportedContactTypes(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.SupportedContactTypes(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -325,23 +325,23 @@ func TestIAM_SupportedLanguages(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.SupportedLanguages(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -386,23 +386,23 @@ func TestIAM_ListProducts(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.ListProducts(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -462,23 +462,23 @@ func TestIAM_ListTimeoutPolicies(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) result, err := client.ListTimeoutPolicies(context.Background()) - if test.withError != nil { - test.withError(t, err) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -537,23 +537,23 @@ func TestIAM_ListStates(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.ListStates(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.ListStates(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -727,23 +727,23 @@ func TestIAM_ListAccountSwitchKeys(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.ListAccountSwitchKeys(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.ListAccountSwitchKeys(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } diff --git a/pkg/iam/user.go b/pkg/iam/user.go index c44b7b58..255cf957 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -15,61 +15,7 @@ import ( ) type ( - // Users is the IAM user identity API interface - Users interface { - // CreateUser creates a user in the account specified in your own API client credentials or clone an existing user's role assignments - // - // See: https://techdocs.akamai.com/iam-user-admin/reference/post-ui-identity - CreateUser(context.Context, CreateUserRequest) (*User, error) - - // GetUser gets a specific user's profile - // - // See: https://techdocs.akamai.com/iam-user-admin/reference/get-ui-identity - GetUser(context.Context, GetUserRequest) (*User, error) - - // ListUsers returns a list of users who have access on this account - // - // See: https://techdocs.akamai.com/iam-api/reference/get-ui-identities - ListUsers(context.Context, ListUsersRequest) ([]UserListItem, error) - - // RemoveUser removes a user identity - // - // See: https://techdocs.akamai.com/iam-api/reference/delete-ui-identity - RemoveUser(context.Context, RemoveUserRequest) error - - // UpdateUserAuthGrants edits what groups a user has access to, and how the user can interact with the objects in those groups - // - // See: https://techdocs.akamai.com/iam-api/reference/put-ui-uiidentity-auth-grants - UpdateUserAuthGrants(context.Context, UpdateUserAuthGrantsRequest) ([]AuthGrant, error) - - // UpdateUserInfo updates a user's information - // - // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-basic-info - UpdateUserInfo(context.Context, UpdateUserInfoRequest) (*UserBasicInfo, error) - - // UpdateUserNotifications subscribes or un-subscribes user to product notification emails - // - // See: https://techdocs.akamai.com/iam-api/reference/put-notifications - UpdateUserNotifications(context.Context, UpdateUserNotificationsRequest) (*UserNotifications, error) - - // UpdateTFA updates a user's two-factor authentication setting and can reset tfa - // - // See: https://techdocs.akamai.com/iam-user-admin/reference/put-ui-identity-tfa - /** @deprecated */ - UpdateTFA(context.Context, UpdateTFARequest) error - - // UpdateMFA updates a user's profile authentication method - // - // See: https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication - UpdateMFA(context.Context, UpdateMFARequest) error - - // ResetMFA resets a user's profile authentication method - // - // See: https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication - ResetMFA(context.Context, ResetMFARequest) error - } - - // CreateUserRequest contains the request parameters for the create user endpoint + // CreateUserRequest contains the request parameters for the CreateUser endpoint. CreateUserRequest struct { UserBasicInfo AuthGrants []AuthGrantRequest `json:"authGrants,omitempty"` @@ -77,14 +23,14 @@ type ( SendEmail bool `json:"-"` } - // ListUsersRequest contains the request parameters for the list users endpoint + // ListUsersRequest contains the request parameters for the ListUsers endpoint. ListUsersRequest struct { GroupID *int64 AuthGrants bool Actions bool } - // GetUserRequest contains the request parameters of the get user endpoint + // GetUserRequest contains the request parameters for the GetUser endpoint. GetUserRequest struct { IdentityID string Actions bool @@ -92,30 +38,30 @@ type ( Notifications bool } - // UpdateUserInfoRequest contains the request parameters of the update user endpoint + // UpdateUserInfoRequest contains the request parameters for the UpdateUser endpoint. UpdateUserInfoRequest struct { IdentityID string User UserBasicInfo } - // UpdateUserNotificationsRequest contains the request parameters of the update user notifications endpoint + // UpdateUserNotificationsRequest contains the request parameters for the UpdateUserNotifications endpoint. UpdateUserNotificationsRequest struct { IdentityID string Notifications *UserNotifications } - // UpdateUserAuthGrantsRequest contains the request parameters of the update user auth grants endpoint + // UpdateUserAuthGrantsRequest contains the request parameters for the UpdateUserAuthGrants endpoint. UpdateUserAuthGrantsRequest struct { IdentityID string AuthGrants []AuthGrantRequest } - // RemoveUserRequest contains the request parameters of the remove user endpoint + // RemoveUserRequest contains the request parameters of the RemoveUser endpoint. RemoveUserRequest struct { IdentityID string } - // User describes the response of the get and create user endpoints + // User describes the response from the GetUser and CreateUser endpoints. User struct { UserBasicInfo IdentityID string `json:"uiIdentityId"` @@ -132,7 +78,7 @@ type ( AdditionalAuthenticationConfigured bool `json:"additionalAuthenticationConfigured"` } - // UserListItem describes the response of the list endpoint + // UserListItem describes the response from the ListUsers endpoint. UserListItem struct { FirstName string `json:"firstName"` LastName string `json:"lastName"` @@ -150,7 +96,7 @@ type ( AdditionalAuthenticationConfigured bool `json:"additionalAuthenticationConfigured"` } - // UserBasicInfo is the user basic info structure + // UserBasicInfo is the user basic info structure. UserBasicInfo struct { FirstName string `json:"firstName"` LastName string `json:"lastName"` @@ -173,7 +119,7 @@ type ( AdditionalAuthentication Authentication `json:"additionalAuthentication"` } - // UserActions encapsulates permissions available to the user for this group + // UserActions encapsulates permissions available to the user for this group. UserActions struct { APIClient bool `json:"apiClient"` Delete bool `json:"delete"` @@ -189,7 +135,7 @@ type ( CanGenerateBypassCode bool `json:"canGenerateBypassCode"` } - // AuthGrant is user’s role assignments, per group + // AuthGrant is user’s role assignments, per group. AuthGrant struct { GroupID int64 `json:"groupId"` GroupName string `json:"groupName"` @@ -200,7 +146,7 @@ type ( Subgroups []AuthGrant `json:"subGroups,omitempty"` } - // AuthGrantRequest is user’s role assignments, per group for the create/update operation + // AuthGrantRequest is user’s role assignments, per group for the create/update operation. AuthGrantRequest struct { GroupID int64 `json:"groupId"` IsBlocked bool `json:"isBlocked"` @@ -208,13 +154,13 @@ type ( Subgroups []AuthGrantRequest `json:"subGroups,omitempty"` } - // UserNotifications types of notification emails the user receives + // UserNotifications types of notification emails the user receives. UserNotifications struct { EnableEmail bool `json:"enableEmailNotifications"` Options UserNotificationOptions `json:"options"` } - // UserNotificationOptions types of notification emails the user receives + // UserNotificationOptions types of notification emails the user receives. UserNotificationOptions struct { NewUser bool `json:"newUserNotification"` PasswordExpiry bool `json:"passwordExpiry"` @@ -223,78 +169,86 @@ type ( APIClientCredentialExpiry bool `json:"apiClientCredentialExpiryNotification"` } - // TFAActionType is a type for tfa action constants + // TFAActionType is a type for tfa action constants. TFAActionType string - // UpdateTFARequest contains the request parameters of the tfa user endpoint + // UpdateTFARequest contains the request parameters for the UpdateTFA endpoint. UpdateTFARequest struct { IdentityID string Action TFAActionType } - // Authentication is a type of additional authentication + // Authentication is a type of additional authentication. Authentication string - // UpdateMFARequest contains the request body of the mfa user endpoint + // UpdateMFARequest contains the request body for the UpdateMFA endpoint. UpdateMFARequest struct { IdentityID string Value Authentication } - // ResetMFARequest contains the request parameters of the rest mfa endpoint + // ResetMFARequest contains the request parameters for the ResetMFA endpoint. ResetMFARequest struct { IdentityID string } ) const ( - // TFAActionEnable is an action value to use to enable tfa + // TFAActionEnable is an action value to use to enable tfa. TFAActionEnable TFAActionType = "enable" - // TFAActionDisable is an action value to use to disable tfa + // TFAActionDisable is an action value to use to disable tfa. TFAActionDisable TFAActionType = "disable" - // TFAActionReset is an action value to use to reset tfa + // TFAActionReset is an action value to use to reset tfa. TFAActionReset TFAActionType = "reset" - // MFAAuthentication is authentication of type MFA + // MFAAuthentication is authentication of type MFA. MFAAuthentication Authentication = "MFA" - // TFAAuthentication is authentication of type TFA + // TFAAuthentication is authentication of type TFA. TFAAuthentication Authentication = "TFA" - // NoneAuthentication represents a state where no authentication method is configured + // NoneAuthentication represents a state where no authentication method is configured. NoneAuthentication Authentication = "NONE" ) var ( - // ErrCreateUser is returned when CreateUser fails + // ErrCreateUser is returned when CreateUser fails. ErrCreateUser = errors.New("create user") - // ErrGetUser is returned when GetUser fails + // ErrGetUser is returned when GetUser fails. ErrGetUser = errors.New("get user") - // ErrListUsers is returned when GetUser fails + // ErrListUsers is returned when ListUsers fails. ErrListUsers = errors.New("list users") - // ErrRemoveUser is returned when RemoveUser fails + // ErrRemoveUser is returned when RemoveUser fails. ErrRemoveUser = errors.New("remove user") - // ErrUpdateUserAuthGrants is returned when UpdateUserAuthGrants fails + // ErrUpdateUserAuthGrants is returned when UpdateUserAuthGrants fails. ErrUpdateUserAuthGrants = errors.New("update user auth grants") - // ErrUpdateUserInfo is returned when UpdateUserInfo fails + // ErrUpdateUserInfo is returned when UpdateUserInfo fails. ErrUpdateUserInfo = errors.New("update user info") - // ErrUpdateUserNotifications is returned when UpdateUserNotifications fails + // ErrUpdateUserNotifications is returned when UpdateUserNotifications fails. ErrUpdateUserNotifications = errors.New("update user notifications") - // ErrUpdateTFA is returned when UpdateTFA fails + // ErrUpdateTFA is returned when UpdateTFA fails. ErrUpdateTFA = errors.New("update user's two-factor authentication") - // ErrUpdateMFA is returned when UpdateMFA fails + // ErrUpdateMFA is returned when UpdateMFA fails. ErrUpdateMFA = errors.New("update user's authentication method") - // ErrResetMFA is returned when ResetMFA fails + // ErrResetMFA is returned when ResetMFA fails. ErrResetMFA = errors.New("reset user's authentication method") ) -// Validate performs validation on AuthGrant +// Validate validates Authentication. +func (a Authentication) Validate() error { + return validation.In(MFAAuthentication, TFAAuthentication, NoneAuthentication). + Error(fmt.Sprintf("value '%s' is invalid. Must be one of: '%s', '%s' or '%s'", + a, MFAAuthentication, TFAAuthentication, NoneAuthentication)). + Validate(a) +} + +// Validate validates validation on AuthGrant. func (r AuthGrant) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "GroupID": validation.Validate(r.GroupID, validation.Required), @@ -302,29 +256,29 @@ func (r AuthGrant) Validate() error { }) } -// Validate validates CreateUserRequest +// Validate validates CreateUserRequest. func (r CreateUserRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "Country": validation.Validate(r.Country, validation.Required), "Email": validation.Validate(r.Email, validation.Required, is.EmailFormat), "FirstName": validation.Validate(r.FirstName, validation.Required), "LastName": validation.Validate(r.LastName, validation.Required), "AuthGrants": validation.Validate(r.AuthGrants, validation.Required), "Notifications": validation.Validate(r.Notifications), - "AdditionalAuthentication": validation.Validate(r.AdditionalAuthentication, validation.In(MFAAuthentication, TFAAuthentication, NoneAuthentication), validation.Required), - }.Filter() + "AdditionalAuthentication": validation.Validate(r.AdditionalAuthentication, validation.Required), + }) } -// Validate validates GetUserRequest +// Validate validates GetUserRequest. func (r GetUserRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), }) } -// Validate validates UpdateUserInfoRequest +// Validate validates UpdateUserInfoRequest. func (r UpdateUserInfoRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), "FirstName": validation.Validate(r.User.FirstName, validation.Required), "LastName": validation.Validate(r.User.LastName, validation.Required), @@ -332,10 +286,10 @@ func (r UpdateUserInfoRequest) Validate() error { "TimeZone": validation.Validate(r.User.TimeZone, validation.Required), "PreferredLanguage": validation.Validate(r.User.PreferredLanguage, validation.Required), "SessionTimeOut": validation.Validate(r.User.SessionTimeOut, validation.Required), - }.Filter() + }) } -// Validate validates UpdateUserNotificationsRequest +// Validate validates UpdateUserNotificationsRequest. func (r UpdateUserNotificationsRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), @@ -343,7 +297,7 @@ func (r UpdateUserNotificationsRequest) Validate() error { }) } -// Validate validates UpdateUserAuthGrantsRequest +// Validate validates UpdateUserAuthGrantsRequest. func (r UpdateUserAuthGrantsRequest) Validate() error { return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), @@ -351,46 +305,48 @@ func (r UpdateUserAuthGrantsRequest) Validate() error { }) } -// Validate validates RemoveUserRequest +// Validate validates RemoveUserRequest. func (r RemoveUserRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "uiIdentity": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + }) } -// Validate validates UpdateTFARequest +// Validate validates UpdateTFARequest. func (r UpdateTFARequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), "Action": validation.Validate(r.Action, validation.Required, validation.In(TFAActionEnable, TFAActionDisable, TFAActionReset). Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'enable', 'disable' or 'reset'", r.Action))), - }.Filter() + }) } -// Validate validates UpdateMFARequest +// Validate validates UpdateMFARequest. func (r UpdateMFARequest) Validate() error { - return validation.Errors{ - "Value": validation.Validate(r.Value, validation.Required, validation.In(MFAAuthentication, TFAAuthentication, NoneAuthentication). - Error(fmt.Sprintf("value '%s' is invalid. Must be one of: 'TFA', 'MFA' or 'NONE'", r.Value))), - }.Filter() + return edgegriderr.ParseValidationErrors(validation.Errors{ + "Value": validation.Validate(r.Value, validation.Required), + }) } func (i *iam) CreateUser(ctx context.Context, params CreateUserRequest) (*User, error) { + logger := i.Log(ctx) + logger.Debug("CreateUser") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrCreateUser, ErrStructValidation, err) } - u, err := url.Parse("/identity-management/v3/user-admin/ui-identities") + uri, err := url.Parse("/identity-management/v3/user-admin/ui-identities") if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateUser, err) } - q := u.Query() + q := uri.Query() q.Add("sendEmail", strconv.FormatBool(params.SendEmail)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateUser, err) } @@ -409,23 +365,26 @@ func (i *iam) CreateUser(ctx context.Context, params CreateUserRequest) (*User, } func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) { + logger := i.Log(ctx) + logger.Debug("GetUser") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrGetUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } - q := u.Query() + q := uri.Query() q.Add("actions", strconv.FormatBool(params.Actions)) q.Add("authGrants", strconv.FormatBool(params.AuthGrants)) q.Add("notifications", strconv.FormatBool(params.Notifications)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetUser, err) } @@ -444,20 +403,23 @@ func (i *iam) GetUser(ctx context.Context, params GetUserRequest) (*User, error) } func (i *iam) ListUsers(ctx context.Context, params ListUsersRequest) ([]UserListItem, error) { - u, err := url.Parse("/identity-management/v3/user-admin/ui-identities") + logger := i.Log(ctx) + logger.Debug("ListUsers") + + uri, err := url.Parse("/identity-management/v3/user-admin/ui-identities") if err != nil { return nil, fmt.Errorf("%w: failed to parse the URL:\n%s", ErrListUsers, err) } - q := u.Query() + q := uri.Query() q.Add("actions", strconv.FormatBool(params.Actions)) q.Add("authGrants", strconv.FormatBool(params.AuthGrants)) if params.GroupID != nil { q.Add("groupId", strconv.FormatInt(*params.GroupID, 10)) } - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request:\n%s", ErrListUsers, err) } @@ -476,16 +438,19 @@ func (i *iam) ListUsers(ctx context.Context, params ListUsersRequest) ([]UserLis } func (i *iam) RemoveUser(ctx context.Context, params RemoveUserRequest) error { + logger := i.Log(ctx) + logger.Debug("RemoveUser") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrRemoveUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveUser, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodDelete, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrRemoveUser, err) } @@ -503,16 +468,19 @@ func (i *iam) RemoveUser(ctx context.Context, params RemoveUserRequest) error { } func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGrantsRequest) ([]AuthGrant, error) { + logger := i.Log(ctx) + logger.Debug("UpdateUserAuthGrants") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserAuthGrants, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/auth-grants", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/auth-grants", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserAuthGrants, err) } @@ -532,22 +500,25 @@ func (i *iam) UpdateUserAuthGrants(ctx context.Context, params UpdateUserAuthGra } func (i *iam) UpdateUserInfo(ctx context.Context, params UpdateUserInfoRequest) (*UserBasicInfo, error) { + logger := i.Log(ctx) + logger.Debug("UpdateUserInfo") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserInfo, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/basic-info", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/basic-info", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserInfo, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserInfo, err) } - var rval UserBasicInfo - resp, err := i.Exec(req, &rval, params.User) + var result UserBasicInfo + resp, err := i.Exec(req, &result, params.User) if err != nil { return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateUserInfo, err) } @@ -556,20 +527,23 @@ func (i *iam) UpdateUserInfo(ctx context.Context, params UpdateUserInfoRequest) return nil, fmt.Errorf("%s: %w", ErrUpdateUserInfo, i.Error(resp)) } - return &rval, nil + return &result, nil } func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNotificationsRequest) (*UserNotifications, error) { + logger := i.Log(ctx) + logger.Debug("UpdateUserNotifications") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateUserNotifications, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/notifications", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/notifications", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateUserNotifications, err) } @@ -588,20 +562,23 @@ func (i *iam) UpdateUserNotifications(ctx context.Context, params UpdateUserNoti } func (i *iam) UpdateTFA(ctx context.Context, params UpdateTFARequest) error { + logger := i.Log(ctx) + logger.Debug("UpdateTFA") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrUpdateTFA, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/tfa", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v2/user-admin/ui-identities/%s/tfa", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateTFA, err) } - q := u.Query() + q := uri.Query() q.Add("action", string(params.Action)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateTFA, err) } @@ -619,16 +596,19 @@ func (i *iam) UpdateTFA(ctx context.Context, params UpdateTFARequest) error { } func (i *iam) UpdateMFA(ctx context.Context, params UpdateMFARequest) error { + logger := i.Log(ctx) + logger.Debug("UpdateMFA") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrUpdateMFA, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUpdateMFA, err) } @@ -646,13 +626,15 @@ func (i *iam) UpdateMFA(ctx context.Context, params UpdateMFARequest) error { } func (i *iam) ResetMFA(ctx context.Context, params ResetMFARequest) error { + logger := i.Log(ctx) + logger.Debug("ResetMFA") - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication/reset", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/additionalAuthentication/reset", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrResetMFA, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrResetMFA, err) } diff --git a/pkg/iam/user_lock.go b/pkg/iam/user_lock.go index 3028bbb3..5e05f435 100644 --- a/pkg/iam/user_lock.go +++ b/pkg/iam/user_lock.go @@ -7,67 +7,58 @@ import ( "net/http" "net/url" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // UserLock is the IAM user lock/unlock API interface - UserLock interface { - // LockUser locks the user - // - // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-lock - LockUser(context.Context, LockUserRequest) error - - // UnlockUser releases the lock on a user's account - // - // See: https://techdocs.akamai.com/iam-api/reference/post-ui-identity-unlock - UnlockUser(context.Context, UnlockUserRequest) error - } - - // LockUserRequest contains the request parameters of the lock user endpoint + // LockUserRequest contains the request parameters for the LockUser endpoint. LockUserRequest struct { IdentityID string } - // UnlockUserRequest contains the request parameters of the unlock user endpoint + // UnlockUserRequest contains the request parameters for the UnlockUser endpoint. UnlockUserRequest struct { IdentityID string } ) var ( - // ErrLockUser is returned when LockUser fails + // ErrLockUser is returned when LockUser fails. ErrLockUser = errors.New("lock user") - // ErrUnlockUser is returned when UnlockUser fails + // ErrUnlockUser is returned when UnlockUser fails. ErrUnlockUser = errors.New("unlock user") ) -// Validate validates LockUserRequest +// Validate validates LockUserRequest. func (r LockUserRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + }) } -// Validate validates UnlockUserRequest +// Validate validates UnlockUserRequest. func (r UnlockUserRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + }) } func (i *iam) LockUser(ctx context.Context, params LockUserRequest) error { + logger := i.Log(ctx) + logger.Debug("LockUser") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrLockUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/lock", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/lock", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrLockUser, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrLockUser, err) } @@ -85,16 +76,19 @@ func (i *iam) LockUser(ctx context.Context, params LockUserRequest) error { } func (i *iam) UnlockUser(ctx context.Context, params UnlockUserRequest) error { + logger := i.Log(ctx) + logger.Debug("UnlockUser") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrUnlockUser, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/unlock", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/unlock", params.IdentityID)) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUnlockUser, err) } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrUnlockUser, err) } diff --git a/pkg/iam/user_lock_test.go b/pkg/iam/user_lock_test.go index fd6194c1..66672593 100644 --- a/pkg/iam/user_lock_test.go +++ b/pkg/iam/user_lock_test.go @@ -86,19 +86,19 @@ func TestIAM_LockUser(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.LockUser(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.LockUser(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -181,19 +181,19 @@ func TestIAM_UnlockUser(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.UnlockUser(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.UnlockUser(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/iam/user_password.go b/pkg/iam/user_password.go index 0fb4d5c2..a58adc86 100644 --- a/pkg/iam/user_password.go +++ b/pkg/iam/user_password.go @@ -8,37 +8,23 @@ import ( "net/url" "strconv" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) type ( - // UserPassword is the IAM managing user's password API interface - UserPassword interface { - // ResetUserPassword optionally sends a one-time use password to the user. - // If you send the email with the password directly to the user, the response for this operation doesn't include that password. - // If you don't send the password to the user through email, the password is included in the response. - // - // See: https://techdocs.akamai.com/iam-api/reference/post-reset-password - ResetUserPassword(context.Context, ResetUserPasswordRequest) (*ResetUserPasswordResponse, error) - - // SetUserPassword sets a specific password for a user - // - // See: https://techdocs.akamai.com/iam-api/reference/post-set-password - SetUserPassword(context.Context, SetUserPasswordRequest) error - } - - // ResetUserPasswordRequest contains the request parameters of the reset user password endpoint + // ResetUserPasswordRequest contains the request parameters for the ResetUserPassword endpoint. ResetUserPasswordRequest struct { IdentityID string SendEmail bool } - // ResetUserPasswordResponse contains the response from the reset user password endpoint + // ResetUserPasswordResponse contains the response from the ResetUserPassword endpoint. ResetUserPasswordResponse struct { NewPassword string `json:"newPassword"` } - // SetUserPasswordRequest contains the request parameters of the set user password endpoint + // SetUserPasswordRequest contains the request parameters for the SetUserPassword endpoint. SetUserPasswordRequest struct { IdentityID string `json:"-"` NewPassword string `json:"newPassword"` @@ -46,43 +32,46 @@ type ( ) var ( - // ErrResetUserPassword is returned when ResetUserPassword fails + // ErrResetUserPassword is returned when ResetUserPassword fails. ErrResetUserPassword = errors.New("reset user password") - // ErrSetUserPassword is returned when SetUserPassword fails + // ErrSetUserPassword is returned when SetUserPassword fails. ErrSetUserPassword = errors.New("set user password") ) -// Validate validates ResetUserPasswordRequest +// Validate validates ResetUserPasswordRequest. func (r ResetUserPasswordRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), - }.Filter() + }) } -// Validate validates SetUserPasswordRequest +// Validate validates SetUserPasswordRequest. func (r SetUserPasswordRequest) Validate() error { - return validation.Errors{ + return edgegriderr.ParseValidationErrors(validation.Errors{ "IdentityID": validation.Validate(r.IdentityID, validation.Required), "NewPassword": validation.Validate(r.NewPassword, validation.Required), - }.Filter() + }) } func (i *iam) ResetUserPassword(ctx context.Context, params ResetUserPasswordRequest) (*ResetUserPasswordResponse, error) { + logger := i.Log(ctx) + logger.Debug("ResetUserPassword") + if err := params.Validate(); err != nil { return nil, fmt.Errorf("%s: %w:\n%s", ErrResetUserPassword, ErrStructValidation, err) } - u, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/reset-password", params.IdentityID)) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/reset-password", params.IdentityID)) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrResetUserPassword, err) } - q := u.Query() + q := uri.Query() q.Add("sendEmail", strconv.FormatBool(params.SendEmail)) - u.RawQuery = q.Encode() + uri.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return nil, fmt.Errorf("%w: failed to create request: %s", ErrResetUserPassword, err) } @@ -101,13 +90,19 @@ func (i *iam) ResetUserPassword(ctx context.Context, params ResetUserPasswordReq } func (i *iam) SetUserPassword(ctx context.Context, params SetUserPasswordRequest) error { + logger := i.Log(ctx) + logger.Debug("SetUserPassword") + if err := params.Validate(); err != nil { return fmt.Errorf("%s: %w:\n%s", ErrSetUserPassword, ErrStructValidation, err) } - u := fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/set-password", params.IdentityID) + uri, err := url.Parse(fmt.Sprintf("/identity-management/v3/user-admin/ui-identities/%s/set-password", params.IdentityID)) + if err != nil { + return fmt.Errorf("%w: failed to parse url: %s", ErrSetUserPassword, err) + } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil) if err != nil { return fmt.Errorf("%w: failed to create request: %s", ErrSetUserPassword, err) } diff --git a/pkg/iam/user_password_test.go b/pkg/iam/user_password_test.go index da5e4b77..3492b878 100644 --- a/pkg/iam/user_password_test.go +++ b/pkg/iam/user_password_test.go @@ -3,7 +3,7 @@ package iam import ( "context" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -95,23 +95,23 @@ func TestIAM_ResetUserPassword(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - response, err := client.ResetUserPassword(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + response, err := client.ResetUserPassword(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, *response) + assert.Equal(t, tc.expectedResponse, *response) }) } } @@ -214,25 +214,25 @@ func TestIAM_SetUserPassword(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) - if len(test.expectedRequestBody) > 0 { - body, err := ioutil.ReadAll(r.Body) + if len(tc.expectedRequestBody) > 0 { + body, err := io.ReadAll(r.Body) require.NoError(t, err) - assert.Equal(t, test.expectedRequestBody, string(body)) + assert.Equal(t, tc.expectedRequestBody, string(body)) } })) client := mockAPIClient(t, mockServer) - err := client.SetUserPassword(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.SetUserPassword(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index 48ae507c..2f73f062 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -133,7 +133,7 @@ func TestIAM_CreateUser(t *testing.T) { "validation errors": { params: CreateUserRequest{}, withError: func(t *testing.T, err error) { - assert.Equal(t, "create user: struct validation:\nAdditionalAuthentication: cannot be blank; AuthGrants: cannot be blank; Country: cannot be blank; Email: cannot be blank; FirstName: cannot be blank; LastName: cannot be blank.", err.Error()) + assert.Equal(t, "create user: struct validation:\nAdditionalAuthentication: cannot be blank\nAuthGrants: cannot be blank\nCountry: cannot be blank\nEmail: cannot be blank\nFirstName: cannot be blank\nLastName: cannot be blank", err.Error()) }, }, "500 internal server error": { @@ -170,30 +170,30 @@ func TestIAM_CreateUser(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPost, r.Method) - w.WriteHeader(test.responseStatus) - if test.requestBody != "" { + w.WriteHeader(tc.responseStatus) + if tc.requestBody != "" { buf := new(bytes.Buffer) _, err := buf.ReadFrom(r.Body) assert.NoError(t, err) req := buf.String() - assert.Equal(t, test.requestBody, req) + assert.Equal(t, tc.requestBody, req) } - _, err := w.Write([]byte(test.responseBody)) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.CreateUser(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.CreateUser(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -264,28 +264,28 @@ func TestIAM_GetUser(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.GetUser(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.GetUser(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } -func TestIam_ListUsers(t *testing.T) { +func TestIAM_ListUsers(t *testing.T) { tests := map[string]struct { params ListUsersRequest responseStatus int @@ -480,23 +480,23 @@ func TestIam_ListUsers(t *testing.T) { }, }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - users, err := client.ListUsers(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + users, err := client.ListUsers(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } assert.NoError(t, err) - assert.Equal(t, test.expectedResponse, users) + assert.Equal(t, tc.expectedResponse, users) }) } } @@ -596,30 +596,30 @@ func TestIAM_UpdateUserInfo(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - if test.requestBody != "" { + if tc.requestBody != "" { buf := new(bytes.Buffer) _, err := buf.ReadFrom(r.Body) assert.NoError(t, err) req := buf.String() - assert.Equal(t, test.requestBody, req) + assert.Equal(t, tc.requestBody, req) } - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateUserInfo(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.UpdateUserInfo(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -719,30 +719,30 @@ func TestIAM_UpdateUserNotifications(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - if test.requestBody != "" { + if tc.requestBody != "" { buf := new(bytes.Buffer) _, err := buf.ReadFrom(r.Body) assert.NoError(t, err) req := buf.String() - assert.Equal(t, test.requestBody, req) + assert.Equal(t, tc.requestBody, req) } - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateUserNotifications(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.UpdateUserNotifications(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -833,23 +833,23 @@ func TestIAM_UpdateUserAuthGrants(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - result, err := client.UpdateUserAuthGrants(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + result, err := client.UpdateUserAuthGrants(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) - assert.Equal(t, test.expectedResponse, result) + assert.Equal(t, tc.expectedResponse, result) }) } } @@ -903,19 +903,19 @@ func TestIAM_RemoveUser(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodDelete, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.RemoveUser(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.RemoveUser(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -966,19 +966,19 @@ func TestIAM_UpdateTFA(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.UpdateTFA(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.UpdateTFA(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -1029,19 +1029,19 @@ func TestIAM_UpdateMFA(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.UpdateMFA(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.UpdateMFA(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) @@ -1090,19 +1090,19 @@ func TestIAM_ResetMFA(t *testing.T) { }, } - for name, test := range tests { + for name, tc := range tests { t.Run(name, func(t *testing.T) { mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, test.expectedPath, r.URL.String()) + assert.Equal(t, tc.expectedPath, r.URL.String()) assert.Equal(t, http.MethodPut, r.Method) - w.WriteHeader(test.responseStatus) - _, err := w.Write([]byte(test.responseBody)) + w.WriteHeader(tc.responseStatus) + _, err := w.Write([]byte(tc.responseBody)) assert.NoError(t, err) })) client := mockAPIClient(t, mockServer) - err := client.ResetMFA(context.Background(), test.params) - if test.withError != nil { - test.withError(t, err) + err := client.ResetMFA(context.Background(), tc.params) + if tc.withError != nil { + tc.withError(t, err) return } require.NoError(t, err) From 7489eae57938c16a6696b2cbe7000b09c1f936c9 Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Fri, 27 Sep 2024 11:25:41 +0000 Subject: [PATCH 32/34] DXE-4233 CHANGELOG cleanup --- CHANGELOG.md | 458 +++++++++++---------------------------------------- 1 file changed, 93 insertions(+), 365 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31dee3a9..d60f0ea4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,185 +1,24 @@ # RELEASE NOTES -## X.X.X (X X, X) +## 9.0.0 (Oct 3, 2024) #### BREAKING CHANGES: -* IAM - * Migrated V2 endpoints to V3. - * Added new methods: - * [UpdateMFA](https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication) - * [ResetMFA](https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication) - - - - -* IAM - * Improved date handling to use `time.Time` instead of `string` - * Changed fields in following structures: - * `Users` - * `LastLoginDate` changed type from `string` to `time.Time` - * `PasswordExpiryDate` changed type from `string` to `time.Time` - * `UserListItem` - * `LastLoginDate` changed type from `string` to `time.Time` - * `Role` - * `CreatedDate` changed type from `string` to `time.Time` - * `ModifiedDate` changed type from `string` to `time.Time` - * `RoleUser` - * `LastLoginDate` changed type from `string` to `time.Time` - * `GroupUser` - * `LastLoginDate` changed type from `string` to `time.Time` - - - -* IAM - * Changed `Notifications` to pointer type in following structures: - * `CreateUserRequest` - * `UpdateUserNotificationsRequest` - * Added `UsertStatus`, `AccountID` to the `User` structure - * Added required field `AdditionalAuthentication` to the `CreateUserRequest` - * Made `Notifications` required in `UpdateUserNotifications` method - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#### FEATURES/ENHANCEMENTS: - - - - -* IAM - * Added API Clients Credentials methods - * [CreateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credentials) and [CreateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credentials) - * [GetYourCredential](https://techdocs.akamai.com/iam-api/reference/get-self-credential) and [GetCredential](https://techdocs.akamai.com/iam-api/reference/get-client-credential) - * [UpdateYourCredential](https://techdocs.akamai.com/iam-api/reference/put-self-credential) and [UpdateCredential](https://techdocs.akamai.com/iam-api/reference/put-client-credential) - * [DeleteYourCredential](https://techdocs.akamai.com/iam-api/reference/delete-self-credential) and [DeleteCredential](https://techdocs.akamai.com/iam-api/reference/delete-client-credential) - * [ListYourCredentials](https://techdocs.akamai.com/iam-api/reference/get-self-credentials) and [ListCredentials](https://techdocs.akamai.com/iam-api/reference/get-client-credentials) - * [DeactivateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate) and [DeactivateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate) - * [DeactivateYourCredentials](https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate) and [DeactivateCredentials](https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate) - - - - - - - - -* IAM - * Added method to get the password policy for the account - * [GetPasswordPolicy](https://techdocs.akamai.com/iam-api/reference/get-common-password-policy) - - - - - - - -# EDGEGRID GOLANG RELEASE NOTES - -## X.X.X (X X, X) - -#### BREAKING CHANGES: - - * General * Consolidated multiple sub-interfaces into a single interface for each sub-provider. - - - - - - - - - - - - - - - - - -* Global * Removed `tools` package in favour of `ptr` package -* EDGEKV - * For `CreateEdgeKVAccessTokenRequest` removed `Expiry` and added `RestrictToEdgeWorkerIDs` - * For `CreateEdgeKVAccessTokenResponse` removed `Expiry`, `Value` and added - * `AllowOnProduction` - * `AllowOnStaging` - * `CPCode` - * `IssueDate` - * `LatestRefreshDate` - * `NamespacePermissions` - * `NextScheduledRefreshDate` - * `RestrictToEdgeWorkerIDs` - * `TokenActivationStatus` - * For `EdgeKVAccessToken` added fields: - * `TokenActivationStatus` - * `IssueDate` - * `LatestRefreshDate` - * `NextScheduledRefreshDate` - - - - - * Cloudaccess - * Changed naming of request body fields for following structures: + * Changed naming of request body fields for following structures: * `BodyParams` to `Body` in `CreateAccessKeyVersionRequest` * `CreateAccessKeyVersionBodyParams` to `CreateAccessKeyVersionRequestBody` - - * Cloudlets * Changed naming of request body fields for following structures: * `BodyParams` to `Body` in `UpdatePolicyRequest` and `ClonePolicyRequest` * `UpdatePolicyBodyParams` to `UpdatePolicyRequestBody` * `ClonePolicyBodyParams` to `ClonePolicyRequestBody` - - - * Cloudwrapper * Changed naming of request body fields for following structures: * `CreateConfigurationBody` to `CreateConfigurationRequestBody` @@ -222,7 +61,6 @@ * `CreateBulkZones` - from (context.Context, *BulkZonesCreate, ZoneQueryString) into (context.Context, `CreateBulkZonesRequest`) * `DeleteBulkZones` - from (context.Context, *ZoneNameListResponse, ...bool) into (context.Context, `DeleteBulkZonesRequest`) * `GetRdata` - from (context.Context, string, string, string) into (context.Context, `GetRdataRequest`) - * Refactored response in following methods: * `GetAuthorities` - `*AuthorityResponse` into `*GetAuthoritiesResponse` * `GetRecord` - `*RecordBody` into `*GetRecordResponse` @@ -242,7 +80,6 @@ * `GetBulkZoneDeleteResult` - `*BulkDeleteResultResponse` into `*GetBulkZoneDeleteResultResponse` * `CreateBulkZones` - `*BulkZonesResponse` into `*CreateBulkZonesResponse` * `DeleteBulkZones` - `*BulkZonesResponse` into `*DeleteBulkZonesResponse` - * Removed following interfaces: * `Authorities` * `Data` @@ -250,14 +87,35 @@ * `Recordsets` * `TSIGKeys` * `Zones` - * Renamed following methods: * `SaveChangelist` into `SaveChangeList` * `SubmitChangelist` into `SubmitChangeList` * `TSIGKeyBulkUpdate` into `UpdateTSIGKeyBulk` +* EdgeKV + * For the `CreateEdgeKVAccessTokenRequest`, removed the `Expiry` field and added the `RestrictToEdgeWorkerIDs` field. + * For the `CreateEdgeKVAccessTokenResponse`, removed the `Expiry` and `Value` fields, and added these fields: + * `AllowOnProduction` + * `AllowOnStaging` + * `CPCode` + * `IssueDate` + * `LatestRefreshDate` + * `NamespacePermissions` + * `NextScheduledRefreshDate` + * `RestrictToEdgeWorkerIDs` + * `TokenActivationStatus` + * Added these fields to the `EdgeKVAccessToken` method: + * `TokenActivationStatus` + * `IssueDate` + * `LatestRefreshDate` + * `NextScheduledRefreshDate` + +* Edgeworkers + * Changed naming of request body fields for these structures: + * `EdgeWorkerIDBodyRequest` to `EdgeWorkerIDRequestBody` + * GTM - * Refactored parameters in following methods: + * Refactored parameters in these methods: * `ListASMaps` - from (context.Context, string) into (context.Context, `ListASMapsRequest`) * `GetASMap` - from (context.Context, string, string) into (context.Context, `GetASMapRequests`) * `CreateASMap` - from (context.Context, *ASMap, string) into (context.Context, `CreateASMapRequest`) @@ -292,9 +150,8 @@ * `GetResource` - from (context.Context, string, string) into (context.Context, `GetResourceRequest`) * `CreateResource` - from (context.Context, *Resource, string) into (context.Context, `CreateResourceRequest`) * `UpdateResource` - from (context.Context, *Resource, string) into (context.Context, `UpdateResourceRequest`) - * `DeleteResource` - from (context.Context, *Resource, string) into (context.Context, `DeleteResourceRequest`) - - * Refactored response in following methods: + * `DeleteResource` - from (context.Context, *Resource, string) into (context.Context, `DeleteResourceRequest`) + * Refactored response in these methods: * `ListASMaps` - `[]*ASMap` into `[]ASMap` * `GetASMap` - `*ASMap` into `*GetASMapResponse` * `CreateASMap` - `*ASMapResponse` into `*CreateASMapResponse` @@ -330,8 +187,7 @@ * `CreateResource` - `*ResourceResponse` into `*CreateResourceResponse` * `UpdateResource` - `*ResponseStatus` into `*UpdateResourceResponse` * `DeleteResource` - `*ResponseStatus` into `*DeleteResourceResponse` - - * Extended response for following methods - previously only status was returned, now status and resource are returned: + * Extended response for these methods - previously only status was returned, now status and resource are returned: * `UpdateASMap` * `DeleteASMap` * `UpdateCIDRMap` @@ -345,8 +201,7 @@ * `DeleteProperty` * `UpdateResource` * `DeleteResource` - - * Removed following interfaces: + * Removed these interfaces: * `ASMaps` * `CIDRMaps` * `Datacenters` @@ -355,44 +210,40 @@ * `Properties` * `Resources` -* Edgeworkers - * Changed naming of request body fields for following structures: - * `EdgeWorkerIDBodyRequest` to `EdgeWorkerIDRequestBody` - - - - - - - - - - - - -#### FEATURES/ENHANCEMENTS: +* IAM + * Migrated V2 endpoints to V3. + * Improved date handling to use `time.Time` instead of `string`. + * Changed fields in these structures: + * `Users` + * `LastLoginDate`. Changed the field data type from `string` to `time.Time` + * `PasswordExpiryDate`. Changed the field data type from `string` to `time.Time` + * `UserListItem` + * `LastLoginDate`. Changed the field data type from `string` to `time.Time` + * `Role` + * `CreatedDate`. Changed the field data type from `string` to `time.Time` + * `ModifiedDate`. Changed the field data type from `string` to `time.Time` + * `RoleUser` + * `LastLoginDate`. Changed the field data type from `string` to `time.Time` + * `GroupUser` + * `LastLoginDate`. Changed the field data type from `string` to `time.Time` + * Changed the `Notifications` field to a pointer type in these structures: + * `CreateUserRequest` + * `UpdateUserNotificationsRequest` + * Added the required `AdditionalAuthentication` field to the `CreateUserRequest` method. + * Made the `Notifications` field required in the `UpdateUserNotifications` method. * PAPI - * Removed `rule_format` and `product_id` from `Property` struct as this information is populated from `GetPropertyVersion` - - - - + * Removed the `rule_format` and `product_id` fields from the `Property` structure, as this information is populated in the `GetPropertyVersion` method. +#### FEATURES/ENHANCEMENTS: * APPSEC - * Added field `Exceptions` in the following structures: + * Added the `Exceptions` field to these structures: * `GetSiemSettingsResponse` * `GetSiemSettingResponse` * `UpdateSiemSettingsRequest` * `UpdateSiemSettingsResponse` - - * Added field `Source` in `GetExportConfigurationRequest` and field `TargetProduct` in `GetExportConfigurationResponse` - - - - - + * Added the `Source` field to the `GetExportConfigurationRequest` method and the `TargetProduct` field to the `GetExportConfigurationResponse` method. * IAM * Updated structures: @@ -401,103 +252,38 @@ * `UserBasicInfo` with `AdditionalAuthentication` * `UserActions` with `CanGenerateBypassCode` * `UserNotificationOptions` with `APIClientCredentialExpiry` - - - - - - - - - - - - - - - - - - - - - - - -* IAM + * Added new methods: + * [UpdateMFA](https://techdocs.akamai.com/iam-api/reference/put-user-profile-additional-authentication) + * [ResetMFA](https://techdocs.akamai.com/iam-api/reference/put-ui-identity-reset-additional-authentication) + * Added API Client Credentials methods: + * [CreateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credentials) and [CreateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credentials) + * [GetYourCredential](https://techdocs.akamai.com/iam-api/reference/get-self-credential) and [GetCredential](https://techdocs.akamai.com/iam-api/reference/get-client-credential) + * [UpdateYourCredential](https://techdocs.akamai.com/iam-api/reference/put-self-credential) and [UpdateCredential](https://techdocs.akamai.com/iam-api/reference/put-client-credential) + * [DeleteYourCredential](https://techdocs.akamai.com/iam-api/reference/delete-self-credential) and [DeleteCredential](https://techdocs.akamai.com/iam-api/reference/delete-client-credential) + * [ListYourCredentials](https://techdocs.akamai.com/iam-api/reference/get-self-credentials) and [ListCredentials](https://techdocs.akamai.com/iam-api/reference/get-client-credentials) + * [DeactivateYourCredential](https://techdocs.akamai.com/iam-api/reference/post-self-credential-deactivate) and [DeactivateCredential](https://techdocs.akamai.com/iam-api/reference/post-client-credential-deactivate) + * [DeactivateYourCredentials](https://techdocs.akamai.com/iam-api/reference/post-self-credentials-deactivate) and [DeactivateCredentials](https://techdocs.akamai.com/iam-api/reference/post-client-credentials-deactivate) + * Added the `UserStatus` and `AccountID` parameters to the `User` structure. + * Added the [GetPasswordPolicy](https://techdocs.akamai.com/iam-api/reference/get-common-password-policy) method to get a password policy for an account. * Added Helper APIs * [ListAllowedCPCodes](https://techdocs.akamai.com/iam-api/reference/post-api-clients-users-allowed-cpcodes) - -* IAM - * Added Helper APIs - * [ListAuthorizedUsers](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users) - * [ListAllowedAPIs](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis) - * [ListAccessibleGroups](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access) - -* IAM - * Added new methods: - * [ListUsersForProperty](https://techdocs.akamai.com/iam-api/reference/get-property-users) - * [BlockUsers](https://techdocs.akamai.com/iam-api/reference/put-property-users-block) - - - - -* IAM - * Added support for new endpoints: - * [DisableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable) - * [EnableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable) - * [GetIPAllowlistStatus](https://techdocs.akamai.com/iam-api/reference/get-allowlist-status) - - - - - - - - -* IAM + * [ListAuthorizedUsers](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users) + * [ListAllowedAPIs](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-allowed-apis) + * [ListAccessibleGroups](https://techdocs.akamai.com/iam-api/reference/get-api-clients-users-group-access) * Added new methods: + * [ListUsersForProperty](https://techdocs.akamai.com/iam-api/reference/get-property-users) + * [BlockUsers](https://techdocs.akamai.com/iam-api/reference/put-property-users-block) + * [DisableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-disable) + * [EnableIPAllowlist](https://techdocs.akamai.com/iam-api/reference/post-allowlist-enable) + * [GetIPAllowlistStatus](https://techdocs.akamai.com/iam-api/reference/get-allowlist-status) * `ListAccountSwitchKeys` based on [ListAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-client-account-switch-keys) and [ListYourAccountSwitchKeys](https://techdocs.akamai.com/iam-api/reference/get-self-account-switch-keys) * `LockAPIClient` based on [LockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client) and [LockYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-lock-api-client-self) * [UnlockAPIClient](https://techdocs.akamai.com/iam-api/reference/put-unlock-api-client) - - - - - - - - - - -* IAM - * Added new methods: * [ListAPIClients](https://techdocs.akamai.com/iam-api/reference/get-api-clients) * [CreateAPIClient](https://techdocs.akamai.com/iam-api/reference/post-api-clients) * `GetAPIClient` based on [GetAPIClient](https://techdocs.akamai.com/iam-api/reference/get-api-client) and [GetYourAPIClient](https://techdocs.akamai.com/iam-api/reference/get-api-client-self) * `UpdateAPIClient` based on [UpdateAPIClient](https://techdocs.akamai.com/iam-api/reference/put-api-clients) and [UpdateYourAPIClient](https://techdocs.akamai.com/iam-api/reference/put-api-clients-self) * `DeleteAPIClient` based on [DeleteAPIClient](https://techdocs.akamai.com/iam-api/reference/delete-api-client) and [DeleteYourAPIClient](https://techdocs.akamai.com/iam-api/reference/delete-api-client-self) - - - - - - - - - - - - - - - - - - - -* IAM - * Add support for new methods: * [ListCIDRBlocks](https://techdocs.akamai.com/iam-api/reference/get-allowlist) * [CreateCIDRBlock](https://techdocs.akamai.com/iam-api/reference/post-allowlist) * [GetCIDRBlock](https://techdocs.akamai.com/iam-api/reference/get-allowlist-cidrblockid) @@ -505,71 +291,13 @@ * [DeleteCIDRBlock](https://techdocs.akamai.com/iam-api/reference/delete-allowlist-cidrblockid) * [ValidateCIDRBlock](https://techdocs.akamai.com/iam-api/reference/get-allowlist-validate) - - - - - - - - - - - - - - - - - - - - - - - - - - - -#### BUG FIXES: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## 8.4.0 (Aug 22, 2024) #### FEATURES/ENHANCEMENTS: * APPSEC * Added field `ClientLists` to `RuleConditions` and `AttackGroupConditions` - * The `RequestBodyInspectionLimitOverride` field has been added in the following structures: + * The `RequestBodyInspectionLimitOverride` field has been added in these structures: * `GetAdvancedSettingsRequestBodyResponse`, * `UpdateAdvancedSettingsRequestBodyRequest`, * `UpdateAdvancedSettingsRequestBodyResponse`, @@ -632,7 +360,7 @@ #### Deprecations -* Deprecated the following functions in the `tools` package. Use `ptr.To` instead. +* Deprecated these functions in the `tools` package. Use `ptr.To` instead. * `BoolPtr` * `IntPtr` * `Int64Ptr` @@ -658,7 +386,7 @@ #### BUG FIXES: * APPSEC - * The `Override` field in the following structs has been updated from a pointer to a value type within the `AdvancedSettingsAttackPayloadLogging` interface: + * The `Override` field in these structs has been updated from a pointer to a value type within the `AdvancedSettingsAttackPayloadLogging` interface: * `GetAdvancedSettingsAttackPayloadLoggingResponse`, * `UpdateAdvancedSettingsAttackPayloadLoggingResponse`, * `RemoveAdvancedSettingsAttackPayloadLoggingRequest`, @@ -690,12 +418,12 @@ * Split request and response structures for create and update enrollment operations * DNS - * Renamed following structs: + * Renamed these structs: * `RecordsetQueryArgs` into `RecordSetQueryArgs` * `Recordsets` into `RecordSets` * `Recordset` into `RecordSet` * `MetadataH` into `Metadata` - * Renamed following fields: + * Renamed these fields: * `GroupId` into `GroupID` in `ListGroupRequest` * `Recordsets` into `RecordSets` in `RecordSetResponse` * `ContractIds` into `ContractIDs` in `TSIGQueryString` @@ -704,7 +432,7 @@ * `VersionId` into `VersionID` in `ZoneResponse` * `RequestId` into `RequestID` in `BulkZonesResponse`, `BulkStatusResponse`, `BulkCreateResultResponse` and `BulkDeleteResultResponse` * Renamed `RecordSets` interface into `Recordsets` - * Renamed following methods: + * Renamed these methods: * `ListTsigKeys` into `ListTSIGKeys` * `GetTsigKeyZones` into `GetTSIGKeyZones` * `GetTsigKeyAliases` into `GetTSIGKeyAliases` @@ -715,7 +443,7 @@ * `GetRecordsets` into `GetRecordSets` * `CreateRecordsets` into `CreateRecordSets` * `UpdateRecordsets` into `UpdateRecordSets` - * Deleted following methods: + * Deleted these methods: * `NewAuthorityResponse` * `NewChangeListResponse` * `NewRecordBody` @@ -726,13 +454,13 @@ * `NewZoneQueryString` * `NewZoneResponse` * `RecordToMap` - * Unexported following methods: + * Unexported these methods: * `FullIPv6` * `PadCoordinates` * `ValidateZone` * GTM - * Renamed following structs: + * Renamed these structs: * `AsAssignment` into `ASAssignment` * `AsMap` into `ASMap` * `AsMapList` into `ASMapList` @@ -742,7 +470,7 @@ * `CidrMapResponse` into `CIDRMapResponse` * `AsMapResponse` into `ASMapResponse` * `HttpHeader` into `HTTPHeader` - * Renamed following fields: + * Renamed these fields: * `AsNumbers` into `ASNumbers` in `ASAssignment` * `AsMapItems` into `ASMapItems` in `ASMapList` * `CidrMapItems` into `CIDRMapItems` in `CIDRMapList` @@ -763,7 +491,7 @@ * `Ipv6` into `IPv6` in `Property` * `BackupIp` into `BackupIP` in `Property` * Renamed `CidrMaps` interface into `CIDRMaps` - * Renamed following methods: + * Renamed these methods: * `ListAsMaps` into `ListASMaps` * `GetAsMap` into `GetASMap` * `CreateAsMap` into `CreateASMap` @@ -774,7 +502,7 @@ * `CreateCidrMap` into `CreateCIDRMap` * `DeleteCidrMap` into `DeleteCIDRMap` * `UpdateCidrMap` into `UpdateCIDRMap` - * Deleted following methods: + * Deleted these methods: * `NewASAssignment` * `NewAsMap` * `NewCidrAssignment` @@ -985,7 +713,7 @@ ### Deprecations * Challenge Interceptions Rules has been deprecated -* Deprecate the following interfaces used to maintain individual policy protections: +* Deprecate these interfaces used to maintain individual policy protections: * `ApiConstraintsProtection` * `IPGeoProtection` * `MalwareProtection` @@ -1063,7 +791,7 @@ ### FEATURES/ENHANCEMENTS: * APPSEC - * Added following BotManager fields to GetExportConfigurationResponse + * Added these BotManager fields to GetExportConfigurationResponse * BotManagement * CustomBotCategories * CustomDefinedBots @@ -1089,7 +817,7 @@ * [GetAvailableBehaviors](https://techdocs.akamai.com/property-mgr/reference/get-available-behaviors) * CPS - * Update `Accept` header to the latest schema `application/vnd.akamai.cps.enrollment.v11+json` for the following endpoints: + * Update `Accept` header to the latest schema `application/vnd.akamai.cps.enrollment.v11+json` for these endpoints: * [ListEnrollments](https://techdocs.akamai.com/cps/reference/get-enrollments) * [GetEnrollment](https://techdocs.akamai.com/cps/reference/get-enrollment) @@ -1201,7 +929,7 @@ * MalwarePolicyAction * MalwareProtection * Add GetRuleRecommendations method to TuningRecommendations interface - * Add deprecation notes for the following: + * Add deprecation notes for these: * methods: * GetIPGeoProtections * GetNetworkLayerProtections @@ -1437,7 +1165,7 @@ #### BREAKING CHANGES: * APPSEC - * The following have been removed, togther with their unit tests and test data: + * The following have been removed, together with their unit tests and test data: * pkg/appsec/attack_group_action.go * pkg/appsec/attack_group_condition_exception.go * pkg/appsec/eval_rule_action.go @@ -1481,7 +1209,7 @@ ## 2.3.0 (Mar 15, 2021) Network Lists -Add support for the following operations in the Network Lists API v2: +Add support for the these operations in the Network Lists API v2: * Create a network list * Update an existing network list From dfbb832126a1626342bb2c6baf59e5e31d0aea70 Mon Sep 17 00:00:00 2001 From: Michal Wojcik Date: Fri, 27 Sep 2024 13:08:52 +0000 Subject: [PATCH 33/34] DXE-4233 Update to v9 --- .github/workflows/checks.yml | 1 + README.md | 10 +++++----- go.mod | 2 +- pkg/appsec/activations_test.go | 2 +- pkg/appsec/advanced_settings_attack_payload_logging.go | 2 +- .../advanced_settings_attack_payload_logging_test.go | 2 +- .../advanced_settings_evasive_path_match_test.go | 2 +- pkg/appsec/advanced_settings_logging_test.go | 2 +- pkg/appsec/advanced_settings_pii_learning.go | 2 +- pkg/appsec/advanced_settings_pii_learning_test.go | 2 +- pkg/appsec/advanced_settings_pragma_test.go | 2 +- pkg/appsec/advanced_settings_prefetch_test.go | 2 +- pkg/appsec/advanced_settings_request_body.go | 2 +- pkg/appsec/advanced_settings_request_body_test.go | 2 +- pkg/appsec/api_constraints_protection_test.go | 2 +- pkg/appsec/api_endpoints_test.go | 2 +- pkg/appsec/api_hostname_coverage_match_targets_test.go | 2 +- pkg/appsec/api_hostname_coverage_overlapping_test.go | 2 +- pkg/appsec/api_hostname_coverage_test.go | 2 +- pkg/appsec/api_request_constraints_test.go | 2 +- pkg/appsec/appsec.go | 2 +- pkg/appsec/appsec_test.go | 4 ++-- pkg/appsec/attack_group_test.go | 2 +- pkg/appsec/configuration_clone_test.go | 2 +- pkg/appsec/configuration_test.go | 2 +- pkg/appsec/configuration_version_clone_test.go | 2 +- pkg/appsec/configuration_version_test.go | 2 +- pkg/appsec/custom_deny_test.go | 2 +- pkg/appsec/custom_rule_action_test.go | 2 +- pkg/appsec/custom_rule_test.go | 2 +- pkg/appsec/errors.go | 2 +- pkg/appsec/errors_test.go | 2 +- pkg/appsec/eval_group_test.go | 2 +- pkg/appsec/eval_penalty_box_conditions_test.go | 2 +- pkg/appsec/eval_penalty_box_test.go | 2 +- pkg/appsec/eval_rule_test.go | 2 +- pkg/appsec/eval_test.go | 2 +- pkg/appsec/export_configuration.go | 2 +- pkg/appsec/export_configuration_test.go | 2 +- pkg/appsec/failover_hostnames_test.go | 2 +- pkg/appsec/ip_geo_protection_test.go | 2 +- pkg/appsec/ip_geo_test.go | 2 +- pkg/appsec/malware_policy_action_test.go | 2 +- pkg/appsec/malware_policy_test.go | 2 +- pkg/appsec/malware_protection_test.go | 2 +- pkg/appsec/match_target_sequence_test.go | 2 +- pkg/appsec/match_target_test.go | 2 +- pkg/appsec/penalty_box_conditions.go | 2 +- pkg/appsec/penalty_box_conditions_test.go | 2 +- pkg/appsec/penalty_box_test.go | 2 +- pkg/appsec/rate_policy_action_test.go | 2 +- pkg/appsec/rate_policy_test.go | 2 +- pkg/appsec/rate_protection_test.go | 2 +- pkg/appsec/reputation_analysis_test.go | 2 +- pkg/appsec/reputation_profile_action_test.go | 2 +- pkg/appsec/reputation_profile_test.go | 2 +- pkg/appsec/reputation_protection_test.go | 2 +- pkg/appsec/rule_test.go | 2 +- pkg/appsec/rule_upgrade_test.go | 2 +- pkg/appsec/security_policy.go | 2 +- pkg/appsec/security_policy_clone_test.go | 2 +- pkg/appsec/security_policy_protections_test.go | 2 +- pkg/appsec/security_policy_test.go | 2 +- pkg/appsec/selectable_hostnames_test.go | 2 +- pkg/appsec/selected_hostname_test.go | 2 +- pkg/appsec/siem_settings_test.go | 2 +- pkg/appsec/slow_post_protection_setting_test.go | 2 +- pkg/appsec/slowpost_protection_test.go | 2 +- pkg/appsec/threat_intel_test.go | 2 +- pkg/appsec/tuning_recommendations_test.go | 2 +- pkg/appsec/version_notes_test.go | 2 +- pkg/appsec/waf_mode_test.go | 2 +- pkg/appsec/waf_protection_test.go | 2 +- pkg/appsec/wap_bypass_network_lists_test.go | 2 +- pkg/appsec/wap_selected_hostnames_test.go | 2 +- pkg/botman/akamai_bot_category_action_test.go | 2 +- pkg/botman/akamai_bot_category_test.go | 2 +- pkg/botman/akamai_defined_bot_test.go | 2 +- pkg/botman/bot_analytics_cookie_test.go | 2 +- pkg/botman/bot_analytics_cookie_values_test.go | 2 +- pkg/botman/bot_category_exception_test.go | 2 +- pkg/botman/bot_detection_action_test.go | 2 +- pkg/botman/bot_detection_test.go | 2 +- pkg/botman/bot_endpoint_coverage_report_test.go | 2 +- pkg/botman/bot_management_setting_test.go | 2 +- pkg/botman/botman.go | 2 +- pkg/botman/botman_test.go | 4 ++-- pkg/botman/challenge_action_test.go | 2 +- pkg/botman/challenge_injection_rules.go | 2 +- pkg/botman/challenge_injection_rules_test.go | 2 +- pkg/botman/challenge_interception_rules_test.go | 2 +- pkg/botman/client_side_security_test.go | 2 +- pkg/botman/conditonal_action_test.go | 2 +- ...ontent_protection_javascript_injection_rule_test.go | 2 +- pkg/botman/content_protection_rule_sequence_test.go | 2 +- pkg/botman/content_protection_rule_test.go | 2 +- pkg/botman/custom_bot_category_action_test.go | 2 +- pkg/botman/custom_bot_category_item_sequence.go | 2 +- pkg/botman/custom_bot_category_item_sequence_test.go | 2 +- pkg/botman/custom_bot_category_sequence_test.go | 2 +- pkg/botman/custom_bot_category_test.go | 2 +- pkg/botman/custom_client_sequence.go | 2 +- pkg/botman/custom_client_sequence_test.go | 2 +- pkg/botman/custom_client_test.go | 2 +- pkg/botman/custom_code_test.go | 2 +- pkg/botman/custom_defined_bot_test.go | 2 +- pkg/botman/custom_deny_action_test.go | 2 +- pkg/botman/errors.go | 2 +- pkg/botman/errors_test.go | 2 +- pkg/botman/javascript_injection_test.go | 2 +- pkg/botman/recategorized_akamai_defined_bot_test.go | 2 +- pkg/botman/response_action_test.go | 2 +- pkg/botman/serve_alternate_action_test.go | 2 +- pkg/botman/transactional_endpoint_protection_test.go | 2 +- pkg/botman/transactional_endpoint_test.go | 2 +- pkg/clientlists/client_list.go | 2 +- pkg/clientlists/client_list_activation.go | 2 +- pkg/clientlists/client_list_activation_test.go | 2 +- pkg/clientlists/client_list_test.go | 4 ++-- pkg/clientlists/clientlists.go | 2 +- pkg/clientlists/clientlists_test.go | 4 ++-- pkg/clientlists/errors.go | 2 +- pkg/clientlists/errors_test.go | 2 +- pkg/cloudaccess/access_key.go | 2 +- pkg/cloudaccess/access_key_version.go | 2 +- pkg/cloudaccess/cloudaccess.go | 2 +- pkg/cloudaccess/cloudaccess_test.go | 4 ++-- pkg/cloudaccess/errors.go | 2 +- pkg/cloudaccess/errors_test.go | 2 +- pkg/cloudaccess/properties.go | 2 +- pkg/cloudaccess/properties_test.go | 2 +- pkg/cloudlets/cloudlets.go | 2 +- pkg/cloudlets/cloudlets_test.go | 4 ++-- pkg/cloudlets/errors.go | 2 +- pkg/cloudlets/errors_test.go | 2 +- pkg/cloudlets/loadbalancer.go | 2 +- pkg/cloudlets/loadbalancer_activation.go | 2 +- pkg/cloudlets/loadbalancer_activation_test.go | 2 +- pkg/cloudlets/loadbalancer_version.go | 2 +- pkg/cloudlets/loadbalancer_version_test.go | 2 +- pkg/cloudlets/match_rule.go | 2 +- pkg/cloudlets/match_rule_test.go | 2 +- pkg/cloudlets/policy_property.go | 2 +- pkg/cloudlets/policy_test.go | 2 +- pkg/cloudlets/policy_version.go | 2 +- pkg/cloudlets/policy_version_activation.go | 2 +- pkg/cloudlets/policy_version_test.go | 2 +- pkg/cloudlets/v3/cloudlets.go | 2 +- pkg/cloudlets/v3/cloudlets_test.go | 4 ++-- pkg/cloudlets/v3/errors.go | 2 +- pkg/cloudlets/v3/errors_test.go | 2 +- pkg/cloudlets/v3/match_rule.go | 2 +- pkg/cloudlets/v3/match_rule_test.go | 2 +- pkg/cloudlets/v3/policy.go | 2 +- pkg/cloudlets/v3/policy_activation.go | 2 +- pkg/cloudlets/v3/policy_activation_test.go | 4 ++-- pkg/cloudlets/v3/policy_property.go | 2 +- pkg/cloudlets/v3/policy_test.go | 4 ++-- pkg/cloudlets/v3/policy_version.go | 2 +- pkg/cloudlets/v3/policy_version_test.go | 4 ++-- pkg/cloudwrapper/cloudwrapper.go | 2 +- pkg/cloudwrapper/cloudwrapper_test.go | 4 ++-- pkg/cloudwrapper/configurations.go | 2 +- pkg/cloudwrapper/configurations_test.go | 2 +- pkg/cloudwrapper/errors.go | 2 +- pkg/cloudwrapper/errors_test.go | 2 +- pkg/cloudwrapper/multi_cdn.go | 2 +- pkg/cloudwrapper/properties.go | 2 +- pkg/cps/change_management_info_test.go | 2 +- pkg/cps/cps.go | 2 +- pkg/cps/cps_test.go | 4 ++-- pkg/cps/deployment_schedules_test.go | 2 +- pkg/cps/deployments_test.go | 2 +- pkg/cps/enrollments_test.go | 2 +- pkg/cps/errors_test.go | 2 +- pkg/cps/third_party_csr.go | 2 +- pkg/datastream/ds.go | 2 +- pkg/datastream/ds_test.go | 4 ++-- pkg/datastream/errors.go | 2 +- pkg/datastream/errors_test.go | 2 +- pkg/datastream/properties_test.go | 2 +- pkg/datastream/stream_test.go | 2 +- pkg/dns/authorities.go | 2 +- pkg/dns/dns.go | 2 +- pkg/dns/dns_test.go | 4 ++-- pkg/dns/errors.go | 2 +- pkg/dns/errors_test.go | 2 +- pkg/dns/record.go | 2 +- pkg/dns/record_lookup.go | 2 +- pkg/dns/record_lookup_test.go | 2 +- pkg/dns/recordsets.go | 2 +- pkg/dns/tsig.go | 2 +- pkg/dns/zone.go | 2 +- pkg/dns/zone_test.go | 4 ++-- pkg/dns/zonebulk.go | 2 +- pkg/dns/zonebulk_test.go | 2 +- pkg/edgeworkers/edgekv_access_tokens_test.go | 2 +- pkg/edgeworkers/edgekv_groups.go | 2 +- pkg/edgeworkers/edgekv_namespaces_test.go | 2 +- pkg/edgeworkers/edgeworkers.go | 2 +- pkg/edgeworkers/edgeworkers_test.go | 4 ++-- pkg/edgeworkers/errors.go | 2 +- pkg/edgeworkers/errors_test.go | 2 +- pkg/edgeworkers/report_test.go | 2 +- pkg/gtm/asmap.go | 2 +- pkg/gtm/asmap_test.go | 2 +- pkg/gtm/cidrmap.go | 2 +- pkg/gtm/cidrmap_test.go | 2 +- pkg/gtm/datacenter.go | 2 +- pkg/gtm/datacenter_test.go | 2 +- pkg/gtm/domain.go | 2 +- pkg/gtm/domain_test.go | 2 +- pkg/gtm/errors.go | 2 +- pkg/gtm/errors_test.go | 2 +- pkg/gtm/geomap.go | 2 +- pkg/gtm/geomap_test.go | 2 +- pkg/gtm/gtm.go | 2 +- pkg/gtm/gtm_test.go | 4 ++-- pkg/gtm/property.go | 2 +- pkg/gtm/property_test.go | 4 ++-- pkg/gtm/resource.go | 2 +- pkg/gtm/resource_test.go | 2 +- pkg/hapi/edgehostname.go | 2 +- pkg/hapi/edgehostname_test.go | 2 +- pkg/hapi/errors.go | 2 +- pkg/hapi/errors_test.go | 2 +- pkg/hapi/hapi.go | 2 +- pkg/hapi/hapi_test.go | 4 ++-- pkg/iam/api_clients.go | 2 +- pkg/iam/api_clients_credentials.go | 2 +- pkg/iam/api_clients_credentials_test.go | 4 ++-- pkg/iam/api_clients_test.go | 2 +- pkg/iam/blocked_properties.go | 2 +- pkg/iam/cidr.go | 2 +- pkg/iam/cidr_test.go | 4 ++-- pkg/iam/errors.go | 2 +- pkg/iam/errors_test.go | 2 +- pkg/iam/groups.go | 2 +- pkg/iam/groups_test.go | 2 +- pkg/iam/helper.go | 2 +- pkg/iam/iam.go | 2 +- pkg/iam/iam_test.go | 4 ++-- pkg/iam/properties.go | 2 +- pkg/iam/properties_test.go | 4 ++-- pkg/iam/roles.go | 2 +- pkg/iam/roles_test.go | 2 +- pkg/iam/support.go | 2 +- pkg/iam/user.go | 2 +- pkg/iam/user_lock.go | 2 +- pkg/iam/user_password.go | 2 +- pkg/iam/user_test.go | 4 ++-- pkg/imaging/errors.go | 2 +- pkg/imaging/errors_test.go | 2 +- pkg/imaging/imaging.go | 2 +- pkg/imaging/imaging_test.go | 4 ++-- pkg/imaging/policy.go | 2 +- pkg/imaging/policy_test.go | 2 +- pkg/imaging/policyset.go | 2 +- pkg/networklists/activations_test.go | 2 +- pkg/networklists/errors.go | 2 +- pkg/networklists/errors_test.go | 2 +- pkg/networklists/network_list_description_test.go | 2 +- pkg/networklists/network_list_subscription_test.go | 2 +- pkg/networklists/network_list_test.go | 2 +- pkg/networklists/networklists.go | 2 +- pkg/networklists/networklists_test.go | 4 ++-- pkg/papi/cpcode_test.go | 2 +- pkg/papi/edgehostname.go | 2 +- pkg/papi/errors.go | 2 +- pkg/papi/errors_test.go | 4 ++-- pkg/papi/include.go | 2 +- pkg/papi/include_activations.go | 4 ++-- pkg/papi/include_rule.go | 2 +- pkg/papi/include_rule_test.go | 2 +- pkg/papi/include_test.go | 2 +- pkg/papi/include_versions.go | 2 +- pkg/papi/papi.go | 2 +- pkg/papi/papi_test.go | 4 ++-- pkg/papi/property.go | 2 +- pkg/papi/property_test.go | 2 +- pkg/papi/propertyversion.go | 2 +- pkg/papi/propertyversion_test.go | 2 +- pkg/papi/rule.go | 2 +- pkg/papi/rule_test.go | 2 +- pkg/session/request_test.go | 2 +- pkg/session/session.go | 4 ++-- pkg/session/session_test.go | 4 ++-- 287 files changed, 322 insertions(+), 321 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 7538a57a..35b96152 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -12,6 +12,7 @@ on: - v5 - v6 - v7 + - v8 - master jobs: test: diff --git a/README.md b/README.md index 1dd3e2fa..814c4d22 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Akamai OPEN EdgeGrid for GoLang v8 +# Akamai OPEN EdgeGrid for GoLang v9 ![Build Status](https://github.com/akamai/akamaiOPEN-edgegrid-golang/actions/workflows/checks.yml/badge.svg) -[![Go Report Card](https://goreportcard.com/badge/github.com/akamai/AkamaiOPEN-edgegrid-golang/v8)](https://goreportcard.com/report/github.com/akamai/AkamaiOPEN-edgegrid-golang/v8) +[![Go Report Card](https://goreportcard.com/badge/github.com/akamai/AkamaiOPEN-edgegrid-golang/v9)](https://goreportcard.com/report/github.com/akamai/AkamaiOPEN-edgegrid-golang/v9) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/akamai/akamaiOPEN-edgegrid-golang) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![GoDoc](https://pkg.go.dev/badge/github.com/akamai/akamaiOPEN-edgegrid-golang?utm_source=godoc)](https://pkg.go.dev/github.com/akamai/AkamaiOPEN-edgegrid-golang/v8) +[![GoDoc](https://pkg.go.dev/badge/github.com/akamai/akamaiOPEN-edgegrid-golang?utm_source=godoc)](https://pkg.go.dev/github.com/akamai/AkamaiOPEN-edgegrid-golang/v9) This module is presently in active development and provides Akamai REST API support for the Akamai Terraform Provider. @@ -12,7 +12,7 @@ This module is presently in active development and provides Akamai REST API supp This module is not backward compatible with the version `v1`. -Originally branch `master` was representing version `v1`. Now it is representing the latest version `v8` and +Originally branch `master` was representing version `v1`. Now it is representing the latest version `v9` and version `v1` was moved to dedicated `v1` branch. @@ -23,6 +23,6 @@ The packages of library can be imported alongside the `v1` library versions with ``` import ( papiv1 "github.com/akamai/AkamaiOPEN-edgegrid-golang/papi-v1" - papi "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/papi" + papi "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/papi" ) ``` diff --git a/go.mod b/go.mod index a4b26851..af7a1d2b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/akamai/AkamaiOPEN-edgegrid-golang/v8 +module github.com/akamai/AkamaiOPEN-edgegrid-golang/v9 go 1.21 diff --git a/pkg/appsec/activations_test.go b/pkg/appsec/activations_test.go index a6bdb983..b2a3bb8f 100644 --- a/pkg/appsec/activations_test.go +++ b/pkg/appsec/activations_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_attack_payload_logging.go b/pkg/appsec/advanced_settings_attack_payload_logging.go index 539bfb22..b72bad52 100644 --- a/pkg/appsec/advanced_settings_attack_payload_logging.go +++ b/pkg/appsec/advanced_settings_attack_payload_logging.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/advanced_settings_attack_payload_logging_test.go b/pkg/appsec/advanced_settings_attack_payload_logging_test.go index d2aabdb9..dda9664b 100644 --- a/pkg/appsec/advanced_settings_attack_payload_logging_test.go +++ b/pkg/appsec/advanced_settings_attack_payload_logging_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_evasive_path_match_test.go b/pkg/appsec/advanced_settings_evasive_path_match_test.go index e4aea961..a0fc8cd4 100644 --- a/pkg/appsec/advanced_settings_evasive_path_match_test.go +++ b/pkg/appsec/advanced_settings_evasive_path_match_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_logging_test.go b/pkg/appsec/advanced_settings_logging_test.go index f4c6570d..81d27ca5 100644 --- a/pkg/appsec/advanced_settings_logging_test.go +++ b/pkg/appsec/advanced_settings_logging_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_pii_learning.go b/pkg/appsec/advanced_settings_pii_learning.go index c6649efa..f4b9e5f7 100644 --- a/pkg/appsec/advanced_settings_pii_learning.go +++ b/pkg/appsec/advanced_settings_pii_learning.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/advanced_settings_pii_learning_test.go b/pkg/appsec/advanced_settings_pii_learning_test.go index 4d80ab4e..6bf2cb07 100644 --- a/pkg/appsec/advanced_settings_pii_learning_test.go +++ b/pkg/appsec/advanced_settings_pii_learning_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_pragma_test.go b/pkg/appsec/advanced_settings_pragma_test.go index 6826a8d8..428778bc 100644 --- a/pkg/appsec/advanced_settings_pragma_test.go +++ b/pkg/appsec/advanced_settings_pragma_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_prefetch_test.go b/pkg/appsec/advanced_settings_prefetch_test.go index 9ad00a7f..d961084a 100644 --- a/pkg/appsec/advanced_settings_prefetch_test.go +++ b/pkg/appsec/advanced_settings_prefetch_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/advanced_settings_request_body.go b/pkg/appsec/advanced_settings_request_body.go index 0228c5b2..68be4b02 100644 --- a/pkg/appsec/advanced_settings_request_body.go +++ b/pkg/appsec/advanced_settings_request_body.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/advanced_settings_request_body_test.go b/pkg/appsec/advanced_settings_request_body_test.go index e85eba2c..4eea315d 100644 --- a/pkg/appsec/advanced_settings_request_body_test.go +++ b/pkg/appsec/advanced_settings_request_body_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_constraints_protection_test.go b/pkg/appsec/api_constraints_protection_test.go index 1fdca331..90dbf797 100644 --- a/pkg/appsec/api_constraints_protection_test.go +++ b/pkg/appsec/api_constraints_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_endpoints_test.go b/pkg/appsec/api_endpoints_test.go index e86c8434..fa4ce5a8 100644 --- a/pkg/appsec/api_endpoints_test.go +++ b/pkg/appsec/api_endpoints_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_hostname_coverage_match_targets_test.go b/pkg/appsec/api_hostname_coverage_match_targets_test.go index 75745d47..dd9642e0 100644 --- a/pkg/appsec/api_hostname_coverage_match_targets_test.go +++ b/pkg/appsec/api_hostname_coverage_match_targets_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_hostname_coverage_overlapping_test.go b/pkg/appsec/api_hostname_coverage_overlapping_test.go index e7901175..fb574831 100644 --- a/pkg/appsec/api_hostname_coverage_overlapping_test.go +++ b/pkg/appsec/api_hostname_coverage_overlapping_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_hostname_coverage_test.go b/pkg/appsec/api_hostname_coverage_test.go index ef345e44..2ffb92b9 100644 --- a/pkg/appsec/api_hostname_coverage_test.go +++ b/pkg/appsec/api_hostname_coverage_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/api_request_constraints_test.go b/pkg/appsec/api_request_constraints_test.go index b39feae6..416326ba 100644 --- a/pkg/appsec/api_request_constraints_test.go +++ b/pkg/appsec/api_request_constraints_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/appsec.go b/pkg/appsec/appsec.go index cf935b83..ae94d2f0 100644 --- a/pkg/appsec/appsec.go +++ b/pkg/appsec/appsec.go @@ -4,7 +4,7 @@ package appsec import ( "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/appsec/appsec_test.go b/pkg/appsec/appsec_test.go index 268ab76b..1058dbcb 100644 --- a/pkg/appsec/appsec_test.go +++ b/pkg/appsec/appsec_test.go @@ -12,8 +12,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/attack_group_test.go b/pkg/appsec/attack_group_test.go index 7c46d2b3..00592b6d 100644 --- a/pkg/appsec/attack_group_test.go +++ b/pkg/appsec/attack_group_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/configuration_clone_test.go b/pkg/appsec/configuration_clone_test.go index 04e8eeb9..faaad4d0 100644 --- a/pkg/appsec/configuration_clone_test.go +++ b/pkg/appsec/configuration_clone_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/configuration_test.go b/pkg/appsec/configuration_test.go index c3571d37..1a76acab 100644 --- a/pkg/appsec/configuration_test.go +++ b/pkg/appsec/configuration_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/configuration_version_clone_test.go b/pkg/appsec/configuration_version_clone_test.go index a42e60dd..570564e4 100644 --- a/pkg/appsec/configuration_version_clone_test.go +++ b/pkg/appsec/configuration_version_clone_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/configuration_version_test.go b/pkg/appsec/configuration_version_test.go index a604f7d3..a5f692a5 100644 --- a/pkg/appsec/configuration_version_test.go +++ b/pkg/appsec/configuration_version_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/custom_deny_test.go b/pkg/appsec/custom_deny_test.go index 2abfadd3..b4927e17 100644 --- a/pkg/appsec/custom_deny_test.go +++ b/pkg/appsec/custom_deny_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/custom_rule_action_test.go b/pkg/appsec/custom_rule_action_test.go index c28b166e..87976a58 100644 --- a/pkg/appsec/custom_rule_action_test.go +++ b/pkg/appsec/custom_rule_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/custom_rule_test.go b/pkg/appsec/custom_rule_test.go index ff2f98ab..647e6d97 100644 --- a/pkg/appsec/custom_rule_test.go +++ b/pkg/appsec/custom_rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/errors.go b/pkg/appsec/errors.go index 77bf0f4c..a56849ad 100644 --- a/pkg/appsec/errors.go +++ b/pkg/appsec/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) var ( diff --git a/pkg/appsec/errors_test.go b/pkg/appsec/errors_test.go index 9f5c6f68..1b4b3061 100644 --- a/pkg/appsec/errors_test.go +++ b/pkg/appsec/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/appsec/eval_group_test.go b/pkg/appsec/eval_group_test.go index 19c36874..d9e813c0 100644 --- a/pkg/appsec/eval_group_test.go +++ b/pkg/appsec/eval_group_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/eval_penalty_box_conditions_test.go b/pkg/appsec/eval_penalty_box_conditions_test.go index 59f22b86..bad209ef 100644 --- a/pkg/appsec/eval_penalty_box_conditions_test.go +++ b/pkg/appsec/eval_penalty_box_conditions_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/eval_penalty_box_test.go b/pkg/appsec/eval_penalty_box_test.go index ccb1eb1c..03fc31b9 100644 --- a/pkg/appsec/eval_penalty_box_test.go +++ b/pkg/appsec/eval_penalty_box_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/eval_rule_test.go b/pkg/appsec/eval_rule_test.go index 16267999..512ca28d 100644 --- a/pkg/appsec/eval_rule_test.go +++ b/pkg/appsec/eval_rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/eval_test.go b/pkg/appsec/eval_test.go index 2aa50739..26756398 100644 --- a/pkg/appsec/eval_test.go +++ b/pkg/appsec/eval_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/export_configuration.go b/pkg/appsec/export_configuration.go index e4a1456c..98cde722 100644 --- a/pkg/appsec/export_configuration.go +++ b/pkg/appsec/export_configuration.go @@ -11,7 +11,7 @@ import ( "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/export_configuration_test.go b/pkg/appsec/export_configuration_test.go index fdcefe6b..b5fec0ef 100644 --- a/pkg/appsec/export_configuration_test.go +++ b/pkg/appsec/export_configuration_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/failover_hostnames_test.go b/pkg/appsec/failover_hostnames_test.go index 328f866b..e33a99a2 100644 --- a/pkg/appsec/failover_hostnames_test.go +++ b/pkg/appsec/failover_hostnames_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/ip_geo_protection_test.go b/pkg/appsec/ip_geo_protection_test.go index bac1fa93..d43038f0 100644 --- a/pkg/appsec/ip_geo_protection_test.go +++ b/pkg/appsec/ip_geo_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/ip_geo_test.go b/pkg/appsec/ip_geo_test.go index a0dea382..18ba7410 100644 --- a/pkg/appsec/ip_geo_test.go +++ b/pkg/appsec/ip_geo_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/malware_policy_action_test.go b/pkg/appsec/malware_policy_action_test.go index 17816941..1dd7ee8c 100644 --- a/pkg/appsec/malware_policy_action_test.go +++ b/pkg/appsec/malware_policy_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/malware_policy_test.go b/pkg/appsec/malware_policy_test.go index 6046dd65..2d722654 100644 --- a/pkg/appsec/malware_policy_test.go +++ b/pkg/appsec/malware_policy_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/malware_protection_test.go b/pkg/appsec/malware_protection_test.go index 21e79d49..d1367b0f 100644 --- a/pkg/appsec/malware_protection_test.go +++ b/pkg/appsec/malware_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/match_target_sequence_test.go b/pkg/appsec/match_target_sequence_test.go index 75e6b023..211a871d 100644 --- a/pkg/appsec/match_target_sequence_test.go +++ b/pkg/appsec/match_target_sequence_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/match_target_test.go b/pkg/appsec/match_target_test.go index 74edbc99..c6979f0a 100644 --- a/pkg/appsec/match_target_test.go +++ b/pkg/appsec/match_target_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/penalty_box_conditions.go b/pkg/appsec/penalty_box_conditions.go index ddb1894c..849d6c3c 100644 --- a/pkg/appsec/penalty_box_conditions.go +++ b/pkg/appsec/penalty_box_conditions.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/penalty_box_conditions_test.go b/pkg/appsec/penalty_box_conditions_test.go index 94a8ae17..4feb24cf 100644 --- a/pkg/appsec/penalty_box_conditions_test.go +++ b/pkg/appsec/penalty_box_conditions_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/penalty_box_test.go b/pkg/appsec/penalty_box_test.go index b583a338..dbf42aaf 100644 --- a/pkg/appsec/penalty_box_test.go +++ b/pkg/appsec/penalty_box_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/rate_policy_action_test.go b/pkg/appsec/rate_policy_action_test.go index 6ac39d21..f3471fb6 100644 --- a/pkg/appsec/rate_policy_action_test.go +++ b/pkg/appsec/rate_policy_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/rate_policy_test.go b/pkg/appsec/rate_policy_test.go index 1ed7ae9a..b12f835b 100644 --- a/pkg/appsec/rate_policy_test.go +++ b/pkg/appsec/rate_policy_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/rate_protection_test.go b/pkg/appsec/rate_protection_test.go index fab78eb0..cd72d5b6 100644 --- a/pkg/appsec/rate_protection_test.go +++ b/pkg/appsec/rate_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/reputation_analysis_test.go b/pkg/appsec/reputation_analysis_test.go index 37ba4902..0a1d014e 100644 --- a/pkg/appsec/reputation_analysis_test.go +++ b/pkg/appsec/reputation_analysis_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/reputation_profile_action_test.go b/pkg/appsec/reputation_profile_action_test.go index 985a3c6a..26115e57 100644 --- a/pkg/appsec/reputation_profile_action_test.go +++ b/pkg/appsec/reputation_profile_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/reputation_profile_test.go b/pkg/appsec/reputation_profile_test.go index 0369cfa0..7099d6ae 100644 --- a/pkg/appsec/reputation_profile_test.go +++ b/pkg/appsec/reputation_profile_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/reputation_protection_test.go b/pkg/appsec/reputation_protection_test.go index 49624695..3dbda7ec 100644 --- a/pkg/appsec/reputation_protection_test.go +++ b/pkg/appsec/reputation_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/rule_test.go b/pkg/appsec/rule_test.go index 77a392b4..9d146aae 100644 --- a/pkg/appsec/rule_test.go +++ b/pkg/appsec/rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/rule_upgrade_test.go b/pkg/appsec/rule_upgrade_test.go index 10d4272f..ae26399e 100644 --- a/pkg/appsec/rule_upgrade_test.go +++ b/pkg/appsec/rule_upgrade_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/security_policy.go b/pkg/appsec/security_policy.go index 983a3677..56546423 100644 --- a/pkg/appsec/security_policy.go +++ b/pkg/appsec/security_policy.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/appsec/security_policy_clone_test.go b/pkg/appsec/security_policy_clone_test.go index a2641353..955cca37 100644 --- a/pkg/appsec/security_policy_clone_test.go +++ b/pkg/appsec/security_policy_clone_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/security_policy_protections_test.go b/pkg/appsec/security_policy_protections_test.go index 60c0ca6d..375d9fbe 100644 --- a/pkg/appsec/security_policy_protections_test.go +++ b/pkg/appsec/security_policy_protections_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/security_policy_test.go b/pkg/appsec/security_policy_test.go index be104ed0..b8a30e19 100644 --- a/pkg/appsec/security_policy_test.go +++ b/pkg/appsec/security_policy_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/selectable_hostnames_test.go b/pkg/appsec/selectable_hostnames_test.go index 1f10fe64..598345ca 100644 --- a/pkg/appsec/selectable_hostnames_test.go +++ b/pkg/appsec/selectable_hostnames_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/selected_hostname_test.go b/pkg/appsec/selected_hostname_test.go index cb16f4fa..bfdb5a64 100644 --- a/pkg/appsec/selected_hostname_test.go +++ b/pkg/appsec/selected_hostname_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/siem_settings_test.go b/pkg/appsec/siem_settings_test.go index 6240673d..46ae4835 100644 --- a/pkg/appsec/siem_settings_test.go +++ b/pkg/appsec/siem_settings_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/slow_post_protection_setting_test.go b/pkg/appsec/slow_post_protection_setting_test.go index 0aafcdee..a9e02c47 100644 --- a/pkg/appsec/slow_post_protection_setting_test.go +++ b/pkg/appsec/slow_post_protection_setting_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/slowpost_protection_test.go b/pkg/appsec/slowpost_protection_test.go index 723f45a6..9c85f805 100644 --- a/pkg/appsec/slowpost_protection_test.go +++ b/pkg/appsec/slowpost_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/threat_intel_test.go b/pkg/appsec/threat_intel_test.go index 93f394d3..548114cd 100644 --- a/pkg/appsec/threat_intel_test.go +++ b/pkg/appsec/threat_intel_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/tuning_recommendations_test.go b/pkg/appsec/tuning_recommendations_test.go index 4ff76065..7e83a293 100644 --- a/pkg/appsec/tuning_recommendations_test.go +++ b/pkg/appsec/tuning_recommendations_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/version_notes_test.go b/pkg/appsec/version_notes_test.go index 2f2cf363..4298b900 100644 --- a/pkg/appsec/version_notes_test.go +++ b/pkg/appsec/version_notes_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/waf_mode_test.go b/pkg/appsec/waf_mode_test.go index 72039ec9..03dcdcd0 100644 --- a/pkg/appsec/waf_mode_test.go +++ b/pkg/appsec/waf_mode_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/waf_protection_test.go b/pkg/appsec/waf_protection_test.go index 47e64983..18a4ff69 100644 --- a/pkg/appsec/waf_protection_test.go +++ b/pkg/appsec/waf_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/wap_bypass_network_lists_test.go b/pkg/appsec/wap_bypass_network_lists_test.go index 26475963..3ff0943b 100644 --- a/pkg/appsec/wap_bypass_network_lists_test.go +++ b/pkg/appsec/wap_bypass_network_lists_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/appsec/wap_selected_hostnames_test.go b/pkg/appsec/wap_selected_hostnames_test.go index 14e7d349..05077cdc 100644 --- a/pkg/appsec/wap_selected_hostnames_test.go +++ b/pkg/appsec/wap_selected_hostnames_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/akamai_bot_category_action_test.go b/pkg/botman/akamai_bot_category_action_test.go index 9f2debe8..16090f14 100644 --- a/pkg/botman/akamai_bot_category_action_test.go +++ b/pkg/botman/akamai_bot_category_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/akamai_bot_category_test.go b/pkg/botman/akamai_bot_category_test.go index b202d4fb..f39f0811 100644 --- a/pkg/botman/akamai_bot_category_test.go +++ b/pkg/botman/akamai_bot_category_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/akamai_defined_bot_test.go b/pkg/botman/akamai_defined_bot_test.go index 54eeb483..b728938d 100644 --- a/pkg/botman/akamai_defined_bot_test.go +++ b/pkg/botman/akamai_defined_bot_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_analytics_cookie_test.go b/pkg/botman/bot_analytics_cookie_test.go index 823db04c..c4eb2372 100644 --- a/pkg/botman/bot_analytics_cookie_test.go +++ b/pkg/botman/bot_analytics_cookie_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_analytics_cookie_values_test.go b/pkg/botman/bot_analytics_cookie_values_test.go index c4f08a19..26f43ae1 100644 --- a/pkg/botman/bot_analytics_cookie_values_test.go +++ b/pkg/botman/bot_analytics_cookie_values_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_category_exception_test.go b/pkg/botman/bot_category_exception_test.go index 2b1bbbe1..ebba6474 100644 --- a/pkg/botman/bot_category_exception_test.go +++ b/pkg/botman/bot_category_exception_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/pkg/botman/bot_detection_action_test.go b/pkg/botman/bot_detection_action_test.go index ec06a913..abe45b27 100644 --- a/pkg/botman/bot_detection_action_test.go +++ b/pkg/botman/bot_detection_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_detection_test.go b/pkg/botman/bot_detection_test.go index 9e5454e9..363fc9fa 100644 --- a/pkg/botman/bot_detection_test.go +++ b/pkg/botman/bot_detection_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_endpoint_coverage_report_test.go b/pkg/botman/bot_endpoint_coverage_report_test.go index 75c5ef5d..b4c1a3d7 100644 --- a/pkg/botman/bot_endpoint_coverage_report_test.go +++ b/pkg/botman/bot_endpoint_coverage_report_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/bot_management_setting_test.go b/pkg/botman/bot_management_setting_test.go index cd7231f3..3db52706 100644 --- a/pkg/botman/bot_management_setting_test.go +++ b/pkg/botman/bot_management_setting_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/pkg/botman/botman.go b/pkg/botman/botman.go index c5a43329..a43bc033 100644 --- a/pkg/botman/botman.go +++ b/pkg/botman/botman.go @@ -4,7 +4,7 @@ package botman import ( "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/botman/botman_test.go b/pkg/botman/botman_test.go index b30a12ee..b84d3036 100644 --- a/pkg/botman/botman_test.go +++ b/pkg/botman/botman_test.go @@ -12,8 +12,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/challenge_action_test.go b/pkg/botman/challenge_action_test.go index f017d8f2..41a94ebc 100644 --- a/pkg/botman/challenge_action_test.go +++ b/pkg/botman/challenge_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/challenge_injection_rules.go b/pkg/botman/challenge_injection_rules.go index 9d455a5d..019b5785 100644 --- a/pkg/botman/challenge_injection_rules.go +++ b/pkg/botman/challenge_injection_rules.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/botman/challenge_injection_rules_test.go b/pkg/botman/challenge_injection_rules_test.go index 0d4f4743..489d2494 100644 --- a/pkg/botman/challenge_injection_rules_test.go +++ b/pkg/botman/challenge_injection_rules_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/challenge_interception_rules_test.go b/pkg/botman/challenge_interception_rules_test.go index 0f757cd3..cb8b8bc1 100644 --- a/pkg/botman/challenge_interception_rules_test.go +++ b/pkg/botman/challenge_interception_rules_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/client_side_security_test.go b/pkg/botman/client_side_security_test.go index 3fbcc949..6953e6d8 100644 --- a/pkg/botman/client_side_security_test.go +++ b/pkg/botman/client_side_security_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/conditonal_action_test.go b/pkg/botman/conditonal_action_test.go index 0feaeddb..6a143461 100644 --- a/pkg/botman/conditonal_action_test.go +++ b/pkg/botman/conditonal_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/content_protection_javascript_injection_rule_test.go b/pkg/botman/content_protection_javascript_injection_rule_test.go index 3a6fdc7f..7d25d991 100644 --- a/pkg/botman/content_protection_javascript_injection_rule_test.go +++ b/pkg/botman/content_protection_javascript_injection_rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/content_protection_rule_sequence_test.go b/pkg/botman/content_protection_rule_sequence_test.go index 92f7c114..bbf3aee6 100644 --- a/pkg/botman/content_protection_rule_sequence_test.go +++ b/pkg/botman/content_protection_rule_sequence_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/content_protection_rule_test.go b/pkg/botman/content_protection_rule_test.go index c7ecaf97..03e14780 100644 --- a/pkg/botman/content_protection_rule_test.go +++ b/pkg/botman/content_protection_rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_bot_category_action_test.go b/pkg/botman/custom_bot_category_action_test.go index ec230c50..a2477154 100644 --- a/pkg/botman/custom_bot_category_action_test.go +++ b/pkg/botman/custom_bot_category_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_bot_category_item_sequence.go b/pkg/botman/custom_bot_category_item_sequence.go index 1d18cfc7..fef932d6 100644 --- a/pkg/botman/custom_bot_category_item_sequence.go +++ b/pkg/botman/custom_bot_category_item_sequence.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/botman/custom_bot_category_item_sequence_test.go b/pkg/botman/custom_bot_category_item_sequence_test.go index 0463fba2..a90843b8 100644 --- a/pkg/botman/custom_bot_category_item_sequence_test.go +++ b/pkg/botman/custom_bot_category_item_sequence_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_bot_category_sequence_test.go b/pkg/botman/custom_bot_category_sequence_test.go index c7c7719b..00f7d68e 100644 --- a/pkg/botman/custom_bot_category_sequence_test.go +++ b/pkg/botman/custom_bot_category_sequence_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_bot_category_test.go b/pkg/botman/custom_bot_category_test.go index 20508a48..9187db20 100644 --- a/pkg/botman/custom_bot_category_test.go +++ b/pkg/botman/custom_bot_category_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_client_sequence.go b/pkg/botman/custom_client_sequence.go index 5fbfc96b..1a383453 100644 --- a/pkg/botman/custom_client_sequence.go +++ b/pkg/botman/custom_client_sequence.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/botman/custom_client_sequence_test.go b/pkg/botman/custom_client_sequence_test.go index 6b18b426..d2f5ad11 100644 --- a/pkg/botman/custom_client_sequence_test.go +++ b/pkg/botman/custom_client_sequence_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_client_test.go b/pkg/botman/custom_client_test.go index d5cd2758..b02e3bba 100644 --- a/pkg/botman/custom_client_test.go +++ b/pkg/botman/custom_client_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_code_test.go b/pkg/botman/custom_code_test.go index e0d43ba3..9aef73c2 100644 --- a/pkg/botman/custom_code_test.go +++ b/pkg/botman/custom_code_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_defined_bot_test.go b/pkg/botman/custom_defined_bot_test.go index ce4885cf..827da2ae 100644 --- a/pkg/botman/custom_defined_bot_test.go +++ b/pkg/botman/custom_defined_bot_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/custom_deny_action_test.go b/pkg/botman/custom_deny_action_test.go index 68fcabc2..d396f57c 100644 --- a/pkg/botman/custom_deny_action_test.go +++ b/pkg/botman/custom_deny_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/errors.go b/pkg/botman/errors.go index c2c1a306..2279b6dd 100644 --- a/pkg/botman/errors.go +++ b/pkg/botman/errors.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/botman/errors_test.go b/pkg/botman/errors_test.go index 4efa1882..fb856143 100644 --- a/pkg/botman/errors_test.go +++ b/pkg/botman/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" diff --git a/pkg/botman/javascript_injection_test.go b/pkg/botman/javascript_injection_test.go index f7f5f900..4784b343 100644 --- a/pkg/botman/javascript_injection_test.go +++ b/pkg/botman/javascript_injection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/recategorized_akamai_defined_bot_test.go b/pkg/botman/recategorized_akamai_defined_bot_test.go index b51696bc..489655c2 100644 --- a/pkg/botman/recategorized_akamai_defined_bot_test.go +++ b/pkg/botman/recategorized_akamai_defined_bot_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/response_action_test.go b/pkg/botman/response_action_test.go index 47744a23..85609e80 100644 --- a/pkg/botman/response_action_test.go +++ b/pkg/botman/response_action_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/serve_alternate_action_test.go b/pkg/botman/serve_alternate_action_test.go index f9c1ead8..f31e02cd 100644 --- a/pkg/botman/serve_alternate_action_test.go +++ b/pkg/botman/serve_alternate_action_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/transactional_endpoint_protection_test.go b/pkg/botman/transactional_endpoint_protection_test.go index d8120e06..f45fb66c 100644 --- a/pkg/botman/transactional_endpoint_protection_test.go +++ b/pkg/botman/transactional_endpoint_protection_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/botman/transactional_endpoint_test.go b/pkg/botman/transactional_endpoint_test.go index 5541c8f5..b27ba2d2 100644 --- a/pkg/botman/transactional_endpoint_test.go +++ b/pkg/botman/transactional_endpoint_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/clientlists/client_list.go b/pkg/clientlists/client_list.go index 37f455ec..f972a790 100644 --- a/pkg/clientlists/client_list.go +++ b/pkg/clientlists/client_list.go @@ -7,7 +7,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/clientlists/client_list_activation.go b/pkg/clientlists/client_list_activation.go index 466458c6..40f5ddfa 100644 --- a/pkg/clientlists/client_list_activation.go +++ b/pkg/clientlists/client_list_activation.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/clientlists/client_list_activation_test.go b/pkg/clientlists/client_list_activation_test.go index 2c9d807e..aef56b93 100644 --- a/pkg/clientlists/client_list_activation_test.go +++ b/pkg/clientlists/client_list_activation_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/clientlists/client_list_test.go b/pkg/clientlists/client_list_test.go index 9a277407..74353dfc 100644 --- a/pkg/clientlists/client_list_test.go +++ b/pkg/clientlists/client_list_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/clientlists/clientlists.go b/pkg/clientlists/clientlists.go index 72d6e48f..34a6929e 100644 --- a/pkg/clientlists/clientlists.go +++ b/pkg/clientlists/clientlists.go @@ -7,7 +7,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/clientlists/clientlists_test.go b/pkg/clientlists/clientlists_test.go index 7e36a309..d33361cf 100644 --- a/pkg/clientlists/clientlists_test.go +++ b/pkg/clientlists/clientlists_test.go @@ -12,8 +12,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/clientlists/errors.go b/pkg/clientlists/errors.go index 5095c72e..eade8f4e 100644 --- a/pkg/clientlists/errors.go +++ b/pkg/clientlists/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/clientlists/errors_test.go b/pkg/clientlists/errors_test.go index a5bb704d..5a4fc08f 100644 --- a/pkg/clientlists/errors_test.go +++ b/pkg/clientlists/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" diff --git a/pkg/cloudaccess/access_key.go b/pkg/cloudaccess/access_key.go index 73dd6145..f46d864e 100644 --- a/pkg/cloudaccess/access_key.go +++ b/pkg/cloudaccess/access_key.go @@ -8,7 +8,7 @@ import ( "net/url" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudaccess/access_key_version.go b/pkg/cloudaccess/access_key_version.go index 87386f08..a796d161 100644 --- a/pkg/cloudaccess/access_key_version.go +++ b/pkg/cloudaccess/access_key_version.go @@ -7,7 +7,7 @@ import ( "net/http" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudaccess/cloudaccess.go b/pkg/cloudaccess/cloudaccess.go index f4d51d5c..cb207a87 100644 --- a/pkg/cloudaccess/cloudaccess.go +++ b/pkg/cloudaccess/cloudaccess.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/cloudaccess/cloudaccess_test.go b/pkg/cloudaccess/cloudaccess_test.go index 95cf9bc0..919977d0 100644 --- a/pkg/cloudaccess/cloudaccess_test.go +++ b/pkg/cloudaccess/cloudaccess_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudaccess/errors.go b/pkg/cloudaccess/errors.go index f90f14f8..978afba4 100644 --- a/pkg/cloudaccess/errors.go +++ b/pkg/cloudaccess/errors.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/cloudaccess/errors_test.go b/pkg/cloudaccess/errors_test.go index 476037e4..75ba4603 100644 --- a/pkg/cloudaccess/errors_test.go +++ b/pkg/cloudaccess/errors_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudaccess/properties.go b/pkg/cloudaccess/properties.go index 20fe9558..b189e05d 100644 --- a/pkg/cloudaccess/properties.go +++ b/pkg/cloudaccess/properties.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudaccess/properties_test.go b/pkg/cloudaccess/properties_test.go index e2340818..cfc48698 100644 --- a/pkg/cloudaccess/properties_test.go +++ b/pkg/cloudaccess/properties_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/cloudlets.go b/pkg/cloudlets/cloudlets.go index 0ca3414f..9466536b 100644 --- a/pkg/cloudlets/cloudlets.go +++ b/pkg/cloudlets/cloudlets.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/cloudlets/cloudlets_test.go b/pkg/cloudlets/cloudlets_test.go index 341e0394..c02bfcdd 100644 --- a/pkg/cloudlets/cloudlets_test.go +++ b/pkg/cloudlets/cloudlets_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/errors.go b/pkg/cloudlets/errors.go index 993c011b..b1d80e7e 100644 --- a/pkg/cloudlets/errors.go +++ b/pkg/cloudlets/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/cloudlets/errors_test.go b/pkg/cloudlets/errors_test.go index 9511d89e..4d69444e 100644 --- a/pkg/cloudlets/errors_test.go +++ b/pkg/cloudlets/errors_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/loadbalancer.go b/pkg/cloudlets/loadbalancer.go index c390d8cc..c59b2ade 100644 --- a/pkg/cloudlets/loadbalancer.go +++ b/pkg/cloudlets/loadbalancer.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/loadbalancer_activation.go b/pkg/cloudlets/loadbalancer_activation.go index 39da4ce2..93db45d9 100644 --- a/pkg/cloudlets/loadbalancer_activation.go +++ b/pkg/cloudlets/loadbalancer_activation.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/loadbalancer_activation_test.go b/pkg/cloudlets/loadbalancer_activation_test.go index bdc1382d..43a776f1 100644 --- a/pkg/cloudlets/loadbalancer_activation_test.go +++ b/pkg/cloudlets/loadbalancer_activation_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/loadbalancer_version.go b/pkg/cloudlets/loadbalancer_version.go index 24bf407f..24e1c9a4 100644 --- a/pkg/cloudlets/loadbalancer_version.go +++ b/pkg/cloudlets/loadbalancer_version.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/loadbalancer_version_test.go b/pkg/cloudlets/loadbalancer_version_test.go index 69f0f35e..4091b317 100644 --- a/pkg/cloudlets/loadbalancer_version_test.go +++ b/pkg/cloudlets/loadbalancer_version_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/stretchr/testify/require" diff --git a/pkg/cloudlets/match_rule.go b/pkg/cloudlets/match_rule.go index 3532f45b..04ecf864 100644 --- a/pkg/cloudlets/match_rule.go +++ b/pkg/cloudlets/match_rule.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/match_rule_test.go b/pkg/cloudlets/match_rule_test.go index 558f559b..fe62800b 100644 --- a/pkg/cloudlets/match_rule_test.go +++ b/pkg/cloudlets/match_rule_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/policy_property.go b/pkg/cloudlets/policy_property.go index 4b9dc4f0..3cc89568 100644 --- a/pkg/cloudlets/policy_property.go +++ b/pkg/cloudlets/policy_property.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/policy_test.go b/pkg/cloudlets/policy_test.go index b28cc7da..892c0cc5 100644 --- a/pkg/cloudlets/policy_test.go +++ b/pkg/cloudlets/policy_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/policy_version.go b/pkg/cloudlets/policy_version.go index 63b757a8..5efb9865 100644 --- a/pkg/cloudlets/policy_version.go +++ b/pkg/cloudlets/policy_version.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/policy_version_activation.go b/pkg/cloudlets/policy_version_activation.go index 21ff164d..453e9a74 100644 --- a/pkg/cloudlets/policy_version_activation.go +++ b/pkg/cloudlets/policy_version_activation.go @@ -8,7 +8,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/policy_version_test.go b/pkg/cloudlets/policy_version_test.go index 1c50439f..710fed12 100644 --- a/pkg/cloudlets/policy_version_test.go +++ b/pkg/cloudlets/policy_version_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/v3/cloudlets.go b/pkg/cloudlets/v3/cloudlets.go index c9aa5bd3..7a6bc9ce 100644 --- a/pkg/cloudlets/v3/cloudlets.go +++ b/pkg/cloudlets/v3/cloudlets.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/cloudlets/v3/cloudlets_test.go b/pkg/cloudlets/v3/cloudlets_test.go index 1075b301..65d24457 100644 --- a/pkg/cloudlets/v3/cloudlets_test.go +++ b/pkg/cloudlets/v3/cloudlets_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/v3/errors.go b/pkg/cloudlets/v3/errors.go index 860f7664..49b21d7d 100644 --- a/pkg/cloudlets/v3/errors.go +++ b/pkg/cloudlets/v3/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) // Error is a cloudlets error interface. diff --git a/pkg/cloudlets/v3/errors_test.go b/pkg/cloudlets/v3/errors_test.go index b3e3f28c..ed10ec91 100644 --- a/pkg/cloudlets/v3/errors_test.go +++ b/pkg/cloudlets/v3/errors_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/v3/match_rule.go b/pkg/cloudlets/v3/match_rule.go index 65d12e13..dd62fcf2 100644 --- a/pkg/cloudlets/v3/match_rule.go +++ b/pkg/cloudlets/v3/match_rule.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/v3/match_rule_test.go b/pkg/cloudlets/v3/match_rule_test.go index dc409dfb..e6ffbd7b 100644 --- a/pkg/cloudlets/v3/match_rule_test.go +++ b/pkg/cloudlets/v3/match_rule_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudlets/v3/policy.go b/pkg/cloudlets/v3/policy.go index 0e3811f4..441808e6 100644 --- a/pkg/cloudlets/v3/policy.go +++ b/pkg/cloudlets/v3/policy.go @@ -10,7 +10,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/v3/policy_activation.go b/pkg/cloudlets/v3/policy_activation.go index d3492886..42c34182 100644 --- a/pkg/cloudlets/v3/policy_activation.go +++ b/pkg/cloudlets/v3/policy_activation.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/v3/policy_activation_test.go b/pkg/cloudlets/v3/policy_activation_test.go index adb39289..941b97a8 100644 --- a/pkg/cloudlets/v3/policy_activation_test.go +++ b/pkg/cloudlets/v3/policy_activation_test.go @@ -8,8 +8,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/v3/policy_property.go b/pkg/cloudlets/v3/policy_property.go index 19869897..185a36c2 100644 --- a/pkg/cloudlets/v3/policy_property.go +++ b/pkg/cloudlets/v3/policy_property.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/v3/policy_test.go b/pkg/cloudlets/v3/policy_test.go index 660b239c..ed2b8162 100644 --- a/pkg/cloudlets/v3/policy_test.go +++ b/pkg/cloudlets/v3/policy_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudlets/v3/policy_version.go b/pkg/cloudlets/v3/policy_version.go index eaf7abf9..d1a449f7 100644 --- a/pkg/cloudlets/v3/policy_version.go +++ b/pkg/cloudlets/v3/policy_version.go @@ -8,7 +8,7 @@ import ( "net/url" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudlets/v3/policy_version_test.go b/pkg/cloudlets/v3/policy_version_test.go index e884d0f4..74bd6b3c 100644 --- a/pkg/cloudlets/v3/policy_version_test.go +++ b/pkg/cloudlets/v3/policy_version_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudwrapper/cloudwrapper.go b/pkg/cloudwrapper/cloudwrapper.go index e61662e8..a8f418bf 100644 --- a/pkg/cloudwrapper/cloudwrapper.go +++ b/pkg/cloudwrapper/cloudwrapper.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/cloudwrapper/cloudwrapper_test.go b/pkg/cloudwrapper/cloudwrapper_test.go index 1922f35e..71a52232 100644 --- a/pkg/cloudwrapper/cloudwrapper_test.go +++ b/pkg/cloudwrapper/cloudwrapper_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudwrapper/configurations.go b/pkg/cloudwrapper/configurations.go index 37537834..6e585e1c 100644 --- a/pkg/cloudwrapper/configurations.go +++ b/pkg/cloudwrapper/configurations.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudwrapper/configurations_test.go b/pkg/cloudwrapper/configurations_test.go index 995cf54f..4e0656e1 100644 --- a/pkg/cloudwrapper/configurations_test.go +++ b/pkg/cloudwrapper/configurations_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cloudwrapper/errors.go b/pkg/cloudwrapper/errors.go index 428b2b9b..b0ddc7b2 100644 --- a/pkg/cloudwrapper/errors.go +++ b/pkg/cloudwrapper/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/cloudwrapper/errors_test.go b/pkg/cloudwrapper/errors_test.go index aa030f54..4337ed00 100644 --- a/pkg/cloudwrapper/errors_test.go +++ b/pkg/cloudwrapper/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cloudwrapper/multi_cdn.go b/pkg/cloudwrapper/multi_cdn.go index 4189b1ff..6b61b034 100644 --- a/pkg/cloudwrapper/multi_cdn.go +++ b/pkg/cloudwrapper/multi_cdn.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cloudwrapper/properties.go b/pkg/cloudwrapper/properties.go index 604d21e4..9dec3dcb 100644 --- a/pkg/cloudwrapper/properties.go +++ b/pkg/cloudwrapper/properties.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/cps/change_management_info_test.go b/pkg/cps/change_management_info_test.go index 482b0714..4fc10203 100644 --- a/pkg/cps/change_management_info_test.go +++ b/pkg/cps/change_management_info_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cps/cps.go b/pkg/cps/cps.go index a774d933..55269e08 100644 --- a/pkg/cps/cps.go +++ b/pkg/cps/cps.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/cps/cps_test.go b/pkg/cps/cps_test.go index 40aea834..4625e2cf 100644 --- a/pkg/cps/cps_test.go +++ b/pkg/cps/cps_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cps/deployment_schedules_test.go b/pkg/cps/deployment_schedules_test.go index 8e9dc127..13692bca 100644 --- a/pkg/cps/deployment_schedules_test.go +++ b/pkg/cps/deployment_schedules_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cps/deployments_test.go b/pkg/cps/deployments_test.go index 42de650e..0718c35e 100644 --- a/pkg/cps/deployments_test.go +++ b/pkg/cps/deployments_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cps/enrollments_test.go b/pkg/cps/enrollments_test.go index fd5409b5..bc864f1e 100644 --- a/pkg/cps/enrollments_test.go +++ b/pkg/cps/enrollments_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cps/errors_test.go b/pkg/cps/errors_test.go index 416df6db..9fd85af5 100644 --- a/pkg/cps/errors_test.go +++ b/pkg/cps/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/cps/third_party_csr.go b/pkg/cps/third_party_csr.go index 2e8de423..8a18185c 100644 --- a/pkg/cps/third_party_csr.go +++ b/pkg/cps/third_party_csr.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/datastream/ds.go b/pkg/datastream/ds.go index c78193f9..ccc9187f 100644 --- a/pkg/datastream/ds.go +++ b/pkg/datastream/ds.go @@ -7,7 +7,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/datastream/ds_test.go b/pkg/datastream/ds_test.go index 495df802..e879b5c5 100644 --- a/pkg/datastream/ds_test.go +++ b/pkg/datastream/ds_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/datastream/errors.go b/pkg/datastream/errors.go index 97d30292..f132ce6b 100644 --- a/pkg/datastream/errors.go +++ b/pkg/datastream/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/datastream/errors_test.go b/pkg/datastream/errors_test.go index 98e99a1f..13ee2e1d 100644 --- a/pkg/datastream/errors_test.go +++ b/pkg/datastream/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/datastream/properties_test.go b/pkg/datastream/properties_test.go index cd097d25..0557829b 100644 --- a/pkg/datastream/properties_test.go +++ b/pkg/datastream/properties_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/datastream/stream_test.go b/pkg/datastream/stream_test.go index c64f48e5..9291abc1 100644 --- a/pkg/datastream/stream_test.go +++ b/pkg/datastream/stream_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/dns/authorities.go b/pkg/dns/authorities.go index f15663f3..80cfcca1 100644 --- a/pkg/dns/authorities.go +++ b/pkg/dns/authorities.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go index c7b25139..0bf55369 100644 --- a/pkg/dns/dns.go +++ b/pkg/dns/dns.go @@ -8,7 +8,7 @@ import ( "errors" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/dns/dns_test.go b/pkg/dns/dns_test.go index f839d33f..241221f4 100644 --- a/pkg/dns/dns_test.go +++ b/pkg/dns/dns_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/dns/errors.go b/pkg/dns/errors.go index a82ebf23..926c10dd 100644 --- a/pkg/dns/errors.go +++ b/pkg/dns/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) var ( diff --git a/pkg/dns/errors_test.go b/pkg/dns/errors_test.go index e87d671d..9cf796ba 100644 --- a/pkg/dns/errors_test.go +++ b/pkg/dns/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/dns/record.go b/pkg/dns/record.go index f5368593..225a34a5 100644 --- a/pkg/dns/record.go +++ b/pkg/dns/record.go @@ -7,7 +7,7 @@ import ( "net/http" "sync" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/record_lookup.go b/pkg/dns/record_lookup.go index 84538487..05fe16ce 100644 --- a/pkg/dns/record_lookup.go +++ b/pkg/dns/record_lookup.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/record_lookup_test.go b/pkg/dns/record_lookup_test.go index 903aa498..0b163eb3 100644 --- a/pkg/dns/record_lookup_test.go +++ b/pkg/dns/record_lookup_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/dns/recordsets.go b/pkg/dns/recordsets.go index f08d4b73..7c732366 100644 --- a/pkg/dns/recordsets.go +++ b/pkg/dns/recordsets.go @@ -8,7 +8,7 @@ import ( "strconv" "sync" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/tsig.go b/pkg/dns/tsig.go index 5b6a08e3..a2097ec8 100644 --- a/pkg/dns/tsig.go +++ b/pkg/dns/tsig.go @@ -8,7 +8,7 @@ import ( "reflect" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/zone.go b/pkg/dns/zone.go index c671c778..9e0311cd 100644 --- a/pkg/dns/zone.go +++ b/pkg/dns/zone.go @@ -15,7 +15,7 @@ import ( "sync" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/zone_test.go b/pkg/dns/zone_test.go index 4a67aa3b..b08ff4cd 100644 --- a/pkg/dns/zone_test.go +++ b/pkg/dns/zone_test.go @@ -8,8 +8,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/dns/zonebulk.go b/pkg/dns/zonebulk.go index f70e58c9..86767cc9 100644 --- a/pkg/dns/zonebulk.go +++ b/pkg/dns/zonebulk.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/dns/zonebulk_test.go b/pkg/dns/zonebulk_test.go index abaff272..394b6771 100644 --- a/pkg/dns/zonebulk_test.go +++ b/pkg/dns/zonebulk_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/edgeworkers/edgekv_access_tokens_test.go b/pkg/edgeworkers/edgekv_access_tokens_test.go index 18828165..b00bb965 100644 --- a/pkg/edgeworkers/edgekv_access_tokens_test.go +++ b/pkg/edgeworkers/edgekv_access_tokens_test.go @@ -9,7 +9,7 @@ import ( "strconv" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/edgeworkers/edgekv_groups.go b/pkg/edgeworkers/edgekv_groups.go index 4a252617..ae1c381e 100644 --- a/pkg/edgeworkers/edgekv_groups.go +++ b/pkg/edgeworkers/edgekv_groups.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/edgeworkers/edgekv_namespaces_test.go b/pkg/edgeworkers/edgekv_namespaces_test.go index 2761c088..275f759d 100644 --- a/pkg/edgeworkers/edgekv_namespaces_test.go +++ b/pkg/edgeworkers/edgekv_namespaces_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/edgeworkers/edgeworkers.go b/pkg/edgeworkers/edgeworkers.go index 6b521f38..003d2317 100644 --- a/pkg/edgeworkers/edgeworkers.go +++ b/pkg/edgeworkers/edgeworkers.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/edgeworkers/edgeworkers_test.go b/pkg/edgeworkers/edgeworkers_test.go index 3f26db9c..7801cf0c 100644 --- a/pkg/edgeworkers/edgeworkers_test.go +++ b/pkg/edgeworkers/edgeworkers_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/edgeworkers/errors.go b/pkg/edgeworkers/errors.go index b26e913e..cb39ddbf 100644 --- a/pkg/edgeworkers/errors.go +++ b/pkg/edgeworkers/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/edgeworkers/errors_test.go b/pkg/edgeworkers/errors_test.go index c39e3272..5da22969 100644 --- a/pkg/edgeworkers/errors_test.go +++ b/pkg/edgeworkers/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/edgeworkers/report_test.go b/pkg/edgeworkers/report_test.go index 9452514f..d8203759 100644 --- a/pkg/edgeworkers/report_test.go +++ b/pkg/edgeworkers/report_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/asmap.go b/pkg/gtm/asmap.go index a7bf6f09..a110469e 100644 --- a/pkg/gtm/asmap.go +++ b/pkg/gtm/asmap.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/asmap_test.go b/pkg/gtm/asmap_test.go index fe72e39a..226756c6 100644 --- a/pkg/gtm/asmap_test.go +++ b/pkg/gtm/asmap_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/cidrmap.go b/pkg/gtm/cidrmap.go index 3ea263bd..8f6457fa 100644 --- a/pkg/gtm/cidrmap.go +++ b/pkg/gtm/cidrmap.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/cidrmap_test.go b/pkg/gtm/cidrmap_test.go index 271ebac8..1e821955 100644 --- a/pkg/gtm/cidrmap_test.go +++ b/pkg/gtm/cidrmap_test.go @@ -10,7 +10,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/datacenter.go b/pkg/gtm/datacenter.go index 9066992a..e6831407 100644 --- a/pkg/gtm/datacenter.go +++ b/pkg/gtm/datacenter.go @@ -7,7 +7,7 @@ import ( "net/http" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/datacenter_test.go b/pkg/gtm/datacenter_test.go index 71e9b0ad..4391dfc8 100644 --- a/pkg/gtm/datacenter_test.go +++ b/pkg/gtm/datacenter_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/domain.go b/pkg/gtm/domain.go index 6d659d8f..7ecb6e97 100644 --- a/pkg/gtm/domain.go +++ b/pkg/gtm/domain.go @@ -8,7 +8,7 @@ import ( "reflect" "unicode" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/domain_test.go b/pkg/gtm/domain_test.go index 4b6fec35..ae77f098 100644 --- a/pkg/gtm/domain_test.go +++ b/pkg/gtm/domain_test.go @@ -10,7 +10,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/errors.go b/pkg/gtm/errors.go index 130a943e..1271e20f 100644 --- a/pkg/gtm/errors.go +++ b/pkg/gtm/errors.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) var ( diff --git a/pkg/gtm/errors_test.go b/pkg/gtm/errors_test.go index 23cd19d8..2c60a6b5 100644 --- a/pkg/gtm/errors_test.go +++ b/pkg/gtm/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/gtm/geomap.go b/pkg/gtm/geomap.go index b755a204..2a1289f4 100644 --- a/pkg/gtm/geomap.go +++ b/pkg/gtm/geomap.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/geomap_test.go b/pkg/gtm/geomap_test.go index 5c726e24..4b155a2d 100644 --- a/pkg/gtm/geomap_test.go +++ b/pkg/gtm/geomap_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/gtm.go b/pkg/gtm/gtm.go index 68920d49..62623a31 100644 --- a/pkg/gtm/gtm.go +++ b/pkg/gtm/gtm.go @@ -8,7 +8,7 @@ import ( "errors" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/gtm/gtm_test.go b/pkg/gtm/gtm_test.go index 813e7383..5753d5b6 100644 --- a/pkg/gtm/gtm_test.go +++ b/pkg/gtm/gtm_test.go @@ -10,8 +10,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/property.go b/pkg/gtm/property.go index 6afb6e5d..abff6c24 100644 --- a/pkg/gtm/property.go +++ b/pkg/gtm/property.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/property_test.go b/pkg/gtm/property_test.go index bf49d951..fd5ba543 100644 --- a/pkg/gtm/property_test.go +++ b/pkg/gtm/property_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/gtm/resource.go b/pkg/gtm/resource.go index 662b43fd..b1a7b91a 100644 --- a/pkg/gtm/resource.go +++ b/pkg/gtm/resource.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/gtm/resource_test.go b/pkg/gtm/resource_test.go index b1c8622e..c634355b 100644 --- a/pkg/gtm/resource_test.go +++ b/pkg/gtm/resource_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/hapi/edgehostname.go b/pkg/hapi/edgehostname.go index bb165894..473b810d 100644 --- a/pkg/hapi/edgehostname.go +++ b/pkg/hapi/edgehostname.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/hapi/edgehostname_test.go b/pkg/hapi/edgehostname_test.go index e3030aed..5f95851a 100644 --- a/pkg/hapi/edgehostname_test.go +++ b/pkg/hapi/edgehostname_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/hapi/errors.go b/pkg/hapi/errors.go index 9d0f159c..42e9cb09 100644 --- a/pkg/hapi/errors.go +++ b/pkg/hapi/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/hapi/errors_test.go b/pkg/hapi/errors_test.go index 5145e184..24d5a408 100644 --- a/pkg/hapi/errors_test.go +++ b/pkg/hapi/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/hapi/hapi.go b/pkg/hapi/hapi.go index 13a0ba7f..2868f6d0 100644 --- a/pkg/hapi/hapi.go +++ b/pkg/hapi/hapi.go @@ -7,7 +7,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/hapi/hapi_test.go b/pkg/hapi/hapi_test.go index 723a152f..69ef19ed 100644 --- a/pkg/hapi/hapi_test.go +++ b/pkg/hapi/hapi_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/iam/api_clients.go b/pkg/iam/api_clients.go index 81a2bd39..816d93c1 100644 --- a/pkg/iam/api_clients.go +++ b/pkg/iam/api_clients.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/api_clients_credentials.go b/pkg/iam/api_clients_credentials.go index 2386c652..47d4b04a 100644 --- a/pkg/iam/api_clients_credentials.go +++ b/pkg/iam/api_clients_credentials.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/api_clients_credentials_test.go b/pkg/iam/api_clients_credentials_test.go index ab4ebcbf..6eb771ab 100644 --- a/pkg/iam/api_clients_credentials_test.go +++ b/pkg/iam/api_clients_credentials_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/api_clients_test.go b/pkg/iam/api_clients_test.go index 7a8432d1..7c321a60 100644 --- a/pkg/iam/api_clients_test.go +++ b/pkg/iam/api_clients_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/blocked_properties.go b/pkg/iam/blocked_properties.go index e4a668cf..6720eac4 100644 --- a/pkg/iam/blocked_properties.go +++ b/pkg/iam/blocked_properties.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/cidr.go b/pkg/iam/cidr.go index c1848db6..ed28b947 100644 --- a/pkg/iam/cidr.go +++ b/pkg/iam/cidr.go @@ -10,7 +10,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/cidr_test.go b/pkg/iam/cidr_test.go index cd2e0fcf..b11234d2 100644 --- a/pkg/iam/cidr_test.go +++ b/pkg/iam/cidr_test.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/iam/errors.go b/pkg/iam/errors.go index 846ea39b..84a9b3ea 100644 --- a/pkg/iam/errors.go +++ b/pkg/iam/errors.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/iam/errors_test.go b/pkg/iam/errors_test.go index 48b227aa..827776d1 100644 --- a/pkg/iam/errors_test.go +++ b/pkg/iam/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/groups.go b/pkg/iam/groups.go index fc3c34fb..95f4d63d 100644 --- a/pkg/iam/groups.go +++ b/pkg/iam/groups.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/groups_test.go b/pkg/iam/groups_test.go index ef3753e2..e118b55a 100644 --- a/pkg/iam/groups_test.go +++ b/pkg/iam/groups_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/helper.go b/pkg/iam/helper.go index 6a3ca671..573694e7 100644 --- a/pkg/iam/helper.go +++ b/pkg/iam/helper.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/iam.go b/pkg/iam/iam.go index 401e14de..9d31b075 100644 --- a/pkg/iam/iam.go +++ b/pkg/iam/iam.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/iam/iam_test.go b/pkg/iam/iam_test.go index 84a3a631..f3301864 100644 --- a/pkg/iam/iam_test.go +++ b/pkg/iam/iam_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/iam/properties.go b/pkg/iam/properties.go index 2ccc7f4d..66c5aedb 100644 --- a/pkg/iam/properties.go +++ b/pkg/iam/properties.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/properties_test.go b/pkg/iam/properties_test.go index b6483240..e4e7d9bb 100644 --- a/pkg/iam/properties_test.go +++ b/pkg/iam/properties_test.go @@ -8,8 +8,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/iam/roles.go b/pkg/iam/roles.go index 0c7a0b77..6c032bf8 100644 --- a/pkg/iam/roles.go +++ b/pkg/iam/roles.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/roles_test.go b/pkg/iam/roles_test.go index c1fab76c..ab77deca 100644 --- a/pkg/iam/roles_test.go +++ b/pkg/iam/roles_test.go @@ -9,7 +9,7 @@ import ( "strconv" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/iam/support.go b/pkg/iam/support.go index 89bd9f16..382dae87 100644 --- a/pkg/iam/support.go +++ b/pkg/iam/support.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/user.go b/pkg/iam/user.go index 255cf957..9667659b 100644 --- a/pkg/iam/user.go +++ b/pkg/iam/user.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is" ) diff --git a/pkg/iam/user_lock.go b/pkg/iam/user_lock.go index 5e05f435..c77d3eef 100644 --- a/pkg/iam/user_lock.go +++ b/pkg/iam/user_lock.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/user_password.go b/pkg/iam/user_password.go index a58adc86..459099e1 100644 --- a/pkg/iam/user_password.go +++ b/pkg/iam/user_password.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/iam/user_test.go b/pkg/iam/user_test.go index 2f73f062..f1138050 100644 --- a/pkg/iam/user_test.go +++ b/pkg/iam/user_test.go @@ -8,8 +8,8 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/internal/test" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/internal/test" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/imaging/errors.go b/pkg/imaging/errors.go index 9eb00c6d..c2909628 100644 --- a/pkg/imaging/errors.go +++ b/pkg/imaging/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/imaging/errors_test.go b/pkg/imaging/errors_test.go index 19001aa2..22464015 100644 --- a/pkg/imaging/errors_test.go +++ b/pkg/imaging/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/imaging/imaging.go b/pkg/imaging/imaging.go index 47f04e16..e3ec9c87 100644 --- a/pkg/imaging/imaging.go +++ b/pkg/imaging/imaging.go @@ -5,7 +5,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/imaging/imaging_test.go b/pkg/imaging/imaging_test.go index 94138655..4ac04d2d 100644 --- a/pkg/imaging/imaging_test.go +++ b/pkg/imaging/imaging_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/imaging/policy.go b/pkg/imaging/policy.go index c72e34e4..8407fa93 100644 --- a/pkg/imaging/policy.go +++ b/pkg/imaging/policy.go @@ -7,7 +7,7 @@ import ( "fmt" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/imaging/policy_test.go b/pkg/imaging/policy_test.go index cc03d7c5..1ed2e783 100644 --- a/pkg/imaging/policy_test.go +++ b/pkg/imaging/policy_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/imaging/policyset.go b/pkg/imaging/policyset.go index aa318c1e..ee10cc46 100644 --- a/pkg/imaging/policyset.go +++ b/pkg/imaging/policyset.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/networklists/activations_test.go b/pkg/networklists/activations_test.go index 507f24dc..27932cf3 100644 --- a/pkg/networklists/activations_test.go +++ b/pkg/networklists/activations_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/networklists/errors.go b/pkg/networklists/errors.go index d6e0c900..b7a5a2e6 100644 --- a/pkg/networklists/errors.go +++ b/pkg/networklists/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) var ( diff --git a/pkg/networklists/errors_test.go b/pkg/networklists/errors_test.go index c49cb97e..011e9acc 100644 --- a/pkg/networklists/errors_test.go +++ b/pkg/networklists/errors_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/networklists/network_list_description_test.go b/pkg/networklists/network_list_description_test.go index a2487030..ade94e08 100644 --- a/pkg/networklists/network_list_description_test.go +++ b/pkg/networklists/network_list_description_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/networklists/network_list_subscription_test.go b/pkg/networklists/network_list_subscription_test.go index 215ef255..e2367aff 100644 --- a/pkg/networklists/network_list_subscription_test.go +++ b/pkg/networklists/network_list_subscription_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/networklists/network_list_test.go b/pkg/networklists/network_list_test.go index 27b5ffcf..7a77addb 100644 --- a/pkg/networklists/network_list_test.go +++ b/pkg/networklists/network_list_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/networklists/networklists.go b/pkg/networklists/networklists.go index efea9d4e..2030717e 100644 --- a/pkg/networklists/networklists.go +++ b/pkg/networklists/networklists.go @@ -7,7 +7,7 @@ import ( "context" "errors" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" ) var ( diff --git a/pkg/networklists/networklists_test.go b/pkg/networklists/networklists_test.go index 921ba433..f1e4ba1c 100644 --- a/pkg/networklists/networklists_test.go +++ b/pkg/networklists/networklists_test.go @@ -12,8 +12,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/cpcode_test.go b/pkg/papi/cpcode_test.go index e0ca334f..6668b186 100644 --- a/pkg/papi/cpcode_test.go +++ b/pkg/papi/cpcode_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/edgehostname.go b/pkg/papi/edgehostname.go index 17ec8a9d..a6707108 100644 --- a/pkg/papi/edgehostname.go +++ b/pkg/papi/edgehostname.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/errors.go b/pkg/papi/errors.go index 5e04a1da..add7767b 100644 --- a/pkg/papi/errors.go +++ b/pkg/papi/errors.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/errs" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/errs" ) type ( diff --git a/pkg/papi/errors_test.go b/pkg/papi/errors_test.go index 07664e32..15e6d207 100644 --- a/pkg/papi/errors_test.go +++ b/pkg/papi/errors_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/require" "github.com/tj/assert" ) diff --git a/pkg/papi/include.go b/pkg/papi/include.go index 5d0447c4..b11fa11d 100644 --- a/pkg/papi/include.go +++ b/pkg/papi/include.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/include_activations.go b/pkg/papi/include_activations.go index d54f924b..5df617cd 100644 --- a/pkg/papi/include_activations.go +++ b/pkg/papi/include_activations.go @@ -9,8 +9,8 @@ import ( "net/url" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/include_rule.go b/pkg/papi/include_rule.go index d3644602..ee72c51e 100644 --- a/pkg/papi/include_rule.go +++ b/pkg/papi/include_rule.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/include_rule_test.go b/pkg/papi/include_rule_test.go index ceaabaee..eaf3ee98 100644 --- a/pkg/papi/include_rule_test.go +++ b/pkg/papi/include_rule_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/include_test.go b/pkg/papi/include_test.go index c41cbc75..645ece8f 100644 --- a/pkg/papi/include_test.go +++ b/pkg/papi/include_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/include_versions.go b/pkg/papi/include_versions.go index 64c9f84f..eeafea0d 100644 --- a/pkg/papi/include_versions.go +++ b/pkg/papi/include_versions.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/papi.go b/pkg/papi/papi.go index 9804bcaa..160293bd 100644 --- a/pkg/papi/papi.go +++ b/pkg/papi/papi.go @@ -6,7 +6,7 @@ import ( "errors" "net/http" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/spf13/cast" ) diff --git a/pkg/papi/papi_test.go b/pkg/papi/papi_test.go index eb4b55f1..6effefa5 100644 --- a/pkg/papi/papi_test.go +++ b/pkg/papi/papi_test.go @@ -8,8 +8,8 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/property.go b/pkg/papi/property.go index 74485492..057cdc20 100644 --- a/pkg/papi/property.go +++ b/pkg/papi/property.go @@ -7,7 +7,7 @@ import ( "net/http" "net/url" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/property_test.go b/pkg/papi/property_test.go index 02d98f3e..a06093e3 100644 --- a/pkg/papi/property_test.go +++ b/pkg/papi/property_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/propertyversion.go b/pkg/papi/propertyversion.go index 59399a1e..af6df251 100644 --- a/pkg/papi/propertyversion.go +++ b/pkg/papi/propertyversion.go @@ -9,7 +9,7 @@ import ( "net/url" "strconv" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/propertyversion_test.go b/pkg/papi/propertyversion_test.go index c92670e2..51e488e2 100644 --- a/pkg/papi/propertyversion_test.go +++ b/pkg/papi/propertyversion_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/papi/rule.go b/pkg/papi/rule.go index 7eb3099c..c13e1443 100644 --- a/pkg/papi/rule.go +++ b/pkg/papi/rule.go @@ -7,7 +7,7 @@ import ( "net/http" "regexp" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegriderr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegriderr" validation "github.com/go-ozzo/ozzo-validation/v4" ) diff --git a/pkg/papi/rule_test.go b/pkg/papi/rule_test.go index bd5ffb4d..13e3055a 100644 --- a/pkg/papi/rule_test.go +++ b/pkg/papi/rule_test.go @@ -9,7 +9,7 @@ import ( "net/http/httptest" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/ptr" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/ptr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/session/request_test.go b/pkg/session/request_test.go index 7e32c057..767b8d08 100644 --- a/pkg/session/request_test.go +++ b/pkg/session/request_test.go @@ -9,7 +9,7 @@ import ( "net/url" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/session/session.go b/pkg/session/session.go index 02c1913e..f35920c9 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -7,7 +7,7 @@ import ( "runtime" "strings" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" "github.com/apex/log" "github.com/apex/log/handlers/discard" ) @@ -63,7 +63,7 @@ var ( const ( // Version is the client version - Version = "8.0.0" + Version = "9.0.0" ) // New returns a new session diff --git a/pkg/session/session_test.go b/pkg/session/session_test.go index 1802bee4..ac498e02 100644 --- a/pkg/session/session_test.go +++ b/pkg/session/session_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v9/pkg/edgegrid" "github.com/apex/log" "github.com/apex/log/handlers/discard" "github.com/stretchr/testify/require" @@ -28,7 +28,7 @@ func TestNew(t *testing.T) { signer: &edgegrid.Config{}, log: log.Log, trace: false, - userAgent: "Akamai-Open-Edgegrid-golang/8.0.0 golang/" + strings.TrimPrefix(runtime.Version(), "go"), + userAgent: "Akamai-Open-Edgegrid-golang/9.0.0 golang/" + strings.TrimPrefix(runtime.Version(), "go"), }, }, "with options provided": { From c58a8bc53f062594316a45deeb8d0dd82b32e179 Mon Sep 17 00:00:00 2001 From: Rahul Bhatvedekar Date: Tue, 1 Oct 2024 12:12:31 +0000 Subject: [PATCH 34/34] DXE-4060 Changelog entry for renaming the NTWRKLISTS interface. Merge in DEVEXP/akamaiopen-edgegrid-golang from feature/changelog_update to release/v9.0.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d60f0ea4..eea76a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * General * Consolidated multiple sub-interfaces into a single interface for each sub-provider. + * Renamed `NTWRKLISTS` interface to `NetworkList` for `networklists` provider * Removed `tools` package in favour of `ptr` package * Cloudaccess