pax_global_header00006660000000000000000000000064140016156060014511gustar00rootroot0000000000000052 comment=daa85461177ae83b9b4de1161899219aa76227a4 golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/000077500000000000000000000000001400161560600226005ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/.gitignore000066400000000000000000000003141400161560600245660ustar00rootroot00000000000000# testing and custom build code *.log # local files .DS_Store /dist # vscode .vscode/ _debug_bin # eclipse .classpath .project .settings # IntelliJ /.idea/ *.ipr *.iws *.iml # go dependencies vendor/golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/.travis.yml000066400000000000000000000022461400161560600247150ustar00rootroot00000000000000language: go sudo: false # Fix patching for forks go_import_path: github.com/akamai/AkamaiOPEN-edgegrid-golang cache: directories: - $GOPATH/pkg/mod matrix: fast_finish: true include: - go: 1.12.x - go: 1.13.x - go: 1.x - go: tip allow_failures: - go: tip env: global: - GO111MODULE=on install: - go mod tidy - git diff --exit-code go.mod - git diff --exit-code go.sum - go mod download script: - go test -v ./... notifications: slack: secure: sf5CrgPZ2UjTmGFg1hbSdEB3GXyBybeoZQDOI/pk1ywId4mjN1HgAFooDaZx9Qn+orhdQny3jMcdx1qyLe9YtV7WhIRGRQWgJiZ7H+6YRCWYNnSopsSDJ91Q/PaQrgsPSIHL+vfSkyW9iDXrT09SK0IOlWHTrrYMcJiiOCkx2QZgIBMASXWzCRFMSxfqDBuZ8FuNMhcYTIEz4xBLO7seAl9+FvQTzpSXXyEwoKeZjLx2J2+9J1onx9ccnb5ioPeICRuiIKlSvu7VfFkDgc8k8luoktKSG+ZRpwcdae8VoQCzyt7OPzI1kSoZZw20gp2oYQcRkwpLBM007JkW2+KQraF5tZ9Ok8C1vG97lsByhd23r022joyTGpD+TZqWfXUX7K461GJJpohWoFlHshOaAwNj37XWKD8REpb0Qj7vABIfH+gXQhlJHBRCfKMRf12ILzU2yUbbQftwcPkcivNHGknEAkHIjWKk5lDH9uC2is5nWJHDCt/h/xa/AfvNbt28Kol+8yexRypnmorTzG9CBHq+pKrm48cBEGUxREiUjN7v5RGgJH+DB5nKkV4nH3P7mvWV+mkDcAXZPhDprplFl1Q7YV56OyjAY+dlpY6xyGopDz9DmmZifqLxR6mP9eSCIeIM9VsDJUwhfnnwyxRuuzZWFa+Adu8kuaBR8RqjcdE= golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/CHANGELOG.md000066400000000000000000000043541400161560600244170ustar00rootroot00000000000000# EDGEGRID GOLANG RELEASE NOTES ## 1.0.1 (Jan 7, 2021) * CPSv2 - Fixed several issues with listing enrollments ## 2.0.0 (Oct 15, 2020) * [IMPORTANT] Breaking changes from earlier clients. Project updated to use v2 directory structure. * [ENHANCEMENT] PAPI - Api error return to the user when an activation or validation error occurs. * [NOTE] Project re-organized to prepare for additional APIs to be included in future versions of this library. ## 1.0.0 (Oct 15, 2020) * Official release for the EdgeGrid Golang library * DNSv2 - Zone create signature to pass blank instead of nil * PAPI - Return nil instead of error if no cp code was found * GTM - Datacenter API requires blank instead of nil ## 0.9.18 (Jul 13, 2020) * [AT-40][Add] Preliminary Logging CorrelationID ## 0.9.17 (Jun 9, 2020) * Corrected AKAMAICDN target parsing * Added endpoints for list zones, creating and updating multiple recordsets * Refactored recordsets into separate source file ## 0.9.16 (May 29, 2020) * Client-v1, Papi-v1 Updates * Add lock around http request creation. * papi - add logging to papi endpoints. ## 0.9.15 (May 15, 2020) * DNSv2 - Added CERT, TSLA Record parsing. Removed MX Record parsing ## 0.9.14 (May 12, 2020) * DNSv2 - Enhance RecordError functions ## 0.9.13 (Apr 26, 2020) * DNSv2 - filterZoneCreate check upper case Type ## 0.9.12 (Apr 21, 2020) * DNSv2 - Added optional arg to bypass dns record lock for create, update and delete functions. default preserves prior behavior ## 0.9.11 (Apr 13 , 2020) * DNSv2 Updates * Add additional fields, including TSIG, to zone * Support alias zone types * Add utility functions for Rdata parsing and process. * Add GetRecord, GetRecordSet functions * Add additional Recordset metadata * Add http request/response logging ## 0.9.10 (Mar 5, 2020) * Add support for caching Edgehostnames and Products * Support for cache in papi library for edgehostnames and products to minimize round trips to fetch repeated common data to avoid WAF deny rule IPBLOCK-BURST4-54013 issue ## 0.9.9 (Feb 29, 2020) * Add support for caching Contract, Groups, and Cp Codes * cache to minimize round trips on repeated common data fetches to avoid WAF deny rule IPBLOCK-BURST4-54013 issue ## 0.9.0 (Aug 6, 2019) * Added support for GTM golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/LICENSE000066400000000000000000000261351400161560600236140ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/README.md000066400000000000000000000133011400161560600240550ustar00rootroot00000000000000# Akamai OPEN EdgeGrid for GoLang v1 [![Build Status](https://travis-ci.org/akamai/AkamaiOPEN-edgegrid-golang.svg?branch=master)](https://travis-ci.org/akamai/AkamaiOPEN-edgegrid-golang) [![GoDoc](https://godoc.org/github.com/akamai/AkamaiOPEN-edgegrid-golang?status.svg)](https://godoc.org/github.com/akamai/AkamaiOPEN-edgegrid-golang) [![Go Report Card](https://goreportcard.com/badge/github.com/akamai/AkamaiOPEN-edgegrid-golang)](https://goreportcard.com/report/github.com/akamai/AkamaiOPEN-edgegrid-golang) [![License](http://img.shields.io/:license-apache-blue.svg)](https://github.com/akamai/AkamaiOPEN-edgegrid-golang/blob/master/LICENSE) This library implements an Authentication handler for [net/http](https://golang.org/pkg/net/http/) that provides the [Akamai OPEN Edgegrid Authentication](https://developer.akamai.com/introduction/Client_Auth.html) scheme. For more information visit the [Akamai OPEN Developer Community](https://developer.akamai.com). This library has been released as a v1 library though future development will be on the v2 branch ## Announcing Akamai OPEN EdgeGrid for GoLang v2 (release v2.0.0) The v2 branch of this module is under active development and provides a subset of Akamai APIs for use in the Akamai Terraform Provider. The v2 branch **does not yet** implement the full set of Akamai endpoints supported by the 0.x and 1.x releases. New users are encouraged to adopt v2 branch it is a simpler API wrapper with little to no business logic. Current direct users of this v0.9 library are recommended to continue to use the the v1 version as initialization and package structure has significantly changed in v2 and will require substantial work to migrate existing applications. Non-backwards compatible changes were made to improve the code quality and make the project more maintainable. ## Usage of the v1 library GET Example: ```go package main import ( "fmt" "io/ioutil" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { config, _ := edgegrid.Init("~/.edgerc", "default") // Retrieve all locations for diagnostic tools req, _ := client.NewRequest(config, "GET", "/diagnostic-tools/v2/ghost-locations/available", nil) resp, _ := client.Do(config, req) defer resp.Body.Close() byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } ``` Parameter Example: ```go package main import ( "fmt" "io/ioutil" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { config, _ := edgegrid.Init("~/.edgerc", "default") // Retrieve dig information for specified location req, _ := client.NewRequest(config, "GET", "/diagnostic-tools/v2/ghost-locations/zurich-switzerland/dig-info", nil) q := req.URL.Query() q.Add("hostName", "developer.akamai.com") q.Add("queryType", "A") req.URL.RawQuery = q.Encode() resp, _ := client.Do(config, req) defer resp.Body.Close() byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } ``` POST Example: ```go package main import ( "fmt" "io/ioutil" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { config, _ := edgegrid.Init("~/.edgerc", "default") // Acknowledge a map req, _ := client.NewRequest(config, "POST", "/siteshield/v1/maps/1/acknowledge", nil) resp, _ := client.Do(config, req) defer resp.Body.Close() byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } ``` PUT Example: ```go package main import ( "fmt" "io/ioutil" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { config, _ := edgegrid.Init("~/.edgerc", "default") body := []byte("{\n \"name\": \"Simple List\",\n \"type\": \"IP\",\n \"unique-id\": \"345_BOTLIST\",\n \"list\": [\n \"192.168.0.1\",\n \"192.168.0.2\",\n ],\n \"sync-point\": 0\n}") // Update a Network List req, _ := client.NewJSONRequest(config, "PUT", "/network-list/v1/network_lists/unique-id?extended=extended", body) resp, _ := client.Do(config, req) defer resp.Body.Close() byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } ``` Alternatively, your program can read it from config struct. ```go package main import ( "fmt" "io/ioutil" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { config := edgegrid.Config{ Host : "xxxxxx.luna.akamaiapis.net", ClientToken: "xxxx-xxxxxxxxxxx-xxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", AccessToken: "xxxx-xxxxxxxxxxx-xxxxxxxxxxx", MaxBody: 1024, HeaderToSign: []string{ "X-Test1", "X-Test2", "X-Test3", }, Debug: false, } // Retrieve all locations for diagnostic tools req, _ := client.NewRequest(config, "GET", fmt.Sprintf("https://%s/diagnostic-tools/v2/ghost-locations/available",config.Host), nil) resp, _ := client.Do(config, req) defer resp.Body.Close() byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } ``` ## Contribute 1. Fork [the repository](https://github.com/akamai/AkamaiOPEN-edgegrid-golang) to start making your changes to the **master** branch 2. Send a pull request. ## Author [Davey Shafik](mailto:dshafik@akamai.com) - Developer Evangelist @ [Akamai Technologies](https://developer.akamai.com) [Nick Juettner](mailto:hello@juni.io) - Software Engineer @ [Zalando SE](https://tech.zalando.com/) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/000077500000000000000000000000001400161560600256775ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/acg_pair.go000066400000000000000000000003111400161560600277660ustar00rootroot00000000000000package apiendpoints type AcgPair []struct { DisplayName string `json:"displayName"` AcgID string `json:"acgId"` GroupID int `json:"groupId"` ContractID string `json:"contractId"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/activations.go000066400000000000000000000032411400161560600305520ustar00rootroot00000000000000package apiendpoints import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type Activation struct { Networks []string `json:"networks"` NotificationRecipients []string `json:"notificationRecipients"` Notes string `json:"notes"` } type ActivateEndpointOptions struct { APIEndPointId int VersionNumber int } func ActivateEndpoint(options *ActivateEndpointOptions, activation *Activation) (*Activation, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/activate", options.APIEndPointId, options.VersionNumber, ), activation, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if client.IsError(res) { return nil, client.NewAPIError(res) } return activation, nil } func DeactivateEndpoint(options *ActivateEndpointOptions, activation *Activation) (*Activation, error) { req, err := client.NewJSONRequest( Config, "DELETE", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/deactivate", options.APIEndPointId, options.VersionNumber, ), activation, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if client.IsError(res) { return nil, client.NewAPIError(res) } return activation, nil } func IsActive(endpoint *Endpoint, network string) bool { if network == "production" { if endpoint.ProductionStatus == StatusPending || endpoint.ProductionStatus == StatusActive { return true } } if network == "staging" { if endpoint.StagingStatus == StatusPending || endpoint.StagingStatus == StatusActive { return true } } return false } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/api_privacy_settings.go000066400000000000000000000004331400161560600324540ustar00rootroot00000000000000package apiendpoints type APIPrivacySettings struct { Resources map[int]APIPrivacyResource `json:"resources"` Public bool `json:"public"` } type APIPrivacyResource struct { ResourceSettings Notes string `json:"notes"` Public bool `json:"public"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/cache_settings.go000066400000000000000000000037771400161560600312270ustar00rootroot00000000000000package apiendpoints type CacheSettings struct { Enabled bool `json:"enabled"` Option string `json:"option"` MaxAge *MaxAge `json:"maxAge"` ServeStale bool `json:"serveStale"` DownstreamCaching DownstreamCaching `json:"downstreamCaching"` ErrorCaching ErrorCaching `json:"errorCaching"` Resources map[int]CacheResource `json:"resources"` } type DownstreamCaching struct { Option string `json:"option"` Lifetime string `json:"lifetime"` MaxAge *MaxAge `json:"maxAge"` Headers string `json:"headers"` MarkAsPrivate bool `json:"markAsPrivate"` } type ErrorCaching struct { Enabled bool `json:"enabled"` MaxAge *MaxAge `json:"maxAge"` PreserveStale bool `json:"preserveStale"` } type MaxAge struct { Duration int `json:"duration"` Unit string `json:"unit"` } type CacheResource struct { ResourceSettings Option CacheResourceOptionValue `json:"option"` MaxAge *MaxAge `json:"maxAge"` ServeStale bool `json:"serveStale"` } type MaxAgeUnitValue string type CacheResourceOptionValue string const ( MaxAgeUnitSeconds MaxAgeUnitValue = "SECONDS" MaxAgeUnitMinutes MaxAgeUnitValue = "MINUTES" MaxAgeUnitHours MaxAgeUnitValue = "HOURS" MaxAgeUnitDays MaxAgeUnitValue = "DAYS" CacheResourceOptionCache CacheResourceOptionValue = "CACHE" CacheResourceOptionBypassCache CacheResourceOptionValue = "BYPASS_CACHE" CacheResourceOptionNoStore CacheResourceOptionValue = "NO_STORE" CacheResourceOptionHonorOriginCacheControl CacheResourceOptionValue = "HONOR_ORIGIN_CACHE_CONTROL" CacheResourceOptionHonorOriginExpires CacheResourceOptionValue = "HONOR_ORIGIN_EXPIRES" CacheResourceOptionHonorOriginCacheControlAndExpires CacheResourceOptionValue = "HONOR_ORIGIN_CACHE_CONTROL_AND_EXPIRES" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/category.go000066400000000000000000000010711400161560600300420ustar00rootroot00000000000000package apiendpoints type Category struct { APICategoryID int `json:"apiCategoryId,omitempty"` APICategoryName string `json:"apiCategoryName"` APICategoryDescription string `json:"apiCategoryDescription"` Link string `json:"link"` LockVersion int `json:"lockVersion"` CreatedBy string `json:"createdBy,omitempty"` CreateDate string `json:"createDate,omitempty"` UpdatedBy string `json:"updatedBy,omitempty"` UpdateDate string `json:"updateDate,omitempty"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/cors_settings.go000066400000000000000000000007621400161560600311210ustar00rootroot00000000000000package apiendpoints type CORSSetings struct { Enabled bool `json:"enabled"` AllowedOrigins []string `json:"allowedOrigins,omitempty"` AllowedHeaders []string `json:"allowedHeaders,omitempty"` AllowedMethods []MethodValue `json:"allowedMethods,omitempty"` AllowCredentials bool `json:"allowCredentials,omitempty"` ExposedHeaders []string `json:"exposedHeaders,omitempty"` PreflightMaxAge int `json:"preflightMaxAge,omitempty"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/endpoints.go000066400000000000000000000144741400161560600302430ustar00rootroot00000000000000package apiendpoints import ( "fmt" "strconv" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/google/go-querystring/query" ) type Endpoints []Endpoint type Endpoint struct { APICategoryIds []int `json:"apiCategoryIds,omitempty"` APIEndPointHosts []string `json:"apiEndPointHosts"` APIEndPointID int `json:"apiEndPointId,omitempty"` APIEndPointLocked bool `json:"apiEndPointLocked,omitempty"` APIEndPointName string `json:"apiEndPointName"` APIEndPointScheme string `json:"apiEndPointScheme,omitempty"` APIResourceBaseInfo []*ResourceBaseInfo `json:"apiResourceBaseInfo,omitempty"` BasePath string `json:"basePath,omitempty"` ClonedFromVersion *int `json:"clonedFromVersion,omitempty"` ConsumeType string `json:"consumeType,omitempty"` ContractID string `json:"contractId,omitempty"` CreateDate string `json:"createDate,omitempty"` CreatedBy string `json:"createdBy,omitempty"` Description string `json:"description,omitempty"` GroupID int `json:"groupId,omitempty"` ProductionVersion *VersionSummary `json:"productionVersion,omitempty"` ProductionStatus string `json:"productionStatus,omitempty"` ProtectedByAPIKey bool `json:"protectedByApiKey,omitempty"` StagingStatus string `json:"stagingStatus,omitempty"` StagingVersion *VersionSummary `json:"stagingVersion,omitempty"` UpdateDate string `json:"updateDate,omitempty"` UpdatedBy string `json:"updatedBy,omitempty"` VersionNumber int `json:"versionNumber,omitempty"` SecurityScheme *SecurityScheme `json:"securityScheme,omitempty"` AkamaiSecurityRestrictions *SecurityRestrictions `json:"akamaiSecurityRestrictions,omitempty"` APIResources *Resources `json:"apiResources,omitempty"` } type SecurityScheme struct { SecuritySchemeType string `json:"securitySchemeType,omitempty"` SecuritySchemeDetail *SecuritySchemeDetail `json:"securitySchemeDetail,omitempty"` } type SecuritySchemeDetail struct { APIKeyLocation string `json:"apiKeyLocation,omitempty"` APIKeyName string `json:"apiKeyName,omitempty"` } type SecurityRestrictions struct { MaxJsonxmlElement int `json:"MAX_JSONXML_ELEMENT,omitempty"` MaxElementNameLength int `json:"MAX_ELEMENT_NAME_LENGTH,omitempty"` MaxDocDepth int `json:"MAX_DOC_DEPTH,omitempty"` PositiveSecurityEnabled int `json:"POSITIVE_SECURITY_ENABLED,omitempty"` MaxStringLength int `json:"MAX_STRING_LENGTH,omitempty"` MaxBodySize int `json:"MAX_BODY_SIZE,omitempty"` MaxIntegerValue int `json:"MAX_INTEGER_VALUE,omitempty"` } type CreateEndpointOptions struct { ContractId string `json:"contractId,omitempty"` GroupId int `json:"groupId,omitempty"` Name string `json:"apiEndPointName,omitempty"` BasePath string `json:"basePath,omitempty"` Hostnames []string `json:"apiEndPointHosts,omitempty"` } func CreateEndpoint(options *CreateEndpointOptions) (*Endpoint, error) { req, err := client.NewJSONRequest( Config, "POST", "/api-definitions/v2/endpoints", options, ) return call(req, err) } type CreateEndpointFromFileOptions struct { File string Format string ContractId string GroupId int } func CreateEndpointFromFile(options *CreateEndpointFromFileOptions) (*Endpoint, error) { req, err := client.NewMultiPartFormDataRequest( Config, "/api-definitions/v2/endpoints/files", options.File, map[string]string{ "contractId": options.ContractId, "groupId": strconv.Itoa(options.GroupId), "importFileFormat": options.Format, }, ) return call(req, err) } type UpdateEndpointFromFileOptions struct { EndpointId int Version int File string Format string } func UpdateEndpointFromFile(options *UpdateEndpointFromFileOptions) (*Endpoint, error) { url := fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/file", options.EndpointId, options.Version, ) req, err := client.NewMultiPartFormDataRequest( Config, url, options.File, map[string]string{ "importFileFormat": options.Format, }, ) return call(req, err) } type ListEndpointOptions struct { ContractId string `url:"contractId,omitempty"` GroupId int `url:"groupId,omitempty"` Category string `url:"category,omitempty"` Contains string `url:"contains,omitempty"` Page int `url:"page,omitempty"` PageSize int `url:"pageSize,omitempty"` Show string `url:show,omitempty` SortBy string `url:"sortBy,omitempty"` SortOrder string `url:"sortOrder,omitempty"` VersionPreference string `url:"versionPreference,omitempty"` } type EndpointList struct { APIEndPoints Endpoints `json:"apiEndPoints"` Links Links `json:"links"` Page int `json:"page"` PageSize int `json:"pageSize"` TotalSize int `json:"totalSize"` } func (list *EndpointList) ListEndpoints(options *ListEndpointOptions) error { q, err := query.Values(options) if err != nil { return err } url := fmt.Sprintf( "/api-definitions/v2/endpoints?%s", q.Encode(), ) req, err := client.NewJSONRequest(Config, "GET", url, nil) if err != nil { return err } res, err := client.Do(Config, req) if err != nil { return err } if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, list); err != nil { return err } return nil } func RemoveEndpoint(endpointId int) (*Endpoint, error) { req, err := client.NewJSONRequest( Config, "DELETE", fmt.Sprintf( "/api-definitions/v2/endpoints/%d", endpointId, ), nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Endpoint{} return rep, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/gzip_settings.go000066400000000000000000000005471400161560600311250ustar00rootroot00000000000000package apiendpoints type GzipSettings struct { CompressResponse CompressResponseValue `json:"compressResponse"` } type CompressResponseValue string const ( CompressResponseAlways CompressResponseValue = "ALWAYS" CompressResponseNever CompressResponseValue = "NEVER" CompressResponseSameAsOrigin CompressResponseValue = "SAME_AS_ORIGIN" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/import_results.go000066400000000000000000000002331400161560600313170ustar00rootroot00000000000000package apiendpoints type ImportResult struct { APIEndpointDetails Endpoint `json:"apiEndpointDetails"` Problems Problems `json:"problems"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/jwt_settings.go000066400000000000000000000023071400161560600307540ustar00rootroot00000000000000package apiendpoints type JWTSettings struct { Enabled bool `json:"enabled"` Settings struct { Location JWTSettingsLocationValue `json:"location"` ParamName string `json:"paramName"` ClockSkew int `json:"clockSkew"` Validation *struct { Claims []JWTClaim `json:"claims"` RsaPublicKeyA RsaPublicKey `json:"rsaPublicKeyA"` RsaPublicKeyB *RsaPublicKey `json:"rsaPublicKeyB,omitempty"` } `json:"validation"` } `json:"settings"` Resources map[int]JWTSettingsResource `json:"resources"` } type JWTSettingsResource struct { ResourceSettings Enabled bool `json:"enabled"` Notes *string `json:"notes,omitempty"` } type RsaPublicKey struct { Name string `json:"name"` Content string `json:"content"` } type JWTClaim struct { Name string `json:"name"` Validate bool `json:"validate"` Required bool `json:"required"` Value []string `json:"value"` Type string `json:"type"` } type JWTSettingsLocationValue string const ( JWTSettingsLocationHeader JWTSettingsLocationValue = "HEADER" JWTSettingsLocationCookie JWTSettingsLocationValue = "COOKIE" JWTSettingsLocationQuery JWTSettingsLocationValue = "QUERY" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/links.go000066400000000000000000000001431400161560600273440ustar00rootroot00000000000000package apiendpoints type Links []struct { Rel string `json:"rel"` Href string `json:"href"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/methods.go000066400000000000000000000011651400161560600276740ustar00rootroot00000000000000package apiendpoints type Methods []Method type Method struct { APIResourceMethodID int `json:"apiResourceMethodId"` APIResourceMethod MethodValue `json:"apiResourceMethod"` APIResourceMethodLogicID int `json:"apiResourceMethodLogicId"` APIParameters []Parameters `json:"apiParameters"` } type MethodValue string const ( MethodGet MethodValue = "get" MethodPost MethodValue = "post" MethodPut MethodValue = "put" MethodDelete MethodValue = "delete" MethodHead MethodValue = "head" MethodPatch MethodValue = "patch" MethodOptions MethodValue = "options" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/parameters.go000066400000000000000000000031371400161560600303750ustar00rootroot00000000000000package apiendpoints type Parameters struct { APIChildParameters []*Parameters `json:"apiChildParameters"` APIParameterID int `json:"apiParameterId"` APIParameterRequired bool `json:"apiParameterRequired"` APIParameterName string `json:"apiParameterName"` APIParameterLocation APIParameterLocationValue `json:"apiParameterLocation"` APIParameterType APIParameterTypeValue `json:"apiParameterType"` APIParameterNotes *string `json:"apiParameterNotes"` APIParamLogicID int `json:"apiParamLogicId"` Array bool `json:"array"` APIParameterRestriction struct { RangeRestriction struct { RangeMin int `json:"rangeMin"` RangeMax int `json:"rangeMax"` } `json:"rangeRestriction"` } `json:"apiParameterRestriction"` } type APIParameterLocationValue string type APIParameterTypeValue string const ( APIParameterLocationHeader APIParameterLocationValue = "header" APIParameterLocationCookie APIParameterLocationValue = "cookie" APIParameterLocationQuery APIParameterLocationValue = "query" APIParameterLocationBody APIParameterLocationValue = "body" APIParameterTypeString APIParameterTypeValue = "string" APIParameterTypeInteger APIParameterTypeValue = "integer" APIParameterTypeNumber APIParameterTypeValue = "number" APIParameterTypeBoolean APIParameterTypeValue = "boolean" APIParameterTypeJson APIParameterTypeValue = "json/xml" APIParameterTypeXml APIParameterTypeValue = "json/xml" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/problems.go000066400000000000000000000004311400161560600300470ustar00rootroot00000000000000package apiendpoints type Problems []*Problem type Problem struct { Detail string `json:"detail"` Errors Problems `json:"errors"` Instance string `json:"instance"` Status int `json:"status"` Title string `json:"title"` Type string `json:"type"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/resources.go000066400000000000000000000043431400161560600302440ustar00rootroot00000000000000package apiendpoints import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type Resources []Resource type Resource struct { APIResourceID int `json:"apiResourceId"` APIResourceName string `json:"apiResourceName"` ResourcePath string `json:"resourcePath"` Description string `json:"description"` LockVersion int `json:"lockVersion"` APIResourceClonedFromID *int `json:"apiResourceClonedFromId"` APIResourceLogicID int `json:"apiResourceLogicId"` CreatedBy string `json:"createdBy"` CreateDate string `json:"createDate"` UpdatedBy string `json:"updatedBy"` UpdateDate string `json:"updateDate"` APIResourceMethods Methods `json:"apiResourceMethods"` } type ResourceBaseInfo struct { APIResourceClonedFromID *int `json:"apiResourceClonedFromId"` APIResourceID int `json:"apiResourceId"` APIResourceLogicID int `json:"apiResourceLogicId"` APIResourceName string `json:"apiResourceName"` CreateDate string `json:"createDate"` CreatedBy string `json:"createdBy"` Description *string `json:"description"` Link *string `json:"link"` LockVersion int `json:"lockVersion"` Private bool `json:"private"` ResourcePath string `json:"resourcePath"` UpdateDate string `json:"updateDate"` UpdatedBy string `json:"updatedBy"` } type ResourceSettings struct { Path string `json:"path"` Methods []MethodValue `json:"methods"` InheritsFromEndpoint bool `json:"inheritsFromEndpoint"` } func GetResources(endpointId int, version int) (*Resources, error) { req, err := client.NewJSONRequest( Config, "GET", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/resources", endpointId, version, ), nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Resources{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/service.go000066400000000000000000000013461400161560600276720ustar00rootroot00000000000000package apiendpoints import ( "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the CCU edgegrid Config func Init(config edgegrid.Config) { Config = config } func call(req *http.Request, err error) (*Endpoint, error) { if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Endpoint{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/service_test.go000066400000000000000000000015111400161560600307230ustar00rootroot00000000000000package apiendpoints import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) func TestInit(t *testing.T) { Init(config) assert.Equal(t, config.Host, Config.Host) assert.Equal(t, config.AccessToken, Config.AccessToken) assert.Equal(t, config.ClientToken, Config.ClientToken) assert.Equal(t, config.ClientSecret, Config.ClientSecret) assert.Equal(t, config.MaxBody, Config.MaxBody) assert.Equal(t, config.Debug, Config.Debug) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/api-endpoints-v2/versions.go000066400000000000000000000071761400161560600301110ustar00rootroot00000000000000package apiendpoints import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type Versions struct { APIEndPointID int `json:"apiEndPointId"` APIEndPointName string `json:"apiEndPointName"` APIVersions []Version `json:"apiVersions"` } type Version struct { CreatedBy string `json:"createdBy"` CreateDate string `json:"createDate"` UpdateDate string `json:"updateDate"` UpdatedBy string `json:"updatedBy"` APIEndPointVersionID int `json:"apiEndPointVersionId"` BasePath string `json:"basePath"` Description *string `json:"description` BasedOn *int `json:"basedOn"` StagingStatus *StatusValue `json:"stagingStatus"` ProductionStatus *StatusValue `json:"productionStatus"` StagingDate *string `json:"stagingDate"` ProductionDate *string `json:"productionDate"` IsVersionLocked bool `json:"isVersionLocked"` AvailableActions []string `json:"availableActions"` VersionNumber int `json:"versionNumber"` LockVersion int `json:"lockVersion"` } type VersionSummary struct { Status StatusValue `json:"status,omitempty"` VersionNumber int `json:"versionNumber,omitempty"` } type StatusValue string const ( StatusPending string = "PENDING" StatusActive string = "ACTIVE" StatusDeactivated string = "DEACTIVATED" StatusFailed string = "FAILED" ) type ListVersionsOptions struct { EndpointId int } func ListVersions(options *ListVersionsOptions) (*Versions, error) { req, err := client.NewJSONRequest( Config, "GET", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions", options.EndpointId, ), nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Versions{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } type GetVersionOptions struct { EndpointId int Version int } func GetVersion(options *GetVersionOptions) (*Endpoint, error) { if options.Version == 0 { versions, err := ListVersions(&ListVersionsOptions{EndpointId: options.EndpointId}) if err != nil { return nil, err } loc := len(versions.APIVersions) - 1 v := versions.APIVersions[loc] options.Version = v.VersionNumber } req, err := client.NewJSONRequest( Config, "GET", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/resources-detail", options.EndpointId, options.Version, ), nil, ) return call(req, err) } func ModifyVersion(endpoint *Endpoint) (*Endpoint, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d", endpoint.APIEndPointID, endpoint.VersionNumber, ), endpoint, ) return call(req, err) } type CloneVersionOptions struct { EndpointId int Version int } func CloneVersion(options *CloneVersionOptions) (*Endpoint, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d/cloneVersion", options.EndpointId, options.Version, ), options, ) return call(req, err) } type RemoveVersionOptions struct { EndpointId int VersionNumber int } func RemoveVersion(options *RemoveVersionOptions) (*Endpoint, error) { req, err := client.NewJSONRequest( Config, "DELETE", fmt.Sprintf( "/api-definitions/v2/endpoints/%d/versions/%d", options.EndpointId, options.VersionNumber, ), nil, ) return call(req, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/apikey-manager-v1/000077500000000000000000000000001400161560600260165ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/apikey-manager-v1/collections.go000066400000000000000000000120401400161560600306600ustar00rootroot00000000000000package apikeymanager import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type Collections []Collection type Collection struct { Id int `json:"id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` KeyCount int `json:"keyCount,omitempty"` Dirty bool `json:"dirty,omitempty"` ContractId string `json:"contractId,omitempty"` GroupId int `json:"groupId,omitempty"` GrantedACL []string `json:"grantedACL,omitempty"` DirtyACL []string `json:"dirtyACL,omitempty"` Quota Quota `json:"quota,omitempty"` } func ListCollections() (*Collections, error) { req, err := client.NewJSONRequest( Config, "GET", "/apikey-manager-api/v1/collections", nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collections{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } type CreateCollectionOptions struct { ContractId string `json:"contractId,omitempty"` GroupId int `json:"groupId,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` } func CreateCollection(options *CreateCollectionOptions) (*Collection, error) { req, err := client.NewJSONRequest( Config, "POST", "/apikey-manager-api/v1/collections", options, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collection{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } func GetCollection(collectionId int) (*Collection, error) { req, err := client.NewJSONRequest( Config, "GET", fmt.Sprintf("/apikey-manager-api/v1/collections/%d", collectionId), nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collection{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } func CollectionAclAllow(collectionId int, acl []string) (*Collection, error) { collection, err := GetCollection(collectionId) if err != nil { return collection, err } acl = append(acl, collection.GrantedACL...) req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/apikey-manager-api/v1/collections/%d/acl", collectionId), acl, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collection{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } func CollectionAclDeny(collectionId int, acl []string) (*Collection, error) { collection, err := GetCollection(collectionId) if err != nil { return collection, err } for cIndex, currentAcl := range collection.GrantedACL { for _, newAcl := range acl { if newAcl == currentAcl { collection.GrantedACL = append( collection.GrantedACL[:cIndex], collection.GrantedACL[cIndex+1:]..., ) } } } req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/apikey-manager-api/v1/collections/%d/acl", collectionId), collection.GrantedACL, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collection{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } type Quota struct { Enabled bool `json:"enabled,omitempty"` Value int `json:"value,omitempty"` Interval string `json:"interval,omitempty"` Headers struct { DenyLimitHeaderShown bool `json:"denyLimitHeaderShown,omitempty"` DenyRemainingHeaderShown bool `json:"denyRemainingHeaderShown,omitempty"` DenyNextHeaderShown bool `json:"denyNextHeaderShown,omitempty"` AllowLimitHeaderShown bool `json:"allowLimitHeaderShown,omitempty"` AllowRemainingHeaderShown bool `json:"allowRemainingHeaderShown,omitempty"` AllowResetHeaderShown bool `json:"allowResetHeaderShown,omitempty"` } `json:"headers,omitempty"` } func CollectionSetQuota(collectionId int, value int) (*Collection, error) { collection, err := GetCollection(collectionId) if err != nil { return collection, err } collection.Quota.Value = value req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/apikey-manager-api/v1/collections/%d/quota", collectionId), collection.Quota, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Collection{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/apikey-manager-v1/keys.go000066400000000000000000000062321400161560600273230ustar00rootroot00000000000000package apikeymanager import ( "encoding/json" "io/ioutil" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type Keys []int type Key struct { Id int `json:"id,omitempty"` Value string `json:"value,omitempty"` Label string `json:"label,omitempty"` Tags []string `json:"tags,omitempty"` CollectionName string `json:"collectionName,omitempty"` CollectionId int `json:"collectionId,omitempty"` Description string `json:"description,omitempty"` Revoked bool `json:"revoked,omitempty"` Dirty bool `json:"dirty,omitempty"` CreatedAt string `json:"createdAt,omitempty"` RevokedAt string `json:"revokedAt,omitempty"` TerminationAt string `json:"terminationAt,omitempty"` QuotaUsage int `json:"quotaUsage,omitempty"` QuotaUsageTimestamp string `json:"quotaUsageTimestamp,omitempty"` QuotaUpdateState string `json:"quotaUpdateState,omitempty"` } type CreateKey struct { Value string `json:"value,omitempty"` Label string `json:"label,omitempty"` Tags []string `json:"tags,omitempty"` CollectionId int `json:"collectionId,omitempty"` Description string `json:"description,omitempty"` Mode string `json:"mode,omitempty"` } func CollectionAddKey(collectionId int, name, value string) (*Key, error) { req, err := client.NewJSONRequest( Config, "POST", "/apikey-manager-api/v1/keys", &CreateKey{ Label: name, Value: value, CollectionId: collectionId, Mode: "CREATE_ONE", }, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Key{} if err = client.BodyJSON(res, rep); err != nil { return nil, err } return rep, nil } type ImportKey struct { Name string `json:"name,omitempty"` Content string `json:"content,omitempty"` CollectionId int `json:"collectionId,omitempty"` } func CollectionImportKeys(collectionId int, filename string) (*Keys, error) { fileContent, err := ioutil.ReadFile(filename) if err != nil { return nil, err } req, err := client.NewJSONRequest( Config, "POST", "/apikey-manager-api/v1/keys/import", &ImportKey{ Name: filename, CollectionId: collectionId, Content: string(fileContent), }, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } rep := &Keys{} err = json.Unmarshal(fileContent, rep) return rep, err } type RevokeKeys struct { Keys Keys `json:"keys,omitempty"` } func RevokeKey(key int) (*Key, error) { req, err := client.NewJSONRequest( Config, "POST", "/apikey-manager-api/v1/keys/revoke", &RevokeKeys{ Keys: Keys{key}, }, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } return &Key{}, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/apikey-manager-v1/service.go000066400000000000000000000004701400161560600300060ustar00rootroot00000000000000package apikeymanager import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the edgegrid Config func Init(config edgegrid.Config) { Config = config } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/ccu-v3/000077500000000000000000000000001400161560600237005ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/ccu-v3/purge.go000066400000000000000000000033331400161560600253530ustar00rootroot00000000000000package ccu import ( "errors" fmt "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type PurgeTypeValue string type NetworkValue string var ( PurgeByUrl PurgeTypeValue = "url" PurgeByCpCode PurgeTypeValue = "cpcode" PurgeByCacheTag PurgeTypeValue = "tag" NetworkStaging NetworkValue = "staging" NetworkProduction NetworkValue = "production" ) type Purge struct { Objects []string `json:"objects""` } func NewPurge(objects []string) *Purge { return &Purge{ Objects: objects, } } func (p *Purge) Invalidate(purgeByType PurgeTypeValue, network NetworkValue) (*PurgeResponse, error) { return p.purge("invalidate", purgeByType, network) } func (p *Purge) Delete(purgeByType PurgeTypeValue, network NetworkValue) (*PurgeResponse, error) { return p.purge("delete", purgeByType, network) } func (p *Purge) purge(purgeMethod string, purgeByType PurgeTypeValue, network NetworkValue) (*PurgeResponse, error) { if len(p.Objects) == 0 { return nil, errors.New("one of more purge objects must be defined") } url := fmt.Sprintf( "/ccu/v3/%s/%s/%s", purgeMethod, purgeByType, network, ) req, err := client.NewJSONRequest(Config, "POST", url, p) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } purge := &PurgeResponse{} if err = client.BodyJSON(res, purge); err != nil { return nil, err } return purge, nil } type PurgeResponse struct { PurgeID string `json:"purgeId"` EstimatedSeconds int `json:"estimatedSeconds"` HTTPStatus int `json:"httpStatus"` Detail string `json:"detail"` SupportID string `json:"supportId"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/ccu-v3/purge_test.go000066400000000000000000000136441400161560600264200ustar00rootroot00000000000000package ccu import ( "testing" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) func TestPurge_Invalidate(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/invalidate/url/production") mock. Post("/ccu/v3/invalidate/url/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"https://www.daveyshafik.com"}) res, err := purge.Invalidate(PurgeByUrl, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } func TestPurge_Delete(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/delete/url/production") mock. Post("/ccu/v3/delete/url/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"https://www.daveyshafik.com"}) res, err := purge.Delete(PurgeByUrl, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } func TestPurge_Invalidate_CpCode(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/invalidate/cpcode/production") mock. Post("/ccu/v3/invalidate/cpcode/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"cpc_12345"}) res, err := purge.Invalidate(PurgeByCpCode, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } func TestPurge_Invalidate_CacheTag(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/invalidate/tag/production") mock. Post("/ccu/v3/invalidate/tag/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"https://www.daveyshafik.com"}) res, err := purge.Invalidate(PurgeByCacheTag, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } func TestPurge_Delete_CpCode(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/delete/cpcode/production") mock. Post("/ccu/v3/delete/cpcode/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"cpc_12345"}) res, err := purge.Delete(PurgeByCpCode, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } func TestPurge_Delete_CacheTag(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/ccu/v3/delete/tag/production") mock. Post("/ccu/v3/delete/tag/production"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "detail": "Request accepted", "estimatedSeconds": 5, "httpStatus": 201, "purgeId": "674e54ae-3131-11e8-ba75-615d2757a3f3", "supportId": "17PY1522094889114372-178558144" }`) Init(config) purge := NewPurge([]string{"https://www.daveyshafik.com"}) res, err := purge.Delete(PurgeByCacheTag, NetworkProduction) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, res.Detail, "Request accepted") assert.Equal(t, res.EstimatedSeconds, 5) assert.Equal(t, res.HTTPStatus, 201) assert.Equal(t, res.PurgeID, "674e54ae-3131-11e8-ba75-615d2757a3f3") assert.Equal(t, res.SupportID, "17PY1522094889114372-178558144") } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/ccu-v3/service.go000066400000000000000000000004621400161560600256710ustar00rootroot00000000000000package ccu import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the CCU edgegrid Config func Init(config edgegrid.Config) { Config = config } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/ccu-v3/service_test.go000066400000000000000000000015001400161560600267220ustar00rootroot00000000000000package ccu import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) func TestInit(t *testing.T) { Init(config) assert.Equal(t, config.Host, Config.Host) assert.Equal(t, config.AccessToken, Config.AccessToken) assert.Equal(t, config.ClientToken, Config.ClientToken) assert.Equal(t, config.ClientSecret, Config.ClientSecret) assert.Equal(t, config.MaxBody, Config.MaxBody) assert.Equal(t, config.Debug, Config.Debug) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/000077500000000000000000000000001400161560600244025ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/README.md000066400000000000000000000002011400161560600256520ustar00rootroot00000000000000# Akamai Client A golang package which helps facilitate making HTTP requests to [Akamai OPEN APIs](https://developer.akamai.com)golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/api.go000066400000000000000000000020231400161560600254770ustar00rootroot00000000000000package client import ( "encoding/json" ) // Resource is the "base" type for all API resources type Resource struct { Complete chan bool `json:"-"` } // Init initializes the Complete channel, if it is necessary // need to create a resource specific Init(), make sure to // initialize the channel. func (resource *Resource) Init() { resource.Complete = make(chan bool, 1) } // PostUnmarshalJSON is a default implementation of the // PostUnmarshalJSON hook that simply calls Init() and // sends true to the Complete channel. This is overridden // in many resources, in particular those that represent // collections, and have to initialize sub-resources also. func (resource *Resource) PostUnmarshalJSON() error { resource.Init() resource.Complete <- true return nil } // GetJSON returns the raw (indented) JSON (as []bytes) func (resource *Resource) GetJSON() ([]byte, error) { return json.MarshalIndent(resource, "", " ") } // JSONBody is a generic struct for temporary JSON unmarshalling. type JSONBody map[string]interface{} golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/api_test.go000066400000000000000000000012121400161560600265350ustar00rootroot00000000000000package client import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" ) type Test struct { Resource Foo string `json:"foo"` } func (test *Test) PreMarshalJSON() error { test.Foo = "bat" return nil } func TestResourceUnmarshal(t *testing.T) { body := []byte(`{"foo":"bar"}`) test := &Test{} err := jsonhooks.Unmarshal(body, test) assert.NoError(t, err) assert.True(t, <-test.Complete) } func TestResourceMarshal(t *testing.T) { test := &Test{Foo: "bar"} body, err := jsonhooks.Marshal(test) assert.NoError(t, err) assert.Equal(t, []byte(`{"foo":"bat"}`), body) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/client.go000066400000000000000000000100301400161560600262010ustar00rootroot00000000000000// Package client is a simple library for http.Client to sign Akamai OPEN Edgegrid API requests package client import ( "bytes" "errors" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "io" "io/ioutil" "mime/multipart" "net/http" "net/url" "os" "path/filepath" "runtime" "strings" "sync" ) var ( libraryVersion = "0.6.2" // UserAgent is the User-Agent value sent for all requests UserAgent = "Akamai-Open-Edgegrid-golang/" + libraryVersion + " golang/" + strings.TrimPrefix(runtime.Version(), "go") // Client is the *http.Client to use Client = http.DefaultClient reqLock sync.Mutex ) // NewRequest creates an HTTP request that can be sent to Akamai APIs. A relative URL can be provided in path, which will be resolved to the // Host specified in Config. If body is specified, it will be sent as the request body. func NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error) { var ( baseURL *url.URL err error ) reqLock.Lock() defer reqLock.Unlock() if strings.HasPrefix(config.Host, "https://") { baseURL, err = url.Parse(config.Host) } else { baseURL, err = url.Parse("https://" + config.Host) } if err != nil { return nil, err } rel, err := url.Parse(strings.TrimPrefix(path, "/")) if err != nil { return nil, err } u := baseURL.ResolveReference(rel) if config.AccountKey != "" { q := u.Query() q.Add("accountSwitchKey", config.AccountKey) u.RawQuery = q.Encode() } req, err := http.NewRequest(method, u.String(), body) if err != nil { return nil, err } req.Header.Add("User-Agent", UserAgent) return req, nil } // NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body // The JSON body is encoded and the Content-Type/Accept headers are set automatically. func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) { var req *http.Request var err error if body != nil { jsonBody, err := jsonhooks.Marshal(body) if err != nil { return nil, err } buf := bytes.NewReader(jsonBody) req, err = NewRequest(config, method, path, buf) } else { req, err = NewRequest(config, method, path, nil) } if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json,*/*") return req, nil } // NewMultiPartFormDataRequest creates an HTTP request that uploads a file to the Akamai API func NewMultiPartFormDataRequest(config edgegrid.Config, uriPath, filePath string, otherFormParams map[string]string) (*http.Request, error) { file, err := os.Open(filePath) if err != nil { return nil, err } defer file.Close() body := &bytes.Buffer{} writer := multipart.NewWriter(body) // TODO: make this field name configurable part, err := writer.CreateFormFile("importFile", filepath.Base(filePath)) if err != nil { return nil, err } _, err = io.Copy(part, file) for key, val := range otherFormParams { _ = writer.WriteField(key, val) } err = writer.Close() if err != nil { return nil, err } req, err := NewRequest(config, "POST", uriPath, body) req.Header.Set("Content-Type", writer.FormDataContentType()) return req, err } // Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid // Authorization header. An edgegrid.Response or an error is returned. func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) { Client.CheckRedirect = func(req *http.Request, via []*http.Request) error { req = edgegrid.AddRequestHeader(config, req) return nil } req = edgegrid.AddRequestHeader(config, req) res, err := Client.Do(req) if err != nil { return nil, err } return res, nil } // BodyJSON unmarshals the Response.Body into a given data structure func BodyJSON(r *http.Response, data interface{}) error { if data == nil { return errors.New("You must pass in an interface{}") } body, err := ioutil.ReadAll(r.Body) if err != nil { return err } err = jsonhooks.Unmarshal(body, data) return err } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/client_test.go000066400000000000000000000044201400161560600272460ustar00rootroot00000000000000package client import ( "net/http" "strings" "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" ) func TestNewRequest(t *testing.T) { config := edgegrid.Config{ Host: "https://httpbin.org", AccessToken: "local-config", ClientSecret: "local-config", ClientToken: "local-config", } req, err := NewRequest(config, "GET", "/headers", nil) assert.NotNil(t, req) assert.NoError(t, err) assert.Equal(t, "https://httpbin.org/headers", req.URL.String()) verifyResponseConfig(t, config, req) } func TestNewRequestWithSwitchedAccount(t *testing.T) { config := edgegrid.Config{ Host: "https://httpbin.org", AccessToken: "local-config", ClientSecret: "local-config", ClientToken: "local-config", AccountKey: "ABC-DEF", } req, err := NewRequest(config, "GET", "/headers", nil) assert.NotNil(t, req) assert.NoError(t, err) assert.Equal(t, "https://httpbin.org/headers?accountSwitchKey=ABC-DEF", req.URL.String()) verifyResponseConfig(t, config, req) } func TestNewJSONRequest(t *testing.T) { config := edgegrid.Config{ Host: "https://httpbin.org", AccessToken: "local-config", ClientSecret: "local-config", ClientToken: "local-config", } req, err := NewJSONRequest(config, "GET", "/headers", config) assert.NotNil(t, req) assert.NoError(t, err) assert.Equal(t, "https://httpbin.org/headers", req.URL.String()) verifyResponseConfig(t, config, req) } func TestNewJSONRequestWithSwitchedAccount(t *testing.T) { config := edgegrid.Config{ Host: "https://httpbin.org", AccessToken: "local-config", ClientSecret: "local-config", ClientToken: "local-config", AccountKey: "ABC-DEF", } req, err := NewJSONRequest(config, "GET", "/headers", config) assert.NotNil(t, req) assert.NoError(t, err) assert.Equal(t, "https://httpbin.org/headers?accountSwitchKey=ABC-DEF", req.URL.String()) verifyResponseConfig(t, config, req) } func verifyResponseConfig(t *testing.T, config edgegrid.Config, req *http.Request) { resp, err := Do(config, req) assert.NotNil(t, resp) assert.NoError(t, err) json := make(map[string]interface{}) BodyJSON(resp, &json) assert.True(t, strings.Contains(json["headers"].(map[string]interface{})["Authorization"].(string), "local-config")) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client-v1/errors.go000066400000000000000000000063201400161560600262460ustar00rootroot00000000000000package client import ( "fmt" "io/ioutil" "net/http" "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" ) // APIError exposes an Akamai OPEN Edgegrid Error type APIError struct { error Type string `json:"type"` Title string `json:"title"` Status int `json:"status"` Detail string `json:"detail"` Errors []APIErrorDetail `json:"errors"` Problems []APIErrorDetail `json:"problems"` Instance string `json:"instance"` Method string `json:"method"` ServerIP string `json:"serverIp"` ClientIP string `json:"clientIp"` RequestID string `json:"requestId"` RequestTime string `json:"requestTime"` Response *http.Response `json:"-"` RawBody string `json:"-"` } type APIErrorDetail struct { Type string `json:"type"` Title string `json:"title"` Detail string `json:"detail"` RejectedValue string `json:"rejectedValue"` } func (error APIError) Error() string { var errorDetails string if len(error.Errors) > 0 { for _, e := range error.Errors { errorDetails = fmt.Sprintf("%s \n %s", errorDetails, e) } } if len(error.Problems) > 0 { for _, e := range error.Problems { errorDetails = fmt.Sprintf("%s \n %s", errorDetails, e) } } return strings.TrimSpace(fmt.Sprintf("API Error: %d %s %s More Info %s\n %s", error.Status, error.Title, error.Detail, error.Type, errorDetails)) } // NewAPIError creates a new API error based on a Response, // or http.Response-like. func NewAPIError(response *http.Response) APIError { // TODO: handle this error body, _ := ioutil.ReadAll(response.Body) return NewAPIErrorFromBody(response, body) } // NewAPIErrorFromBody creates a new API error, allowing you to pass in a body // // This function is intended to be used after the body has already been read for // other purposes. func NewAPIErrorFromBody(response *http.Response, body []byte) APIError { error := APIError{} if err := jsonhooks.Unmarshal(body, &error); err != nil { error.Status = response.StatusCode error.Title = response.Status } error.Response = response error.RawBody = string(body) return error } // IsInformational determines if a response was informational (1XX status) func IsInformational(r *http.Response) bool { return r.StatusCode > 99 && r.StatusCode < 200 } // IsSuccess determines if a response was successful (2XX status) func IsSuccess(r *http.Response) bool { return r.StatusCode > 199 && r.StatusCode < 300 } // IsRedirection determines if a response was a redirect (3XX status) func IsRedirection(r *http.Response) bool { return r.StatusCode > 299 && r.StatusCode < 400 } // IsClientError determines if a response was a client error (4XX status) func IsClientError(r *http.Response) bool { return r.StatusCode > 399 && r.StatusCode < 500 } // IsServerError determines if a response was a server error (5XX status) func IsServerError(r *http.Response) bool { return r.StatusCode > 499 && r.StatusCode < 600 } // IsError determines if the response was a client or server error (4XX or 5XX status) func IsError(r *http.Response) bool { return r.StatusCode > 399 && r.StatusCode < 600 } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/client.go000066400000000000000000000132201400161560600244030ustar00rootroot00000000000000// Package edgegrid provides the Akamai OPEN Edgegrid Authentication scheme // // Deprecated: use client-v1/client instead package edgegrid import ( "bytes" "encoding/json" "errors" "io/ioutil" "net/http" "net/url" "runtime" "strings" ) const ( libraryVersion = "0.3.0" ) // Response is a Wrapper for http.Response // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client type Response http.Response // Client is a simple http.Client wrapper that transparently signs requests // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client type Client struct { http.Client // HTTP client used to communicate with the Akamai APIs. //client *http.Client // Base URL for API requests. BaseURL *url.URL // User agent for client UserAgent string Config Config } // JSONBody represents a generic JSON response // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client type JSONBody map[string]interface{} // New creates a new Client with a given Config // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func New(httpClient *http.Client, config Config) (*Client, error) { c := NewClient(httpClient) c.Config = config baseURL, err := url.Parse("https://" + config.Host) if err != nil { return nil, err } c.BaseURL = baseURL return c, nil } // NewClient creates a new Client // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func NewClient(httpClient *http.Client) *Client { if httpClient == nil { httpClient = http.DefaultClient } client := &Client{ Client: *httpClient, UserAgent: "Akamai-Open-Edgegrid-golang/" + libraryVersion + " golang/" + strings.TrimPrefix(runtime.Version(), "go"), } return client } // NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the // BaseURL of the Client. If specified, the value pointed to by body is JSON encoded and included in as the request body. // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { var req *http.Request urlStr = strings.TrimPrefix(urlStr, "/") rel, err := url.Parse(urlStr) if err != nil { return nil, err } u := c.BaseURL.ResolveReference(rel) req, err = http.NewRequest(method, u.String(), nil) if err != nil { return nil, err } req.Header.Add("User-Agent", c.UserAgent) return req, nil } // NewJSONRequest creates an API request with JSON body. A relative URL can be provided in urlStr, which will be resolved to the // BaseURL of the Client. If specified, the value pointed to by body is JSON encoded and included in as the request body. // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) NewJSONRequest(method, urlStr string, body interface{}) (*http.Request, error) { buf := new(bytes.Buffer) err := json.NewEncoder(buf).Encode(body) if err != nil { return nil, err } req, err := c.NewRequest(method, urlStr, buf) if err != nil { return nil, err } req.Header.Add("Content-Type", "application/json") req.Header.Add("Accept", "application/json,*/*") return req, nil } // Do executes the HTTP request // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) Do(req *http.Request) (*Response, error) { req = c.Config.AddRequestHeader(req) response, err := c.Client.Do(req) if err != nil { return nil, err } res := Response(*response) return &res, nil } // Get performs an HTTP GET request // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) Get(url string) (*Response, error) { req, err := c.NewRequest("GET", url, nil) if err != nil { return nil, err } req = c.Config.AddRequestHeader(req) response, err := c.Do(req) if err != nil { return nil, err } return response, nil } // Post performs an HTTP POST request // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) Post(url string, bodyType string, body interface{}) (*Response, error) { req, err := c.NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", bodyType) req = c.Config.AddRequestHeader(req) response, err := c.Do(req) if err != nil { return nil, err } return response, nil } // PostForm performs an HTTP POST request with a form body // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) PostForm(url string, data url.Values) (*Response, error) { return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } // PostJSON performs an HTTP POST request with a JSON body // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) PostJSON(url string, data interface{}) (*Response, error) { buf := new(bytes.Buffer) err := json.NewEncoder(buf).Encode(data) if err != nil { return nil, err } return c.Post(url, "application/json", buf) } // Head performs an HTTP HEAD request // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (c *Client) Head(url string) (*Response, error) { req, err := c.NewRequest("HEAD", url, nil) if err != nil { return nil, err } response, err := c.Do(req) if err != nil { return nil, err } return response, nil } // BodyJSON retrieves and unmarshals a responses JSON body // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/client func (r *Response) BodyJSON(data interface{}) error { if data == nil { return errors.New("You must pass in an interface{}") } body, err := ioutil.ReadAll(r.Body) if err != nil { return err } err = json.Unmarshal(body, &data) return err } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/000077500000000000000000000000001400161560600250765ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/README.md000066400000000000000000000002551400161560600263570ustar00rootroot00000000000000# Akamai Config DNS (Zone Record Management) A golang package that talks to the [Akamai OPEN Config DNS API](https://developer.akamai.com/api/luna/config-dns/overview.html).golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/errors.go000066400000000000000000000042211400161560600267400ustar00rootroot00000000000000package dns import ( "fmt" ) type ConfigDNSError interface { error Network() bool NotFound() bool FailedToSave() bool ValidationFailed() bool } func IsConfigDNSError(e error) bool { _, ok := e.(ConfigDNSError) return ok } type ZoneError struct { zoneName string httpErrorMessage string apiErrorMessage string err error } func (e *ZoneError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e *ZoneError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } return false } func (e *ZoneError) FailedToSave() bool { return false } func (e *ZoneError) ValidationFailed() bool { if e.apiErrorMessage != "" { return true } return false } func (e *ZoneError) Error() string { if e.Network() { return fmt.Sprintf("Zone \"%s\" network error: [%s]", e.zoneName, e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("Zone \"%s\" not found.", e.zoneName) } if e.FailedToSave() { return fmt.Sprintf("Zone \"%s\" failed to save: [%s]", e.zoneName, e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("Zone \"%s\" validation failed: [%s]", e.zoneName, e.apiErrorMessage) } if e.err != nil { return e.err.Error() } return "" } type RecordError struct { fieldName string httpErrorMessage string err error } func (e *RecordError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e *RecordError) NotFound() bool { return false } func (e *RecordError) FailedToSave() bool { if e.fieldName == "" { return true } return false } func (e *RecordError) ValidationFailed() bool { if e.fieldName != "" { return true } return false } func (e *RecordError) Error() string { if e.Network() { return fmt.Sprintf("Record network error: [%s]", e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("Record not found.") } if e.FailedToSave() { return fmt.Sprintf("Record failed to save: [%s]", e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("Record validation failed for field [%s]", e.fieldName) } return "" } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/record.go000066400000000000000000001034471400161560600267140ustar00rootroot00000000000000package dns import ( "strings" "time" ) // All record types (below) must implement the DNSRecord interface // This allows the record to be used dynamically in slices - see the Zone struct definition in zone.go // // The record types implemented and their fields are as defined here // https://developer.akamai.com/api/luna/config-dns/data.html type DNSRecord interface { // Get the list of allowed fields for this type GetAllowedFields() []string // Set a field on the struct, which check for valid fields SetField(name string, value interface{}) error // Translate struct properties to a map ToMap() map[string]interface{} } type ARecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewARecord() *ARecord { return &ARecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *ARecord) GetAllowedFields() []string { return record.fieldMap } func (record *ARecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *ARecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type AaaaRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewAaaaRecord() *AaaaRecord { return &AaaaRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *AaaaRecord) GetAllowedFields() []string { return record.fieldMap } func (record *AaaaRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *AaaaRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type AfsdbRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` Subtype int `json:"subtype,omitempty"` } func NewAfsdbRecord() *AfsdbRecord { return &AfsdbRecord{ fieldMap: []string{ "name", "ttl", "active", "target", "subtype", }, } } func (record *AfsdbRecord) GetAllowedFields() []string { return record.fieldMap } func (record *AfsdbRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } case "subtype": v, ok := value.(int) if ok { record.Subtype = v return nil } } } return &RecordError{fieldName: name} } func (record *AfsdbRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, "subtype": record.Subtype, } } type CnameRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewCnameRecord() *CnameRecord { return &CnameRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *CnameRecord) GetAllowedFields() []string { return record.fieldMap } func (record *CnameRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *CnameRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type DnskeyRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Flags int `json:"flags,omitempty"` Protocol int `json:"protocol,omitempty"` Algorithm int `json:"algorithm,omitempty"` Key string `json:"key,omitempty"` } func NewDnskeyRecord() *DnskeyRecord { return &DnskeyRecord{ fieldMap: []string{ "name", "ttl", "active", "flags", "protocol", "algorithm", "key", }, } } func (record *DnskeyRecord) GetAllowedFields() []string { return record.fieldMap } func (record *DnskeyRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "flags": v, ok := value.(int) if ok { record.Flags = v return nil } case "protocol": v, ok := value.(int) if ok { record.Protocol = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "key": v, ok := value.(string) if ok { record.Key = v return nil } } } return &RecordError{fieldName: name} } func (record *DnskeyRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "flags": record.Flags, "protocol": record.Protocol, "algorithm": record.Algorithm, "key": record.Key, } } type DsRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Keytag int `json:"keytag,omitempty"` Algorithm int `json:"algorithm,omitempty"` DigestType int `json:"digest_type,omitempty"` Digest string `json:"digest,omitempty"` } func NewDsRecord() *DsRecord { return &DsRecord{ fieldMap: []string{ "name", "ttl", "active", "keytag", "algorithm", "digesttype", "digest", }, } } func (record *DsRecord) GetAllowedFields() []string { return record.fieldMap } func (record *DsRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "keytag": v, ok := value.(int) if ok { record.Keytag = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "digesttype": v, ok := value.(int) if ok { record.DigestType = v return nil } case "digest": v, ok := value.(string) if ok { record.Digest = v return nil } } } return &RecordError{fieldName: name} } func (record *DsRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "keytag": record.Keytag, "algorithm": record.Algorithm, "digesttype": record.DigestType, "digest": record.DigestType, } } type HinfoRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Hardware string `json:"hardware,omitempty"` Software string `json:"software,omitempty"` } func NewHinfoRecord() *HinfoRecord { return &HinfoRecord{ fieldMap: []string{ "name", "ttl", "active", "hardware", "software", }, } } func (record *HinfoRecord) GetAllowedFields() []string { return record.fieldMap } func (record *HinfoRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "hardware": v, ok := value.(string) if ok { record.Hardware = v return nil } case "software": v, ok := value.(string) if ok { record.Software = v return nil } } } return &RecordError{fieldName: name} } func (record *HinfoRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "hardware": record.Hardware, "software": record.Software, } } type LocRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewLocRecord() *LocRecord { return &LocRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *LocRecord) GetAllowedFields() []string { return record.fieldMap } func (record *LocRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *LocRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type MxRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` Priority int `json:"priority,omitempty"` } func NewMxRecord() *MxRecord { return &MxRecord{ fieldMap: []string{ "name", "ttl", "active", "target", "priority", }, } } func (record *MxRecord) GetAllowedFields() []string { return record.fieldMap } func (record *MxRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } case "priority": v, ok := value.(int) if ok { record.Priority = v return nil } } } return &RecordError{fieldName: name} } func (record *MxRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, "priority": record.Priority, } } type NaptrRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Order uint16 `json:"order,omitempty"` Preference uint16 `json:"preference,omitempty"` Flags string `json:"flags,omitempty"` Service string `json:"service,omitempty"` Regexp string `json:"regexp,omitempty"` Replacement string `json:"replacement,omitempty"` } func NewNaptrRecord() *NaptrRecord { return &NaptrRecord{ fieldMap: []string{ "name", "ttl", "active", "order", "preference", "flags", "service", "regexp", "replacement", }, } } func (record *NaptrRecord) GetAllowedFields() []string { return record.fieldMap } func (record *NaptrRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "order": v, ok := value.(uint16) if ok { record.Order = v return nil } case "preference": v, ok := value.(uint16) if ok { record.Preference = v return nil } case "flags": v, ok := value.(string) if ok { record.Flags = v return nil } case "service": v, ok := value.(string) if ok { record.Service = v return nil } case "regexp": v, ok := value.(string) if ok { record.Regexp = v return nil } case "replacement": v, ok := value.(string) if ok { record.Replacement = v return nil } } } return &RecordError{fieldName: name} } func (record *NaptrRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "order": record.Order, "preference": record.Preference, "flags": record.Flags, "service": record.Service, "regexp": record.Regexp, "replacement": record.Replacement, } } type NsRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewNsRecord() *NsRecord { return &NsRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *NsRecord) GetAllowedFields() []string { return record.fieldMap } func (record *NsRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *NsRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type Nsec3Record struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Algorithm int `json:"algorithm,omitempty"` Flags int `json:"flags,omitempty"` Iterations int `json:"iterations,omitempty"` Salt string `json:"salt,omitempty"` NextHashedOwnerName string `json:"next_hashed_owner_name,omitempty"` TypeBitmaps string `json:"type_bitmaps,omitempty"` } func NewNsec3Record() *Nsec3Record { return &Nsec3Record{ fieldMap: []string{ "name", "ttl", "active", "algorithm", "flags", "iterations", "salt", "nexthashedownername", "typebitmaps", }, } } func (record *Nsec3Record) GetAllowedFields() []string { return record.fieldMap } func (record *Nsec3Record) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "flags": v, ok := value.(int) if ok { record.Flags = v return nil } case "iterations": v, ok := value.(int) if ok { record.Iterations = v return nil } case "salt": v, ok := value.(string) if ok { record.Salt = v return nil } case "nexthashedownername": v, ok := value.(string) if ok { record.NextHashedOwnerName = v return nil } case "typebitmaps": v, ok := value.(string) if ok { record.TypeBitmaps = v return nil } } } return &RecordError{fieldName: name} } func (record *Nsec3Record) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "algorithm": record.Algorithm, "flags": record.Flags, "iterations": record.Iterations, "salt": record.Salt, "nexthashedownername": record.NextHashedOwnerName, "typebitmaps": record.TypeBitmaps, } } type Nsec3paramRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Algorithm int `json:"algorithm,omitempty"` Flags int `json:"flags,omitempty"` Iterations int `json:"iterations,omitempty"` Salt string `json:"salt,omitempty"` } func NewNsec3paramRecord() *Nsec3paramRecord { return &Nsec3paramRecord{ fieldMap: []string{ "name", "ttl", "active", "algorithm", "flags", "iterations", "salt", }, } } func (record *Nsec3paramRecord) GetAllowedFields() []string { return record.fieldMap } func (record *Nsec3paramRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "flags": v, ok := value.(int) if ok { record.Flags = v return nil } case "iterations": v, ok := value.(int) if ok { record.Iterations = v return nil } case "salt": v, ok := value.(string) if ok { record.Salt = v return nil } } } return &RecordError{fieldName: name} } func (record *Nsec3paramRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "algorithm": record.Algorithm, "flags": record.Flags, "iterations": record.Iterations, "salt": record.Salt, } } type PtrRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewPtrRecord() *PtrRecord { return &PtrRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *PtrRecord) GetAllowedFields() []string { return record.fieldMap } func (record *PtrRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *PtrRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type RpRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Mailbox string `json:"mailbox,omitempty"` Txt string `json:"txt,omitempty"` } func NewRpRecord() *RpRecord { return &RpRecord{ fieldMap: []string{ "name", "ttl", "active", "mailbox", "txt", }, } } func (record *RpRecord) GetAllowedFields() []string { return record.fieldMap } func (record *RpRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "mailbox": v, ok := value.(string) if ok { record.Mailbox = v return nil } case "txt": v, ok := value.(string) if ok { record.Txt = v return nil } } } return &RecordError{fieldName: name} } func (record *RpRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "mailbox": record.Mailbox, "txt": record.Txt, } } type RrsigRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` TypeCovered string `json:"type_covered,omitempty"` Algorithm int `json:"algorithm,omitempty"` OriginalTTL int `json:"original_ttl,omitempty"` Expiration string `json:"expiration,omitempty"` Inception string `json:"inception,omitempty"` Keytag int `json:"keytag,omitempty"` Signer string `json:"signer,omitempty"` Signature string `json:"signature,omitempty"` Labels int `json:"labels,omitempty"` } func NewRrsigRecord() *RrsigRecord { return &RrsigRecord{ fieldMap: []string{ "name", "ttl", "active", "typecovered", "algorithm", "originalttl", "expiration", "inception", "keytag", "signer", "signature", "labels", }, } } func (record *RrsigRecord) GetAllowedFields() []string { return record.fieldMap } func (record *RrsigRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "typecovered": v, ok := value.(string) if ok { record.TypeCovered = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "originalttl": v, ok := value.(int) if ok { record.OriginalTTL = v return nil } case "expiration": v, ok := value.(string) if ok { record.Expiration = v return nil } case "inception": v, ok := value.(string) if ok { record.Inception = v return nil } case "keytag": v, ok := value.(int) if ok { record.Keytag = v return nil } case "signer": v, ok := value.(string) if ok { record.Signer = v return nil } case "signature": v, ok := value.(string) if ok { record.Signature = v return nil } case "labels": v, ok := value.(int) if ok { record.Labels = v return nil } } } return &RecordError{fieldName: name} } func (record *RrsigRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "typecovered": record.TypeCovered, "algorithm": record.Algorithm, "originalttl": record.OriginalTTL, "expiration": record.Expiration, "inception": record.Inception, "keytag": record.Keytag, "signer": record.Signer, "signature": record.Signature, "labels": record.Labels, } } type SoaRecord struct { fieldMap []string `json:"-"` originalSerial uint `json:"-"` TTL int `json:"ttl,omitempty"` Originserver string `json:"originserver,omitempty"` Contact string `json:"contact,omitempty"` Serial uint `json:"serial,omitempty"` Refresh int `json:"refresh,omitempty"` Retry int `json:"retry,omitempty"` Expire int `json:"expire,omitempty"` Minimum uint `json:"minimum,omitempty"` } func NewSoaRecord() *SoaRecord { r := &SoaRecord{ fieldMap: []string{ "ttl", "originserver", "contact", "serial", "refresh", "retry", "expire", "minimum", }, } r.SetField("serial", int(time.Now().Unix())) return r } func (record *SoaRecord) GetAllowedFields() []string { return record.fieldMap } func (record *SoaRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "originserver": v, ok := value.(string) if ok { record.Originserver = v return nil } case "contact": v, ok := value.(string) if ok { record.Contact = v return nil } case "serial": v, ok := value.(uint) if ok { record.Serial = v return nil } case "refresh": v, ok := value.(int) if ok { record.Refresh = v return nil } case "retry": v, ok := value.(int) if ok { record.Retry = v return nil } case "expire": v, ok := value.(int) if ok { record.Expire = v return nil } case "minimum": v, ok := value.(uint) if ok { record.Minimum = v return nil } } } return &RecordError{fieldName: name} } func (record *SoaRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "ttl": record.TTL, "originserver": record.Originserver, "contact": record.Contact, "serial": record.Serial, "refresh": record.Refresh, "retry": record.Retry, "expire": record.Expire, "minimum": record.Minimum, } } type SpfRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewSpfRecord() *SpfRecord { return &SpfRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *SpfRecord) GetAllowedFields() []string { return record.fieldMap } func (record *SpfRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *SpfRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } type SrvRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` Priority int `json:"priority,omitempty"` Weight uint16 `json:"weight,omitempty"` Port uint16 `json:"port,omitempty"` } func NewSrvRecord() *SrvRecord { return &SrvRecord{ fieldMap: []string{ "name", "ttl", "active", "target", "priority", "weight", "port", }, } } func (record *SrvRecord) GetAllowedFields() []string { return record.fieldMap } func (record *SrvRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } case "priority": v, ok := value.(int) if ok { record.Priority = v return nil } case "weight": v, ok := value.(uint16) if ok { record.Weight = v return nil } case "port": v, ok := value.(uint16) if ok { record.Port = v return nil } } } return &RecordError{fieldName: name} } func (record *SrvRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, "priority": record.Priority, "weight": record.Weight, "port": record.Port, } } type SshfpRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Algorithm int `json:"algorithm,omitempty"` FingerprintType int `json:"fingerprint_type,omitempty"` Fingerprint string `json:"fingerprint,omitempty"` } func NewSshfpRecord() *SshfpRecord { return &SshfpRecord{ fieldMap: []string{ "name", "ttl", "active", "algorithm", "fingerprinttype", "fingerprint", }, } } func (record *SshfpRecord) GetAllowedFields() []string { return record.fieldMap } func (record *SshfpRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "algorithm": v, ok := value.(int) if ok { record.Algorithm = v return nil } case "fingerprinttype": v, ok := value.(int) if ok { record.FingerprintType = v return nil } case "fingerprint": v, ok := value.(string) if ok { record.Fingerprint = v return nil } } } return &RecordError{fieldName: name} } func (record *SshfpRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "algorithm": record.Algorithm, "fingerprinttype": record.FingerprintType, "fingerprint": record.Fingerprint, } } type TxtRecord struct { fieldMap []string `json:"-"` Name string `json:"name,omitempty"` TTL int `json:"ttl,omitempty"` Active bool `json:"active,omitempty"` Target string `json:"target,omitempty"` } func NewTxtRecord() *TxtRecord { return &TxtRecord{ fieldMap: []string{ "name", "ttl", "active", "target", }, } } func (record *TxtRecord) GetAllowedFields() []string { return record.fieldMap } func (record *TxtRecord) SetField(name string, value interface{}) error { if contains(record.fieldMap, name) { switch name { case "name": v, ok := value.(string) if ok { record.Name = v return nil } case "ttl": v, ok := value.(int) if ok { record.TTL = v return nil } case "active": v, ok := value.(bool) if ok { record.Active = v return nil } case "target": v, ok := value.(string) if ok { record.Target = v return nil } } } return &RecordError{fieldName: name} } func (record *TxtRecord) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } func contains(fieldMap []string, field string) bool { field = strings.ToLower(field) for _, r := range fieldMap { if r == field { return true } } return false } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/record_test.go000066400000000000000000000062251400161560600277470ustar00rootroot00000000000000package dns import ( "testing" "github.com/stretchr/testify/assert" ) func TestRecord_ContainsHelper(t *testing.T) { tm1 := []string{ "test1", "test2", "test3", } assert.Equal(t, contains(tm1, "test1"), true) assert.Equal(t, contains(tm1, "test2"), true) assert.Equal(t, contains(tm1, "test3"), true) assert.Equal(t, contains(tm1, "test4"), false) } func TestRecord_ARecord(t *testing.T) { a := NewARecord() f := []string{ "name", "ttl", "active", "target", } assert.Equal(t, a.fieldMap, f) assert.Equal(t, a.fieldMap, a.GetAllowedFields()) assert.Equal(t, a.SetField("name", "test1"), nil) assert.Equal(t, a.SetField("doesntExist", "test1"), &RecordError{fieldName: "doesntExist"}) a.SetField("ttl", 900) a.SetField("active", true) a.SetField("target", "test2") assert.Equal(t, a.ToMap(), map[string]interface{}{ "name": "test1", "ttl": 900, "active": true, "target": "test2", }) } func TestRecord_AllRecords_WrongTypes(t *testing.T) { a := NewARecord() e := a.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a1 := NewAaaaRecord() e1 := a1.SetField("name", 1) assert.Equal(t, e1, &RecordError{fieldName: "name"}) a2 := NewAfsdbRecord() e = a2.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a3 := NewCnameRecord() e = a3.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a4 := NewDnskeyRecord() e = a4.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a5 := NewDsRecord() e = a5.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a6 := NewHinfoRecord() e = a6.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a7 := NewLocRecord() e = a7.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a8 := NewMxRecord() e = a8.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a9 := NewNaptrRecord() e = a9.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a10 := NewNsRecord() e = a10.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a11 := NewNsec3Record() e = a11.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a12 := NewNsec3paramRecord() e = a12.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a13 := NewPtrRecord() e = a13.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a14 := NewRpRecord() e = a14.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a15 := NewRrsigRecord() e = a15.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a16 := NewSoaRecord() e = a16.SetField("ttl", "test") assert.Equal(t, e, &RecordError{fieldName: "ttl"}) a17 := NewSpfRecord() e = a17.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a18 := NewSrvRecord() e = a18.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a19 := NewSshfpRecord() e = a19.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a20 := NewTxtRecord() e = a20.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/service.go000066400000000000000000000004661400161560600270730ustar00rootroot00000000000000package dns import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the FastDNS edgegrid Config func Init(config edgegrid.Config) { Config = config } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/service_test.go000066400000000000000000000463471400161560600301420ustar00rootroot00000000000000package dns import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) func TestGetZoneSimple(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v1/zones/example.com") mock. Get("/config-dns/v1/zones/example.com"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "token": "a184671d5307a388180fbf7f11dbdf46", "zone": { "name": "example.com", "soa": { "contact": "hostmaster.akamai.com.", "expire": 604800, "minimum": 180, "originserver": "use4.akamai.com.", "refresh": 900, "retry": 300, "serial": 1271354824, "ttl": 900 }, "ns": [ { "active": true, "name": "", "target": "use4.akam.net.", "ttl": 3600 }, { "active": true, "name": "", "target": "use3.akam.net.", "ttl": 3600 } ], "a": [ { "active": true, "name": "www", "target": "1.2.3.4", "ttl": 30 } ] } }`) Init(config) zone, err := GetZone("example.com") assert.NoError(t, err) assert.IsType(t, &Zone{}, zone) assert.Equal(t, "a184671d5307a388180fbf7f11dbdf46", zone.Token) assert.Equal(t, "example.com", zone.Zone.Name) assert.IsType(t, &SoaRecord{}, zone.Zone.Soa) assert.Equal(t, "hostmaster.akamai.com.", zone.Zone.Soa.Contact) assert.Equal(t, 604800, zone.Zone.Soa.Expire) assert.Equal(t, uint(180), zone.Zone.Soa.Minimum) assert.Equal(t, "use4.akamai.com.", zone.Zone.Soa.Originserver) assert.Equal(t, 900, zone.Zone.Soa.Refresh) assert.Equal(t, 300, zone.Zone.Soa.Retry) assert.Equal(t, uint(1271354824), zone.Zone.Soa.Serial) assert.Equal(t, 900, zone.Zone.Soa.TTL) assert.IsType(t, []*NsRecord{}, zone.Zone.Ns) assert.Len(t, zone.Zone.Ns, 2) assert.Equal(t, true, zone.Zone.Ns[0].Active) assert.Equal(t, "", zone.Zone.Ns[0].Name) assert.Equal(t, "use4.akam.net.", zone.Zone.Ns[0].Target) assert.Equal(t, 3600, zone.Zone.Ns[0].TTL) assert.Equal(t, true, zone.Zone.Ns[1].Active) assert.Equal(t, "", zone.Zone.Ns[1].Name) assert.Equal(t, "use3.akam.net.", zone.Zone.Ns[1].Target) assert.Equal(t, 3600, zone.Zone.Ns[1].TTL) assert.IsType(t, []*ARecord{}, zone.Zone.A) assert.Len(t, zone.Zone.A, 1) assert.Equal(t, true, zone.Zone.A[0].Active) assert.Equal(t, "www", zone.Zone.A[0].Name) assert.Equal(t, "1.2.3.4", zone.Zone.A[0].Target) assert.Equal(t, 30, zone.Zone.A[0].TTL) } func TestGetZone(t *testing.T) { defer gock.Off() tests := testGetZoneCompleteProvider() for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v1/zones/example.com") mock. Get("/config-dns/v1/zones/example.com"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(test.responseBody) Init(config) zone, err := GetZone("example.com") assert.NoError(t, err) assert.IsType(t, &Zone{}, zone) if test.expectedRecords != nil { switch test.recordType { case "A": assert.Equal(t, len(test.expectedRecords.([]*ARecord)), len(zone.Zone.A)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.A) break case "AAAA": assert.Equal(t, len(test.expectedRecords.([]*AaaaRecord)), len(zone.Zone.Aaaa)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Aaaa) break case "AFSDB": assert.Equal(t, len(test.expectedRecords.([]*AfsdbRecord)), len(zone.Zone.Afsdb)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Afsdb) break case "CNAME": assert.Equal(t, len(test.expectedRecords.([]*CnameRecord)), len(zone.Zone.Cname)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Cname) break case "DNSKEY": assert.Equal(t, len(test.expectedRecords.([]*DnskeyRecord)), len(zone.Zone.Dnskey)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Dnskey) break case "DS": assert.Equal(t, len(test.expectedRecords.([]*DsRecord)), len(zone.Zone.Ds)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Ds) break case "HINFO": assert.Equal(t, len(test.expectedRecords.([]*HinfoRecord)), len(zone.Zone.Hinfo)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Hinfo) break case "LOC": assert.Equal(t, len(test.expectedRecords.([]*LocRecord)), len(zone.Zone.Loc)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Loc) break case "MX": assert.Equal(t, len(test.expectedRecords.([]*MxRecord)), len(zone.Zone.Mx)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Mx) break case "NAPTR": assert.Equal(t, len(test.expectedRecords.([]*NaptrRecord)), len(zone.Zone.Naptr)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Naptr) break case "NS": assert.Equal(t, len(test.expectedRecords.([]*NsRecord)), len(zone.Zone.Ns)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Ns) break case "NSEC3": assert.Equal(t, len(test.expectedRecords.([]*Nsec3Record)), len(zone.Zone.Nsec3)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Nsec3) break case "NSEC3PARAM": assert.Equal(t, len(test.expectedRecords.([]*Nsec3paramRecord)), len(zone.Zone.Nsec3param)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Nsec3param) break case "PTR": assert.Equal(t, len(test.expectedRecords.([]*PtrRecord)), len(zone.Zone.Ptr)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Ptr) break case "RP": assert.Equal(t, len(test.expectedRecords.([]*RpRecord)), len(zone.Zone.Rp)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Rp) break case "RRSIG": assert.Equal(t, len(test.expectedRecords.([]*RrsigRecord)), len(zone.Zone.Rrsig)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Rrsig) break case "SPF": assert.Equal(t, len(test.expectedRecords.([]*SpfRecord)), len(zone.Zone.Spf)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Spf) break case "SRV": assert.Equal(t, len(test.expectedRecords.([]*SrvRecord)), len(zone.Zone.Srv)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Srv) break case "SSHFP": assert.Equal(t, len(test.expectedRecords.([]*SshfpRecord)), len(zone.Zone.Sshfp)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Sshfp) break case "TXT": assert.Equal(t, len(test.expectedRecords.([]*TxtRecord)), len(zone.Zone.Txt)) assert.ObjectsAreEqual(test.expectedRecords, zone.Zone.Txt) break } } }) } } type recordTests []struct { name string recordType string responseBody string expectedType interface{} expectedRecord ARecord expectedRecords interface{} } func testGetZoneCompleteProvider() recordTests { return recordTests{ { name: "A Records", recordType: "A", responseBody: `{ "zone": { "a": [ { "active": true, "name": "arecord", "target": "1.2.3.5", "ttl": 3600 }, { "active": true, "name": "origin", "target": "1.2.3.9", "ttl": 3600 }, { "active": true, "name": "arecord", "target": "1.2.3.4", "ttl": 3600 } ] } }`, expectedType: []*ARecord{}, expectedRecords: []*ARecord{ &ARecord{ Active: true, Name: "arecord", Target: "1.2.3.5", TTL: 3600, }, &ARecord{ Active: true, Name: "origin", Target: "1.2.3.9", TTL: 3600, }, &ARecord{ Active: true, Name: "arecord", Target: "1.2.3.4", TTL: 3600, }, }, }, { name: "AAAA Records", recordType: "AAAA", responseBody: `{ "zone": { "aaaa": [ { "active": true, "name": "ipv6record", "target": "2001:0db8::ff00:0042:8329", "ttl": 3600 } ] } }`, expectedType: []*AaaaRecord{}, expectedRecords: []*AaaaRecord{ &AaaaRecord{ Active: true, Name: "ipv6record", Target: "2001:0db8::ff00:0042:8329", TTL: 3600, }, }, }, { name: "AFSDB Records", recordType: "AFSDB", responseBody: `{ "zone": { "afsdb": [ { "active": true, "name": "afsdb", "subtype": 1, "target": "example.com.", "ttl": 7200 } ] } }`, expectedType: []*AfsdbRecord{}, expectedRecords: []*AfsdbRecord{ &AfsdbRecord{ Active: true, Name: "afsdb", Subtype: 1, Target: "example.com.", TTL: 7200, }, }, }, { name: "CNAME Records", recordType: "CNAME", responseBody: `{ "zone": { "cname": [ { "active": true, "name": "redirect", "target": "arecord.example.com.", "ttl": 3600 } ] } }`, expectedType: []*CnameRecord{}, expectedRecords: []*CnameRecord{ &CnameRecord{ Active: true, Name: "redirect", Target: "arecord.example.com.", TTL: 3600, }, }, }, { name: "DNSKEY Records", recordType: "DNSKEY", responseBody: `{ "zone": { "dnskey": [ { "active": true, "algorithm": 3, "flags": 257, "key": "Av//0/goGKPtaa28nQvPoUwVQ ... i/0hC+1CrmQkuuKtQt98WObuv7q8iQ==", "name": "dnskey", "protocol": 7, "ttl": 7200 } ] } }`, expectedType: []*DnskeyRecord{}, expectedRecords: []*DnskeyRecord{ &DnskeyRecord{ Active: true, Algorithm: 3, Flags: 257, Key: "Av//0/goGKPtaa28nQvPoUwVQ ... i/0hC+1CrmQkuuKtQt98WObuv7q8iQ==", Name: "dnskey", Protocol: 7, TTL: 7200, }, }, }, { name: "DS Records", recordType: "DS", responseBody: `{ "zone": { "ds": [ { "active": true, "algorithm": 7, "digest": "909FF0B4DD66F91F56524C4F968D13083BE42380", "digest_type": 1, "keytag": 30336, "name": "ds", "ttl": 7200 } ] } }`, expectedType: []*DsRecord{}, expectedRecords: []*DsRecord{ &DsRecord{ Active: true, Algorithm: 7, Digest: "909FF0B4DD66F91F56524C4F968D13083BE42380", DigestType: 1, Keytag: 30336, Name: "ds", TTL: 7200, }, }, }, { name: "HINFO Records", recordType: "HINFO", responseBody: `{ "zone": { "hinfo": [ { "active": true, "hardware": "INTEL-386", "name": "hinfo", "software": "UNIX", "ttl": 7200 } ] } }`, expectedType: []*HinfoRecord{}, expectedRecords: []*HinfoRecord{ &HinfoRecord{ Active: true, Hardware: "INTEL-386", Name: "hinfo", Software: "UNIX", TTL: 7200, }, }, }, { name: "LOC Records", recordType: "LOC", responseBody: `{ "zone": { "loc": [ { "active": true, "name": "location", "target": "51 30 12.748 N 0 7 39.611 W 0.00m 0.00m 0.00m 0.00m", "ttl": 7200 } ] } }`, expectedType: []*LocRecord{}, expectedRecords: []*LocRecord{ &LocRecord{ Active: true, Name: "location", Target: "51 30 12.748 N 0 7 39.611 W 0.00m 0.00m 0.00m 0.00m", TTL: 7200, }, }, }, { name: "MX Records", recordType: "MX", responseBody: `{ "zone": { "mx": [ { "active": true, "name": "four", "priority": 10, "target": "mx1.akamai.com.", "ttl": 7200 } ] } }`, expectedType: []*MxRecord{}, expectedRecords: []*MxRecord{ &MxRecord{ Active: true, Name: "four", Priority: 10, Target: "mx1.akamai.com.", TTL: 7200, }, }, }, { name: "NAPTR Records", recordType: "NAPTR", responseBody: `{ "zone": { "naptr": [ { "active": true, "flags": "S", "name": "naptrrecord", "order": 0, "preference": 10, "regexp": "!^.*$!sip:customer-service@example.com!", "replacement": ".", "service": "SIP+D2U", "ttl": 3600 } ] } }`, expectedType: []*NaptrRecord{}, expectedRecords: []*NaptrRecord{ &NaptrRecord{ Active: true, Flags: "S", Name: "naptrrecord", Order: 0, Preference: 10, Regexp: "!^.*$!sip:customer-service@example.com!", Replacement: ".", Service: "SIP+D2U", TTL: 3600, }, }, }, { name: "NS Records", recordType: "NS", responseBody: `{ "zone": { "ns": [ { "active": true, "name": null, "target": "use4.akam.net.", "ttl": 3600 }, { "active": true, "name": null, "target": "use3.akam.net.", "ttl": 3600 }, { "active": true, "name": "five", "target": "use4.akam.net.", "ttl": 172800 } ] } }`, expectedType: []*NsRecord{}, expectedRecords: []*NsRecord{ &NsRecord{ Active: true, Target: "use4.akam.net.", TTL: 3600, }, &NsRecord{ Active: true, Target: "us34.akam.net.", TTL: 3600, }, &NsRecord{ Active: true, Name: "five", Target: "use4.akam.net.", TTL: 172800, }, }, }, { name: "NSEC3 Records", recordType: "NSEC3", responseBody: `{ "zone": { "nsec3": [ { "active": true, "algorithm": 1, "flags": 0, "iterations": 1, "name": "qdeo8lqu4l81uo67oolpo9h0nv9l13dh", "next_hashed_owner_name": "R2NUSMGFSEUHT195P59KOU2AI30JR96P", "salt": "EBD1E0942543A01B", "ttl": 7200, "type_bitmaps": "CNAME RRSIG" } ] } }`, expectedType: []*Nsec3Record{}, expectedRecords: []*Nsec3Record{ &Nsec3Record{ Active: true, Algorithm: 1, Flags: 0, Iterations: 1, Name: "qdeo8lqu4l81uo67oolpo9h0nv9l13dh", NextHashedOwnerName: "R2NUSMGFSEUHT195P59KOU2AI30JR96P", Salt: "EBD1E0942543A01B", TTL: 7200, TypeBitmaps: "CNAME RRSIG", }, }, }, { name: "NSEC3PARAM Records", recordType: "NSEC3PARAM", responseBody: `{ "zone": { "nsec3param": [ { "active": true, "algorithm": 1, "flags": 0, "iterations": 1, "name": "qnsec3param", "salt": "EBD1E0942543A01B", "ttl": 7200 } ] } }`, expectedType: []*Nsec3paramRecord{}, expectedRecords: []*Nsec3paramRecord{ &Nsec3paramRecord{ Active: true, Algorithm: 1, Flags: 0, Iterations: 1, Name: "qnsec3param", Salt: "EBD1E0942543A01B", TTL: 7200, }, }, }, { name: "PTR Records", recordType: "PTR", responseBody: `{ "zone": { "ptr": [ { "active": true, "name": "ptr", "target": "ptr.example.com.", "ttl": 7200 } ] } }`, expectedType: []*PtrRecord{}, expectedRecords: []*PtrRecord{ &PtrRecord{ Active: true, Name: "ptr", Target: "ptr.example.com.", TTL: 7200, }, }, }, { name: "RP Records", recordType: "RP", responseBody: `{ "zone": { "rp": [ { "active": true, "mailbox": "admin.example.com.", "name": "rp", "ttl": 7200, "txt": "txt.example.com." } ] } }`, expectedType: []*RpRecord{}, expectedRecords: []*RpRecord{ &RpRecord{ Active: true, Mailbox: "admin.example.com.", Name: "rp", TTL: 7200, Txt: "txt.example.com.", }, }, }, { name: "RRSIG Records", recordType: "RRSIG", responseBody: `{ "zone": { "rrsig": [ { "active": true, "algorithm": 7, "expiration": "20120318104101", "inception": "20120315094101", "keytag": 63761, "labels": 3, "name": "arecord", "original_ttl": 3600, "signature": "toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv", "signer": "example.com.", "ttl": 7200, "type_covered": "A" } ] } }`, expectedType: []*RrsigRecord{}, expectedRecords: []*RrsigRecord{ &RrsigRecord{ Active: true, Algorithm: 7, Expiration: "20120318104101", Inception: "20120315094101", Keytag: 63761, Labels: 3, Name: "arecord", OriginalTTL: 3600, Signature: "toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv", Signer: "example.com.", TTL: 7200, TypeCovered: "A", }, }, }, { name: "SPF Records", recordType: "SPF", responseBody: `{ "zone": { "spf": [ { "active": true, "name": "spf", "target": "v=spf a -all", "ttl": 7200 } ] } }`, expectedType: []*SpfRecord{}, expectedRecords: []*SpfRecord{ &SpfRecord{ Active: true, Name: "spf", Target: "v=spf a -all", TTL: 7200, }, }, }, { name: "SSHFP Records", recordType: "SSHFP", responseBody: `{ "zone": { "sshfp": [ { "active": true, "algorithm": 2, "fingerprint": "123456789ABCDEF67890123456789ABCDEF67890", "fingerprint_type": 1, "name": "host", "ttl": 3600 } ] } }`, expectedType: []*SshfpRecord{}, expectedRecords: []*SshfpRecord{ &SshfpRecord{ Active: true, Algorithm: 2, Fingerprint: "123456789ABCDEF67890123456789ABCDEF67890", FingerprintType: 1, Name: "host", TTL: 3600, }, }, }, { name: "SRV Records", recordType: "SRV", responseBody: `{ "zone": { "srv": [ { "active": true, "name": "srv", "port": 522, "priority": 10, "target": "target.akamai.com.", "ttl": 7200, "weight": 0 } ] } }`, expectedType: []*SrvRecord{}, expectedRecords: []*SrvRecord{ &SrvRecord{ Active: true, Name: "srv", Port: 522, Priority: 10, Target: "target.akamai.com.", TTL: 7200, Weight: 0, }, }, }, { name: "TXT Records", recordType: "TXT", responseBody: `{ "zone": { "txt": [ { "active": true, "name": "text", "target": "Hello world!", "ttl": 7200 } ] } }`, expectedType: []*TxtRecord{}, expectedRecords: []*TxtRecord{ &TxtRecord{ Active: true, Name: "text", Target: "Hello world!", TTL: 7200, }, }, }, } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/zone.go000066400000000000000000001162711400161560600264100ustar00rootroot00000000000000package dns import ( "errors" "fmt" "reflect" "strings" "sync" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type name struct { recordType string name string } var ( cnameNames []name nonCnameNames []name zoneWriteLock sync.Mutex ) // Zone represents a DNS zone type Zone struct { Token string `json:"token"` Zone struct { Name string `json:"name,omitempty"` A []*ARecord `json:"a,omitempty"` Aaaa []*AaaaRecord `json:"aaaa,omitempty"` Afsdb []*AfsdbRecord `json:"afsdb,omitempty"` Cname []*CnameRecord `json:"cname,omitempty"` Dnskey []*DnskeyRecord `json:"dnskey,omitempty"` Ds []*DsRecord `json:"ds,omitempty"` Hinfo []*HinfoRecord `json:"hinfo,omitempty"` Loc []*LocRecord `json:"loc,omitempty"` Mx []*MxRecord `json:"mx,omitempty"` Naptr []*NaptrRecord `json:"naptr,omitempty"` Ns []*NsRecord `json:"ns,omitempty"` Nsec3 []*Nsec3Record `json:"nsec3,omitempty"` Nsec3param []*Nsec3paramRecord `json:"nsec3param,omitempty"` Ptr []*PtrRecord `json:"ptr,omitempty"` Rp []*RpRecord `json:"rp,omitempty"` Rrsig []*RrsigRecord `json:"rrsig,omitempty"` Soa *SoaRecord `json:"soa,omitempty"` Spf []*SpfRecord `json:"spf,omitempty"` Srv []*SrvRecord `json:"srv,omitempty"` Sshfp []*SshfpRecord `json:"sshfp,omitempty"` Txt []*TxtRecord `json:"txt,omitempty"` } `json:"zone"` } // NewZone creates a new Zone func NewZone(hostname string) *Zone { zone := &Zone{Token: "new"} zone.Zone.Soa = NewSoaRecord() zone.Zone.Name = hostname return zone } // GetZone retrieves a DNS Zone for a given hostname func GetZone(hostname string) (*Zone, error) { zone := NewZone(hostname) req, err := client.NewRequest( Config, "GET", "/config-dns/v1/zones/"+hostname, nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: hostname} } else { err = client.BodyJSON(res, zone) if err != nil { return nil, err } return zone, nil } } // Save updates the Zone func (zone *Zone) Save() 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 zoneWriteLock.Lock() defer zoneWriteLock.Unlock() valid, f := zone.validateCnames() if valid == false { var msg string for _, v := range f { msg = msg + fmt.Sprintf("\n%s Record '%s' conflicts with CNAME", v.recordType, v.name) } return &ZoneError{ zoneName: zone.Zone.Name, apiErrorMessage: "All CNAMEs must be unique in the zone" + msg, } } req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v1/zones/"+zone.Zone.Name, zone, ) if err != nil { return err } res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone.Name, httpErrorMessage: err.Error(), err: err, } } // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone.Name, apiErrorMessage: err.Detail, err: err} } for { updatedZone, err := GetZone(zone.Zone.Name) if err != nil { return err } if updatedZone.Token != zone.Token { *zone = *updatedZone break } time.Sleep(time.Second) } return nil } func (zone *Zone) Delete() error { // remove all the records except for SOA // which is required and save the zone zone.Zone.A = nil zone.Zone.Aaaa = nil zone.Zone.Afsdb = nil zone.Zone.Cname = nil zone.Zone.Dnskey = nil zone.Zone.Ds = nil zone.Zone.Hinfo = nil zone.Zone.Loc = nil zone.Zone.Mx = nil zone.Zone.Naptr = nil zone.Zone.Ns = nil zone.Zone.Nsec3 = nil zone.Zone.Nsec3param = nil zone.Zone.Ptr = nil zone.Zone.Rp = nil zone.Zone.Rrsig = nil zone.Zone.Spf = nil zone.Zone.Srv = nil zone.Zone.Sshfp = nil zone.Zone.Txt = nil return zone.Save() } func (zone *Zone) AddRecord(recordPtr interface{}) error { switch recordPtr.(type) { case *ARecord: zone.addARecord(recordPtr.(*ARecord)) case *AaaaRecord: zone.addAaaaRecord(recordPtr.(*AaaaRecord)) case *AfsdbRecord: zone.addAfsdbRecord(recordPtr.(*AfsdbRecord)) case *CnameRecord: zone.addCnameRecord(recordPtr.(*CnameRecord)) case *DnskeyRecord: zone.addDnskeyRecord(recordPtr.(*DnskeyRecord)) case *DsRecord: zone.addDsRecord(recordPtr.(*DsRecord)) case *HinfoRecord: zone.addHinfoRecord(recordPtr.(*HinfoRecord)) case *LocRecord: zone.addLocRecord(recordPtr.(*LocRecord)) case *MxRecord: zone.addMxRecord(recordPtr.(*MxRecord)) case *NaptrRecord: zone.addNaptrRecord(recordPtr.(*NaptrRecord)) case *NsRecord: zone.addNsRecord(recordPtr.(*NsRecord)) case *Nsec3Record: zone.addNsec3Record(recordPtr.(*Nsec3Record)) case *Nsec3paramRecord: zone.addNsec3paramRecord(recordPtr.(*Nsec3paramRecord)) case *PtrRecord: zone.addPtrRecord(recordPtr.(*PtrRecord)) case *RpRecord: zone.addRpRecord(recordPtr.(*RpRecord)) case *RrsigRecord: zone.addRrsigRecord(recordPtr.(*RrsigRecord)) case *SoaRecord: zone.addSoaRecord(recordPtr.(*SoaRecord)) case *SpfRecord: zone.addSpfRecord(recordPtr.(*SpfRecord)) case *SrvRecord: zone.addSrvRecord(recordPtr.(*SrvRecord)) case *SshfpRecord: zone.addSshfpRecord(recordPtr.(*SshfpRecord)) case *TxtRecord: zone.addTxtRecord(recordPtr.(*TxtRecord)) } return nil } func (zone *Zone) RemoveRecord(recordPtr interface{}) error { switch recordPtr.(type) { case *ARecord: return zone.removeARecord(recordPtr.(*ARecord)) case *AaaaRecord: return zone.removeAaaaRecord(recordPtr.(*AaaaRecord)) case *AfsdbRecord: return zone.removeAfsdbRecord(recordPtr.(*AfsdbRecord)) case *CnameRecord: return zone.removeCnameRecord(recordPtr.(*CnameRecord)) case *DnskeyRecord: return zone.removeDnskeyRecord(recordPtr.(*DnskeyRecord)) case *DsRecord: return zone.removeDsRecord(recordPtr.(*DsRecord)) case *HinfoRecord: return zone.removeHinfoRecord(recordPtr.(*HinfoRecord)) case *LocRecord: return zone.removeLocRecord(recordPtr.(*LocRecord)) case *MxRecord: return zone.removeMxRecord(recordPtr.(*MxRecord)) case *NaptrRecord: return zone.removeNaptrRecord(recordPtr.(*NaptrRecord)) case *NsRecord: return zone.removeNsRecord(recordPtr.(*NsRecord)) case *Nsec3Record: return zone.removeNsec3Record(recordPtr.(*Nsec3Record)) case *Nsec3paramRecord: return zone.removeNsec3paramRecord(recordPtr.(*Nsec3paramRecord)) case *PtrRecord: return zone.removePtrRecord(recordPtr.(*PtrRecord)) case *RpRecord: return zone.removeRpRecord(recordPtr.(*RpRecord)) case *RrsigRecord: return zone.removeRrsigRecord(recordPtr.(*RrsigRecord)) case *SoaRecord: return zone.removeSoaRecord(recordPtr.(*SoaRecord)) case *SpfRecord: return zone.removeSpfRecord(recordPtr.(*SpfRecord)) case *SrvRecord: return zone.removeSrvRecord(recordPtr.(*SrvRecord)) case *SshfpRecord: return zone.removeSshfpRecord(recordPtr.(*SshfpRecord)) case *TxtRecord: return zone.removeTxtRecord(recordPtr.(*TxtRecord)) } return nil } func (zone *Zone) addARecord(record *ARecord) { zone.Zone.A = append(zone.Zone.A, record) nonCnameNames = append(nonCnameNames, name{recordType: "A", name: record.Name}) } func (zone *Zone) addAaaaRecord(record *AaaaRecord) { zone.Zone.Aaaa = append(zone.Zone.Aaaa, record) nonCnameNames = append(nonCnameNames, name{recordType: "AAAA", name: record.Name}) } func (zone *Zone) addAfsdbRecord(record *AfsdbRecord) { zone.Zone.Afsdb = append(zone.Zone.Afsdb, record) nonCnameNames = append(nonCnameNames, name{recordType: "AFSDB", name: record.Name}) } func (zone *Zone) addCnameRecord(record *CnameRecord) { zone.Zone.Cname = append(zone.Zone.Cname, record) cnameNames = append(cnameNames, name{recordType: "CNAME", name: record.Name}) } func (zone *Zone) addDnskeyRecord(record *DnskeyRecord) { zone.Zone.Dnskey = append(zone.Zone.Dnskey, record) nonCnameNames = append(nonCnameNames, name{recordType: "DNSKEY", name: record.Name}) } func (zone *Zone) addDsRecord(record *DsRecord) { zone.Zone.Ds = append(zone.Zone.Ds, record) nonCnameNames = append(nonCnameNames, name{recordType: "DS", name: record.Name}) } func (zone *Zone) addHinfoRecord(record *HinfoRecord) { zone.Zone.Hinfo = append(zone.Zone.Hinfo, record) nonCnameNames = append(nonCnameNames, name{recordType: "HINFO", name: record.Name}) } func (zone *Zone) addLocRecord(record *LocRecord) { zone.Zone.Loc = append(zone.Zone.Loc, record) nonCnameNames = append(nonCnameNames, name{recordType: "LOC", name: record.Name}) } func (zone *Zone) addMxRecord(record *MxRecord) { zone.Zone.Mx = append(zone.Zone.Mx, record) nonCnameNames = append(nonCnameNames, name{recordType: "MX", name: record.Name}) } func (zone *Zone) addNaptrRecord(record *NaptrRecord) { zone.Zone.Naptr = append(zone.Zone.Naptr, record) nonCnameNames = append(nonCnameNames, name{recordType: "NAPTR", name: record.Name}) } func (zone *Zone) addNsRecord(record *NsRecord) { zone.Zone.Ns = append(zone.Zone.Ns, record) nonCnameNames = append(nonCnameNames, name{recordType: "NS", name: record.Name}) } func (zone *Zone) addNsec3Record(record *Nsec3Record) { zone.Zone.Nsec3 = append(zone.Zone.Nsec3, record) nonCnameNames = append(nonCnameNames, name{recordType: "NSEC3", name: record.Name}) } func (zone *Zone) addNsec3paramRecord(record *Nsec3paramRecord) { zone.Zone.Nsec3param = append(zone.Zone.Nsec3param, record) nonCnameNames = append(nonCnameNames, name{recordType: "NSEC3PARAM", name: record.Name}) } func (zone *Zone) addPtrRecord(record *PtrRecord) { zone.Zone.Ptr = append(zone.Zone.Ptr, record) nonCnameNames = append(nonCnameNames, name{recordType: "PTR", name: record.Name}) } func (zone *Zone) addRpRecord(record *RpRecord) { zone.Zone.Rp = append(zone.Zone.Rp, record) nonCnameNames = append(nonCnameNames, name{recordType: "RP", name: record.Name}) } func (zone *Zone) addRrsigRecord(record *RrsigRecord) { zone.Zone.Rrsig = append(zone.Zone.Rrsig, record) nonCnameNames = append(nonCnameNames, name{recordType: "RRSIG", name: record.Name}) } func (zone *Zone) addSoaRecord(record *SoaRecord) { // Only one SOA records is allowed zone.Zone.Soa = record } func (zone *Zone) addSpfRecord(record *SpfRecord) { zone.Zone.Spf = append(zone.Zone.Spf, record) nonCnameNames = append(nonCnameNames, name{recordType: "SPF", name: record.Name}) } func (zone *Zone) addSrvRecord(record *SrvRecord) { zone.Zone.Srv = append(zone.Zone.Srv, record) nonCnameNames = append(nonCnameNames, name{recordType: "SRV", name: record.Name}) } func (zone *Zone) addSshfpRecord(record *SshfpRecord) { zone.Zone.Sshfp = append(zone.Zone.Sshfp, record) nonCnameNames = append(nonCnameNames, name{recordType: "SSHFP", name: record.Name}) } func (zone *Zone) addTxtRecord(record *TxtRecord) { zone.Zone.Txt = append(zone.Zone.Txt, record) nonCnameNames = append(nonCnameNames, name{recordType: "TXT", name: record.Name}) } func (zone *Zone) removeARecord(record *ARecord) error { for key, r := range zone.Zone.A { if reflect.DeepEqual(r, record) { records := zone.Zone.A[:key] if len(zone.Zone.A) > key { if len(zone.Zone.A) > key { zone.Zone.A = append(records, zone.Zone.A[key+1:]...) } else { zone.Zone.A = records } } zone.removeNonCnameName(record.Name) return nil } } return errors.New("A Record not found") } func (zone *Zone) removeAaaaRecord(record *AaaaRecord) error { for key, r := range zone.Zone.Aaaa { if reflect.DeepEqual(r, record) { records := zone.Zone.Aaaa[:key] if len(zone.Zone.Aaaa) > key { zone.Zone.Aaaa = append(records, zone.Zone.Aaaa[key+1:]...) } else { zone.Zone.Aaaa = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("AAAA Record not found") } func (zone *Zone) removeAfsdbRecord(record *AfsdbRecord) error { for key, r := range zone.Zone.Afsdb { if reflect.DeepEqual(r, record) { records := zone.Zone.Afsdb[:key] if len(zone.Zone.Afsdb) > key { zone.Zone.Afsdb = append(records, zone.Zone.Afsdb[key+1:]...) } else { zone.Zone.Afsdb = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Afsdb Record not found") } func (zone *Zone) removeCnameRecord(record *CnameRecord) error { for key, r := range zone.Zone.Cname { if reflect.DeepEqual(r, record) { records := zone.Zone.Cname[:key] if len(zone.Zone.Cname) > key { zone.Zone.Cname = append(records, zone.Zone.Cname[key+1:]...) } else { zone.Zone.Cname = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Cname Record not found") zone.removeCnameName(record.Name) return nil } func (zone *Zone) removeDnskeyRecord(record *DnskeyRecord) error { for key, r := range zone.Zone.Dnskey { if reflect.DeepEqual(r, record) { records := zone.Zone.Dnskey[:key] if len(zone.Zone.Dnskey) > key { zone.Zone.Dnskey = append(records, zone.Zone.Dnskey[key+1:]...) } else { zone.Zone.Dnskey = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Dnskey Record not found") } func (zone *Zone) removeDsRecord(record *DsRecord) error { for key, r := range zone.Zone.Ds { if reflect.DeepEqual(r, record) { records := zone.Zone.Ds[:key] if len(zone.Zone.Ds) > key { zone.Zone.Ds = append(records, zone.Zone.Ds[key+1:]...) } else { zone.Zone.Ds = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Ds Record not found") } func (zone *Zone) removeHinfoRecord(record *HinfoRecord) error { for key, r := range zone.Zone.Hinfo { if reflect.DeepEqual(r, record) { records := zone.Zone.Hinfo[:key] if len(zone.Zone.Hinfo) > key { zone.Zone.Hinfo = append(records, zone.Zone.Hinfo[key+1:]...) } else { zone.Zone.Hinfo = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Hinfo Record not found") } func (zone *Zone) removeLocRecord(record *LocRecord) error { for key, r := range zone.Zone.Loc { if reflect.DeepEqual(r, record) { records := zone.Zone.Loc[:key] if len(zone.Zone.Loc) > key { zone.Zone.Loc = append(records, zone.Zone.Loc[key+1:]...) } else { zone.Zone.Loc = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Loc Record not found") } func (zone *Zone) removeMxRecord(record *MxRecord) error { for key, r := range zone.Zone.Mx { if reflect.DeepEqual(r, record) { records := zone.Zone.Mx[:key] if len(zone.Zone.Mx) > key { zone.Zone.Mx = append(records, zone.Zone.Mx[key+1:]...) } else { zone.Zone.Mx = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Mx Record not found") } func (zone *Zone) removeNaptrRecord(record *NaptrRecord) error { for key, r := range zone.Zone.Naptr { if reflect.DeepEqual(r, record) { records := zone.Zone.Naptr[:key] if len(zone.Zone.Naptr) > key { zone.Zone.Naptr = append(records, zone.Zone.Naptr[key+1:]...) } else { zone.Zone.Naptr = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Naptr Record not found") } func (zone *Zone) removeNsRecord(record *NsRecord) error { for key, r := range zone.Zone.Ns { if reflect.DeepEqual(r, record) { records := zone.Zone.Ns[:key] if len(zone.Zone.Ns) > key { zone.Zone.Ns = append(records, zone.Zone.Ns[key+1:]...) } else { zone.Zone.Ns = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Ns Record not found") } func (zone *Zone) removeNsec3Record(record *Nsec3Record) error { for key, r := range zone.Zone.Nsec3 { if reflect.DeepEqual(r, record) { records := zone.Zone.Nsec3[:key] if len(zone.Zone.Nsec3) > key { zone.Zone.Nsec3 = append(records, zone.Zone.Nsec3[key+1:]...) } else { zone.Zone.Nsec3 = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Nsec3 Record not found") } func (zone *Zone) removeNsec3paramRecord(record *Nsec3paramRecord) error { for key, r := range zone.Zone.Nsec3param { if reflect.DeepEqual(r, record) { records := zone.Zone.Nsec3param[:key] if len(zone.Zone.Nsec3param) > key { zone.Zone.Nsec3param = append(records, zone.Zone.Nsec3param[key+1:]...) } else { zone.Zone.Nsec3param = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Nsec3param Record not found") } func (zone *Zone) removePtrRecord(record *PtrRecord) error { for key, r := range zone.Zone.Ptr { if reflect.DeepEqual(r, record) { records := zone.Zone.Ptr[:key] if len(zone.Zone.Ptr) > key { zone.Zone.Ptr = append(records, zone.Zone.Ptr[key+1:]...) } else { zone.Zone.Ptr = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Ptr Record not found") } func (zone *Zone) removeRpRecord(record *RpRecord) error { for key, r := range zone.Zone.Rp { if reflect.DeepEqual(r, record) { records := zone.Zone.Rp[:key] if len(zone.Zone.Rp) > key { zone.Zone.Rp = append(records, zone.Zone.Rp[key+1:]...) } else { zone.Zone.Rp = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Rp Record not found") } func (zone *Zone) removeRrsigRecord(record *RrsigRecord) error { for key, r := range zone.Zone.Rrsig { if reflect.DeepEqual(r, record) { records := zone.Zone.Rrsig[:key] if len(zone.Zone.Rrsig) > key { zone.Zone.Rrsig = append(records, zone.Zone.Rrsig[key+1:]...) } else { zone.Zone.Rrsig = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Rrsig Record not found") } func (zone *Zone) removeSoaRecord(record *SoaRecord) error { if reflect.DeepEqual(zone.Zone.Soa, record) { zone.Zone.Soa = nil return nil } return errors.New("SOA Record does not match") } func (zone *Zone) removeSpfRecord(record *SpfRecord) error { for key, r := range zone.Zone.Spf { if reflect.DeepEqual(r, record) { records := zone.Zone.Spf[:key] if len(zone.Zone.Spf) > key { zone.Zone.Spf = append(records, zone.Zone.Spf[key+1:]...) } else { zone.Zone.Spf = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Spf Record not found") } func (zone *Zone) removeSrvRecord(record *SrvRecord) error { for key, r := range zone.Zone.Srv { if reflect.DeepEqual(r, record) { records := zone.Zone.Srv[:key] if len(zone.Zone.Srv) > key { zone.Zone.Srv = append(records, zone.Zone.Srv[key+1:]...) } else { zone.Zone.Srv = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Srv Record not found") } func (zone *Zone) removeSshfpRecord(record *SshfpRecord) error { for key, r := range zone.Zone.Sshfp { if reflect.DeepEqual(r, record) { records := zone.Zone.Sshfp[:key] if len(zone.Zone.Sshfp) > key { zone.Zone.Sshfp = append(records, zone.Zone.Sshfp[key+1:]...) } else { zone.Zone.Sshfp = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Sshfp Record not found") } func (zone *Zone) removeTxtRecord(record *TxtRecord) error { for key, r := range zone.Zone.Txt { if reflect.DeepEqual(r, record) { records := zone.Zone.Txt[:key] if len(zone.Zone.Txt) > key { zone.Zone.Txt = append(records, zone.Zone.Txt[key+1:]...) } else { zone.Zone.Txt = records } zone.removeNonCnameName(record.Name) return nil } } return errors.New("Txt Record not found") } func (zone *Zone) PostUnmarshalJSON() error { if zone.Zone.Soa.Serial > 0 { zone.Zone.Soa.originalSerial = zone.Zone.Soa.Serial } return nil } func (zone *Zone) PreMarshalJSON() error { if zone.Zone.Soa.Serial == 0 { zone.Zone.Soa.Serial = uint(time.Now().Unix()) } else if zone.Zone.Soa.Serial == zone.Zone.Soa.originalSerial { zone.Zone.Soa.Serial = zone.Zone.Soa.Serial + 1 } return nil } func (zone *Zone) validateCnames() (bool, []name) { var valid bool = true var failedRecords []name for _, v := range cnameNames { for _, vv := range nonCnameNames { if v.name == vv.name { valid = false failedRecords = append(failedRecords, vv) } } } return valid, failedRecords } func (zone *Zone) removeCnameName(host string) { var ncn []name for _, v := range cnameNames { if v.name != host { ncn = append(ncn, v) } } cnameNames = ncn } func (zone *Zone) removeNonCnameName(host string) { var ncn []name for _, v := range nonCnameNames { if v.name != host { ncn = append(ncn, v) } } nonCnameNames = ncn } func (zone *Zone) FindRecords(recordType string, options map[string]interface{}) []DNSRecord { switch strings.ToUpper(recordType) { case "A": return zone.findARecord(options) case "AAAA": return zone.findAaaaRecord(options) case "AFSDB": return zone.findAfsdbRecord(options) case "CNAME": return zone.findCnameRecord(options) case "DNSKEY": return zone.findDnskeyRecord(options) case "DS": return zone.findDsRecord(options) case "HINFO": return zone.findHinfoRecord(options) case "LOC": return zone.findLocRecord(options) case "MX": return zone.findMxRecord(options) case "NAPTR": return zone.findNaptrRecord(options) case "NS": return zone.findNsRecord(options) case "NSEC3": return zone.findNsec3Record(options) case "NSEC3PARAM": return zone.findNsec3paramRecord(options) case "PTR": return zone.findPtrRecord(options) case "RP": return zone.findRpRecord(options) case "RRSIG": return zone.findRrsigRecord(options) case "SPF": return zone.findSpfRecord(options) case "SRV": return zone.findSrvRecord(options) case "SSHFP": return zone.findSshfpRecord(options) case "TXT": return zone.findTxtRecord(options) } return make([]DNSRecord, 0) } func (zone *Zone) findARecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.A { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findAaaaRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Aaaa { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findAfsdbRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Afsdb { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if subtype, ok := options["subtype"]; ok && record.Subtype == subtype.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findCnameRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Cname { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findDnskeyRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Dnskey { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if flags, ok := options["flags"]; ok && record.Flags == flags.(int) { matchCounter++ } if protocol, ok := options["protocol"]; ok && record.Protocol == protocol.(int) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if key, ok := options["key"]; ok && record.Key == key.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findDsRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Ds { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if keytag, ok := options["keytag"]; ok && record.Keytag == keytag.(int) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if digesttype, ok := options["digesttype"]; ok && record.DigestType == digesttype.(int) { matchCounter++ } if digest, ok := options["digest"]; ok && record.Digest == digest.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findHinfoRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Hinfo { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if hardware, ok := options["hardware"]; ok && record.Hardware == hardware.(string) { matchCounter++ } if software, ok := options["software"]; ok && record.Software == software.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findLocRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Loc { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findMxRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Mx { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if priority, ok := options["priority"]; ok && record.Priority == priority.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findNaptrRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Naptr { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if order, ok := options["order"]; ok && record.Order == order.(uint16) { matchCounter++ } if preference, ok := options["preference"]; ok && record.Preference == preference.(uint16) { matchCounter++ } if flags, ok := options["flags"]; ok && record.Flags == flags.(string) { matchCounter++ } if service, ok := options["service"]; ok && record.Service == service.(string) { matchCounter++ } if regexp, ok := options["regexp"]; ok && record.Regexp == regexp.(string) { matchCounter++ } if replacement, ok := options["replacement"]; ok && record.Replacement == replacement.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findNsRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Ns { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findNsec3Record(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Nsec3 { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if flags, ok := options["flags"]; ok && record.Flags == flags.(int) { matchCounter++ } if iterations, ok := options["iterations"]; ok && record.Iterations == iterations.(int) { matchCounter++ } if salt, ok := options["salt"]; ok && record.Salt == salt.(string) { matchCounter++ } if nextHashedOwnerName, ok := options["nextHashedOwnerName"]; ok && record.NextHashedOwnerName == nextHashedOwnerName.(string) { matchCounter++ } if typeBitmaps, ok := options["typeBitmaps"]; ok && record.TypeBitmaps == typeBitmaps.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findNsec3paramRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Nsec3param { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if flags, ok := options["flags"]; ok && record.Flags == flags.(int) { matchCounter++ } if iterations, ok := options["iterations"]; ok && record.Iterations == iterations.(int) { matchCounter++ } if salt, ok := options["salt"]; ok && record.Salt == salt.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findPtrRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Ptr { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findRpRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Rp { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if mailbox, ok := options["mailbox"]; ok && record.Mailbox == mailbox.(string) { matchCounter++ } if txt, ok := options["txt"]; ok && record.Txt == txt.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findRrsigRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Rrsig { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if typeCovered, ok := options["typeCovered"]; ok && record.TypeCovered == typeCovered.(string) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if originalTTL, ok := options["originalTTL"]; ok && record.OriginalTTL == originalTTL.(int) { matchCounter++ } if expiration, ok := options["expiration"]; ok && record.Expiration == expiration.(string) { matchCounter++ } if inception, ok := options["inception"]; ok && record.Inception == inception.(string) { matchCounter++ } if keytag, ok := options["keytag"]; ok && record.Keytag == keytag.(int) { matchCounter++ } if signer, ok := options["signer"]; ok && record.Signer == signer.(string) { matchCounter++ } if signature, ok := options["signature"]; ok && record.Signature == signature.(string) { matchCounter++ } if labels, ok := options["labels"]; ok && record.Labels == labels.(int) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findSpfRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Spf { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findSrvRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Srv { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if priority, ok := options["priority"]; ok && record.Priority == priority.(int) { matchCounter++ } if weight, ok := options["weight"]; ok && record.Weight == weight.(uint16) { matchCounter++ } if port, ok := options["port"]; ok && record.Port == port.(uint16) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findSshfpRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Sshfp { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) { matchCounter++ } if fingerprintType, ok := options["fingerprintType"]; ok && record.FingerprintType == fingerprintType.(int) { matchCounter++ } if fingerprint, ok := options["fingerprint"]; ok && record.Fingerprint == fingerprint.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } func (zone *Zone) findTxtRecord(options map[string]interface{}) []DNSRecord { found := make([]DNSRecord, 0) matchesNeeded := len(options) for _, record := range zone.Zone.Txt { matchCounter := 0 if name, ok := options["name"]; ok && record.Name == name.(string) { matchCounter++ } if active, ok := options["active"]; ok && record.Active == active.(bool) { matchCounter++ } if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) { matchCounter++ } if target, ok := options["target"]; ok && record.Target == target.(string) { matchCounter++ } if matchCounter >= matchesNeeded { found = append(found, record) } } return found } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v1/zone_test.go000066400000000000000000000141621400161560600274430ustar00rootroot00000000000000package dns import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" ) func TestZone_JSON(t *testing.T) { responseBody := []byte(`{ "token": "a184671d5307a388180fbf7f11dbdf46", "zone": { "name": "example.com", "a": [ { "active": true, "name": "arecord", "target": "1.2.3.5", "ttl": 3600 }, { "active": true, "name": "origin", "target": "1.2.3.9", "ttl": 3600 }, { "active": true, "name": "arecord", "target": "1.2.3.4", "ttl": 3600 } ], "aaaa": [ { "active": true, "name": "ipv6record", "target": "2001:0db8::ff00:0042:8329", "ttl": 3600 } ], "afsdb": [ { "active": true, "name": "afsdb", "subtype": 1, "target": "example.com.", "ttl": 7200 } ], "cname": [ { "active": true, "name": "redirect", "target": "arecord.example.com.", "ttl": 3600 } ], "dnskey": [ { "active": true, "algorithm": 3, "flags": 257, "key": "Av//0/goGKPtaa28nQvPoUwVQ ... i/0hC+1CrmQkuuKtQt98WObuv7q8iQ==", "name": "dnskey", "protocol": 7, "ttl": 7200 } ], "ds": [ { "active": true, "algorithm": 7, "digest": "909FF0B4DD66F91F56524C4F968D13083BE42380", "digest_type": 1, "keytag": 30336, "name": "ds", "ttl": 7200 } ], "hinfo": [ { "active": true, "hardware": "INTEL-386", "name": "hinfo", "software": "UNIX", "ttl": 7200 } ], "loc": [ { "active": true, "name": "location", "target": "51 30 12.748 N 0 7 39.611 W 0.00m 0.00m 0.00m 0.00m", "ttl": 7200 } ], "mx": [ { "active": true, "name": "four", "priority": 10, "target": "mx1.akamai.com.", "ttl": 7200 } ], "naptr": [ { "active": true, "flags": "S", "name": "naptrrecord", "order": 0, "preference": 10, "regexp": "!^.*$!sip:customer-service@example.com!", "replacement": ".", "service": "SIP+D2U", "ttl": 3600 } ], "ns": [ { "active": true, "name": null, "target": "use4.akam.net.", "ttl": 3600 }, { "active": true, "name": null, "target": "use3.akam.net.", "ttl": 3600 }, { "active": true, "name": "five", "target": "use4.akam.net.", "ttl": 172800 } ], "nsec3": [ { "active": true, "algorithm": 1, "flags": 0, "iterations": 1, "name": "qdeo8lqu4l81uo67oolpo9h0nv9l13dh", "next_hashed_owner_name": "R2NUSMGFSEUHT195P59KOU2AI30JR96P", "salt": "EBD1E0942543A01B", "ttl": 7200, "type_bitmaps": "CNAME RRSIG" } ], "nsec3param": [ { "active": true, "algorithm": 1, "flags": 0, "iterations": 1, "name": "qnsec3param", "salt": "EBD1E0942543A01B", "ttl": 7200 } ], "ptr": [ { "active": true, "name": "ptr", "target": "ptr.example.com.", "ttl": 7200 } ], "rp": [ { "active": true, "mailbox": "admin.example.com.", "name": "rp", "ttl": 7200, "txt": "txt.example.com." } ], "rrsig": [ { "active": true, "algorithm": 7, "expiration": "20120318104101", "inception": "20120315094101", "keytag": 63761, "labels": 3, "name": "arecord", "original_ttl": 3600, "signature": "toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv", "signer": "example.com.", "ttl": 7200, "type_covered": "A" } ], "soa": { "contact": "hostmaster.akamai.com.", "expire": 604800, "minimum": 180, "originserver": "use4.akamai.com.", "refresh": 900, "retry": 300, "serial": 1271354824, "ttl": 900 }, "spf": [ { "active": true, "name": "spf", "target": "v=spf a -all", "ttl": 7200 } ], "srv": [ { "active": true, "name": "srv", "port": 522, "priority": 10, "target": "target.akamai.com.", "ttl": 7200, "weight": 0 } ], "sshfp": [ { "active": true, "algorithm": 2, "fingerprint": "123456789ABCDEF67890123456789ABCDEF67890", "fingerprint_type": 1, "name": "host", "ttl": 3600 } ], "txt": [ { "active": true, "name": "text", "target": "Hello world!", "ttl": 7200 } ] } }`) zone := NewZone("example.com") err := jsonhooks.Unmarshal(responseBody, zone) assert.NoError(t, err) assert.Equal(t, zone.Zone.Soa.Serial, zone.Zone.Soa.originalSerial) _, err = jsonhooks.Marshal(zone) assert.NoError(t, err) assert.True(t, zone.Zone.Soa.Serial-zone.Zone.Soa.originalSerial == 1) zone.Zone.Soa.Serial = uint(12345) _, err = jsonhooks.Marshal(zone) assert.NoError(t, err) assert.Equal(t, zone.Zone.Soa.Serial, uint(12345)) assert.NotEqual(t, zone.Zone.Soa.originalSerial, uint(12345)) } func TestZone_AddRecord(t *testing.T) { records := testZone_AddRecord_Provider() zone := NewZone("example.org") for _, record := range records { err := zone.AddRecord(record) assert.NoError(t, err) } assert.Equal(t, records, zone.Zone.A) } func Test_removeNonCnameName(t *testing.T) { backup := nonCnameNames defer func() { nonCnameNames = backup }() names := []name{ {recordType: "TXT", name: "test.com"}, {recordType: "TXT", name: "foo.com"}, {recordType: "TXT", name: "bar.com"}, {recordType: "TXT", name: "test.com"}, } for _, n := range names { nonCnameNames = append(nonCnameNames, n) } zone := Zone{} zone.removeNonCnameName("test.com") } func Test_removeCnameName(t *testing.T) { backup := cnameNames defer func() { cnameNames = backup }() names := []name{ {recordType: "TXT", name: "test.com"}, {recordType: "TXT", name: "foo.com"}, {recordType: "TXT", name: "bar.com"}, {recordType: "TXT", name: "test.com"}, } for _, n := range names { cnameNames = append(cnameNames, n) } zone := Zone{} zone.removeCnameName("test.com") } func testZone_AddRecord_Provider() []*ARecord { return []*ARecord{ &ARecord{ Name: "www", Active: true, Target: "1.2.3.4", TTL: 30, }, &ARecord{ Name: "www", Active: true, Target: "1.2.3.4", TTL: 30, }, &ARecord{ Name: "www", Active: true, Target: "1.2.3.5", TTL: 30, }, } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/000077500000000000000000000000001400161560600250775ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/README.md000066400000000000000000000002551400161560600263600ustar00rootroot00000000000000# Akamai Config DNS (Zone Record Management) A golang package that talks to the [Akamai OPEN Config DNS API](https://developer.akamai.com/api/luna/config-dns/overview.html).golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/authorities.go000066400000000000000000000030451400161560600277700ustar00rootroot00000000000000package dnsv2 import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) type AuthorityResponse struct { Contracts []struct { ContractID string `json:"contractId"` Authorities []string `json:"authorities"` } `json:"contracts"` } func NewAuthorityResponse(contract string) *AuthorityResponse { authorities := &AuthorityResponse{} return authorities } func GetAuthorities(contractId string) (*AuthorityResponse, error) { authorities := NewAuthorityResponse(contractId) req, err := client.NewRequest( Config, "GET", "/config-dns/v2/data/authorities?contractIds="+contractId, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: contractId} } else { err = client.BodyJSON(res, authorities) if err != nil { return nil, err } return authorities, nil } } func GetNameServerRecordList(contractId string) ([]string, error) { NSrecords, err := GetAuthorities(contractId) if err != nil { return nil, err } var arrLength int for _, c := range NSrecords.Contracts { arrLength = len(c.Authorities) } ns := make([]string, 0, arrLength) for _, r := range NSrecords.Contracts { for _, n := range r.Authorities { ns = append(ns, n) } } return ns, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/errors.go000066400000000000000000000107131400161560600267440ustar00rootroot00000000000000package dnsv2 import ( "fmt" client "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) type ConfigDNSError interface { error Network() bool NotFound() bool FailedToSave() bool ValidationFailed() bool ConcurrencyConflict() bool } func IsConfigDNSError(e error) bool { _, ok := e.(ConfigDNSError) return ok } type ZoneError struct { zoneName string httpErrorMessage string apiErrorMessage string err error } func (e *ZoneError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e *ZoneError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } else if e.err != nil { _, ok := e.err.(client.APIError) if ok && e.err.(client.APIError).Response.StatusCode == 404 { return true } } return false } func (e *ZoneError) FailedToSave() bool { return false } func (e *ZoneError) ValidationFailed() bool { if e.apiErrorMessage != "" { return true } return false } func (e *ZoneError) ConcurrencyConflict() bool { _, ok := e.err.(client.APIError) if ok && e.err.(client.APIError).Response.StatusCode == 409 { return true } return false } func (e *ZoneError) Error() string { if e.Network() { return fmt.Sprintf("Zone \"%s\" network error: [%s]", e.zoneName, e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("Zone \"%s\" not found.", e.zoneName) } if e.ConcurrencyConflict() { return fmt.Sprintf("Modification Confict: [%s]", e.apiErrorMessage) } if e.FailedToSave() { return fmt.Sprintf("Zone \"%s\" failed to save: [%s]", e.zoneName, e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("Zone \"%s\" validation failed: [%s]", e.zoneName, e.apiErrorMessage) } if e.err != nil { return e.err.Error() } return "" } type RecordError struct { fieldName string httpErrorMessage string apiErrorMessage string err error } func (e *RecordError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e *RecordError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } else if e.err != nil { _, ok := e.err.(client.APIError) if ok && e.err.(client.APIError).Response.StatusCode == 404 { return true } } return false } func (e *RecordError) FailedToSave() bool { if e.fieldName == "" { return true } return false } func (e *RecordError) ValidationFailed() bool { if e.fieldName != "" && e.err == nil { return true } return false } func (e *RecordError) ConcurrencyConflict() bool { _, ok := e.err.(client.APIError) if ok && e.err.(client.APIError).Response.StatusCode == 409 { return true } return false } func (e *RecordError) BadRequest() bool { _, ok := e.err.(client.APIError) if ok && e.err.(client.APIError).Status == 400 { return true } return false } func (e *RecordError) Error() string { if e.Network() { return fmt.Sprintf("Record network error: [%s]", e.httpErrorMessage) } if e.ConcurrencyConflict() { return fmt.Sprintf("Modification Confict: [%s]", e.apiErrorMessage) } if e.BadRequest() { return fmt.Sprintf("Invalid Operation: [%s]", e.apiErrorMessage) } if e.NotFound() { return fmt.Sprintf("Record not found.") } if e.FailedToSave() { return fmt.Sprintf("Record failed to save: [%s]", e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("Record validation failed for field [%s]", e.fieldName) } if e.err != nil { return fmt.Sprintf("%s", e.err.Error()) } return "" } type TsigError struct { keyName string httpErrorMessage string apiErrorMessage string err error } func (e *TsigError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e *TsigError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } return false } func (e *TsigError) FailedToSave() bool { return false } func (e *TsigError) ValidationFailed() bool { if e.apiErrorMessage != "" { return true } return false } func (e *TsigError) Error() string { if e.Network() { return fmt.Sprintf("Tsig network error: [%s]", e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("tsig key not found.") } if e.FailedToSave() { return fmt.Sprintf("tsig key failed to save: [%s]", e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("tsig key validation failed: [%s]", e.apiErrorMessage) } return "" } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/record.go000066400000000000000000000166531400161560600267170ustar00rootroot00000000000000package dnsv2 import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "sync" ) // The record types implemented and their fields are as defined here // https://developer.akamai.com/api/luna/config-dns/data.html type RecordBody struct { Name string `json:"name,omitempty"` RecordType string `json:"type,omitempty"` TTL int `json:"ttl,omitempty"` // Active field no longer used in v2 Active bool `json:"active,omitempty"` Target []string `json:"rdata,omitempty"` // Remaining Fields are not used in the v2 API Subtype int `json:"subtype,omitempty"` //AfsdbRecord Flags int `json:"flags,omitempty"` //DnskeyRecord Nsec3paramRecord Protocol int `json:"protocol,omitempty"` //DnskeyRecord Algorithm int `json:"algorithm,omitempty"` //DnskeyRecord DsRecord Nsec3paramRecord RrsigRecord SshfpRecord Key string `json:"key,omitempty"` //DnskeyRecord Keytag int `json:"keytag,omitempty"` //DsRecord RrsigRecord DigestType int `json:"digest_type,omitempty"` //DsRecord Digest string `json:"digest,omitempty"` //DsRecord Hardware string `json:"hardware,omitempty"` //HinfoRecord Software string `json:"software,omitempty"` //HinfoRecord Priority int `json:"priority,omitempty"` //MxRecord SrvRecord Order uint16 `json:"order,omitempty"` //NaptrRecord Preference uint16 `json:"preference,omitempty"` //NaptrRecord FlagsNaptr string `json:"flags,omitempty"` //NaptrRecord Service string `json:"service,omitempty"` //NaptrRecord Regexp string `json:"regexp,omitempty"` //NaptrRecord Replacement string `json:"replacement,omitempty"` //NaptrRecord Iterations int `json:"iterations,omitempty"` //Nsec3Record Nsec3paramRecord Salt string `json:"salt,omitempty"` //Nsec3Record Nsec3paramRecord NextHashedOwnerName string `json:"next_hashed_owner_name,omitempty"` //Nsec3Record TypeBitmaps string `json:"type_bitmaps,omitempty"` //Nsec3Record Mailbox string `json:"mailbox,omitempty"` //RpRecord Txt string `json:"txt,omitempty"` //RpRecord TypeCovered string `json:"type_covered,omitempty"` //RrsigRecord OriginalTTL int `json:"original_ttl,omitempty"` //RrsigRecord Expiration string `json:"expiration,omitempty"` //RrsigRecord Inception string `json:"inception,omitempty"` //RrsigRecord Signer string `json:"signer,omitempty"` //RrsigRecord Signature string `json:"signature,omitempty"` //RrsigRecord Labels int `json:"labels,omitempty"` //RrsigRecord Weight uint16 `json:"weight,omitempty"` //SrvRecord Port uint16 `json:"port,omitempty"` //SrvRecord FingerprintType int `json:"fingerprint_type,omitempty"` //SshfpRecord Fingerprint string `json:"fingerprint,omitempty"` //SshfpRecord PriorityIncrement int `json:"priority_increment,omitempty"` //MX priority Increment } var ( zoneRecordWriteLock sync.Mutex ) func (record *RecordBody) ToMap() map[string]interface{} { return map[string]interface{}{ "name": record.Name, "ttl": record.TTL, "active": record.Active, "target": record.Target, } } func NewRecordBody(params RecordBody) *RecordBody { recordbody := &RecordBody{Name: params.Name} return recordbody } // Eval option lock arg passed into writable endpoints. Default is true, e.g. lock func localLock(lockArg []bool) bool { for _, lock := range lockArg { // should only be one entry return lock } return true } func (record *RecordBody) Save(zone string, recLock ...bool) 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) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/zones/"+zone+"/names/"+record.Name+"/types/"+record.RecordType, record, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &RecordError{ fieldName: record.Name, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &RecordError{fieldName: record.Name, apiErrorMessage: err.Detail, err: err} } return nil } func (record *RecordBody) Update(zone string, recLock ...bool) 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) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } req, err := client.NewJSONRequest( Config, "PUT", "/config-dns/v2/zones/"+zone+"/names/"+record.Name+"/types/"+record.RecordType, record, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &RecordError{ fieldName: record.Name, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &RecordError{fieldName: record.Name, apiErrorMessage: err.Detail, err: err} } return nil } func (record *RecordBody) Delete(zone string, recLock ...bool) 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) { zoneRecordWriteLock.Lock() defer zoneRecordWriteLock.Unlock() } req, err := client.NewJSONRequest( Config, "DELETE", "/config-dns/v2/zones/"+zone+"/names/"+record.Name+"/types/"+record.RecordType, nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &RecordError{ fieldName: record.Name, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { if res.StatusCode != 404 { err := client.NewAPIError(res) return &RecordError{fieldName: record.Name, apiErrorMessage: err.Detail, err: err} } } return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/record_lookup.go000066400000000000000000000255071400161560600303060ustar00rootroot00000000000000package dnsv2 import ( "encoding/hex" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "net" //"sort" "strconv" "strings" ) /* { "metadata": { "zone": "example.com", "types": [ "A" ], "page": 1, "pageSize": 25, "totalElements": 2 }, "recordsets": [ { "name": "www.example.com", "type": "A", "ttl": 300, "rdata": [ "10.0.0.2", "10.0.0.3" ] }, { "name": "mail.example.com", "type": "A", "ttl": 300, "rdata": [ "192.168.0.1", "192.168.0.2" ] } ] } */ func FullIPv6(ip net.IP) string { dst := make([]byte, hex.EncodedLen(len(ip))) _ = hex.Encode(dst, ip) return string(dst[0:4]) + ":" + string(dst[4:8]) + ":" + string(dst[8:12]) + ":" + string(dst[12:16]) + ":" + string(dst[16:20]) + ":" + string(dst[20:24]) + ":" + string(dst[24:28]) + ":" + string(dst[28:]) } func padvalue(str string) string { v_str := strings.Replace(str, "m", "", -1) v_float, err := strconv.ParseFloat(v_str, 32) if err != nil { return "FAIL" } v_result := fmt.Sprintf("%.2f", v_float) return v_result } // Used to pad coordinates to x.xxm format func PadCoordinates(str string) string { s := strings.Split(str, " ") lat_d, lat_m, lat_s, lat_dir, long_d, long_m, long_s, long_dir, altitude, size, horiz_precision, vert_precision := s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11] return lat_d + " " + lat_m + " " + lat_s + " " + lat_dir + " " + long_d + " " + long_m + " " + long_s + " " + long_dir + " " + padvalue(altitude) + "m " + padvalue(size) + "m " + padvalue(horiz_precision) + "m " + padvalue(vert_precision) + "m" } // Get single Recordset. Following convention for other single record CRUD operations, return a RecordBody. func GetRecord(zone string, name string, record_type string) (*RecordBody, error) { record := &RecordBody{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, name, record_type), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &RecordError{fieldName: name} } else { err = client.BodyJSON(res, record) if err != nil { return nil, err } return record, nil } } func GetRecordList(zone string, name string, record_type string) (*RecordSetResponse, error) { records := NewRecordSetResponse(name) req, err := client.NewRequest( Config, "GET", "/config-dns/v2/zones/"+zone+"/recordsets?types="+record_type+"&showAll=true", nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &RecordError{fieldName: name} } else { err = client.BodyJSON(res, records) if err != nil { return nil, err } return records, nil } } func GetRdata(zone string, name string, record_type string) ([]string, error) { records, err := GetRecordList(zone, name, record_type) if err != nil { return nil, err } var arrLength int for _, c := range records.Recordsets { if c.Name == name { arrLength = len(c.Rdata) } } rdata := make([]string, 0, arrLength) for _, r := range records.Recordsets { if r.Name == name { for _, i := range r.Rdata { str := i if record_type == "AAAA" { addr := net.ParseIP(str) result := FullIPv6(addr) str = result } else if record_type == "LOC" { str = PadCoordinates(str) } rdata = append(rdata, str) } } } return rdata, nil } func ProcessRdata(rdata []string, rtype string) []string { newrdata := make([]string, 0, len(rdata)) for _, i := range rdata { str := i if rtype == "AAAA" { addr := net.ParseIP(str) result := FullIPv6(addr) str = result } else if rtype == "LOC" { str = PadCoordinates(str) } newrdata = append(newrdata, str) } return newrdata } // Utility method to parse RData in context of type. Return map of fields and values func ParseRData(rtype string, rdata []string) map[string]interface{} { fieldMap := make(map[string]interface{}, 0) if len(rdata) == 0 { return fieldMap } newrdata := make([]string, 0, len(rdata)) fieldMap["target"] = newrdata switch rtype { case "AFSDB": parts := strings.Split(rdata[0], " ") fieldMap["subtype"], _ = strconv.Atoi(parts[0]) for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") newrdata = append(newrdata, parts[1]) } fieldMap["target"] = newrdata case "DNSKEY": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["flags"], _ = strconv.Atoi(parts[0]) fieldMap["protocol"], _ = strconv.Atoi(parts[1]) fieldMap["algorithm"], _ = strconv.Atoi(parts[2]) key := parts[3] // key can have whitespace if len(parts) > 4 { i := 4 for i < len(parts) { key += " " + parts[i] } } fieldMap["key"] = key break } case "DS": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["keytag"], _ = strconv.Atoi(parts[0]) fieldMap["digest_type"], _ = strconv.Atoi(parts[2]) fieldMap["algorithm"], _ = strconv.Atoi(parts[1]) dig := parts[3] // digest can have whitespace if len(parts) > 4 { i := 4 for i < len(parts) { dig += " " + parts[i] } } fieldMap["digest"] = dig break } case "HINFO": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["hardware"] = parts[0] fieldMap["software"] = parts[1] break } /* // too many variations to calculate pri and increment case "MX": sort.Strings(rdata) parts := strings.Split(rdata[0], " ") fieldMap["priority"], _ = strconv.Atoi(parts[0]) if len(rdata) > 1 { parts = strings.Split(rdata[1], " ") tpri, _ := strconv.Atoi(parts[0]) fieldMap["priority_increment"] = tpri - fieldMap["priority"].(int) } for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") newrdata = append(newrdata, parts[1]) } fieldMap["target"] = newrdata */ case "NAPTR": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["order"], _ = strconv.Atoi(parts[0]) fieldMap["preference"], _ = strconv.Atoi(parts[1]) fieldMap["flagsnaptr"] = parts[2] fieldMap["service"] = parts[3] fieldMap["regexp"] = parts[4] fieldMap["replacement"] = parts[5] break } case "NSEC3": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["flags"], _ = strconv.Atoi(parts[1]) fieldMap["algorithm"], _ = strconv.Atoi(parts[0]) fieldMap["iterations"], _ = strconv.Atoi(parts[2]) fieldMap["salt"] = parts[3] fieldMap["next_hashed_owner_name"] = parts[4] fieldMap["type_bitmaps"] = parts[5] break } case "NSEC3PARAM": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["flags"], _ = strconv.Atoi(parts[1]) fieldMap["algorithm"], _ = strconv.Atoi(parts[0]) fieldMap["iterations"], _ = strconv.Atoi(parts[2]) fieldMap["salt"] = parts[3] break } case "RP": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["mailbox"] = parts[0] fieldMap["txt"] = parts[1] break } case "RRSIG": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["type_covered"] = parts[0] fieldMap["algorithm"], _ = strconv.Atoi(parts[1]) fieldMap["labels"], _ = strconv.Atoi(parts[2]) fieldMap["original_ttl"], _ = strconv.Atoi(parts[3]) fieldMap["expiration"] = parts[4] fieldMap["inception"] = parts[5] fieldMap["signer"] = parts[7] fieldMap["keytag"], _ = strconv.Atoi(parts[6]) sig := parts[8] // sig can have whitespace if len(parts) > 9 { i := 9 for i < len(parts) { sig += " " + parts[i] } } fieldMap["signature"] = sig break } case "SRV": // pull out some fields parts := strings.Split(rdata[0], " ") fieldMap["priority"], _ = strconv.Atoi(parts[0]) fieldMap["weight"], _ = strconv.Atoi(parts[1]) fieldMap["port"], _ = strconv.Atoi(parts[2]) // populate target for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") newrdata = append(newrdata, parts[3]) } fieldMap["target"] = newrdata case "SSHFP": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["algorithm"], _ = strconv.Atoi(parts[0]) fieldMap["fingerprint_type"], _ = strconv.Atoi(parts[1]) fieldMap["fingerprint"] = parts[2] break } case "SOA": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["name_server"] = parts[0] fieldMap["email_address"] = parts[1] fieldMap["serial"], _ = strconv.Atoi(parts[2]) fieldMap["refresh"], _ = strconv.Atoi(parts[3]) fieldMap["retry"], _ = strconv.Atoi(parts[4]) fieldMap["expiry"], _ = strconv.Atoi(parts[5]) fieldMap["nxdomain_ttl"], _ = strconv.Atoi(parts[6]) break } case "AKAMAITLC": parts := strings.Split(rdata[0], " ") fieldMap["answer_type"] = parts[0] fieldMap["dns_name"] = parts[1] case "SPF": for _, rcontent := range rdata { newrdata = append(newrdata, rcontent) } fieldMap["target"] = newrdata case "TXT": for _, rcontent := range rdata { newrdata = append(newrdata, rcontent) } fieldMap["target"] = newrdata case "AAAA": for _, i := range rdata { str := i addr := net.ParseIP(str) result := FullIPv6(addr) str = result newrdata = append(newrdata, str) } fieldMap["target"] = newrdata case "LOC": for _, i := range rdata { str := i str = PadCoordinates(str) newrdata = append(newrdata, str) } fieldMap["target"] = newrdata case "CERT": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") val, err := strconv.Atoi(parts[0]) if err == nil { fieldMap["type_value"] = val } else { fieldMap["type_mnemonic"] = parts[0] } fieldMap["keytag"], _ = strconv.Atoi(parts[1]) fieldMap["algorithm"], _ = strconv.Atoi(parts[2]) fieldMap["certificate"] = parts[3] break } case "TLSA": for _, rcontent := range rdata { parts := strings.Split(rcontent, " ") fieldMap["usage"], _ = strconv.Atoi(parts[0]) fieldMap["selector"], _ = strconv.Atoi(parts[1]) fieldMap["match_type"], _ = strconv.Atoi(parts[2]) fieldMap["certificate"] = parts[3] break } default: for _, rcontent := range rdata { newrdata = append(newrdata, rcontent) } fieldMap["target"] = newrdata } return fieldMap } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/record_test.go000066400000000000000000000167461400161560600277610ustar00rootroot00000000000000package dnsv2 import ( "fmt" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "testing" ) func TestRecord_ContainsHelper(t *testing.T) { tm1 := []string{ "test1", "test2", "test3", } assert.Equal(t, contains(tm1, "test1"), true) assert.Equal(t, contains(tm1, "test2"), true) assert.Equal(t, contains(tm1, "test3"), true) assert.Equal(t, contains(tm1, "test4"), false) } func contains(arr []string, str string) bool { for _, a := range arr { if a == str { return true } } return false } func TestRecord_ARecord(t *testing.T) { a := &RecordBody{Name: "test1", RecordType: "A"} /* a := NewARecord() f := []string{ "name", "ttl", "active", "target", }*/ // assert.Equal(t, a.fieldMap, f) // assert.Equal(t, a.fieldMap, a.GetAllowedFields()) //assert.Equal(t, a.SetField("name", "test1"), nil) assert.Equal(t, "test1", a.Name) //assert.Equal(t, a.SetField("doesntExist", "test1"), &RecordError{fieldName: "doesntExist"}) a.TTL = 900 //a.SetField("ttl", 900) //a.SetField("active", true) a.Active = true //a.SetField("target", "test2") records := make([]string, 0, 1) records = append(records, "test2") a.Target = records assert.Equal(t, a.ToMap(), map[string]interface{}{ "name": "test1", "ttl": 900, "active": true, "target": []string{"test2"}, }) } func TestRecord_AllRecords_WrongTypes(t *testing.T) { /*a := NewARecord() e := a.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a1 := NewAaaaRecord() e1 := a1.SetField("name", 1) assert.Equal(t, e1, &RecordError{fieldName: "name"}) a2 := NewAfsdbRecord() e = a2.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a3 := NewCnameRecord() e = a3.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a4 := NewDnskeyRecord() e = a4.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a5 := NewDsRecord() e = a5.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a6 := NewHinfoRecord() e = a6.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a7 := NewLocRecord() e = a7.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a8 := NewMxRecord() e = a8.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a9 := NewNaptrRecord() e = a9.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a10 := NewNsRecord() e = a10.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a11 := NewNsec3Record() e = a11.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a12 := NewNsec3paramRecord() e = a12.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a13 := NewPtrRecord() e = a13.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a14 := NewRpRecord() e = a14.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a15 := NewRrsigRecord() e = a15.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a16 := NewSoaRecord() e = a16.SetField("ttl", "test") assert.Equal(t, e, &RecordError{fieldName: "ttl"}) a17 := NewSpfRecord() e = a17.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a18 := NewSrvRecord() e = a18.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a19 := NewSshfpRecord() e = a19.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) a20 := NewTxtRecord() e = a20.SetField("name", 1) assert.Equal(t, e, &RecordError{fieldName: "name"}) */ } func TestGetRecordsetsNoArgs(t *testing.T) { dnsTestZone := "testzone.com" defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/recordsets", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "metadata": { "lastPage": 1, "page": 1, "pageSize": 25, "showAll": false, "totalElements": 2 }, "recordsets": [ { "name": "east.testzone.com", "rdata": [ "east.testzone.com.edgesuite.net." ], "ttl": 600, "type": "CNAME" }, { "name": "easttest.testzone.com", "rdata": [ "easttest.testzone.com.edgesuite.net." ], "ttl": 600, "type": "CNAME" }] }`)) Init(config) recordsets, err := GetRecordsets(dnsTestZone) assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &RecordSetResponse{}, recordsets), true) assert.Equal(t, len(recordsets.Recordsets), 2) } func TestGetRecordsets(t *testing.T) { dnsTestZone := "testzone.com" defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/recordsets", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "metadata": { "lastPage": 1, "page": 1, "pageSize": 25, "showAll": false, "totalElements": 1 }, "recordsets": [ { "name": "east.testzone.com", "rdata": [ "east.testzone.com.edgesuite.net." ], "ttl": 600, "type": "CNAME" }] }`)) Init(config) qargs := RecordsetQueryArgs{Search: "east.testzone.com", SortBy: "name"} recordsets, err := GetRecordsets(dnsTestZone, qargs) assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &RecordSetResponse{}, recordsets), true) assert.Equal(t, len(recordsets.Recordsets), 1) } func TestGetRecord(t *testing.T) { dnsTestZone := "testzone.com" dnsTestRecordName := "east.testzone.com" dnsTestRecordType := "CNAME" defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/names/%s/types/%s", dnsTestZone, dnsTestRecordName, dnsTestRecordType)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", dnsTestZone, dnsTestRecordName, dnsTestRecordType)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "name": "east.testzone.com", "rdata": [ "east.testzone.com.edgesuite.net." ], "ttl": 600, "type": "CNAME" }`)) Init(config) testrecord, err := GetRecord(dnsTestZone, dnsTestRecordName, "CNAME") assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &RecordBody{}, testrecord), true) assert.Equal(t, testrecord.Name, dnsTestRecordName) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/recordsets.go000066400000000000000000000112741400161560600276100ustar00rootroot00000000000000package dnsv2 import ( "errors" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "strconv" "sync" ) var ( zoneRecordsetsWriteLock sync.Mutex ) // Recordset Query args struct type RecordsetQueryArgs struct { Page int PageSize int Search string ShowAll bool SortBy string Types string } // Recordsets Struct. Used for Create and Update Recordsets type Recordsets struct { Recordsets []Recordset `json:"recordsets"` } type Recordset struct { Name string `json:"name"` Type string `json:"type"` TTL int `json:"ttl"` Rdata []string `json:"rdata"` } //`json:"recordsets"` type MetadataH struct { LastPage int `json:"lastPage"` Page int `json:"page"` PageSize int `json:"pageSize"` ShowAll bool `json:"showAll"` TotalElements int `json:"totalElements"` } //`json:"metadata"` type RecordSetResponse struct { Metadata MetadataH `json:"metadata"` Recordsets []Recordset `json:"recordsets"` } func NewRecordSetResponse(name string) *RecordSetResponse { recordset := &RecordSetResponse{} return recordset } // Get RecordSets with Query Args. No formatting of arg values! func GetRecordsets(zone string, queryArgs ...RecordsetQueryArgs) (*RecordSetResponse, error) { recordsetResp := NewRecordSetResponse("") // construct GET url getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) if len(queryArgs) > 1 { return nil, errors.New("GetRecordsets QueryArgs invalid.") } req, err := client.NewRequest( Config, "GET", getURL, nil, ) if err != nil { return nil, err } 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) } req.URL.RawQuery = q.Encode() } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { err = client.BodyJSON(res, recordsetResp) if err != nil { return nil, err } return recordsetResp, nil } } // Create Recordstes func (recordsets *Recordsets) Save(zone string, recLock ...bool) 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) { zoneRecordsetsWriteLock.Lock() defer zoneRecordsetsWriteLock.Unlock() } req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/zones/"+zone+"/recordsets", recordsets, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone, apiErrorMessage: err.Detail, err: err} } return nil } func (recordsets *Recordsets) Update(zone string, recLock ...bool) 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) { zoneRecordsetsWriteLock.Lock() defer zoneRecordsetsWriteLock.Unlock() } req, err := client.NewJSONRequest( Config, "PUT", "/config-dns/v2/zones/"+zone+"/recordsets", recordsets, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone, apiErrorMessage: err.Detail, err: err} } return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/recordsets_test.go000066400000000000000000000055761400161560600306570ustar00rootroot00000000000000package dnsv2 import ( "testing" //edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var recordsetBody = []byte(fmt.Sprintf(`{ "recordsets": [{ "name": "new.%s", "type": "CNAME", "ttl": 900, "rdata": ["www.example.com"] }, { "name": "a_rec_%s", "type": "A", "ttl": 900, "rdata": ["10.0.0.10"] }]}`, dnsTestZone, dnsTestZone)) func createTestRecordsets() *Recordsets { rs := &Recordsets{} jsonhooks.Unmarshal(recordsetBody, rs) return rs } func TestListRecordsets(t *testing.T) { /* // for live testing config, err := edge.Init("","") if err != nil { t.Fatalf("TestListRecordsets failed initializing: %s", err.Error()) } */ defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/recordsets", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "metadata": { "totalElements":2 }, "recordsets": [ { "name": "new.%s", "type": "CNAME", "ttl": 900, "rdata": ["www.example.com"] }, { "name": "a_rec_%s", "type": "A", "ttl": 900, "rdata": ["10.0.0.10"] }]}`, dnsTestZone, dnsTestZone)) Init(config) listResp, err := GetRecordsets(dnsTestZone) assert.NoError(t, err) assert.Equal(t, int(len(listResp.Recordsets)), listResp.Metadata.TotalElements) } func TestCreateRecordsets(t *testing.T) { defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/recordsets", dnsTestZone)) mock. Post(fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", dnsTestZone)). HeaderPresent("Authorization"). Reply(204). SetHeader("Content-Type", "application/json;charset=UTF-8") Init(config) sets := createTestRecordsets() err := sets.Save(dnsTestZone) assert.NoError(t, err) } func TestUpdateRecordsets(t *testing.T) { defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/recordsets", dnsTestZone)) mock. Put(fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", dnsTestZone)). HeaderPresent("Authorization"). Reply(204). SetHeader("Content-Type", "application/json;charset=UTF-8") Init(config) sets := createTestRecordsets() err := sets.Update(dnsTestZone) assert.NoError(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/service.go000066400000000000000000000005201400161560600270630ustar00rootroot00000000000000package dnsv2 import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the DNSv2 edgegrid Config func Init(config edgegrid.Config) { Config = config edgegrid.SetupLogging() } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/service_test.go000066400000000000000000000664631400161560600301440ustar00rootroot00000000000000package dnsv2 import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "testing" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) func TestGetZoneSimple(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/example.com") mock. Get("/config-dns/v2/zones/example.com"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "contractId": "C-1FRYVV3", "zone": "example.com", "type": "PRIMARY", "comment": "This is a test zone", "versionId": "5e311536-c4b7-4dec-b8a9-1fe3d6042406", "lastActivationDate": "2019-02-23T22:31:48Z", "lastModifiedDate": "2019-02-23T22:31:48Z", "lastModifiedBy": "davey.shafik", "activationState": "PENDING", "signAndServe": false }`) Init(config) zone, err := GetZone("example.com") assert.NoError(t, err) assert.IsType(t, &ZoneResponse{}, zone) //assert.Equal(t, "a184671d5307a388180fbf7f11dbdf46", zone.Token) assert.Equal(t, "example.com", zone.Zone) /*assert.IsType(t, &SoaRecord{}, zone.Zone.Soa) assert.Equal(t, "hostmaster.akamai.com.", zone.Zone.Soa.Contact) assert.Equal(t, 604800, zone.Zone.Soa.Expire) assert.Equal(t, uint(180), zone.Zone.Soa.Minimum) assert.Equal(t, "use4.akamai.com.", zone.Zone.Soa.Originserver) assert.Equal(t, 900, zone.Zone.Soa.Refresh) assert.Equal(t, 300, zone.Zone.Soa.Retry) assert.Equal(t, uint(1271354824), zone.Zone.Soa.Serial) assert.Equal(t, 900, zone.Zone.Soa.TTL) */ /* assert.IsType(t, []*NsRecord{}, zone.Zone.Ns) assert.Len(t, zone.Zone.Ns, 2) assert.Equal(t, true, zone.Zone.Ns[0].Active) assert.Equal(t, "", zone.Zone.Ns[0].Name) assert.Equal(t, "use4.akam.net.", zone.Zone.Ns[0].Target) assert.Equal(t, 3600, zone.Zone.Ns[0].TTL) assert.Equal(t, true, zone.Zone.Ns[1].Active) assert.Equal(t, "", zone.Zone.Ns[1].Name) assert.Equal(t, "use3.akam.net.", zone.Zone.Ns[1].Target) assert.Equal(t, 3600, zone.Zone.Ns[1].TTL) assert.IsType(t, []*ARecord{}, zone.Zone.A) assert.Len(t, zone.Zone.A, 1) assert.Equal(t, true, zone.Zone.A[0].Active) assert.Equal(t, "www", zone.Zone.A[0].Name) assert.Equal(t, "1.2.3.4", zone.Zone.A[0].Target) assert.Equal(t, 30, zone.Zone.A[0].TTL) */ } func TestGetZoneRecords(t *testing.T) { defer gock.Off() tests := testGetZoneCompleteProvider() for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/example.com") mock. //Get("/config-dns/v2/zones/example.com/recordsets?types=A&showAll=true"). Get("/config-dns/v2/zones/example.com"). HeaderPresent("Authorization"). Persist(). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(test.responseBody) Init(config) fmt.Println("Record Type " + test.recordType) fmt.Println(test.expectedRecords.([]*RecordSetResponse)[0].Metadata.ShowAll) fmt.Println(test.expectedRecords.([]*RecordSetResponse)[0].Recordsets[0].Name) zone, err := GetZone("example.com") records, err := GetRecordList("example.com", "example.com", test.recordType) // (*RecordSetResponse, error) assert.NoError(t, err) assert.IsType(t, &RecordSetResponse{}, records) if test.expectedRecords != nil { switch test.recordType { case "A": fmt.Println(zone) fmt.Println(records) assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "AAAA": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "AFSDB": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "CNAME": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "DNSKEY": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "DS": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "HINFO": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "LOC": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "MX": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "NAPTR": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "NS": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "NSEC3": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "NSEC3PARAM": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "PTR": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "RP": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "RRSIG": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "SPF": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "SRV": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "SSHFP": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break case "TXT": assert.Equal(t, len(test.expectedRecords.([]*RecordSetResponse)), len(records.Recordsets)) assert.ObjectsAreEqual(test.expectedRecords, records) break } } }) } } type recordTests []struct { name string recordType string responseBody string expectedType interface{} expectedRecord RecordSetResponse //ARecord expectedRecords interface{} } func testGetZoneCompleteProvider() recordTests { return recordTests{ { name: "A Records", recordType: "A", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "arecord", "type": "A", "ttl": 3700, "rdata": [ "10.0.0.2", "10.0.0.3", "1.2.3.9" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ //Active: true, Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "arecord", Type: "A", TTL: 3600, Rdata: []string{"1.2.3.4", "1.2.3.5"}}}, //Recordset {Target: []string{"1.2.3.4","1.2.3.5"}}, //Recordset {TTL: 3600}, }, /* &RecordSetResponse{ //Active: true, //Name: "origin", //Metadata {}, Metadata: MetadataH {ShowAll: true, TotalElements: 1}, Recordsets: []Recordset { Recordset{Name: "arecord", Type: "A", TTL: 3600, Rdata: []string{"1.2.3.9"} }}, //Recordsets {Name: "origin"}, //Recordsets {Target: []string{"1.2.3.9"}}, // Recordsets { TTL: 3600}, },*/ }, }, { name: "AAAA Records", recordType: "AAAA", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "ipv6record.akavaiodeveloper.net", "type": "AAAA", "ttl": 3600, "rdata": [ "2001:db8:0:0:0:ff00:42:8329" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ //Active: true, //Name: "ipv6record", //Target: []string{"2001:0db8::ff00:0042:8329"}, //TTL: 3600, Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "ipv6record.akavaiodeveloper.net", Type: "AAAA", TTL: 3600, Rdata: []string{"2001:db8:0:0:0:ff00:42:8329"}}}, }, }, }, { name: "AFSDB Records", recordType: "AFSDB", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "afsdb.akavaiodeveloper.net", "type": "AFSDB", "ttl": 3600, "rdata": [ "4 example.com." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "afsdb", Subtype: 1, Target: []string{"example.com."}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "afsdb.akavaiodeveloper.net", Type: "AFSDB", TTL: 3600, Rdata: []string{"4 example.com."}}}, }, }, }, { name: "CNAME Records", recordType: "CNAME", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "www.akavaiodeveloper.net", "type": "CNAME", "ttl": 300, "rdata": [ "api.akavaiodeveloper.net." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "redirect", Target: []string{"arecord.example.com."}, TTL: 3600,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "www.akavaiodeveloper.net", Type: "CNAME", TTL: 300, Rdata: []string{"api.akavaiodeveloper.net."}}}, }, }, }, { name: "DNSKEY Records", recordType: "DNSKEY", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "dnskey.akavaiodeveloper.net", "type": "DNSKEY", "ttl": 7200, "rdata": [ "257 7 3 Av//0/goGKPtaa28nQvPoUwVP++/i/0hC+1CrmQkuuKtQt98WObuv7q8iQ==" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Algorithm: 3, Flags: 257, Key: "Av//0/goGKPtaa28nQvPoUwVQ ... i/0hC+1CrmQkuuKtQt98WObuv7q8iQ==", Name: "dnskey", Protocol: 7, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "dnskey.akavaiodeveloper.net", Type: "DNSKEY", TTL: 7200, Rdata: []string{"257 7 3 Av//0/goGKPtaa28nQvPoUwVP++/i/0hC+1CrmQkuuKtQt98WObuv7q8iQ=="}}}, }, }, }, { name: "DS Records", recordType: "DS", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "ds.akavaiodeveloper.net", "type": "DS", "ttl": 7200, "rdata": [ "30336 1 7 909FF0B4DD66F91F56524C4F968D13083BE42380" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Algorithm: 7, Digest: "909FF0B4DD66F91F56524C4F968D13083BE42380", DigestType: 1, Keytag: 30336, Name: "ds", TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "ds.akavaiodeveloper.net", Type: "DS", TTL: 7200, Rdata: []string{"30336 1 7 909FF0B4DD66F91F56524C4F968D13083BE42380"}}}, }, }, }, { name: "HINFO Records", recordType: "HINFO", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "hinfo.akavaiodeveloper.net", "type": "HINFO", "ttl": 7200, "rdata": [ "\"INTEL-386\" \"Unix\"" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Hardware: "INTEL-386", Name: "hinfo", Software: "UNIX", TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "hinfo.akavaiodeveloper.net", Type: "HINFO", TTL: 7200, Rdata: []string{"\"INTEL-386\" \"Unix\""}}}, }, }, }, { name: "LOC Records", recordType: "LOC", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "location.akavaiodeveloper.net", "type": "LOC", "ttl": 7200, "rdata": [ "51 30 12.748 N 0 7 39.611 W 0m 0m 0m 0m" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "location", Target: []string{"51 30 12.748 N 0 7 39.611 W 0.00m 0.00m 0.00m 0.00m"}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "afsdb.akavaiodeveloper.net", Type: "LOC", TTL: 7200, Rdata: []string{"51 30 12.748 N 0 7 39.611 W 0m 0m 0m 0m"}}}, }, }, }, { name: "MX Records", recordType: "MX", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "akavaiodeveloper.net", "type": "MX", "ttl": 300, "rdata": [ "10 smtp-1.akavaiodeveloper.net.", "20 smtp-3.akavaiodeveloper.net.", "30 smtp-0.akavaiodeveloper.net." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "four", Priority: 10, Target: []string{"mx1.akamai.com."}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "akavaiodeveloper.net", Type: "AFSDB", TTL: 300, Rdata: []string{"10 smtp-1.akavaiodeveloper.net.", "20 smtp-3.akavaiodeveloper.net.", "30 smtp-0.akavaiodeveloper.net."}}}, }, }, }, { name: "NAPTR Records", recordType: "NAPTR", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "naptrrecord.akavaiodeveloper.net", "type": "NAPTR", "ttl": 3600, "rdata": [ "0 10 \"S\" \"!^.*$!sip:customer-service@example.com!\" \".\" SIP+D2U." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, FlagsNaptr: "S", Name: "naptrrecord", Order: 0, Preference: 10, Regexp: "!^.*$!sip:customer-service@example.com!", Replacement: ".", Service: "SIP+D2U", TTL: 3600,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "naptrrecord.akavaiodeveloper.net", Type: "NAPTR", TTL: 3600, Rdata: []string{"0 10 \"S\" \"!^.*$!sip:customer-service@example.com!\" \".\" SIP+D2U."}}}, }, }, }, { name: "NS Records", recordType: "NS", responseBody: `{ "metadata": { "showAll": true, "totalElements": 2 }, "recordsets": [ { "name": "akavaiodeveloper.net", "type": "NS", "ttl": 86400, "rdata": [ "a1-49.akam.net.", "a16-64.akam.net.", "a22-65.akam.net.", "a26-66.akam.net.", "a7-67.akam.net.", "a9-64.akam.net." ] }, { "name": "ns.akavaiodeveloper.net", "type": "NS", "ttl": 300, "rdata": [ "use4.akam.net." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Target: []string{"use4.akam.net."}, TTL: 3600, }, &RecordBody{ Active: true, Target: []string{"us34.akam.net."}, TTL: 3600, }, &RecordBody{ Active: true, Name: "five", Target: []string{"use4.akam.net."}, TTL: 172800,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "akavaiodeveloper.net", Type: "NS", TTL: 3600, Rdata: []string{"a1-49.akam.net.", "a16-64.akam.net.", "a22-65.akam.net.", "a26-66.akam.net.", "a7-67.akam.net.", "a9-64.akam.net."}}}, }, }, }, { name: "NSEC3 Records", recordType: "NSEC3", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "qdeo8lqu4l81uo67oolpo9h0nv9l13dh.akavaiodeveloper.net", "type": "NSEC3", "ttl": 3600, "rdata": [ "0 1 1 EBD1E0942543A01B R2NUSMGFSEUHT195P59KOU2AI30JR90 CNAME RRSIG" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Algorithm: 1, Flags: 0, Iterations: 1, Name: "qdeo8lqu4l81uo67oolpo9h0nv9l13dh", NextHashedOwnerName: "R2NUSMGFSEUHT195P59KOU2AI30JR96P", Salt: "EBD1E0942543A01B", TTL: 7200, TypeBitmaps: "CNAME RRSIG",*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "qdeo8lqu4l81uo67oolpo9h0nv9l13dh.akavaiodeveloper.net", Type: "NSEC3", TTL: 3600, Rdata: []string{"0 1 1 EBD1E0942543A01B R2NUSMGFSEUHT195P59KOU2AI30JR90 CNAME RRSIG"}}}, }, }, }, { name: "NSEC3PARAM Records", recordType: "NSEC3PARAM", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "qnsec3param.akavaiodeveloper.net", "type": "NSEC3PARAM", "ttl": 3600, "rdata": [ "0 1 1 EBD1E0942543A01B" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Algorithm: 1, Flags: 0, Iterations: 1, Name: "qnsec3param", Salt: "EBD1E0942543A01B", TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "qnsec3param.akavaiodeveloper.net", Type: "NSEC3PARAM", TTL: 3600, Rdata: []string{"0 1 1 EBD1E0942543A01B"}}}, }, }, }, { name: "PTR Records", recordType: "PTR", responseBody: `{ "metadata": { "showAll": true, "totalElements": 2 }, "recordsets": [ { "name": "ptr.akavaiodeveloper.net", "type": "PTR", "ttl": 300, "rdata": [ "ptr.akavaiodeveloper.net." ] }, { "name": "spf.akavaiodeveloper.net", "type": "PTR", "ttl": 7200, "rdata": [ "v=spf." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "ptr", Target: []string{"ptr.example.com."}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "ptr.akavaiodeveloper.net", Type: "PTR", TTL: 7200, Rdata: []string{"v=spf."}}}, }, }, }, { name: "RP Records", recordType: "RP", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "rp.akavaiodeveloper.net", "type": "RP", "ttl": 7200, "rdata": [ "admin.example.com. txt.example.com." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Mailbox: "admin.example.com.", Name: "rp", TTL: 7200, Txt: "txt.example.com.", Metadata: MetadataH {ShowAll: true, TotalElements: 1},*/ Recordsets: []Recordset{Recordset{Name: "rp.akavaiodeveloper.net", Type: "RP", TTL: 7200, Rdata: []string{"admin.example.com. txt.example.com."}}}, }, }, }, { name: "RRSIG Records", recordType: "RRSIG", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "arecord", "ttl": 7200, "rdata": [ "A 7 3 3600 20120318104101 20120315094101 63761 3 toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv example.com." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Algorithm: 7, Expiration: "20120318104101", Inception: "20120315094101", Keytag: 63761, Labels: 3, Name: "arecord", OriginalTTL: 3600, Signature: "toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv", Signer: "example.com.", TTL: 7200, TypeCovered: "A",*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "arecord", Type: "RRSIG", TTL: 7200, Rdata: []string{"A 7 3 3600 20120318104101 20120315094101 63761 3 toCy19QnAb86vRlQjf5 ... z1doJdHEr8PiI+Is9Eafxh+4Idcw8Ysv example.com."}}}, }, }, }, { name: "SPF Records", recordType: "SPF", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "spf.akavaiodeveloper.net", "type": "SPF", "ttl": 7200, "rdata": [ "\"v=spf.\"" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Name: "spf", Target: []string{"v=spf a -all"}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "afsdb.akavaiodeveloper.net", Type: "SPF", TTL: 7200, Rdata: []string{"\"v=spf.\""}}}, }, }, }, { name: "SSHFP Records", recordType: "SSHFP", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "sshfp.akavaiodeveloper.net", "type": "SSHFP", "ttl": 7200, "rdata": [ "2 1 123456789ABCDEF67890123456789ABCDEF67890" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /* Active: true, Algorithm: 2, Fingerprint: "123456789ABCDEF67890123456789ABCDEF67890", FingerprintType: 1, Name: "host", TTL: 3600,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "afsdb.akavaiodeveloper.net", Type: "SSHFP", TTL: 3600, Rdata: []string{"2 1 123456789ABCDEF67890123456789ABCDEF67890"}}}, }, }, }, { name: "SRV Records", recordType: "SRV", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "srv.akavaiodeveloper.net", "type": "SRV", "ttl": 7200, "rdata": [ "0 522 10 target.akavaiodeveloper.net." ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "srv", Port: 522, Priority: 10, Target: []string{"target.akamai.com."}, TTL: 7200, Weight: 0,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "srv.akavaiodeveloper.net", Type: "SRV", TTL: 7200, Rdata: []string{"0 522 10 target.akavaiodeveloper.net."}}}, }, }, }, { name: "TXT Records", recordType: "TXT", responseBody: `{ "metadata": { "showAll": true, "totalElements": 1 }, "recordsets": [ { "name": "text.akavaiodeveloper.net", "type": "TXT", "ttl": 7200, "rdata": [ "\"Hello\" \"world\" \"this\" \"is\" \"text\"" ] } ] }`, expectedType: []*RecordSetResponse{}, expectedRecords: []*RecordSetResponse{ &RecordSetResponse{ /*Active: true, Name: "text", Target: []string{"Hello world!"}, TTL: 7200,*/ Metadata: MetadataH{ShowAll: true, TotalElements: 1}, Recordsets: []Recordset{Recordset{Name: "text.akavaiodeveloper.net", Type: "TXT", TTL: 7200, Rdata: []string{"Hello world!"}}}, }, }, }, } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/tsig.go000066400000000000000000000177611400161560600264100ustar00rootroot00000000000000package dnsv2 import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "reflect" "strings" "sync" ) var ( tsigWriteLock sync.Mutex ) // TODO: Add examples? type TSIGQueryString struct { ContractIds []string `json:"contractIds,omitempty"` Search string `json:"search,omitempty"` SortBy []string `json:"sortBy,omitempty"` Gid int64 `json:"gid,omitempty"` } type TSIGKey struct { Name string `json:"name"` Algorithm string `json:"algorithm,omitempty"` Secret string `json:"secret,omitempty"` } type TSIGKeyResponse struct { TSIGKey ZoneCount int64 `json:"zoneCount,omitempty"` } type TSIGKeyBulkPost struct { Key *TSIGKey `json:"key"` Zones []string `json:"zones"` } type TSIGZoneAliases struct { Aliases []string `json:"aliases"` } type TSIGReportMeta struct { TotalElements int64 `json:"totalElements"` Search string `json:"search,omitempty"` Contracts []string `json:"contracts,omitempty"` Gid int64 `json:"gid,omitempty"` SortBy []string `json:"sortBy,omitempty"` } type TSIGReportResponse struct { Metadata *TSIGReportMeta `json:"metadata"` Keys []*TSIGKeyResponse `json:"keys,omitempty"` } // Return bare bones tsig key struct func NewTSIGKey(name string) *TSIGKey { key := &TSIGKey{Name: name} return key } // Return empty query string struct. No elements required. func NewTSIGQueryString() *TSIGQueryString { tsigquerystring := &TSIGQueryString{} return tsigquerystring } func constructTsigQueryString(tsigquerystring *TSIGQueryString) string { queryString := "" qsElems := reflect.ValueOf(tsigquerystring).Elem() for i := 0; i < qsElems.NumField(); i++ { varName := qsElems.Type().Field(i).Name varValue := qsElems.Field(i).Interface() keyVal := fmt.Sprint(varValue) switch varName { case "ContractIds": contractList := "" for j, id := range varValue.([]string) { contractList += id if j < len(varValue.([]string))-1 { contractList += "%2C" } } if len(varValue.([]string)) > 0 { queryString += "contractIds=" + contractList } case "SortBy": sortByList := "" for j, sb := range varValue.([]string) { sortByList += sb if j < len(varValue.([]string))-1 { sortByList += "%2C" } } if len(varValue.([]string)) > 0 { queryString += "sortBy=" + sortByList } case "Search": if keyVal != "" { queryString += "search=" + keyVal } case "Gid": if varValue.(int64) != 0 { queryString += "gid=" + keyVal } } if i < qsElems.NumField()-1 { queryString += "&" } } queryString = strings.TrimRight(queryString, "&") if len(queryString) > 0 { return "?" + queryString } else { return "" } } // List TSIG Keys func ListTsigKeys(tsigquerystring *TSIGQueryString) (*TSIGReportResponse, error) { tsigList := &TSIGReportResponse{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/keys%s", constructTsigQueryString(tsigquerystring)), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &TsigError{ keyName: "TsigKeyList", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &TsigError{keyName: "TsigKeyList", apiErrorMessage: err.Detail, err: err} } err = client.BodyJSON(res, tsigList) if err != nil { return nil, err } return tsigList, nil } // GetZones retrieves DNS Zones using tsig key func (tsigKey *TSIGKey) GetZones() (*ZoneNameListResponse, error) { zonesList := &ZoneNameListResponse{} req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/keys/used-by", tsigKey, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &TsigError{keyName: tsigKey.Name} } else { err = client.BodyJSON(res, zonesList) if err != nil { return nil, err } return zonesList, nil } } // GetZoneKeyAliases retrieves a DNS Zone's aliases //func GetZoneKeyAliases(zone string) (*TSIGZoneAliases, error) { // // There is a discrepency between the technical doc and API operation. API currently returns a zone name list. // TODO: Reconcile // func GetZoneKeyAliases(zone string) (*ZoneNameListResponse, error) { zonesList := &ZoneNameListResponse{} //zoneAliases :=&TSIGZoneAliases{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/zones/%s/key/used-by", zone), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { //err = client.BodyJSON(res, zoneAliases) err = client.BodyJSON(res, zonesList) if err != nil { return nil, err } //return zoneAliases, nil return zonesList, nil } } // Bulk Zones tsig key update func (tsigBulk *TSIGKeyBulkPost) BulkUpdate() error { req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/keys/bulk-update", tsigBulk, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) edge.PrintHttpResponse(res, true) // Network error if err != nil { return &TsigError{ keyName: tsigBulk.Key.Name, httpErrorMessage: err.Error(), err: err, } } // API error if client.IsError(res) { err := client.NewAPIError(res) return &TsigError{keyName: tsigBulk.Key.Name, apiErrorMessage: err.Detail, err: err} } return nil } // GetZoneKey retrieves a DNS Zone's key func GetZoneKey(zone string) (*TSIGKeyResponse, error) { zonekey := &TSIGKeyResponse{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/zones/%s/key", zone), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { err = client.BodyJSON(res, zonekey) if err != nil { return nil, err } return zonekey, nil } } // Delete tsig key for zone func DeleteZoneKey(zone string) error { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-dns/v2/zones/%s/key", zone), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone, apiErrorMessage: err.Detail, err: err} } return nil } // Update tsig key for zone func (tsigKey *TSIGKey) Update(zone string) error { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-dns/v2/zones/%s/key", zone), tsigKey, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &TsigError{ keyName: tsigKey.Name, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &TsigError{keyName: tsigKey.Name, apiErrorMessage: err.Detail, err: err} } return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/tsig_test.go000066400000000000000000000127701400161560600274420ustar00rootroot00000000000000package dnsv2 import ( "testing" //edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( dnsTestZone = "dns.test.zone.com" tsigBody = []byte(fmt.Sprintf(`{ "name": "%s", "algorithm": "hmac-md5", "secret": "p/jzrJpXOLf4mPUtx/z+Sw==" }`, dnsTestZone)) tsigKeyResponse = fmt.Sprintf(`{ "name": "%s", "algorithm": "hmac-md5", "secret": "p/jzrJpXOLf4mPUtx/z+Sw==", "zonesCount": 1 }`, dnsTestZone) ) func createTestTsigKey() *TSIGKey { key := &TSIGKey{} jsonhooks.Unmarshal(tsigBody, key) return key } func TestListTsigKeys(t *testing.T) { /* // for live testing config, err := edge.Init("","") if err != nil { t.Fatalf("TestListTsigKeys failed initializing: %s", err.Error()) } */ defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/keys") mock. Get("/config-dns/v2/keys"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprint(`{ "metadata": { "totalElements":2 }, "keys": [{ "name":"mbnewtsig", "algorithm":"HMAC-MD5.SIG-ALG.REG.INT", "secret":"abc78w==", "zonesCount":2 },{ "name":"fred", "algorithm":"hmac-sha256", "secret":"IxSErTXxsCN8JO1jsAqW4We0rwbdu5R2jwFFmXoS//Y=", "zonesCount":1 }] }`)) Init(config) tsigQueryString := &TSIGQueryString{} tsigReport, err := ListTsigKeys(tsigQueryString) assert.NoError(t, err) assert.Equal(t, int64(len(tsigReport.Keys)), tsigReport.Metadata.TotalElements) } func TestUpdateZoneKey(t *testing.T) { defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/key", dnsTestZone)) mock. Put(fmt.Sprintf("/config-dns/v2/zones/%s/key", dnsTestZone)). HeaderPresent("Authorization"). Reply(204). SetHeader("Content-Type", "application/json;charset=UTF-8") Init(config) testKey := createTestTsigKey() err := testKey.Update(dnsTestZone) assert.NoError(t, err) /* // live testing ... zoneResp, err := GetZone("xxxxxxxxxxxxx.com") assert.NoError(t, err) assert.Equal(t, testKey.Name, zoneResp.TsigKey.Name) */ } func TestGetZoneKey(t *testing.T) { defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/key", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/key", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(tsigKeyResponse) Init(config) keyResp, err := GetZoneKey(dnsTestZone) if err == nil { fmt.Sprintf("Key resp: %v", keyResp) } else { fmt.Sprintf(err.Error()) } assert.NoError(t, err) assert.Equal(t, keyResp.Name, createTestTsigKey().Name) } func TestDeleteZoneKey(t *testing.T) { defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/key", dnsTestZone)) mock. Delete(fmt.Sprintf("/config-dns/v2/zones/%s/key", dnsTestZone)). HeaderPresent("Authorization"). Reply(204). SetHeader("Content-Type", "application/json;charset=UTF-8") Init(config) err := DeleteZoneKey(dnsTestZone) assert.NoError(t, err) } func TestGetTsigKeyUsers(t *testing.T) { // // NOTE: Currently a discrepency between docs and API operation!!! // TODO: Reconcile and correct // defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/key/used-by", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/key/used-by", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "zones":["%s"] }`, dnsTestZone)) Init(config) zoneKeyAliases, err := GetZoneKeyAliases(dnsTestZone) assert.NoError(t, err) // CORRECT assert.Equal(t, assert.IsType(t, &ZoneNameListResponse{}, zoneKeyAliases), true) //assert.Equal(t, assert.IsType(t, &TSIGZoneAliases{}, zoneKeyAliases), true) } func TestTsigKeyBulkUpdate(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/keys/bulk-update") mock. Post("/config-dns/v2/keys/bulk-update"). HeaderPresent("Authorization"). Reply(204). SetHeader("Content-Type", "application/json;charset=UTF-8") Init(config) testKey := createTestTsigKey() bulkUpdate := &TSIGKeyBulkPost{Key: testKey, Zones: []string{dnsTestZone}} err := bulkUpdate.BulkUpdate() assert.NoError(t, err) } func TestTsigKeyGetZones(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/keys/used-by") mock. Post("/config-dns/v2/keys/used-by"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "zones":["%s"] }`, dnsTestZone)) Init(config) testKey := createTestTsigKey() zoneList, err := testKey.GetZones() assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &ZoneNameListResponse{}, zoneList), true) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/zone.go000066400000000000000000000444371400161560600264150ustar00rootroot00000000000000package dnsv2 import ( "bytes" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "io/ioutil" "log" "reflect" "strconv" "strings" "sync" ) var ( zoneWriteLock sync.Mutex ) // Zone represents a DNS zone /*{ "zone": "river.com", "type": "secondary", "masters": [ "1.2.3.4", "1.2.3.5" ], "comment": "Adding bodies of water" } { "activationState": "ACTIVE", "contractId": "C-1FRYVV3", "lastActivationDate": "2018-03-20T06:49:30Z", "lastModifiedBy": "vwwuq65mjvsrbvcr", "lastModifiedDate": "2019-01-28T12:05:13Z", "signAndServe": false, "type": "PRIMARY", "versionId": "2e9aa959-5e99-405c-b233-360639449fa1", "zone": "akamaideveloper.net" } */ type ZoneQueryString struct { Contract string Group string } type ZoneCreate struct { Zone string `json:"zone"` Type string `json:"type"` Masters []string `json:"masters,omitempty"` Comment string `json:"comment,omitempty"` SignAndServe bool `json:"signAndServe"` SignAndServeAlgorithm string `json:"signAndServeAlgorithm,omitempty"` TsigKey *TSIGKey `json:"tsigKey,omitempty"` Target string `json:"target,omitempty"` EndCustomerId string `json:"endCustomerId,omitempty"` ContractId string `json:"contractId,omitempty"` } var zoneStructMap map[string]string = map[string]string{ "Zone": "zone", "Type": "type", "Masters": "masters", "Comment": "comment", "SignAndServe": "signAndServe", "SignAndServeAlgorithm": "signAndServeAlgorithm", "TsigKey": "tsigKey", "Target": "target", "EndCustomerId": "endCustomerId", "ContractId": "contractId"} type ZoneResponse struct { Zone string `json:"zone,omitempty"` Type string `json:"type,omitempty"` Masters []string `json:"masters,omitempty"` Comment string `json:"comment,omitempty"` SignAndServe bool `json:"signAndServe"` SignAndServeAlgorithm string `json:"signAndServeAlgorithm,omitempty"` TsigKey *TSIGKey `json:"tsigKey,omitempty"` Target string `json:"target,omitempty"` EndCustomerId string `json:"endCustomerId,omitempty"` ContractId string `json:"contractId,omitempty"` AliasCount int64 `json:"aliasCount,omitempty"` ActivationState string `json:"activationState,omitempty"` LastActivationDate string `json:"lastActivationDate,omitempty"` LastModifiedBy string `json:"lastModifiedBy,omitempty"` LastModifiedDate string `json:"lastModifiedDate,omitempty"` VersionId string `json:"versionId,omitempty"` } // Zone List Query args struct type ZoneListQueryArgs struct { ContractIds string Page int PageSize int Search string ShowAll bool SortBy string Types string } type ListMetadata struct { ContractIds []string `json:"contractIds"` Page int `json:"page"` PageSize int `json:"pageSize"` ShowAll bool `json:"showAll"` TotalElements int `json:"totalElements"` } //`json:"metadata"` type ZoneListResponse struct { Metadata *ListMetadata `json:"metadata,omitempty"` Zones []*ZoneResponse `json:"zones,omitempty"` } type ChangeListResponse struct { Zone string `json:"zone,omitempty"` ChangeTag string `json:"changeTag,omitempty"` ZoneVersionId string `json:"zoneVersionId,omitempty"` LastModifiedDate string `json:"lastModifiedDate,omitempty"` Stale bool `json:"stale,omitempty"` } // Zones List Response type ZoneNameListResponse struct { Zones []string `json:"zones"` } /* { "names": [ "example.com", "bar.example.com" ] } */ // returned list of Zone Names type ZoneNamesResponse struct { Names []string `json:"names"` } /* { "types": [ "A", "MX" ] } */ // Recordset Types for Zone|Name Response type ZoneNameTypesResponse struct { Types []string `json:"types"` } // List Zones func ListZones(queryArgs ...ZoneListQueryArgs) (*ZoneListResponse, error) { zoneListResp := &ZoneListResponse{} // construct GET url getURL := fmt.Sprintf("/config-dns/v2/zones") if len(queryArgs) > 1 { return nil, fmt.Errorf("ListZones QueryArgs invalid.") } req, err := client.NewRequest( Config, "GET", getURL, nil, ) if err != nil { return nil, err } 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() } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return nil, client.NewAPIError(res) } else { err = client.BodyJSON(res, zoneListResp) if err != nil { return nil, err } return zoneListResp, nil } } // NewZone creates a new Zone. Supports subset of fields func NewZone(params ZoneCreate) *ZoneCreate { zone := &ZoneCreate{Zone: params.Zone, Type: params.Type, Masters: params.Masters, TsigKey: params.TsigKey, Target: params.Target, EndCustomerId: params.EndCustomerId, ContractId: params.ContractId, Comment: params.Comment, SignAndServe: params.SignAndServe, SignAndServeAlgorithm: params.SignAndServeAlgorithm} return zone } func NewZoneResponse(zonename string) *ZoneResponse { zone := &ZoneResponse{Zone: zonename} return zone } func NewChangeListResponse(zone string) *ChangeListResponse { changelist := &ChangeListResponse{Zone: zone} return changelist } func NewZoneQueryString(Contract string, group string) *ZoneQueryString { zonequerystring := &ZoneQueryString{Contract: Contract, Group: group} return zonequerystring } // GetZone retrieves a DNS Zone for a given hostname func GetZone(zonename string) (*ZoneResponse, error) { zone := NewZoneResponse(zonename) req, err := client.NewRequest( Config, "GET", //"/config-dns/v2/zones/"+zone.Zone, "/config-dns/v2/zones/"+zonename, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zonename} } else { err = client.BodyJSON(res, zone) if err != nil { return nil, err } return zone, nil } } // GetZone retrieves a DNS Zone for a given hostname func GetChangeList(zone string) (*ChangeListResponse, error) { changelist := NewChangeListResponse(zone) req, err := client.NewRequest( Config, "GET", "/config-dns/v2/changelists/"+zone, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { err = client.BodyJSON(res, changelist) if err != nil { return nil, err } return changelist, nil } } // GetZone retrieves a DNS Zone for a given hostname func GetMasterZoneFile(zone string) (string, error) { req, err := client.NewRequest( Config, "GET", "/config-dns/v2/zones/"+zone+"/zone-file", nil, ) if err != nil { return "", err } req.Header.Add("Accept", "text/dns") edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { log.Printf("[DEBUG] [Akamai LIB] ZM %v %v", res, err) return "", err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return "", client.NewAPIError(res) } else if res.StatusCode == 404 { return "", &ZoneError{zoneName: zone} } else { bodyBytes, err2 := ioutil.ReadAll(res.Body) if err2 != nil { return "", err } masterZone := string(bodyBytes) return masterZone, nil } } // Update Master Zone file func PostMasterZoneFile(zone string, filedata string) error { buf := bytes.NewReader([]byte(filedata)) req, err := client.NewRequest( Config, "POST", fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", zone), buf, ) if err != nil { return err } req.Header.Set("Content-Type", "text/dns") edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone, apiErrorMessage: err.Detail, err: err} } return nil } // Create a Zone func (zone *ZoneCreate) Save(zonequerystring ZoneQueryString, clearConn ...bool) 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 zoneWriteLock.Lock() defer zoneWriteLock.Unlock() zoneMap := filterZoneCreate(zone) zoneurl := "/config-dns/v2/zones/?contractId=" + zonequerystring.Contract if len(zonequerystring.Group) > 0 { zoneurl += "&gid=" + zonequerystring.Group } req, err := client.NewJSONRequest( Config, "POST", zoneurl, zoneMap, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone, apiErrorMessage: err.Detail, err: err} } if strings.ToUpper(zone.Type) == "PRIMARY" { // Timing issue with Create immediately followed by SaveChangelist for _, clear := range clearConn { // should only be one entry if clear { edge.LogMultiline(edge.EdgegridLog.Traceln, "Clearing Idle Connections") client.Client.CloseIdleConnections() } } } return nil } // Create changelist for the Zone. Side effect is to create default NS SOA records func (zone *ZoneCreate) SaveChangelist() 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 req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/changelists/?zone="+zone.Zone, "", ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone, apiErrorMessage: err.Detail, err: err} } return nil } // Save changelist for the Zone to create default NS SOA records func (zone *ZoneCreate) SubmitChangelist() 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 req, err := client.NewJSONRequest( Config, "POST", "/config-dns/v2/changelists/"+zone.Zone+"/submit", "", ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone, apiErrorMessage: err.Detail, err: err} } return nil } // Save updates the Zone func (zone *ZoneCreate) Update(zonequerystring ZoneQueryString) 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 zoneMap := filterZoneCreate(zone) req, err := client.NewJSONRequest( Config, "PUT", "/config-dns/v2/zones/"+zone.Zone, zoneMap, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone, apiErrorMessage: err.Detail, err: err} } return nil } func (zone *ZoneCreate) Delete(zonequerystring ZoneQueryString) error { // remove all the records except for SOA // which is required and save the zone req, err := client.NewJSONRequest( Config, "DELETE", "/config-dns/v2/zones/"+zone.Zone, nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return &ZoneError{ zoneName: zone.Zone, httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { if res.StatusCode != 404 { err := client.NewAPIError(res) return &ZoneError{zoneName: zone.Zone, apiErrorMessage: err.Detail, err: err} } } return nil } func filterZoneCreate(zone *ZoneCreate) map[string]interface{} { zoneType := strings.ToUpper(zone.Type) filteredZone := make(map[string]interface{}) zoneElems := reflect.ValueOf(zone).Elem() for i := 0; i < zoneElems.NumField(); i++ { varName := zoneElems.Type().Field(i).Name varLower := zoneStructMap[varName] varValue := zoneElems.Field(i).Interface() switch varName { case "Target": if zoneType == "ALIAS" { filteredZone[varLower] = varValue } case "TsigKey": if zoneType == "SECONDARY" { filteredZone[varLower] = varValue } case "Masters": if zoneType == "SECONDARY" { filteredZone[varLower] = varValue } case "SignAndServe": if zoneType != "ALIAS" { filteredZone[varLower] = varValue } case "SignAndServeAlgorithm": if zoneType != "ALIAS" { filteredZone[varLower] = varValue } default: filteredZone[varLower] = varValue } } return filteredZone } // Validate ZoneCreate Object func ValidateZone(zone *ZoneCreate) error { if len(zone.Zone) == 0 { return fmt.Errorf("Zone name is required") } ztype := strings.ToUpper(zone.Type) if ztype != "PRIMARY" && ztype != "SECONDARY" && ztype != "ALIAS" { return fmt.Errorf("Invalid zone type") } if ztype != "SECONDARY" && zone.TsigKey != nil { return fmt.Errorf("TsigKey is invalid for %s zone type", ztype) } if ztype == "ALIAS" { if len(zone.Target) == 0 { return fmt.Errorf("Target is required for Alias zone type") } if zone.Masters != nil && len(zone.Masters) > 0 { return fmt.Errorf("Masters is invalid for Alias zone type") } if zone.SignAndServe { return fmt.Errorf("SignAndServe is invalid for Alias zone type") } if len(zone.SignAndServeAlgorithm) > 0 { return fmt.Errorf("SignAndServeAlgorithm is invalid for Alias zone type") } return nil } // Primary or Secondary if len(zone.Target) > 0 { return fmt.Errorf("Target is invalid for %s zone type", ztype) } if zone.Masters != nil && len(zone.Masters) > 0 && ztype == "PRIMARY" { return fmt.Errorf("Masters is invalid for Primary zone type") } return nil } // Get Zone's Names func GetZoneNames(zone string) (*ZoneNamesResponse, error) { zoneNameResponse := &ZoneNamesResponse{Names: make([]string, 0)} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/zones/%s/names", zone), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { err = client.BodyJSON(res, zoneNameResponse) if err != nil { return nil, err } return zoneNameResponse, nil } } // Get Zone Name's record types func GetZoneNameTypes(zname string, zone string) (*ZoneNameTypesResponse, error) { zoneNameTypesResponse := &ZoneNameTypesResponse{Types: make([]string, 0)} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types", zone, zname), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, &ZoneError{zoneName: zone} } else { err = client.BodyJSON(res, zoneNameTypesResponse) if err != nil { return nil, err } return zoneNameTypesResponse, nil } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/zone_test.go000066400000000000000000000044771400161560600274540ustar00rootroot00000000000000package dnsv2 import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "testing" ) func TestZone_JSON(t *testing.T) { responseBody := []byte(`{ "zone": "example.com", "type": "PRIMARY", "comment": "This is a test zone", "signAndServe": false }`) zonecreate := ZoneCreate{Zone: "example.com", Type: "PRIMARY", Masters: []string{""}, Comment: "This is a test zone", SignAndServe: false} zone := NewZone(zonecreate) err := jsonhooks.Unmarshal(responseBody, zone) assert.NoError(t, err) assert.Equal(t, zone.Zone, "example.com") assert.Equal(t, zone.Type, "PRIMARY") assert.Equal(t, zone.Comment, "This is a test zone") assert.Equal(t, zone.SignAndServe, false) } func TestGetZoneNames(t *testing.T) { dnsTestZone := "testzone.com" defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/names", dnsTestZone)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/names", dnsTestZone)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "names":["test1.testzone.com","test2.testzone.com"] }`)) Init(config) nameList, err := GetZoneNames(dnsTestZone) assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &ZoneNamesResponse{}, nameList), true) assert.Equal(t, len(nameList.Names), 2) } func TestGetZoneNameTypes(t *testing.T) { dnsTestZone := "testzone.com" dnsTestRecordName := "test.testzone.com" defer gock.Off() mock := gock.New(fmt.Sprintf("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-dns/v2/zones/%s/names/%s/types", dnsTestZone, dnsTestRecordName)) mock. Get(fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types", dnsTestZone, dnsTestRecordName)). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json;charset=UTF-8"). BodyString(fmt.Sprintf(`{ "types":["CNAME", "AKAMAICDN"] }`)) Init(config) typeList, err := GetZoneNameTypes(dnsTestRecordName, dnsTestZone) assert.NoError(t, err) assert.Equal(t, assert.IsType(t, &ZoneNameTypesResponse{}, typeList), true) assert.Equal(t, len(typeList.Types), 2) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configdns-v2/zonebulk.go000066400000000000000000000170721400161560600272660ustar00rootroot00000000000000package dnsv2 import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) /* type ZoneQueryString struct { Contract string Group string } type ZoneCreate struct { Zone string `json:"zone"` Type string `json:"type"` Masters []string `json:"masters,omitempty"` Comment string `json:"comment,omitempty"` SignAndServe bool `json:"signAndServe"` SignAndServeAlgorithm string `json:"signAndServeAlgorithm,omitempty"` TsigKey *TSIGKey `json:"tsigKey,omitempty"` Target string `json:"target,omitempty"` EndCustomerId string `json:"endCustomerId,omitempty"` ContractId string `json:"contractId,omitempty"` } */ type BulkZonesCreate struct { Zones []*ZoneCreate `json:"zones"` } type BulkZonesResponse struct { RequestId string `json:"requestId"` ExpirationDate string `json:"expirationDate"` } 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"` } type BulkFailedZone struct { Zone string `json:"zone"` FailureReason string `json:"failureReason"` } type BulkCreateResultResponse struct { RequestId string `json:"requestId"` SuccessfullyCreatedZones []string `json:"successfullyCreatedZones"` FailedZones []*BulkFailedZone `JSON:"failedZones"` } type BulkDeleteResultResponse struct { RequestId string `json:"requestId"` SuccessfullyDeletedZones []string `json:"successfullyDeletedZones"` FailedZones []*BulkFailedZone `JSON:"failedZones"` } // Get Bulk Zone Create Status func GetBulkZoneCreateStatus(requestid string) (*BulkStatusResponse, error) { bulkzonesurl := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s", requestid) req, err := client.NewRequest( Config, "GET", bulkzonesurl, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone create status", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone create status", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkStatusResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } // Get Bulk Zone Delete Status func GetBulkZoneDeleteStatus(requestid string) (*BulkStatusResponse, error) { bulkzonesurl := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s", requestid) req, err := client.NewRequest( Config, "GET", bulkzonesurl, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone delete status", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone delete status", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkStatusResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } // Get Bulk Zone Create Result func GetBulkZoneCreateResult(requestid string) (*BulkCreateResultResponse, error) { bulkzonesurl := fmt.Sprintf("/config-dns/v2/zones/create-requests/%s/result", requestid) req, err := client.NewRequest( Config, "GET", bulkzonesurl, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone create result", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone create result", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkCreateResultResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } // Get Bulk Zone Delete Result func GetBulkZoneDeleteResult(requestid string) (*BulkDeleteResultResponse, error) { bulkzonesurl := fmt.Sprintf("/config-dns/v2/zones/delete-requests/%s/result", requestid) req, err := client.NewRequest( Config, "GET", bulkzonesurl, nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone delete result", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone delete result", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkDeleteResultResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } // Bulk Create Zones func CreateBulkZones(bulkzones *BulkZonesCreate, zonequerystring ZoneQueryString) (*BulkZonesResponse, error) { bulkzonesurl := "/config-dns/v2/zones/create-requests?contractId=" + zonequerystring.Contract if len(zonequerystring.Group) > 0 { bulkzonesurl += "&gid=" + zonequerystring.Group } req, err := client.NewJSONRequest( Config, "POST", bulkzonesurl, bulkzones, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone create", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone create", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkZonesResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } // Bulk Delete Zones func DeleteBulkZones(zoneslist *ZoneNameListResponse, bypassSafetyChecks ...bool) (*BulkZonesResponse, error) { bulkzonesurl := "/config-dns/v2/zones/delete-requests" if len(bypassSafetyChecks) > 0 { bulkzonesurl += fmt.Sprintf("?bypassSafetyChecks=%t", bypassSafetyChecks[0]) } req, err := client.NewJSONRequest( Config, "POST", bulkzonesurl, zoneslist, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, &ZoneError{ zoneName: "bulk zone delete", httpErrorMessage: err.Error(), err: err, } } edge.PrintHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, &ZoneError{zoneName: "bulk zone delete", apiErrorMessage: err.Detail, err: err} } bulkresponse := &BulkZonesResponse{} err = client.BodyJSON(res, bulkresponse) if err != nil { return nil, err } return bulkresponse, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/000077500000000000000000000000001400161560600253235ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/README.md000066400000000000000000000002611400161560600266010ustar00rootroot00000000000000# Akamai Config GTM (Global Traffic Management) A golang package that talks to the [Akamai OPEN Config GTM API](https://developer.akamai.com/api/luna/config-gtm/overview.html). golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/asmap.go000066400000000000000000000103701400161560600267540ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm asmaps // Based on 1.3 schema // // AsAssignment represents a GTM asmap assignment structure type AsAssignment struct { DatacenterBase AsNumbers []int64 `json:"asNumbers,omitempty"` } // AsMap represents a GTM AsMap type AsMap struct { DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` Assignments []*AsAssignment `json:"assignments,omitempty"` Name string `json:"name"` Links []*Link `json:"links,omitempty"` } // NewAsMap creates a new asMap func NewAsMap(name string) *AsMap { asmap := &AsMap{Name: name} return asmap } // GetAsMap retrieves a asMap with the given name. func GetAsMap(name, domainName string) (*AsMap, error) { as := NewAsMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "asMap", name: name} } else { err = client.BodyJSON(res, as) if err != nil { return nil, err } return as, nil } } // Instantiate new Assignment struct func (as *AsMap) NewAssignment(dcID int, nickname string) *AsAssignment { asAssign := &AsAssignment{} asAssign.DatacenterId = dcID asAssign.Nickname = nickname return asAssign } // Instantiate new Default Datacenter Struct func (as *AsMap) NewDefaultDatacenter(dcID int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcID} } // Create asMap in provided domain func (as *AsMap) Create(domainName string) (*AsMapResponse, error) { // Use common code. Any specific validation needed? return as.save(domainName) } // Update AsMap in given domain func (as *AsMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := as.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save AsMap in given domain. Common path for Create and Update. func (as *AsMap) save(domainName string) (*AsMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, as.Name), as, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "asMap", name: as.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "asMap", name: as.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &AsMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete AsMap method func (as *AsMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, as.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "asMap", name: as.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "asMap", name: as.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/asmap_test.go000066400000000000000000000236011400161560600300140ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) var GtmTestAsMap = "testAsMap" var gtmTestDomain = "gtmdomtest.akadns.net" func instantiateAsMap() *AsMap { asMap := NewAsMap(GtmTestAsMap) asMapData := []byte(`{ "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "name": "testAsMap" }`) jsonhooks.Unmarshal(asMapData, asMap) return asMap } // Verify GetAsMap. Name hardcoded. Should pass, e.g. no API errors and resource returned // Depends on CreateAsMap func TestGetAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }`) Init(config) testAsMap, err := GetAsMap(GtmTestAsMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &AsMap{}, testAsMap) assert.Equal(t, GtmTestAsMap, testAsMap.Name) } // Verify failed case for GetAsMap. Should pass, e.g. no API errors and domain not found func TestGetBadAsMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetAsMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create AsMap. func TestCreateAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testAsMap := instantiateAsMap() statresp, err := testAsMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &AsMap{}, statresp.Resource) assert.Equal(t, GtmTestAsMap, statresp.Resource.Name) } func TestUpdateAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testAsMap := instantiateAsMap() _, err := testAsMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getAsMap := instantiateAsMap() stat, err := getAsMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/cidrmap.go000066400000000000000000000123621400161560600272750ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm cidrmaps // Based on 1.3 schema // //CidrAssignment represents a GTM cidr assignment element type CidrAssignment struct { DatacenterBase Blocks []string `json:"blocks,omitempty"` } // 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"` } // CidrMapList represents a GTM returned cidrmap list body type CidrMapList struct { CidrMapItems []*CidrMap `json:"items"` } // NewCidrMap creates a new CidrMap object func NewCidrMap(name string) *CidrMap { cidrmap := &CidrMap{Name: name} return cidrmap } // ListCidrMap retreieves all CidrMaps func ListCidrMaps(domainName string) ([]*CidrMap, error) { cidrs := &CidrMapList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "cidrMap"} } err = client.BodyJSON(res, cidrs) if err != nil { return nil, err } return cidrs.CidrMapItems, nil } // GetCidrMap retrieves a CidrMap with the given name. func GetCidrMap(name, domainName string) (*CidrMap, error) { cidr := NewCidrMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "cidrMap", name: name} } else { err = client.BodyJSON(res, cidr) if err != nil { return nil, err } return cidr, nil } } // Instantiate new Assignment struct func (cidr *CidrMap) NewAssignment(dcid int, nickname string) *CidrAssignment { cidrAssign := &CidrAssignment{} cidrAssign.DatacenterId = dcid cidrAssign.Nickname = nickname return cidrAssign } // Instantiate new Default Datacenter Struct func (cidr *CidrMap) NewDefaultDatacenter(dcid int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcid} } // Create CidrMap in provided domain func (cidr *CidrMap) Create(domainName string) (*CidrMapResponse, error) { // Use common code. Any specific validation needed? return cidr.save(domainName) } // Update CidrMap in given domain func (cidr *CidrMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := cidr.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save CidrMap in given domain. Common path for Create and Update. func (cidr *CidrMap) save(domainName string) (*CidrMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, cidr.Name), cidr, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "cidrMap", name: cidr.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "cidrMap", name: cidr.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &CidrMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete CidrMap method func (cidr *CidrMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, cidr.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) // Network error if err != nil { return nil, CommonError{ entityName: "cidrMap", name: cidr.Name, httpErrorMessage: err.Error(), err: err, } } // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "cidrMap", name: cidr.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/cidrmap_test.go000066400000000000000000000276641400161560600303470ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestCidrMap = "testCidrMap" func instantiateCidrMap() *CidrMap { cidrMap := NewCidrMap(GtmTestCidrMap) cidrMapData := []byte(`{ "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }`) jsonhooks.Unmarshal(cidrMapData, cidrMap) return cidrMap } // Verify ListCidrMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestListCidrMaps(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items" : [ { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" } ] }`) Init(config) testCidrMap, err := ListCidrMaps(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, testCidrMap[0]) assert.Equal(t, GtmTestCidrMap, testCidrMap[0].Name) } // Verify GetCidrMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestGetCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }`) Init(config) testCidrMap, err := GetCidrMap(GtmTestCidrMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, testCidrMap) assert.Equal(t, GtmTestCidrMap, testCidrMap.Name) } // Verify failed case for GetCidrMap. Should pass, e.g. no API errors and domain not found func TestGetBadCidrMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetCidrMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create CidrMap. func TestCreateCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testCidrMap := instantiateCidrMap() statresp, err := testCidrMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, statresp.Resource) assert.Equal(t, GtmTestCidrMap, statresp.Resource.Name) } func TestUpdateCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testCidrMap := instantiateCidrMap() _, err := testCidrMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getCidrMap := instantiateCidrMap() stat, err := getCidrMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/common.go000066400000000000000000000061461400161560600271510ustar00rootroot00000000000000package configgtm import ( "fmt" "net/http" ) // // Common data types and methods // Based on 1.3 schemas // // Append url args to req func appendReqArgs(req *http.Request, queryArgs map[string]string) { // Look for optional args if len(queryArgs) > 0 { q := req.URL.Query() for argName, argVal := range queryArgs { q.Add(argName, argVal) } req.URL.RawQuery = q.Encode() } } // default schema version // TODO: retrieve from environment or elsewhere in Service Init var schemaVersion string = "1.3" // internal method to set version. passed in as string func setVersionHeader(req *http.Request, version string) { req.Header.Set("Accept", fmt.Sprintf("application/vnd.config-gtm.v%s+json", version)) if req.Method != "GET" { req.Header.Set("Content-Type", fmt.Sprintf("application/vnd.config-gtm.v%s+json", version)) } return } // response Status 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"` } // NewResponseStatus returns a new ResponseStatus struct func NewResponseStatus() *ResponseStatus { return &ResponseStatus{} } // Generic response structs type ResponseBody struct { Resource interface{} `json:"resource"` Status *ResponseStatus `json:"status"` } // Response structs by Entity Type type DomainResponse struct { Resource *Domain `json:"resource"` Status *ResponseStatus `json:"status"` } type DatacenterResponse struct { Status *ResponseStatus `json:"status"` Resource *Datacenter `json:"resource"` } type PropertyResponse struct { Resource *Property `json:"resource"` Status *ResponseStatus `json:"status"` } type ResourceResponse struct { Resource *Resource `json:"resource"` Status *ResponseStatus `json:"status"` } type CidrMapResponse struct { Resource *CidrMap `json:"resource"` Status *ResponseStatus `json:"status"` } type GeoMapResponse struct { Resource *GeoMap `json:"resource"` Status *ResponseStatus `json:"status"` } type AsMapResponse struct { Resource *AsMap `json:"resource"` Status *ResponseStatus `json:"status"` } // Probably THE most common type type Link struct { Rel string `json:"rel"` Href string `json:"href"` } // type LoadObject struct { LoadObject string `json:"loadObject,omitempty"` LoadObjectPort int `json:"loadObjectPort,omitempty"` LoadServers []string `json:"loadServers,omitempty"` } // NewLoadObject returns a new LoadObject structure func NewLoadObject() *LoadObject { return &LoadObject{} } type DatacenterBase struct { Nickname string `json:"nickname"` DatacenterId int `json:"datacenterId"` } // NewDatacenterBase returns a new DatacenterBase structure func NewDatacenterBase() *DatacenterBase { return &DatacenterBase{} } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/datacenter.go000066400000000000000000000155471400161560600300000ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" "strconv" ) // // Handle Operations on gtm datacenters // Based on 1.3 schema // // Datacenter represents a GTM datacenter type Datacenter struct { City string `json:"city,omitempty"` CloneOf int `json:"cloneOf,omitempty"` 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"` } type DatacenterList struct { DatacenterItems []*Datacenter `json:"items"` } // NewDatacenterResponse instantiates a new DatacenterResponse structure func NewDatacenterResponse() *DatacenterResponse { dcResp := &DatacenterResponse{} return dcResp } // NewDatacenter creates a new Datacenter object func NewDatacenter() *Datacenter { dc := &Datacenter{} return dc } // ListDatacenters retreieves all Datacenters func ListDatacenters(domainName string) ([]*Datacenter, error) { dcs := &DatacenterList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Datacenter"} } else { err = client.BodyJSON(res, dcs) if err != nil { return nil, err } return dcs.DatacenterItems, nil } } // GetDatacenter retrieves a Datacenter with the given name. NOTE: Id arg is int! func GetDatacenter(dcID int, domainName string) (*Datacenter, error) { dc := NewDatacenter() req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dcID)), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpRequest(req, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dcID)} } else { err = client.BodyJSON(res, dc) if err != nil { return nil, err } return dc, nil } } // Create the datacenter identified by the receiver argument in the specified domain. func (dc *Datacenter) Create(domainName string) (*DatacenterResponse, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName), dc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network if err != nil { return nil, CommonError{ entityName: "Domain", name: domainName, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domainName, apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body for updated DC and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Update the datacenter identified in the receiver argument in the provided domain. func (dc *Datacenter) Update(domainName string) (*ResponseStatus, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterId)), dc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } // Delete the datacenter identified by the receiver argument from the domain specified. func (dc *Datacenter) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterId)), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) // Network error if err != nil { return nil, CommonError{ entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), httpErrorMessage: err.Error(), err: err, } } // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/datacenter_test.go000066400000000000000000000326571400161560600310400ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "fmt" ) var GtmTestDC1 = "testDC1" var GtmTestDC2 = "testDC2" var dcMap = map[string]string{"GtmTestDC1": GtmTestDC1, "GtmTestDC2": GtmTestDC2} func instantiateDatacenter() *Datacenter { dc := NewDatacenter() dcData := []byte(`{ "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false }`) jsonhooks.Unmarshal(dcData, dc) return dc } // Verify ListDatacenters. Should pass, e.g. no API errors and non nil list. func TestListDatacenters(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ] }`) Init(config) dcList, err := ListDatacenters(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, dcList, nil) if len(dcList) > 0 { firstDC := dcList[0] assert.Equal(t, firstDC.Nickname, GtmTestDC1) } else { assert.Equal(t, 0, 1, "ListDatacenters: empty list") fmt.Println("ListDatacenters: empty list") } } // Verify GetDatacenter. Name hardcoded. Should pass, e.g. no API errors and property returned // Depends on CreateDatacenter func TestGetDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }`) Init(config) testDC, err := GetDatacenter(3131, gtmTestDomain) assert.NoError(t, err) assert.Equal(t, 3131, testDC.DatacenterId) } // Verify failed case for GetDatacenter. Should pass, e.g. no API errors and domain not found func TestGetBadDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/9999") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/9999"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetDatacenter(9999, gtmTestDomain) assert.Error(t, err) } // Test Create datacenter. func TestCreateDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters") mock. Post("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters"). HeaderPresent("Authorization"). Reply(201). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) testDC := NewDatacenter() testDC.Nickname = GtmTestDC1 statresp, err := testDC.Create(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, GtmTestDC1, statresp.Resource.Nickname) } func TestUpdateDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDC := instantiateDatacenter() stat, err := testDC.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "4c7e6466-84e1-4895-bdf5-e3608d708d69") } func TestDeleteDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDC := instantiateDatacenter() _, err := testDC.Delete(gtmTestDomain) assert.NoError(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/domain.go000066400000000000000000000223431400161560600271250ustar00rootroot00000000000000package configgtm import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "net/http" "strings" ) // // Support gtm domains thru Edgegrid // Based on 1.3 Schema // // 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"` PingInterval int `json:"pingInterval"` 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 int `json:"defaultHealthMultiplier"` 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,omitempty"` 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"` } type DomainsList struct { DomainItems []*DomainItem `json:"items"` } // 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"` } // NewDomain is a utility function that creates a new Domain object. func NewDomain(domainName, domainType string) *Domain { domain := &Domain{} domain.Name = domainName domain.Type = domainType return domain } // GetStatus retrieves current status for the given domainname. func GetDomainStatus(domainName string) (*ResponseStatus, error) { stat := &ResponseStatus{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/status/current", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } return stat, nil } } // ListDomains retrieves all Domains. func ListDomains() ([]*DomainItem, error) { domains := &DomainsList{} req, err := client.NewRequest( Config, "GET", "/config-gtm/v1/domains/", nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain"} } else { err = client.BodyJSON(res, domains) if err != nil { return nil, err } return domains.DomainItems, nil } } // GetDomain retrieves a Domain with the given domainname. func GetDomain(domainName string) (*Domain, error) { domain := NewDomain(domainName, "basic") req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, domain) if err != nil { return nil, err } return domain, nil } } // Save method; Create or Update func (domain *Domain) save(queryArgs map[string]string, req *http.Request) (*DomainResponse, error) { // set schema version setVersionHeader(req, schemaVersion) // Look for optional args if len(queryArgs) > 0 { q := req.URL.Query() if val, ok := queryArgs["contractId"]; ok { q.Add("contractId", strings.TrimPrefix(val, "ctr_")) } if val, ok := queryArgs["gid"]; ok { q.Add("gid", strings.TrimPrefix(val, "grp_")) } req.URL.RawQuery = q.Encode() } printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Domain", name: domain.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domain.Name, apiErrorMessage: err.Detail, err: err} } // TODO: What validation can we do? E.g. if not equivalent there was a concurrent change... responseBody := &DomainResponse{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Create is a method applied to a domain object resulting in creation. func (domain *Domain) Create(queryArgs map[string]string) (*DomainResponse, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf("/config-gtm/v1/domains/"), domain, ) if err != nil { return nil, err } return domain.save(queryArgs, req) } // Update is a method applied to a domain object resulting in an update. func (domain *Domain) Update(queryArgs map[string]string) (*ResponseStatus, error) { // Any validation to do? req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name), domain, ) if err != nil { return nil, err } stat, err := domain.save(queryArgs, req) if err != nil { return nil, err } return stat.Status, err } // Delete is a method applied to a domain object resulting in removal. func (domain *Domain) Delete() (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Domain", name: domain.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domain.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/domain_test.go000066400000000000000000001321341400161560600301640ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/h2non/gock.v1" ) func instantiateDomain() *Domain { domain := NewDomain(gtmTestDomain, "basic") domainData := []byte(`{ "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-14T19:36:13.174+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 600, "maxProperties" : 100, "maxResources" : 9999, "maxTestTimeout" : 60.0, "maxTTL" : 3600, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : "Add Property testproperty", "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:36:13.174+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ], "datacenters" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }`) jsonhooks.Unmarshal(domainData, domain) return domain } // Verify GetListDomains. Sould pass, e.g. no API errors and non nil list. func TestListDomains(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains") mock. Get("/config-gtm/v1/domains"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items" : [ { "name" : "gtmdomtest.akadns.net", "status" : "Change Pending", "acgId" : "1-3CV382", "lastModified" : "2019-06-06T19:07:20.000+00:00", "lastModifiedBy" : "operator", "changeId" : "c3e1b771-2500-40c9-a7da-6c3cdbce1936", "activationState" : "PENDING", "modificationComments" : "mock test", "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" } ] } ] }`) Init(config) domainsList, err := ListDomains() assert.NoError(t, err) assert.NotEqual(t, domainsList, nil) assert.Equal(t, "gtmdomtest.akadns.net", domainsList[0].Name) } // Verify GetDomain. Name hardcoded. Should pass, e.g. no API errors and domain returned func TestGetDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "cidrMaps": [], "datacenters": [ { "city": "Snæfellsjökull", "cloneOf": null, "cloudServerTargeting": false, "continent": "EU", "country": "IS", "datacenterId": 3132, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 64.808, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3132", "rel": "self" } ], "longitude": -23.776, "nickname": "property_test_dc2", "stateOrProvince": null, "virtual": true }, { "city": "Philadelphia", "cloneOf": null, "cloudServerTargeting": true, "continent": "NA", "country": "US", "datacenterId": 3133, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 39.95, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3133", "rel": "self" } ], "longitude": -75.167, "nickname": "property_test_dc3", "stateOrProvince": null, "virtual": true }, { "city": "Downpat", "cloneOf": null, "cloudServerTargeting": false, "continent": "EU", "country": "GB", "datacenterId": 3131, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 54.367, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131", "rel": "self" } ], "longitude": -5.582, "nickname": "property_test_dc1", "stateOrProvince": "ha", "virtual": true } ], "defaultErrorPenalty": 75, "defaultSslClientCertificate": null, "defaultSslClientPrivateKey": null, "defaultTimeoutPenalty": 25, "emailNotificationList": [], "geographicMaps": [], "lastModified": "2019-04-25T14:53:12.000+00:00", "lastModifiedBy": "operator", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net", "rel": "self" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters", "rel": "datacenters" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties", "rel": "properties" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps", "rel": "geographic-maps" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps", "rel": "cidr-maps" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources", "rel": "resources" } ], "loadFeedback": false, "loadImbalancePercentage": 10.0, "modificationComments": "Edit Property test_property", "name": "gtmdomtest.akadns.net", "properties": [ { "backupCName": null, "backupIp": null, "balanceByDownloadScore": false, "cname": "www.boo.wow", "comments": null, "dynamicTTL": 300, "failbackDelay": 0, "failoverDelay": 0, "handoutMode": "normal", "healthMax": null, "healthMultiplier": null, "healthThreshold": null, "ipv6": false, "lastModified": "2019-04-25T14:53:12.000+00:00", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/test_property", "rel": "self" } ], "livenessTests": [ { "disableNonstandardPortWarning": false, "hostHeader": null, "httpError3xx": true, "httpError4xx": true, "httpError5xx": true, "name": "health check", "requestString": null, "responseString": null, "sslClientCertificate": null, "sslClientPrivateKey": null, "testInterval": 60, "testObject": "/status", "testObjectPassword": null, "testObjectPort": 80, "testObjectProtocol": "HTTP", "testObjectUsername": null, "testTimeout": 25.0 } ], "loadImbalancePercentage": 10.0, "mapName": null, "maxUnreachablePenalty": null, "mxRecords": [], "name": "test_property", "scoreAggregationType": "mean", "staticTTL": 600, "stickinessBonusConstant": null, "stickinessBonusPercentage": 50, "trafficTargets": [ { "datacenterId": 3131, "enabled": true, "handoutCName": null, "name": null, "servers": [ "1.2.3.4", "1.2.3.5" ], "weight": 50.0 }, { "datacenterId": 3132, "enabled": true, "handoutCName": "www.google.com", "name": null, "servers": [], "weight": 25.0 }, { "datacenterId": 3133, "enabled": true, "handoutCName": "www.comcast.com", "name": null, "servers": [ "www.comcast.com" ], "weight": 25.0 } ], "type": "weighted-round-robin", "unreachableThreshold": null, "useComputedTargets": false } ], "resources": [], "status": { "changeId": "40e36abd-bfb2-4635-9fca-62175cf17007", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current", "rel": "self" } ], "message": "Current configuration has been propagated to all GTM nameservers", "passingValidation": true, "propagationStatus": "COMPLETE", "propagationStatusDate": "2019-04-25T14:54:00.000+00:00" }, "type": "weighted" }`) Init(config) testDomain, err := GetDomain(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, gtmTestDomain, testDomain.Name) } // Verify failed case for GetDomain. Should pass, e.g. no API errors and domain not found func TestGetBadDomain(t *testing.T) { baddomainname := "baddomainname.me" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + baddomainname) mock. Get("/config-gtm/v1/domains/"+baddomainname). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetDomain(baddomainname) assert.Error(t, err) } // Test Create domain. Name is hardcoded so this will effectively be an update. What happens to existing? func TestCreateDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/") mock. Post("/config-gtm/v1/domains/"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-24T18:48:57.787+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 0, "maxProperties" : 0, "maxResources" : 512, "maxTestTimeout" : 0.0, "maxTTL" : 0, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : null, "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "539872cc-6ba6-4429-acd5-90bab7fb5e9d", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-24T18:48:57.787+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ ], "datacenters" : [ ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }, "status" : { "message" : "Change Pending", "changeId" : "539872cc-6ba6-4429-acd5-90bab7fb5e9d", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-24T18:48:57.787+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDomain := NewDomain(gtmTestDomain, "basic") qArgs := make(map[string]string) statResponse, err := testDomain.Create(qArgs) require.NoError(t, err) assert.Equal(t, gtmTestDomain, statResponse.Resource.Name) } func TestUpdateDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-14T19:36:13.174+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 600, "maxProperties" : 100, "maxResources" : 9999, "maxTestTimeout" : 60.0, "maxTTL" : 3600, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : "Add Property testproperty", "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:36:13.174+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ], "datacenters" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }, "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDomain := instantiateDomain() //testDomain.MaxResources = 9999 qArgs := make(map[string]string) statResp, err := testDomain.Update(qArgs) require.NoError(t, err) assert.Equal(t, statResp.ChangeId, "df6c04e4-6327-4e0f-8872-bfe9fb2693d2") } /* Future. Presently no domain Delete endpoint. func TestDeleteDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/"+gtmTestDomain) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : null, "status" : { "changeId": "40e36abd-bfb2-4635-9fca-62175cf17007", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2019-04-25T14:54:00.000+00:00" }, }`) Init(config) getDomain := instantiateDomain() _, err := getDomain.Delete() assert.NoError(t, err) } */ golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/errors.go000066400000000000000000000037631400161560600271770ustar00rootroot00000000000000package configgtm import ( "fmt" ) type ConfigGTMError interface { error Network() bool NotFound() bool FailedToSave() bool ValidationFailed() bool } func IsConfigGTMError(e error) bool { _, ok := e.(ConfigGTMError) return ok } type CommonError struct { entityName string name string httpErrorMessage string apiErrorMessage string err error } func (e CommonError) SetItem(itemName string, itemVal interface{}) { switch itemName { case "entityName": e.entityName = itemVal.(string) case "name": e.name = itemVal.(string) case "httpErrorMessage": e.httpErrorMessage = itemVal.(string) case "apiErrorMessage": e.apiErrorMessage = itemVal.(string) case "err": e.err = itemVal.(error) } } func (e CommonError) GetItem(itemName string) interface{} { switch itemName { case "entityName": return e.entityName case "name": return e.name case "httpErrorMessage": return e.httpErrorMessage case "apiErrorMessage": return e.apiErrorMessage case "err": return e.err } return nil } func (e CommonError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e CommonError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } return false } func (CommonError) FailedToSave() bool { return false } func (e CommonError) ValidationFailed() bool { if e.apiErrorMessage != "" { return true } return false } func (e CommonError) Error() string { if e.Network() { return fmt.Sprintf("%s \"%s\" network error: [%s]", e.entityName, e.name, e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("%s \"%s\" not found.", e.entityName, e.name) } if e.FailedToSave() { return fmt.Sprintf("%s \"%s\" failed to save: [%s]", e.entityName, e.name, e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("%s \"%s\" validation failed: [%s]", e.entityName, e.name, e.apiErrorMessage) } if e.err != nil { return e.err.Error() } return "" } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/geomap.go000066400000000000000000000123361400161560600271270ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm geomaps // Based on 1.3 schema // // GeoAssigment represents a GTM geo assignment element type GeoAssignment struct { DatacenterBase Countries []string `json:"countries,omitempty"` } // 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"` } // GeoMapList represents the returned GTM GeoMap List body type GeoMapList struct { GeoMapItems []*GeoMap `json:"items"` } // NewGeoMap creates a new GeoMap object func NewGeoMap(name string) *GeoMap { geomap := &GeoMap{Name: name} return geomap } // ListGeoMap retreieves all GeoMaps func ListGeoMaps(domainName string) ([]*GeoMap, error) { geos := &GeoMapList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "geoMap"} } err = client.BodyJSON(res, geos) if err != nil { return nil, err } return geos.GeoMapItems, nil } // GetGeoMap retrieves a GeoMap with the given name. func GetGeoMap(name, domainName string) (*GeoMap, error) { geo := NewGeoMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "GeographicMap", name: name} } else { err = client.BodyJSON(res, geo) if err != nil { return nil, err } return geo, nil } } // Instantiate new Assignment struct func (geo *GeoMap) NewAssignment(dcID int, nickname string) *GeoAssignment { geoAssign := &GeoAssignment{} geoAssign.DatacenterId = dcID geoAssign.Nickname = nickname return geoAssign } // Instantiate new Default Datacenter Struct func (geo *GeoMap) NewDefaultDatacenter(dcID int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcID} } // Create GeoMap in provided domain func (geo *GeoMap) Create(domainName string) (*GeoMapResponse, error) { // Use common code. Any specific validation needed? return geo.save(domainName) } // Update GeoMap in given domain func (geo *GeoMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := geo.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save GeoMap in given domain. Common path for Create and Update. func (geo *GeoMap) save(domainName string) (*GeoMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, geo.Name), geo, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "geographicMap", name: geo.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "geographicMap", name: geo.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &GeoMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete GeoMap method func (geo *GeoMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, geo.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "geographicMap", name: geo.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "geographicMap", name: geo.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/geomap_test.go000066400000000000000000000242001400161560600301570ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestGeoMap = "testGeoMap" func instantiateGeoMap() *GeoMap { geoMap := NewGeoMap(GtmTestGeoMap) geoMapData := []byte(`{ "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }`) jsonhooks.Unmarshal(geoMapData, geoMap) return geoMap } // Verify ListGeoMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestListGeoMaps(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items" : [ { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" } ] }`) Init(config) testGeoMap, err := ListGeoMaps(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, testGeoMap[0]) assert.Equal(t, GtmTestGeoMap, testGeoMap[0].Name) } // Verify GetGeoMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestGetGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }`) Init(config) testGeoMap, err := GetGeoMap(GtmTestGeoMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, testGeoMap) assert.Equal(t, GtmTestGeoMap, testGeoMap.Name) } // Verify failed case for GetGeoMap. Should pass, e.g. no API errors and domain not found func TestGetBadGeoMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetGeoMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create GeoMap. func TestCreateGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testGeoMap := instantiateGeoMap() statresp, err := testGeoMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, statresp.Resource) assert.Equal(t, GtmTestGeoMap, statresp.Resource.Name) } func TestUpdateGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testGeoMap := instantiateGeoMap() _, err := testGeoMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getGeoMap := instantiateGeoMap() stat, err := getGeoMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/property.go000066400000000000000000000235221400161560600275420ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Support gtm domain properties thru Edgegrid // Based on 1.3 Schema // // TrafficTarget struc 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"` } // MxRecord struc type MxRecord struct { Exchange string `json:"exchange,omitempty"` Preference int `json:"preference,omitempty"` } type LivenessTest struct { Name string `json:"name"` ErrorPenalty float64 `json:"errorPenalty"` 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"` 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"` DisableNonstandardPortWarning bool `json:"disableNonstandardPortWarning"` HostHeader string `json:"hostHeader,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"` } // Property represents a GTM property type Property struct { Name string `json:"name"` Type string `json:"type"` Ipv6 bool `json:"ipv6"` ScoreAggregationType string `json:"scoreAggregationType,omitempty"` StickinessBonusPercent 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"` LastModified string `json:"lastModified,omitempty"` UnreachableThreshold float64 `json:"unreachableThreshold,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,omitempty"` HandoutMode string `json:"handoutMode,omitempty"` 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"` MxRecords []*MxRecord `json:"mxRecords,omitempty"` Links []*Link `json:"links,omitempty"` LivenessTests []*LivenessTest `json:"livenessTests,omitempty"` } type PropertyList struct { PropertyItems []*Property `json:"items"` } // NewTrafficTarget is a method applied to a property object that instantiates a TrafficTarget object. func (prop *Property) NewTrafficTarget() *TrafficTarget { return &TrafficTarget{} } // NewMxRecord is a method applied to a property object that instantiates an MxRecord object. func (prop *Property) NewMxRecord() *MxRecord { return &MxRecord{} } // NewLivenessTest is a method applied to a property object that instantiates a LivenessTest object. func (prop *Property) NewLivenessTest(name string, objproto string, interval int, timeout float32) *LivenessTest { return &LivenessTest{Name: name, TestInterval: interval, TestObjectProtocol: objproto, TestTimeout: timeout} } // NewProperty creates a new Property object. func NewProperty(name string) *Property { property := &Property{Name: name} return property } // ListProperties retreieves all Properties for the provided domainName. func ListProperties(domainName string) ([]*Property, error) { properties := &PropertyList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/properties", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, properties) if err != nil { return nil, err } return properties.PropertyItems, nil } } // GetProperty retrieves a Property with the given name. func GetProperty(name, domainName string) (*Property, error) { property := NewProperty(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Property", name: name} } else { err = client.BodyJSON(res, property) if err != nil { return nil, err } return property, nil } } // Create the property in the receiver argument in the specified domain. func (property *Property) Create(domainName string) (*PropertyResponse, error) { // Need do any validation? return property.save(domainName) } // Update the property in the receiver argument in the specified domain. func (property *Property) Update(domainName string) (*ResponseStatus, error) { // Need do any validation? stat, err := property.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save Property updates method func (property *Property) save(domainName string) (*PropertyResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, property.Name), property, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Property", name: property.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Property", name: property.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &PropertyResponse{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete the property identified by the receiver argument from the domain provided. func (property *Property) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, property.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Property", name: property.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Property", name: property.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/property_test.go000066400000000000000000000440761400161560600306100ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "fmt" ) var GtmTestProperty = "testproperty" func instantiateProperty() *Property { property := NewProperty(GtmTestProperty) propertyData := []byte(`{ "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }`) jsonhooks.Unmarshal(propertyData, property) return property } // Verify GetListProperties. Should pass, e.g. no API errors and non nil list. func TestListProperties(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items": [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ] }`) Init(config) propertyList, err := ListProperties(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, propertyList, nil) if len(propertyList) > 0 { firstProp := propertyList[0] assert.Equal(t, firstProp.Name, GtmTestProperty) } else { assert.Equal(t, 0, 1, "ListProperties: empty list") fmt.Println("ListProperties: empty list") } } // Verify GetProperty. Name hardcoded. Should pass, e.g. no API errors and property returned // Depends on CreateProperty func TestGetProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }`) Init(config) testProperty, err := GetProperty(GtmTestProperty, gtmTestDomain) assert.NoError(t, err) assert.Equal(t, GtmTestProperty, testProperty.Name) } // Verify failed case for GetProperty. Should pass, e.g. no API errors and domain not found func TestGetBadProperty(t *testing.T) { boguspropertyname := "boguspropertyname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + boguspropertyname) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+boguspropertyname). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetProperty("boguspropertyname", gtmTestDomain) assert.Error(t, err) } // Test Create property. Name is hardcoded so this will effectively be an update. What happens to existing? func TestCreateProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }, "status" : { "message" : "Change Pending", "changeId" : "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:46:18.461+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) // initialize required fields testProperty := NewProperty(GtmTestProperty) testProperty.ScoreAggregationType = "median" testProperty.Type = "performance" testProperty.HandoutLimit = 1 testProperty.HandoutMode = "normal" testProperty.FailoverDelay = 0 testProperty.FailbackDelay = 0 testProperty.TrafficTargets = []*TrafficTarget{&TrafficTarget{DatacenterId: 3131, Enabled: true, Servers: []string{"1.2.3.4"}, Weight: 100.0}} statresp, err := testProperty.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Property{}, statresp.Resource) assert.Equal(t, GtmTestProperty, statresp.Resource.Name) } func TestUpdateProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 999, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }, "status" : { "message" : "Change Pending", "changeId" : "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:46:18.461+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testProperty := instantiateProperty() testProperty.HandoutLimit = 999 stat, err := testProperty.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325") } func TestDeleteProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) getProperty := instantiateProperty() _, err := getProperty.Delete(gtmTestDomain) assert.NoError(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/resource.go000066400000000000000000000142241400161560600275040ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm resources // Based on 1.3 schema // // ResourceInstance type ResourceInstance struct { DatacenterId int `json:"datacenterId"` UseDefaultLoadObject bool `json:"useDefaultLoadObject"` LoadObject } // 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"` } // ResourceList is the structure returned by List Resources type ResourceList struct { ResourceItems []*Resource `json:"items"` } // NewResourceInstance instantiates a new ResourceInstance. func (rsrc *Resource) NewResourceInstance(dcID int) *ResourceInstance { return &ResourceInstance{DatacenterId: dcID} } // NewResource creates a new Resource object. func NewResource(name string) *Resource { resource := &Resource{Name: name} return resource } // ListResources retreieves all Resources in the specified domain. func ListResources(domainName string) ([]*Resource, error) { rsrcs := &ResourceList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/resources", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Resources"} } err = client.BodyJSON(res, rsrcs) if err != nil { return nil, err } return rsrcs.ResourceItems, nil } // GetResource retrieves a Resource with the given name in the specified domain. func GetResource(name, domainName string) (*Resource, error) { rsc := NewResource(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Resource", name: name} } else { err = client.BodyJSON(res, rsc) if err != nil { return nil, err } return rsc, nil } } // Create the resource identified by the receiver argument in the specified domain. func (rsrc *Resource) Create(domainName string) (*ResourceResponse, error) { // Use common code. Any specific validation needed? return rsrc.save(domainName) } // Update the resourceidentified in the receiver argument in the specified domain. func (rsrc *Resource) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := rsrc.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save Resource in given domain. Common path for Create and Update. func (rsrc *Resource) save(domainName string) (*ResourceResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, rsrc.Name), rsrc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Resource", name: rsrc.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Resource", name: rsrc.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResourceResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete the resource identified in the receiver argument from the specified domain. func (rsrc *Resource) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, rsrc.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Resource", name: rsrc.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Resource", name: rsrc.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/resource_test.go000066400000000000000000000331041400161560600305410ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestResource = "testResource" func instantiateResource() *Resource { resource := NewResource("dummy") resourceData := []byte(`{ "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }`) jsonhooks.Unmarshal(resourceData, resource) return resource } // Verify ListResources. Should pass, e.g. no API errors and non nil list. func TestListResources(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "items" : [ { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] } ] }`) Init(config) resourceList, err := ListResources(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, resourceList, nil) if len(resourceList) > 0 { firstResource := resourceList[0] assert.Equal(t, firstResource.Name, GtmTestResource) } else { t.Fatal("List empty!") } } // Depends on CreateResource func TestGetResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }`) Init(config) testResource, err := GetResource(GtmTestResource, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Resource{}, testResource) assert.Equal(t, GtmTestResource, testResource.Name) } // Verify failed case for GetResource. Should pass, e.g. no API errors and domain not found func TestGetBadResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/somebadname") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/somebadname"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetResource("somebadname", gtmTestDomain) // Shouldn't have found assert.Error(t, err) } // Test Create resource. func TestCreateResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }, "status" : { "message" : "Change Pending", "changeId" : "5bb9f131-99c8-43ff-afd2-a6ce34db8b95", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-17T17:54:37.383+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testResource := NewResource(GtmTestResource) testResource.AggregationType = "median" testResource.Type = "Download score" // Create a Resource Instance var instanceSlice []*ResourceInstance instance := testResource.NewResourceInstance(3131) instanceSlice = append(instanceSlice, instance) testResource.ResourceInstances = instanceSlice // do the create statresp, err := testResource.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Resource{}, statresp.Resource) assert.Equal(t, GtmTestResource, statresp.Resource.Name) } func TestUpdateResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : 0.5, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }, "status" : { "message" : "Change Pending", "changeId" : "5bb9f131-99c8-43ff-afd2-a6ce34db8b95", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-17T17:54:37.383+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testResource := instantiateResource() newDecay := 0.5 testResource.DecayRate = newDecay stat, err := testResource.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "5bb9f131-99c8-43ff-afd2-a6ce34db8b95") } func TestDeleteResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.3+json;charset=UTF-8"). BodyString(`{ "resource" : null, "status" : { "message" : "Change Pending", "changeId" : "9a7a8f84-704b-40de-a903-bcc2728513ac", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:51:02.273+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) getResource := instantiateResource() stat, err := getResource.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "9a7a8f84-704b-40de-a903-bcc2728513ac", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_3/service.go000066400000000000000000000011551400161560600273140ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "net/http" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the GTM edgegrid Config func Init(config edgegrid.Config) { Config = config edgegrid.SetupLogging() } // Utility func to print http req func printHttpRequest(req *http.Request, body bool) { edgegrid.PrintHttpRequest(req, body) } // Utility func to print http response func printHttpResponse(res *http.Response, body bool) { edgegrid.PrintHttpResponse(res, body) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/000077500000000000000000000000001400161560600253245ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/README.md000066400000000000000000000002611400161560600266020ustar00rootroot00000000000000# Akamai Config GTM (Global Traffic Management) A golang package that talks to the [Akamai OPEN Config GTM API](https://developer.akamai.com/api/luna/config-gtm/overview.html). golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/asmap.go000066400000000000000000000103561400161560600267610ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm asmaps // Based on 1.4 schema // // AsAssignment represents a GTM asmap assignment structure type AsAssignment struct { DatacenterBase AsNumbers []int64 `json:"asNumbers"` } // AsMap represents a GTM AsMap type AsMap struct { DefaultDatacenter *DatacenterBase `json:"defaultDatacenter"` Assignments []*AsAssignment `json:"assignments,omitempty"` Name string `json:"name"` Links []*Link `json:"links,omitempty"` } // NewAsMap creates a new asMap func NewAsMap(name string) *AsMap { asmap := &AsMap{Name: name} return asmap } // GetAsMap retrieves a asMap with the given name. func GetAsMap(name, domainName string) (*AsMap, error) { as := NewAsMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "asMap", name: name} } else { err = client.BodyJSON(res, as) if err != nil { return nil, err } return as, nil } } // Instantiate new Assignment struct func (as *AsMap) NewAssignment(dcID int, nickname string) *AsAssignment { asAssign := &AsAssignment{} asAssign.DatacenterId = dcID asAssign.Nickname = nickname return asAssign } // Instantiate new Default Datacenter Struct func (as *AsMap) NewDefaultDatacenter(dcID int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcID} } // Create asMap in provided domain func (as *AsMap) Create(domainName string) (*AsMapResponse, error) { // Use common code. Any specific validation needed? return as.save(domainName) } // Update AsMap in given domain func (as *AsMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := as.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save AsMap in given domain. Common path for Create and Update. func (as *AsMap) save(domainName string) (*AsMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, as.Name), as, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "asMap", name: as.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "asMap", name: as.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &AsMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete AsMap method func (as *AsMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/as-maps/%s", domainName, as.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "asMap", name: as.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "asMap", name: as.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/asmap_test.go000066400000000000000000000236011400161560600300150ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) var GtmTestAsMap = "testAsMap" var gtmTestDomain = "gtmdomtest.akadns.net" func instantiateAsMap() *AsMap { asMap := NewAsMap(GtmTestAsMap) asMapData := []byte(`{ "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "name": "testAsMap" }`) jsonhooks.Unmarshal(asMapData, asMap) return asMap } // Verify GetAsMap. Name hardcoded. Should pass, e.g. no API errors and resource returned // Depends on CreateAsMap func TestGetAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }`) Init(config) testAsMap, err := GetAsMap(GtmTestAsMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &AsMap{}, testAsMap) assert.Equal(t, GtmTestAsMap, testAsMap.Name) } // Verify failed case for GetAsMap. Should pass, e.g. no API errors and domain not found func TestGetBadAsMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetAsMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create AsMap. func TestCreateAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testAsMap := instantiateAsMap() statresp, err := testAsMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &AsMap{}, statresp.Resource) assert.Equal(t, GtmTestAsMap, statresp.Resource.Name) } func TestUpdateAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "asNumbers": [ 12222, 16702, 17334 ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "asNumbers": [ 16625 ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other AS numbers" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/as-maps/The%20North", "rel": "self" } ], "name": "testAsMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testAsMap := instantiateAsMap() _, err := testAsMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteAsMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/as-maps/" + GtmTestAsMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/as-maps/"+GtmTestAsMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getAsMap := instantiateAsMap() stat, err := getAsMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/cidrmap.go000066400000000000000000000123501400161560600272730ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm cidrmaps // Based on 1.4 schema // //CidrAssignment represents a GTM cidr assignment element type CidrAssignment struct { DatacenterBase Blocks []string `json:"blocks"` } // 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"` } // CidrMapList represents a GTM returned cidrmap list body type CidrMapList struct { CidrMapItems []*CidrMap `json:"items"` } // NewCidrMap creates a new CidrMap object func NewCidrMap(name string) *CidrMap { cidrmap := &CidrMap{Name: name} return cidrmap } // ListCidrMap retreieves all CidrMaps func ListCidrMaps(domainName string) ([]*CidrMap, error) { cidrs := &CidrMapList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "cidrMap"} } err = client.BodyJSON(res, cidrs) if err != nil { return nil, err } return cidrs.CidrMapItems, nil } // GetCidrMap retrieves a CidrMap with the given name. func GetCidrMap(name, domainName string) (*CidrMap, error) { cidr := NewCidrMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "cidrMap", name: name} } else { err = client.BodyJSON(res, cidr) if err != nil { return nil, err } return cidr, nil } } // Instantiate new Assignment struct func (cidr *CidrMap) NewAssignment(dcid int, nickname string) *CidrAssignment { cidrAssign := &CidrAssignment{} cidrAssign.DatacenterId = dcid cidrAssign.Nickname = nickname return cidrAssign } // Instantiate new Default Datacenter Struct func (cidr *CidrMap) NewDefaultDatacenter(dcid int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcid} } // Create CidrMap in provided domain func (cidr *CidrMap) Create(domainName string) (*CidrMapResponse, error) { // Use common code. Any specific validation needed? return cidr.save(domainName) } // Update CidrMap in given domain func (cidr *CidrMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := cidr.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save CidrMap in given domain. Common path for Create and Update. func (cidr *CidrMap) save(domainName string) (*CidrMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, cidr.Name), cidr, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "cidrMap", name: cidr.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "cidrMap", name: cidr.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &CidrMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete CidrMap method func (cidr *CidrMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/cidr-maps/%s", domainName, cidr.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) // Network error if err != nil { return nil, CommonError{ entityName: "cidrMap", name: cidr.Name, httpErrorMessage: err.Error(), err: err, } } // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "cidrMap", name: cidr.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/cidrmap_test.go000066400000000000000000000276641400161560600303500ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestCidrMap = "testCidrMap" func instantiateCidrMap() *CidrMap { cidrMap := NewCidrMap(GtmTestCidrMap) cidrMapData := []byte(`{ "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }`) jsonhooks.Unmarshal(cidrMapData, cidrMap) return cidrMap } // Verify ListCidrMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestListCidrMaps(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items" : [ { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" } ] }`) Init(config) testCidrMap, err := ListCidrMaps(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, testCidrMap[0]) assert.Equal(t, GtmTestCidrMap, testCidrMap[0].Name) } // Verify GetCidrMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestGetCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }`) Init(config) testCidrMap, err := GetCidrMap(GtmTestCidrMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, testCidrMap) assert.Equal(t, GtmTestCidrMap, testCidrMap.Name) } // Verify failed case for GetCidrMap. Should pass, e.g. no API errors and domain not found func TestGetBadCidrMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetCidrMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create CidrMap. func TestCreateCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testCidrMap := instantiateCidrMap() statresp, err := testCidrMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &CidrMap{}, statresp.Resource) assert.Equal(t, GtmTestCidrMap, statresp.Resource.Name) } func TestUpdateCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "blocks": [ "1.2.3.0/24" ], "datacenterId": 3134, "nickname": "Frostfangs and the Fist of First Men" }, { "blocks": [ "1.2.4.0/24" ], "datacenterId": 3133, "nickname": "Winterfell" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "All Other CIDR Blocks" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/cidr-maps/testCidrMap", "rel": "self" } ], "name": "testCidrMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testCidrMap := instantiateCidrMap() _, err := testCidrMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteCidrMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/cidr-maps/" + GtmTestCidrMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/cidr-maps/"+GtmTestCidrMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getCidrMap := instantiateCidrMap() stat, err := getCidrMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/common.go000066400000000000000000000061601400161560600271460ustar00rootroot00000000000000package configgtm import ( "fmt" "net/http" ) // // Common data types and methods // Based on 1.3 schemas // // Append url args to req func appendReqArgs(req *http.Request, queryArgs map[string]string) { // Look for optional args if len(queryArgs) > 0 { q := req.URL.Query() for argName, argVal := range queryArgs { q.Add(argName, argVal) } req.URL.RawQuery = q.Encode() } } // default schema version // TODO: retrieve from environment or elsewhere in Service Init var schemaVersion string = "1.4" // internal method to set version. passed in as string func setVersionHeader(req *http.Request, version string) { req.Header.Set("Accept", fmt.Sprintf("application/vnd.config-gtm.v%s+json", version)) if req.Method != "GET" { req.Header.Set("Content-Type", fmt.Sprintf("application/vnd.config-gtm.v%s+json", version)) } return } // response Status 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"` } // NewResponseStatus returns a new ResponseStatus struct func NewResponseStatus() *ResponseStatus { return &ResponseStatus{} } // Generic response structs type ResponseBody struct { Resource interface{} `json:"resource"` Status *ResponseStatus `json:"status"` } // Response structs by Entity Type type DomainResponse struct { Resource *Domain `json:"resource"` Status *ResponseStatus `json:"status"` } type DatacenterResponse struct { Status *ResponseStatus `json:"status"` Resource *Datacenter `json:"resource"` } type PropertyResponse struct { Resource *Property `json:"resource"` Status *ResponseStatus `json:"status"` } type ResourceResponse struct { Resource *Resource `json:"resource"` Status *ResponseStatus `json:"status"` } type CidrMapResponse struct { Resource *CidrMap `json:"resource"` Status *ResponseStatus `json:"status"` } type GeoMapResponse struct { Resource *GeoMap `json:"resource"` Status *ResponseStatus `json:"status"` } type AsMapResponse struct { Resource *AsMap `json:"resource"` Status *ResponseStatus `json:"status"` } // Probably THE most common type type Link struct { Rel string `json:"rel"` Href string `json:"href"` } // type LoadObject struct { LoadObject string `json:"loadObject,omitempty"` LoadObjectPort int `json:"loadObjectPort,omitempty"` LoadServers []string `json:"loadServers,omitempty"` } // NewLoadObject returns a new LoadObject structure func NewLoadObject() *LoadObject { return &LoadObject{} } type DatacenterBase struct { Nickname string `json:"nickname,omitempty"` DatacenterId int `json:"datacenterId"` } // NewDatacenterBase returns a new DatacenterBase structure func NewDatacenterBase() *DatacenterBase { return &DatacenterBase{} } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/datacenter.go000066400000000000000000000225211400161560600277670ustar00rootroot00000000000000package configgtm import ( "errors" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "strconv" "strings" ) // // Handle Operations on gtm datacenters // Based on 1.4 schema // // 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"` } type DatacenterList struct { DatacenterItems []*Datacenter `json:"items"` } // NewDatacenterResponse instantiates a new DatacenterResponse structure func NewDatacenterResponse() *DatacenterResponse { dcResp := &DatacenterResponse{} return dcResp } // NewDatacenter creates a new Datacenter object func NewDatacenter() *Datacenter { dc := &Datacenter{} return dc } // ListDatacenters retreieves all Datacenters func ListDatacenters(domainName string) ([]*Datacenter, error) { dcs := &DatacenterList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Datacenter"} } else { err = client.BodyJSON(res, dcs) if err != nil { return nil, err } return dcs.DatacenterItems, nil } } // GetDatacenter retrieves a Datacenter with the given name. NOTE: Id arg is int! func GetDatacenter(dcID int, domainName string) (*Datacenter, error) { dc := NewDatacenter() req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dcID)), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpRequest(req, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dcID)} } else { err = client.BodyJSON(res, dc) if err != nil { return nil, err } return dc, nil } } // Create the datacenter identified by the receiver argument in the specified domain. func (dc *Datacenter) Create(domainName string) (*DatacenterResponse, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters", domainName), dc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network if err != nil { return nil, CommonError{ entityName: "Domain", name: domainName, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domainName, apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body for updated DC and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } var MapDefaultDC int = 5400 var Ipv4DefaultDC int = 5401 var Ipv6DefaultDC int = 5402 // Create Default Datacenter for Maps func CreateMapsDefaultDatacenter(domainName string) (*Datacenter, error) { return createDefaultDC(MapDefaultDC, domainName) } // Create Default Datacenter for IPv4 Selector func CreateIPv4DefaultDatacenter(domainName string) (*Datacenter, error) { return createDefaultDC(Ipv4DefaultDC, domainName) } // Create Default Datacenter for IPv6 Selector func CreateIPv6DefaultDatacenter(domainName string) (*Datacenter, error) { return createDefaultDC(Ipv6DefaultDC, domainName) } // Worker function to create Default Datacenter identified id in the specified domain. func createDefaultDC(defaultID int, domainName string) (*Datacenter, error) { if defaultID != MapDefaultDC && defaultID != Ipv4DefaultDC && defaultID != Ipv6DefaultDC { return nil, errors.New("Invalid default datacenter id provided for creation") } // check if already exists dc, err := GetDatacenter(defaultID, domainName) if err == nil { return dc, err } else { if !strings.Contains(err.Error(), "not found") || !strings.Contains(err.Error(), "Datacenter") { return nil, err } } defaultURL := fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/", domainName) switch defaultID { case MapDefaultDC: defaultURL += "default-datacenter-for-maps" case Ipv4DefaultDC: defaultURL += "datacenter-for-ip-version-selector-ipv4" case Ipv6DefaultDC: defaultURL += "datacenter-for-ip-version-selector-ipv6" } req, err := client.NewJSONRequest( Config, "POST", defaultURL, "", ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network if err != nil { return nil, CommonError{ entityName: "Domain", name: domainName, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domainName, apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body for updated DC and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Resource, nil } // Update the datacenter identified in the receiver argument in the provided domain. func (dc *Datacenter) Update(domainName string) (*ResponseStatus, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterId)), dc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } // Delete the datacenter identified by the receiver argument from the domain specified. func (dc *Datacenter) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/datacenters/%s", domainName, strconv.Itoa(dc.DatacenterId)), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Datacenter", name: strconv.Itoa(dc.DatacenterId), apiErrorMessage: err.Detail, err: err} } responseBody := NewDatacenterResponse() // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/datacenter_test.go000066400000000000000000000412051400161560600310260ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" //edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "fmt" ) var GtmTestDC1 = "testDC1" var GtmTestDC2 = "testDC2" var dcMap = map[string]string{"GtmTestDC1": GtmTestDC1, "GtmTestDC2": GtmTestDC2} func instantiateDatacenter() *Datacenter { dc := NewDatacenter() dcData := []byte(`{ "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false }`) jsonhooks.Unmarshal(dcData, dc) return dc } // Verify ListDatacenters. Should pass, e.g. no API errors and non nil list. func TestListDatacenters(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ] }`) Init(config) dcList, err := ListDatacenters(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, dcList, nil) if len(dcList) > 0 { firstDC := dcList[0] assert.Equal(t, firstDC.Nickname, GtmTestDC1) } else { assert.Equal(t, 0, 1, "ListDatacenters: empty list") fmt.Println("ListDatacenters: empty list") } } // Verify GetDatacenter. Name hardcoded. Should pass, e.g. no API errors and property returned // Depends on CreateDatacenter func TestGetDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }`) Init(config) testDC, err := GetDatacenter(3131, gtmTestDomain) assert.NoError(t, err) assert.Equal(t, 3131, testDC.DatacenterId) } // Verify failed case for GetDatacenter. Should pass, e.g. no API errors and domain not found func TestGetBadDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/9999") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/9999"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetDatacenter(9999, gtmTestDomain) assert.Error(t, err) } // Test Create datacenter. func TestCreateDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters") mock. Post("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters"). HeaderPresent("Authorization"). Reply(201). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) testDC := NewDatacenter() testDC.Nickname = GtmTestDC1 statresp, err := testDC.Create(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, GtmTestDC1, statresp.Resource.Nickname) } func TestUpdateDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDC := instantiateDatacenter() stat, err := testDC.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "4c7e6466-84e1-4895-bdf5-e3608d708d69") } func TestDeleteDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/3131") mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/3131"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDC := instantiateDatacenter() _, err := testDC.Delete(gtmTestDomain) assert.NoError(t, err) } func TestCreateMapsDefaultDatacenter(t *testing.T) { defer gock.Off() mock1 := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/5400") mock1. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/5400"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8") mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/datacenters/default-datacenter-for-maps") mock. Post("/config-gtm/v1/domains/"+gtmTestDomain+"/datacenters/default-datacenter-for-maps"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "datacenterId" : 5400, "nickname" : "Default Datacenter", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/5400" } ] }, "status" : { "message" : "Change Pending", "changeId" : "4c7e6466-84e1-4895-bdf5-e3608d708d69", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-05-30T17:47:02.831+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) defDC, err := CreateMapsDefaultDatacenter(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, defDC.DatacenterId, 5400) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/domain.go000066400000000000000000000335251400161560600271320ustar00rootroot00000000000000package configgtm import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "net/http" "reflect" "strings" "unicode" ) // // Support gtm domains thru Edgegrid // Based on 1.4 Schema // // 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"` } type DomainsList struct { DomainItems []*DomainItem `json:"items"` } // 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"` } // NewDomain is a utility function that creates a new Domain object. func NewDomain(domainName, domainType string) *Domain { domain := &Domain{} domain.Name = domainName domain.Type = domainType return domain } // GetStatus retrieves current status for the given domainname. func GetDomainStatus(domainName string) (*ResponseStatus, error) { stat := &ResponseStatus{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/status/current", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } return stat, nil } } // ListDomains retrieves all Domains. func ListDomains() ([]*DomainItem, error) { domains := &DomainsList{} req, err := client.NewRequest( Config, "GET", "/config-gtm/v1/domains/", nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain"} } else { err = client.BodyJSON(res, domains) if err != nil { return nil, err } return domains.DomainItems, nil } } // GetDomain retrieves a Domain with the given domainname. func GetDomain(domainName string) (*Domain, error) { domain := NewDomain(domainName, "basic") req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, domain) if err != nil { return nil, err } return domain, nil } } // Save method; Create or Update func (domain *Domain) save(queryArgs map[string]string, req *http.Request) (*DomainResponse, error) { // set schema version setVersionHeader(req, schemaVersion) // Look for optional args if len(queryArgs) > 0 { q := req.URL.Query() if val, ok := queryArgs["contractId"]; ok { q.Add("contractId", strings.TrimPrefix(val, "ctr_")) } if val, ok := queryArgs["gid"]; ok { q.Add("gid", strings.TrimPrefix(val, "grp_")) } req.URL.RawQuery = q.Encode() } printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Domain", name: domain.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domain.Name, apiErrorMessage: err.Detail, err: err} } // TODO: What validation can we do? E.g. if not equivalent there was a concurrent change... responseBody := &DomainResponse{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Create is a method applied to a domain object resulting in creation. func (domain *Domain) Create(queryArgs map[string]string) (*DomainResponse, error) { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf("/config-gtm/v1/domains/"), domain, ) if err != nil { return nil, err } return domain.save(queryArgs, req) } // Update is a method applied to a domain object resulting in an update. func (domain *Domain) Update(queryArgs map[string]string) (*ResponseStatus, error) { // Any validation to do? req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name), domain, ) if err != nil { return nil, err } stat, err := domain.save(queryArgs, req) if err != nil { return nil, err } return stat.Status, err } // Delete is a method applied to a domain object resulting in removal. func (domain *Domain) Delete() (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Domain", name: domain.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Domain", name: domain.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } // NullObjectAttributeStruct represents core and child null onject attributes type NullPerObjectAttributeStruct struct { CoreObjectFields map[string]string ChildObjectFields map[string]interface{} // NullObjectAttributeStruct } // NullFieldMapStruct returned null Objects structure type NullFieldMapStruct struct { Domain NullPerObjectAttributeStruct // entry is domain Properties map[string]NullPerObjectAttributeStruct // entries are properties Datacenters map[string]NullPerObjectAttributeStruct // entries are datacenters Resources map[string]NullPerObjectAttributeStruct // entries are resources CidrMaps map[string]NullPerObjectAttributeStruct // entries are cidrmaps GeoMaps map[string]NullPerObjectAttributeStruct // entries are geomaps AsMaps map[string]NullPerObjectAttributeStruct // entries are asmaps } type ObjectMap map[string]interface{} // Retrieve map of null fields func (domain *Domain) NullFieldMap() (*NullFieldMapStruct, error) { var nullFieldMap = &NullFieldMapStruct{} var domFields = NullPerObjectAttributeStruct{} domainMap := make(map[string]string) var objMap = ObjectMap{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s", domain.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domain.Name} } else { err = client.BodyJSON(res, &objMap) if err != nil { return nullFieldMap, err } } for i, d := range objMap { objval := fmt.Sprint(d) if fmt.Sprintf("%T", d) == "" { if objval == "" { domainMap[makeFirstCharUpperCase(i)] = "" } continue } switch i { case "properties": nullFieldMap.Properties = processObjectList(d.([]interface{})) case "datacenters": nullFieldMap.Datacenters = processObjectList(d.([]interface{})) case "resources": nullFieldMap.Resources = processObjectList(d.([]interface{})) case "cidrMaps": nullFieldMap.CidrMaps = processObjectList(d.([]interface{})) case "geographicMaps": nullFieldMap.GeoMaps = processObjectList(d.([]interface{})) case "asMaps": nullFieldMap.AsMaps = processObjectList(d.([]interface{})) } } domFields.CoreObjectFields = domainMap nullFieldMap.Domain = domFields return nullFieldMap, nil } func makeFirstCharUpperCase(origString string) string { a := []rune(origString) a[0] = unicode.ToUpper(a[0]) // hack if origString == "cname" { a[1] = unicode.ToUpper(a[1]) } return string(a) } func processObjectList(objectList []interface{}) map[string]NullPerObjectAttributeStruct { nullObjectsList := make(map[string]NullPerObjectAttributeStruct) for _, obj := range objectList { nullObjectFields := NullPerObjectAttributeStruct{} objectName := "" objectDCID := "" objectMap := make(map[string]string) objectChildList := make(map[string]interface{}) for objf, objd := range obj.(map[string]interface{}) { objval := fmt.Sprint(objd) switch fmt.Sprintf("%T", objd) { case "": if objval == "" { objectMap[makeFirstCharUpperCase(objf)] = "" } case "map[string]interface {}": // include null stand alone struct elements in core for moname, movalue := range objd.(map[string]interface{}) { if fmt.Sprintf("%T", movalue) == "" { objectMap[makeFirstCharUpperCase(moname)] = "" } } case "[]interface {}": iSlice := objd.([]interface{}) if len(iSlice) > 0 && reflect.TypeOf(iSlice[0]).Kind() != reflect.String && reflect.TypeOf(iSlice[0]).Kind() != reflect.Int64 && reflect.TypeOf(iSlice[0]).Kind() != reflect.Float64 && reflect.TypeOf(iSlice[0]).Kind() != reflect.Int32 { objectChildList[makeFirstCharUpperCase(objf)] = processObjectList(objd.([]interface{})) } default: if objf == "name" { objectName = objval } if objf == "datacenterId" { objectDCID = objval } } } nullObjectFields.CoreObjectFields = objectMap nullObjectFields.ChildObjectFields = objectChildList if objectDCID == "" { if objectName != "" { nullObjectsList[objectName] = nullObjectFields } else { nullObjectsList["unknown"] = nullObjectFields // TODO: What if mnore than one? } } else { nullObjectsList[objectDCID] = nullObjectFields } } return nullObjectsList } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/domain_test.go000066400000000000000000001321331400161560600301640ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/h2non/gock.v1" ) func instantiateDomain() *Domain { domain := NewDomain(gtmTestDomain, "basic") domainData := []byte(`{ "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-14T19:36:13.174+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 600, "maxProperties" : 100, "maxResources" : 9999, "maxTestTimeout" : 60.0, "maxTTL" : 3600, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : "Add Property testproperty", "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:36:13.174+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ], "datacenters" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }`) jsonhooks.Unmarshal(domainData, domain) return domain } // Verify GetListDomains. Sould pass, e.g. no API errors and non nil list. func TestListDomains(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains") mock. Get("/config-gtm/v1/domains"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items" : [ { "name" : "gtmdomtest.akadns.net", "status" : "Change Pending", "acgId" : "1-3CV382", "lastModified" : "2019-06-06T19:07:20.000+00:00", "lastModifiedBy" : "operator", "changeId" : "c3e1b771-2500-40c9-a7da-6c3cdbce1936", "activationState" : "PENDING", "modificationComments" : "mock test", "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" } ] } ] }`) Init(config) domainsList, err := ListDomains() assert.NoError(t, err) assert.NotEqual(t, domainsList, nil) assert.Equal(t, "gtmdomtest.akadns.net", domainsList[0].Name) } // Verify GetDomain. Name hardcoded. Should pass, e.g. no API errors and domain returned func TestGetDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "cidrMaps": [], "datacenters": [ { "city": "Snæfellsjökull", "cloneOf": null, "cloudServerTargeting": false, "continent": "EU", "country": "IS", "datacenterId": 3132, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 64.808, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3132", "rel": "self" } ], "longitude": -23.776, "nickname": "property_test_dc2", "stateOrProvince": null, "virtual": true }, { "city": "Philadelphia", "cloneOf": null, "cloudServerTargeting": true, "continent": "NA", "country": "US", "datacenterId": 3133, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 39.95, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3133", "rel": "self" } ], "longitude": -75.167, "nickname": "property_test_dc3", "stateOrProvince": null, "virtual": true }, { "city": "Downpat", "cloneOf": null, "cloudServerTargeting": false, "continent": "EU", "country": "GB", "datacenterId": 3131, "defaultLoadObject": { "loadObject": null, "loadObjectPort": 0, "loadServers": null }, "latitude": 54.367, "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131", "rel": "self" } ], "longitude": -5.582, "nickname": "property_test_dc1", "stateOrProvince": "ha", "virtual": true } ], "defaultErrorPenalty": 75, "defaultSslClientCertificate": null, "defaultSslClientPrivateKey": null, "defaultTimeoutPenalty": 25, "emailNotificationList": [], "geographicMaps": [], "lastModified": "2019-04-25T14:53:12.000+00:00", "lastModifiedBy": "operator", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net", "rel": "self" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters", "rel": "datacenters" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties", "rel": "properties" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps", "rel": "geographic-maps" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps", "rel": "cidr-maps" }, { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources", "rel": "resources" } ], "loadFeedback": false, "loadImbalancePercentage": 10.0, "modificationComments": "Edit Property test_property", "name": "gtmdomtest.akadns.net", "properties": [ { "backupCName": null, "backupIp": null, "balanceByDownloadScore": false, "cname": "www.boo.wow", "comments": null, "dynamicTTL": 300, "failbackDelay": 0, "failoverDelay": 0, "handoutMode": "normal", "healthMax": null, "healthMultiplier": null, "healthThreshold": null, "ipv6": false, "lastModified": "2019-04-25T14:53:12.000+00:00", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/test_property", "rel": "self" } ], "livenessTests": [ { "disableNonstandardPortWarning": false, "hostHeader": null, "httpError3xx": true, "httpError4xx": true, "httpError5xx": true, "name": "health check", "requestString": null, "responseString": null, "sslClientCertificate": null, "sslClientPrivateKey": null, "testInterval": 60, "testObject": "/status", "testObjectPassword": null, "testObjectPort": 80, "testObjectProtocol": "HTTP", "testObjectUsername": null, "testTimeout": 25.0 } ], "loadImbalancePercentage": 10.0, "mapName": null, "maxUnreachablePenalty": null, "mxRecords": [], "name": "test_property", "scoreAggregationType": "mean", "staticTTL": 600, "stickinessBonusConstant": null, "stickinessBonusPercentage": 50, "trafficTargets": [ { "datacenterId": 3131, "enabled": true, "handoutCName": null, "name": null, "servers": [ "1.2.3.4", "1.2.3.5" ], "weight": 50.0 }, { "datacenterId": 3132, "enabled": true, "handoutCName": "www.google.com", "name": null, "servers": [], "weight": 25.0 }, { "datacenterId": 3133, "enabled": true, "handoutCName": "www.comcast.com", "name": null, "servers": [ "www.comcast.com" ], "weight": 25.0 } ], "type": "weighted-round-robin", "unreachableThreshold": null, "useComputedTargets": false } ], "resources": [], "status": { "changeId": "40e36abd-bfb2-4635-9fca-62175cf17007", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current", "rel": "self" } ], "message": "Current configuration has been propagated to all GTM nameservers", "passingValidation": true, "propagationStatus": "COMPLETE", "propagationStatusDate": "2019-04-25T14:54:00.000+00:00" }, "type": "weighted" }`) Init(config) testDomain, err := GetDomain(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, gtmTestDomain, testDomain.Name) } // Verify failed case for GetDomain. Should pass, e.g. no API errors and domain not found func TestGetBadDomain(t *testing.T) { baddomainname := "baddomainname.me" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + baddomainname) mock. Get("/config-gtm/v1/domains/"+baddomainname). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetDomain(baddomainname) assert.Error(t, err) } // Test Create domain. Name is hardcoded so this will effectively be an update. What happens to existing? func TestCreateDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains") mock. Post("/config-gtm/v1/domains/"). HeaderPresent("Authorization"). Reply(201). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-24T18:48:57.787+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 0, "maxProperties" : 0, "maxResources" : 512, "maxTestTimeout" : 0.0, "maxTTL" : 0, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : null, "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "539872cc-6ba6-4429-acd5-90bab7fb5e9d", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-24T18:48:57.787+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ ], "datacenters" : [ ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }, "status" : { "message" : "Change Pending", "changeId" : "539872cc-6ba6-4429-acd5-90bab7fb5e9d", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-24T18:48:57.787+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDomain := NewDomain(gtmTestDomain, "basic") qArgs := make(map[string]string) statResponse, err := testDomain.Create(qArgs) require.NoError(t, err) assert.Equal(t, gtmTestDomain, statResponse.Resource.Name) } func TestUpdateDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "cnameCoalescingEnabled" : false, "defaultErrorPenalty" : 75, "defaultHealthMax" : null, "defaultHealthMultiplier" : null, "defaultHealthThreshold" : null, "defaultMaxUnreachablePenalty" : null, "defaultSslClientCertificate" : null, "defaultSslClientPrivateKey" : null, "defaultTimeoutPenalty" : 25, "defaultUnreachableThreshold" : null, "emailNotificationList" : [ ], "endUserMappingEnabled" : false, "lastModified" : "2019-06-14T19:36:13.174+00:00", "lastModifiedBy" : "operator", "loadFeedback" : false, "mapUpdateInterval" : 600, "maxProperties" : 100, "maxResources" : 9999, "maxTestTimeout" : 60.0, "maxTTL" : 3600, "minPingableRegionFraction" : null, "minTestInterval" : 0, "minTTL" : 0, "modificationComments" : "Add Property testproperty", "name" : "gtmdomtest.akadns.net", "pingInterval" : null, "pingPacketSize" : null, "roundRobinPrefix" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "servermonitorPool" : null, "type" : "basic", "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] }, "loadImbalancePercentage" : null, "domainVersionId" : null, "resources" : [ ], "properties" : [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:36:13.174+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ], "datacenters" : [ { "datacenterId" : 3131, "nickname" : "testDC1", "scorePenalty" : 0, "city" : null, "stateOrProvince" : null, "country" : null, "latitude" : null, "longitude" : null, "cloneOf" : null, "virtual" : true, "defaultLoadObject" : null, "continent" : null, "servermonitorPool" : null, "servermonitorLivenessCount" : null, "servermonitorLoadCount" : null, "pingInterval" : null, "pingPacketSize" : null, "cloudServerTargeting" : false, "cloudServerHostHeaderOverride" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters/3131" } ] } ], "geographicMaps" : [ ], "cidrMaps" : [ ], "asMaps" : [ ], "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net" }, { "rel" : "datacenters", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/datacenters" }, { "rel" : "properties", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties" }, { "rel" : "geographic-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/geographic-maps" }, { "rel" : "cidr-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/cidr-maps" }, { "rel" : "resources", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources" }, { "rel" : "as-maps", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/as-maps" } ] }, "status" : { "message" : "Change Pending", "changeId" : "df6c04e4-6327-4e0f-8872-bfe9fb2693d2", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:36:13.174+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testDomain := instantiateDomain() //testDomain.MaxResources = 9999 qArgs := make(map[string]string) statResp, err := testDomain.Update(qArgs) require.NoError(t, err) assert.Equal(t, statResp.ChangeId, "df6c04e4-6327-4e0f-8872-bfe9fb2693d2") } /* Future. Presently no domain Delete endpoint. func TestDeleteDomain(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/"+gtmTestDomain) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : null, "status" : { "changeId": "40e36abd-bfb2-4635-9fca-62175cf17007", "links": [ { "href": "https://akab-ymtebc45gco3ypzj-apz4yxpek55y7fyv.luna.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2019-04-25T14:54:00.000+00:00" }, }`) Init(config) getDomain := instantiateDomain() _, err := getDomain.Delete() assert.NoError(t, err) } */ golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/errors.go000066400000000000000000000037631400161560600272000ustar00rootroot00000000000000package configgtm import ( "fmt" ) type ConfigGTMError interface { error Network() bool NotFound() bool FailedToSave() bool ValidationFailed() bool } func IsConfigGTMError(e error) bool { _, ok := e.(ConfigGTMError) return ok } type CommonError struct { entityName string name string httpErrorMessage string apiErrorMessage string err error } func (e CommonError) SetItem(itemName string, itemVal interface{}) { switch itemName { case "entityName": e.entityName = itemVal.(string) case "name": e.name = itemVal.(string) case "httpErrorMessage": e.httpErrorMessage = itemVal.(string) case "apiErrorMessage": e.apiErrorMessage = itemVal.(string) case "err": e.err = itemVal.(error) } } func (e CommonError) GetItem(itemName string) interface{} { switch itemName { case "entityName": return e.entityName case "name": return e.name case "httpErrorMessage": return e.httpErrorMessage case "apiErrorMessage": return e.apiErrorMessage case "err": return e.err } return nil } func (e CommonError) Network() bool { if e.httpErrorMessage != "" { return true } return false } func (e CommonError) NotFound() bool { if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" { return true } return false } func (CommonError) FailedToSave() bool { return false } func (e CommonError) ValidationFailed() bool { if e.apiErrorMessage != "" { return true } return false } func (e CommonError) Error() string { if e.Network() { return fmt.Sprintf("%s \"%s\" network error: [%s]", e.entityName, e.name, e.httpErrorMessage) } if e.NotFound() { return fmt.Sprintf("%s \"%s\" not found.", e.entityName, e.name) } if e.FailedToSave() { return fmt.Sprintf("%s \"%s\" failed to save: [%s]", e.entityName, e.name, e.err.Error()) } if e.ValidationFailed() { return fmt.Sprintf("%s \"%s\" validation failed: [%s]", e.entityName, e.name, e.apiErrorMessage) } if e.err != nil { return e.err.Error() } return "" } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/geomap.go000066400000000000000000000123241400161560600271250ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Handle Operations on gtm geomaps // Based on 1.4 schema // // GeoAssigment represents a GTM geo assignment element type GeoAssignment struct { DatacenterBase Countries []string `json:"countries"` } // 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"` } // GeoMapList represents the returned GTM GeoMap List body type GeoMapList struct { GeoMapItems []*GeoMap `json:"items"` } // NewGeoMap creates a new GeoMap object func NewGeoMap(name string) *GeoMap { geomap := &GeoMap{Name: name} return geomap } // ListGeoMap retreieves all GeoMaps func ListGeoMaps(domainName string) ([]*GeoMap, error) { geos := &GeoMapList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "geoMap"} } err = client.BodyJSON(res, geos) if err != nil { return nil, err } return geos.GeoMapItems, nil } // GetGeoMap retrieves a GeoMap with the given name. func GetGeoMap(name, domainName string) (*GeoMap, error) { geo := NewGeoMap(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "GeographicMap", name: name} } else { err = client.BodyJSON(res, geo) if err != nil { return nil, err } return geo, nil } } // Instantiate new Assignment struct func (geo *GeoMap) NewAssignment(dcID int, nickname string) *GeoAssignment { geoAssign := &GeoAssignment{} geoAssign.DatacenterId = dcID geoAssign.Nickname = nickname return geoAssign } // Instantiate new Default Datacenter Struct func (geo *GeoMap) NewDefaultDatacenter(dcID int) *DatacenterBase { return &DatacenterBase{DatacenterId: dcID} } // Create GeoMap in provided domain func (geo *GeoMap) Create(domainName string) (*GeoMapResponse, error) { // Use common code. Any specific validation needed? return geo.save(domainName) } // Update GeoMap in given domain func (geo *GeoMap) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := geo.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save GeoMap in given domain. Common path for Create and Update. func (geo *GeoMap) save(domainName string) (*GeoMapResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, geo.Name), geo, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "geographicMap", name: geo.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "geographicMap", name: geo.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &GeoMapResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete GeoMap method func (geo *GeoMap) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/geographic-maps/%s", domainName, geo.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "geographicMap", name: geo.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "geographicMap", name: geo.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/geomap_test.go000066400000000000000000000242001400161560600301600ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestGeoMap = "testGeoMap" func instantiateGeoMap() *GeoMap { geoMap := NewGeoMap(GtmTestGeoMap) geoMapData := []byte(`{ "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }`) jsonhooks.Unmarshal(geoMapData, geoMap) return geoMap } // Verify ListGeoMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestListGeoMaps(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items" : [ { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" } ] }`) Init(config) testGeoMap, err := ListGeoMaps(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, testGeoMap[0]) assert.Equal(t, GtmTestGeoMap, testGeoMap[0].Name) } // Verify GetGeoMap. Name hardcoded. Should pass, e.g. no API errors and resource returned func TestGetGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }`) Init(config) testGeoMap, err := GetGeoMap(GtmTestGeoMap, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, testGeoMap) assert.Equal(t, GtmTestGeoMap, testGeoMap.Name) } // Verify failed case for GetGeoMap. Should pass, e.g. no API errors and domain not found func TestGetBadGeoMap(t *testing.T) { badName := "somebadname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + badName) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+badName). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetGeoMap(badName, gtmTestDomain) assert.Error(t, err) } // Test Create GeoMap. func TestCreateGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testGeoMap := instantiateGeoMap() statresp, err := testGeoMap.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &GeoMap{}, statresp.Resource) assert.Equal(t, GtmTestGeoMap, statresp.Resource.Name) } func TestUpdateGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "assignments": [ { "countries": [ "GB", "IE" ], "datacenterId": 3133, "nickname": "UK and Ireland users" } ], "defaultDatacenter": { "datacenterId": 5400, "nickname": "Default Mapping" }, "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/geographic-maps/UK%20Delivery", "rel": "self" } ], "name": "testGeoMap" }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) testGeoMap := instantiateGeoMap() _, err := testGeoMap.Update(gtmTestDomain) assert.NoError(t, err) } func TestDeleteGeoMap(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/geographic-maps/" + GtmTestGeoMap) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/geographic-maps/"+GtmTestGeoMap). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { }, "status" : { "changeId": "93a48b86-4fc3-4a5f-9ca2-036835034cc6", "links": [ { "href": "/config-gtm/v1/domains/example.akadns.net/status/current", "rel": "self" } ], "message": "Change Pending", "passingValidation": true, "propagationStatus": "PENDING", "propagationStatusDate": "2014-04-15T11:30:27.000+0000" } }`) Init(config) getGeoMap := instantiateGeoMap() stat, err := getGeoMap.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "93a48b86-4fc3-4a5f-9ca2-036835034cc6", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/property.go000066400000000000000000000247101400161560600275430ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "fmt" ) // // Support gtm domain properties thru Edgegrid // Based on 1.4 Schema // // TrafficTarget struc 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"` } // HttpHeader struc type HttpHeader struct { Name string `json:"name"` Value string `json:"value"` } 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"` 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"` 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"` } // StaticRRSet Struct type StaticRRSet struct { Type string `json:"type"` TTL int `json:"ttl"` Rdata []string `json:"rdata"` } // 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"` } type PropertyList struct { PropertyItems []*Property `json:"items"` } // NewTrafficTarget is a method applied to a property object that instantiates a TrafficTarget object. func (prop *Property) NewTrafficTarget() *TrafficTarget { return &TrafficTarget{} } // NewStaticRRSet is a method applied to a property object that instantiates a StaticRRSet object. func (prop *Property) NewStaticRRSet() *StaticRRSet { return &StaticRRSet{} } // NewHttpHeader is a method applied to a livenesstest object that instantiates an HttpHeader object. func (lt *LivenessTest) NewHttpHeader() *HttpHeader { return &HttpHeader{} } // NewLivenessTest is a method applied to a property object that instantiates a LivenessTest object. func (prop *Property) NewLivenessTest(name string, objproto string, interval int, timeout float32) *LivenessTest { return &LivenessTest{Name: name, TestInterval: interval, TestObjectProtocol: objproto, TestTimeout: timeout} } // NewProperty creates a new Property object. func NewProperty(name string) *Property { property := &Property{Name: name} return property } // ListProperties retreieves all Properties for the provided domainName. func ListProperties(domainName string) ([]*Property, error) { properties := &PropertyList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/properties", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Domain", name: domainName} } else { err = client.BodyJSON(res, properties) if err != nil { return nil, err } return properties.PropertyItems, nil } } // GetProperty retrieves a Property with the given name. func GetProperty(name, domainName string) (*Property, error) { property := NewProperty(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Property", name: name} } else { err = client.BodyJSON(res, property) if err != nil { return nil, err } return property, nil } } // Create the property in the receiver argument in the specified domain. func (property *Property) Create(domainName string) (*PropertyResponse, error) { // Need do any validation? return property.save(domainName) } // Update the property in the receiver argument in the specified domain. func (property *Property) Update(domainName string) (*ResponseStatus, error) { // Need do any validation? stat, err := property.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save Property updates method func (property *Property) save(domainName string) (*PropertyResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, property.Name), property, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Property", name: property.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Property", name: property.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &PropertyResponse{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete the property identified by the receiver argument from the domain provided. func (property *Property) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/properties/%s", domainName, property.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Property", name: property.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Property", name: property.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/property_test.go000066400000000000000000000440761400161560600306110ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "fmt" ) var GtmTestProperty = "testproperty" func instantiateProperty() *Property { property := NewProperty(GtmTestProperty) propertyData := []byte(`{ "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }`) jsonhooks.Unmarshal(propertyData, property) return property } // Verify GetListProperties. Should pass, e.g. no API errors and non nil list. func TestListProperties(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items": [ { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] } ] }`) Init(config) propertyList, err := ListProperties(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, propertyList, nil) if len(propertyList) > 0 { firstProp := propertyList[0] assert.Equal(t, firstProp.Name, GtmTestProperty) } else { assert.Equal(t, 0, 1, "ListProperties: empty list") fmt.Println("ListProperties: empty list") } } // Verify GetProperty. Name hardcoded. Should pass, e.g. no API errors and property returned // Depends on CreateProperty func TestGetProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }`) Init(config) testProperty, err := GetProperty(GtmTestProperty, gtmTestDomain) assert.NoError(t, err) assert.Equal(t, GtmTestProperty, testProperty.Name) } // Verify failed case for GetProperty. Should pass, e.g. no API errors and domain not found func TestGetBadProperty(t *testing.T) { boguspropertyname := "boguspropertyname" defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + boguspropertyname) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+boguspropertyname). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetProperty("boguspropertyname", gtmTestDomain) assert.Error(t, err) } // Test Create property. Name is hardcoded so this will effectively be an update. What happens to existing? func TestCreateProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 1, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }, "status" : { "message" : "Change Pending", "changeId" : "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:46:18.461+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) // initialize required fields testProperty := NewProperty(GtmTestProperty) testProperty.ScoreAggregationType = "median" testProperty.Type = "performance" testProperty.HandoutLimit = 1 testProperty.HandoutMode = "normal" testProperty.FailoverDelay = 0 testProperty.FailbackDelay = 0 testProperty.TrafficTargets = []*TrafficTarget{&TrafficTarget{DatacenterId: 3131, Enabled: true, Servers: []string{"1.2.3.4"}, Weight: 100.0}} statresp, err := testProperty.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Property{}, statresp.Resource) assert.Equal(t, GtmTestProperty, statresp.Resource.Name) } func TestUpdateProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "backupCName" : null, "backupIp" : null, "balanceByDownloadScore" : false, "cname" : null, "comments" : null, "dynamicTTL" : 300, "failoverDelay" : null, "failbackDelay" : null, "ghostDemandReporting" : false, "handoutMode" : "normal", "handoutLimit" : 999, "healthMax" : null, "healthMultiplier" : null, "healthThreshold" : null, "lastModified" : "2019-06-14T19:46:17.818+00:00", "livenessTests" : [ ], "loadImbalancePercentage" : null, "mapName" : null, "maxUnreachablePenalty" : null, "minLiveFraction" : null, "mxRecords" : [ ], "name" : "testproperty", "scoreAggregationType" : "median", "stickinessBonusConstant" : null, "stickinessBonusPercentage" : null, "staticTTL" : null, "trafficTargets" : [ { "datacenterId" : 3131, "enabled" : true, "weight" : 100.0, "handoutCName" : null, "name" : null, "servers" : [ "1.2.3.4" ] } ], "type" : "performance", "unreachableThreshold" : null, "useComputedTargets" : false, "weightedHashBitsForIPv4" : null, "weightedHashBitsForIPv6" : null, "ipv6" : false, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/properties/testproperty" } ] }, "status" : { "message" : "Change Pending", "changeId" : "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:46:18.461+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testProperty := instantiateProperty() testProperty.HandoutLimit = 999 stat, err := testProperty.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "ca4ca7a9-2b87-4f7c-8ba6-0cb1571df325") } func TestDeleteProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/properties/" + GtmTestProperty) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) getProperty := instantiateProperty() _, err := getProperty.Delete(gtmTestDomain) assert.NoError(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/resource.go000066400000000000000000000142231400161560600275040ustar00rootroot00000000000000package configgtm import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) // // Handle Operations on gtm resources // Based on 1.4 schema // // ResourceInstance type ResourceInstance struct { DatacenterId int `json:"datacenterId"` UseDefaultLoadObject bool `json:"useDefaultLoadObject"` LoadObject } // 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"` } // ResourceList is the structure returned by List Resources type ResourceList struct { ResourceItems []*Resource `json:"items"` } // NewResourceInstance instantiates a new ResourceInstance. func (rsrc *Resource) NewResourceInstance(dcID int) *ResourceInstance { return &ResourceInstance{DatacenterId: dcID} } // NewResource creates a new Resource object. func NewResource(name string) *Resource { resource := &Resource{Name: name} return resource } // ListResources retreieves all Resources in the specified domain. func ListResources(domainName string) ([]*Resource, error) { rsrcs := &ResourceList{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/resources", domainName), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Resources"} } err = client.BodyJSON(res, rsrcs) if err != nil { return nil, err } return rsrcs.ResourceItems, nil } // GetResource retrieves a Resource with the given name in the specified domain. func GetResource(name, domainName string) (*Resource, error) { rsc := NewResource(name) req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { return nil, CommonError{entityName: "Resource", name: name} } else { err = client.BodyJSON(res, rsc) if err != nil { return nil, err } return rsc, nil } } // Create the resource identified by the receiver argument in the specified domain. func (rsrc *Resource) Create(domainName string) (*ResourceResponse, error) { // Use common code. Any specific validation needed? return rsrc.save(domainName) } // Update the resourceidentified in the receiver argument in the specified domain. func (rsrc *Resource) Update(domainName string) (*ResponseStatus, error) { // common code stat, err := rsrc.save(domainName) if err != nil { return nil, err } return stat.Status, err } // Save Resource in given domain. Common path for Create and Update. func (rsrc *Resource) save(domainName string) (*ResourceResponse, error) { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, rsrc.Name), rsrc, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) // Network error if err != nil { return nil, CommonError{ entityName: "Resource", name: rsrc.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Resource", name: rsrc.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResourceResponse{} // Unmarshall whole response body for updated entity and in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody, nil } // Delete the resource identified in the receiver argument from the specified domain. func (rsrc *Resource) Delete(domainName string) (*ResponseStatus, error) { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf("/config-gtm/v1/domains/%s/resources/%s", domainName, rsrc.Name), nil, ) if err != nil { return nil, err } setVersionHeader(req, schemaVersion) printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // Network error if err != nil { return nil, CommonError{ entityName: "Resource", name: rsrc.Name, httpErrorMessage: err.Error(), err: err, } } printHttpResponse(res, true) // API error if client.IsError(res) { err := client.NewAPIError(res) return nil, CommonError{entityName: "Resource", name: rsrc.Name, apiErrorMessage: err.Detail, err: err} } responseBody := &ResponseBody{} // Unmarshall whole response body in case want status err = client.BodyJSON(res, responseBody) if err != nil { return nil, err } return responseBody.Status, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/resource_test.go000066400000000000000000000331041400161560600305420ustar00rootroot00000000000000package configgtm import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var GtmTestResource = "testResource" func instantiateResource() *Resource { resource := NewResource("dummy") resourceData := []byte(`{ "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }`) jsonhooks.Unmarshal(resourceData, resource) return resource } // Verify ListResources. Should pass, e.g. no API errors and non nil list. func TestListResources(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "items" : [ { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] } ] }`) Init(config) resourceList, err := ListResources(gtmTestDomain) assert.NoError(t, err) assert.NotEqual(t, resourceList, nil) if len(resourceList) > 0 { firstResource := resourceList[0] assert.Equal(t, firstResource.Name, GtmTestResource) } else { t.Fatal("List empty!") } } // Depends on CreateResource func TestGetResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }`) Init(config) testResource, err := GetResource(GtmTestResource, gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Resource{}, testResource) assert.Equal(t, GtmTestResource, testResource.Name) } // Verify failed case for GetResource. Should pass, e.g. no API errors and domain not found func TestGetBadResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/somebadname") mock. Get("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/somebadname"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ }`) Init(config) _, err := GetResource("somebadname", gtmTestDomain) // Shouldn't have found assert.Error(t, err) } // Test Create resource. func TestCreateResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : null, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }, "status" : { "message" : "Change Pending", "changeId" : "5bb9f131-99c8-43ff-afd2-a6ce34db8b95", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-17T17:54:37.383+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testResource := NewResource(GtmTestResource) testResource.AggregationType = "median" testResource.Type = "Download score" // Create a Resource Instance var instanceSlice []*ResourceInstance instance := testResource.NewResourceInstance(3131) instanceSlice = append(instanceSlice, instance) testResource.ResourceInstances = instanceSlice // do the create statresp, err := testResource.Create(gtmTestDomain) assert.NoError(t, err) assert.IsType(t, &Resource{}, statresp.Resource) assert.Equal(t, GtmTestResource, statresp.Resource.Name) } func TestUpdateResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Put("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : { "aggregationType" : "median", "constrainedProperty" : null, "decayRate" : 0.5, "description" : null, "hostHeader" : null, "leaderString" : null, "leastSquaresDecay" : null, "loadImbalancePercentage" : null, "maxUMultiplicativeIncrement" : null, "name" : "testResource", "resourceInstances" : [ { "loadObject" : "", "loadObjectPort" : 0, "loadServers" : null, "datacenterId" : 3131, "useDefaultLoadObject" : false } ], "type" : "Download score", "upperBound" : 0, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/resources/testResource" } ] }, "status" : { "message" : "Change Pending", "changeId" : "5bb9f131-99c8-43ff-afd2-a6ce34db8b95", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-17T17:54:37.383+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) testResource := instantiateResource() newDecay := 0.5 testResource.DecayRate = newDecay stat, err := testResource.Update(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, stat.ChangeId, "5bb9f131-99c8-43ff-afd2-a6ce34db8b95") } func TestDeleteResource(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/config-gtm/v1/domains/" + gtmTestDomain + "/resources/" + GtmTestResource) mock. Delete("/config-gtm/v1/domains/"+gtmTestDomain+"/resources/"+GtmTestResource). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/vnd.config-gtm.v1.4+json;charset=UTF-8"). BodyString(`{ "resource" : null, "status" : { "message" : "Change Pending", "changeId" : "9a7a8f84-704b-40de-a903-bcc2728513ac", "propagationStatus" : "PENDING", "propagationStatusDate" : "2019-06-14T19:51:02.273+00:00", "passingValidation" : true, "links" : [ { "rel" : "self", "href" : "https://akaa-32qkzqewderdchot-d3uwbyqc4pqi2c5l.luna-dev.akamaiapis.net/config-gtm/v1/domains/gtmdomtest.akadns.net/status/current" } ] } }`) Init(config) getResource := instantiateResource() stat, err := getResource.Delete(gtmTestDomain) assert.NoError(t, err) assert.Equal(t, "9a7a8f84-704b-40de-a903-bcc2728513ac", stat.ChangeId) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/configgtm-v1_4/service.go000066400000000000000000000011551400161560600273150ustar00rootroot00000000000000package configgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "net/http" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the GTM edgegrid Config func Init(config edgegrid.Config) { Config = config edgegrid.SetupLogging() } // Utility func to print http req func printHttpRequest(req *http.Request, body bool) { edgegrid.PrintHttpRequest(req, body) } // Utility func to print http response func printHttpResponse(res *http.Response, body bool) { edgegrid.PrintHttpResponse(res, body) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/cps-v2/000077500000000000000000000000001400161560600237125ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/cps-v2/certificate_settings.go000066400000000000000000000105131400161560600304430ustar00rootroot00000000000000package cps type RegistrationAuthority string type CertificateType string type AkamaiCipher string type NetworkType string type OCSPSetting string type TLSType string type SHA string type ValidationType string const ( LetsEncryptRA RegistrationAuthority = "letsencrypt" SymantecRA RegistrationAuthority = "symantec" ThirdPartyRA RegistrationAuthority = "third-party" SanCertificate CertificateType = "san" SymantecCertificate CertificateType = "single" WildCardCertificate CertificateType = "wildcard" WildCardSanCertificate CertificateType = "wildcard-san" ThirdPartyCertificate CertificateType = "third-party" AK2018Q3 AkamaiCipher = "ak-akamai-2018q3" AK2017Q3 AkamaiCipher = "ak-akamai-default-2017q3" AK2016Q3 AkamaiCipher = "ak-akamai-default-2016q3" AKPCIDSS AkamaiCipher = "ak-pci-dss-3.2" AKDefault AkamaiCipher = "ak-akamai-default" AK2016Q1 AkamaiCipher = "ak-akamai-default-2016q1" AKPFSSupported AkamaiCipher = "ak-akamai-pfs-supported" AKPFS AkamaiCipher = "ak-akamai-pfs" AKRecommended AkamaiCipher = "ak-akamai-recommended" AKSoftErrors AkamaiCipher = "ak-soft-errors" AKSoftErrorsWithExport AkamaiCipher = "ak-soft-errors-with-export" AKTLS AkamaiCipher = "ak-akamai-tls-1.2" AKPCIDSSDefault AkamaiCipher = "ak-pci-dss" AKPCIDSS3 AkamaiCipher = "ak-pci-dss-3.1" StandardWorldWide NetworkType = "standard-worldwide" WorldWideRussia NetworkType = "worldwide-russia" WorldWide NetworkType = "worldwide" StandardTLS TLSType = "standard-tls" EnhancedTLS TLSType = "enhanced-tls" SHA1 SHA = "SHA-1" SHA256 SHA = "SHA-256" DomainValidation ValidationType = "dv" OrganizationValidation ValidationType = "ov" ExtendedValidation ValidationType = "ev" ThirdPartyValidation ValidationType = "third-party" ) type Contact struct { FirstName *string `json:"firstName"` LastName *string `json:"lastName"` Title *string `json:"title"` Organization *string `json:"organizationName"` Email *string `json:"email"` Phone *string `json:"phone"` AddressLineOne *string `json:"addressLineOne"` AddressLineTwo *string `json:"addressLineTwo"` City *string `json:"city"` Region *string `json:"region"` PostalCode *string `json:"postalCode"` Country *string `json:"country"` } type Organization struct { Name *string `json:"name"` Phone *string `json:"phone"` AddressLineOne *string `json:"addressLineOne"` AddressLineTwo *string `json:"addressLineTwo"` City *string `json:"city"` Region *string `json:"region"` PostalCode *string `json:"postalCode"` Country *string `json:"country"` } type CSR struct { CommonName string `json:"cn"` AlternativeNames *[]string `json:"sans"` City *string `json:"l"` State *string `json:"st"` CountryCode *string `json:"c"` Organization *string `json:"o"` OrganizationalUnit *string `json:"ou"` } type DomainNameSettings struct { CloneDomainNames bool `json:"cloneDnsNames"` DomainNames *[]string `json:"dnsNames"` } type NetworkConfiguration struct { DisallowedTLSVersions *[]string `json:"disallowedTlsVersions"` DomainNameSettings *DomainNameSettings `json:"dnsNameSettings"` Geography string `json:"geography"` MustHaveCiphers AkamaiCipher `json:"mustHaveCiphers"` // NetworkType *NetworkType `json:"networkType"` OCSPStapling *OCSPSetting `json:"ocspStapling"` PreferredCiphers AkamaiCipher `json:"preferredCiphers"` QUICEnabled bool `json:"quicEnabled"` SecureNetwork TLSType `json:"secureNetwork"` // ServerNameIndication *DomainNameSettings `json:"sni"` SNIOnly bool `json:"sniOnly"` } type ThirdParty struct { ExcludeSANS bool `json:"excludeSans"` } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/cps-v2/certificate_settings_test.go000066400000000000000000000004011400161560600314750ustar00rootroot00000000000000package cps import ( "testing" //cps "github.com/akamai/AkamaiOPEN-edgegrid-golang/cps-v2" "github.com/stretchr/testify/assert" ) func TestSHAConversion(t *testing.T) { assert.NotEqual(t, "dosty", "everts") assert.Equal(t, SHA256, SHA("SHA-256")) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/cps-v2/enrollments.go000066400000000000000000000123711400161560600266070ustar00rootroot00000000000000package cps import ( "encoding/json" "fmt" "time" client "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" ) // Enrollments represents an enrollment // // API Docs: https://developer.akamai.com/api/core_features/certificate_provisioning_system/v2.html#enrollments type Enrollment struct { client.Resource AdminContact *Contact `json:"adminContact"` CertificateChainType *string `json:"certificateChainType"` CertificateType CertificateType `json:"certificateType"` CertificateSigningRequest *CSR `json:"csr"` ChangeManagement bool `json:"changeManagement"` EnableMultiStacked bool `json:"enableMultiStackedCertificates"` Location *string `json:"location"` MaxAllowedSans *int `json:"maxAllowedSanNames"` MaxAllowedWildcardSans *int `json:"maxAllowedWildcardSanNames"` NetworkConfiguration *NetworkConfiguration `json:"networkConfiguration"` Organization *Organization `json:"org"` PendingChanges *[]string `json:"pendingChanges"` RegistrationAuthority RegistrationAuthority `json:"ra"` SignatureAuthority *SHA `json:"signatureAlgorithm"` TechContact *Contact `json:"techContact"` ThirdParty *ThirdParty `json:"thirdParty"` ValidationType ValidationType `json:"validationType"` } type CreateEnrollmentQueryParams struct { ContractID string DeployNotAfter *string DeployNotBefore *string } type ListEnrollmentsQueryParams struct { ContractID string } type CreateEnrollmentResponse struct { Location string `json:"enrollment"` Changes []string `json:"changes"` } func formatTime(t time.Time) string { return fmt.Sprintf("%d-%02d-%02d", t.Year(), t.Month(), t.Day()) } // Create an Enrollment on CPS // // // API Docs: https://developer.akamai.com/api/core_features/certificate_provisioning_system/v2.html#5aaa335c // Endpoint: POST /cps/v2/enrollments{?contractId,deploy-not-after,deploy-not-before} func (enrollment *Enrollment) Create(params CreateEnrollmentQueryParams) (*CreateEnrollmentResponse, error) { var request = fmt.Sprintf( "/cps/v2/enrollments?contractId=%s", params.ContractID, ) if params.DeployNotAfter != nil { request = fmt.Sprintf( "%s&deploy-not-after=%s", request, *params.DeployNotAfter, ) } if params.DeployNotBefore != nil { request = fmt.Sprintf( "%s&deploy-not-before=%s", request, *params.DeployNotBefore, ) } req, err := newRequest( "POST", request, enrollment, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } var response CreateEnrollmentResponse if err = client.BodyJSON(res, &response); err != nil { return nil, err } return &response, nil } // Get an enrollment by location // // // API Docs: https://developer.akamai.com/api/core_features/certificate_provisioning_system/v2.html#getasingleenrollment // Endpoint: POST /cps/v2/enrollments/{enrollmentId} func GetEnrollment(location string) (*Enrollment, error) { req, err := client.NewRequest( Config, "GET", location, nil, ) if err != nil { return nil, err } req.Header.Add("Accept", "application/vnd.akamai.cps.enrollment.v7+json") res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } var response Enrollment if err = client.BodyJSON(res, &response); err != nil { return nil, err } return &response, nil } // ListEnrollments lists the names of each enrollment for the given contractID. // // API Docs: https://developer.akamai.com/api/core_features/certificate_provisioning_system/v2.html#getenrollments // Endpoint: GET /cps/v2/enrollments{contractId} func ListEnrollments(params ListEnrollmentsQueryParams) ([]Enrollment, error) { // the returned JSON is a list in the enrollments parameter enrollmentsResponse := struct { Enrollments []Enrollment `json:"enrollments"` }{} req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/cps/v2/enrollments?contractId=%s", params.ContractID, ), nil, ) if err != nil { return nil, err } req.Header.Set("Accept", "application/vnd.akamai.cps.enrollments.v7+json") res, err := client.Do(Config, req) if err != nil { return nil, err } if client.IsError(res) { return nil, client.NewAPIError(res) } if err = client.BodyJSON(res, &enrollmentsResponse); err != nil { return nil, err } return enrollmentsResponse.Enrollments, nil } func (enrollment *Enrollment) Exists(enrollments []Enrollment) bool { for _, e := range enrollments { if e.CertificateSigningRequest.CommonName == enrollment.CertificateSigningRequest.CommonName { return true } } return false } // CreateEnrollment wraps enrollment.Create to accept json func CreateEnrollment(data []byte, params CreateEnrollmentQueryParams) (*CreateEnrollmentResponse, error) { var enrollment Enrollment if err := json.Unmarshal(data, &enrollment); err != nil { return nil, err } return enrollment.Create(params) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/cps-v2/service.go000066400000000000000000000016711400161560600257060ustar00rootroot00000000000000package cps import ( "bytes" "encoding/json" "log" "net/http" client "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the CPS edgegrid Config func Init(config edgegrid.Config) { Config = config } func newRequest(method, urlStr string, body interface{}) (*http.Request, error) { buf := new(bytes.Buffer) err := json.NewEncoder(buf).Encode(body) if err != nil { return nil, err } log.Printf("[DEBUG] newRequest, buf: %s", string(buf.Bytes())) req, err := client.NewRequest(Config, method, urlStr, buf) if err != nil { return nil, err } req.Header.Add("Content-Type", "application/vnd.akamai.cps.enrollment.v7+json") req.Header.Add("Accept", "application/vnd.akamai.cps.enrollment-status.v1+json") return req, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid.go000066400000000000000000000246041400161560600247070ustar00rootroot00000000000000// Package edgegrid provides the Akamai OPEN Edgegrid Authentication scheme // // Deprecated: use edgegrid/config and edgegrid/signer instead package edgegrid import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/base64" "fmt" "io/ioutil" "net/http" "os" "sort" "strconv" "strings" "time" "unicode" "github.com/google/uuid" "github.com/mitchellh/go-homedir" log "github.com/sirupsen/logrus" "gopkg.in/ini.v1" ) const defaultSection = "DEFAULT" // Config struct provides all the necessary fields to // create authorization header, debug is optional // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid type Config struct { Host string `ini:"host"` ClientToken string `ini:"client_token"` ClientSecret string `ini:"client_secret"` AccessToken string `ini:"access_token"` HeaderToSign []string `ini:"headers_to_sign"` MaxBody int `ini:"max_body"` Debug bool `ini:"debug"` } // Must be assigned the UTC time when the request is signed. // Format of “yyyyMMddTHH:mm:ss+0000” func makeEdgeTimeStamp() string { local := time.FixedZone("GMT", 0) t := time.Now().In(local) return fmt.Sprintf("%d%02d%02dT%02d:%02d:%02d+0000", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) } // Must be assigned a nonce (number used once) for the request. // It is a random string used to detect replayed request messages. // A GUID is recommended. func createNonce() string { uuid, err := uuid.NewRandom() if err != nil { log.Errorf("Generate Uuid failed, %s", err) return "" } return uuid.String() } func stringMinifier(in string) (out string) { white := false for _, c := range in { if unicode.IsSpace(c) { if !white { out = out + " " } white = true } else { out = out + string(c) white = false } } return } func concatPathQuery(path, query string) string { if query == "" { return path } return fmt.Sprintf("%s?%s", path, query) } // createSignature is the base64-encoding of the SHA–256 HMAC of the data to sign with the signing key. func createSignature(message string, secret string) string { key := []byte(secret) h := hmac.New(sha256.New, key) h.Write([]byte(message)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } func createHash(data string) string { h := sha256.Sum256([]byte(data)) return base64.StdEncoding.EncodeToString(h[:]) } func (c *Config) canonicalizeHeaders(req *http.Request) string { var unsortedHeader []string var sortedHeader []string for k := range req.Header { unsortedHeader = append(unsortedHeader, k) } sort.Strings(unsortedHeader) for _, k := range unsortedHeader { for _, sign := range c.HeaderToSign { if sign == k { v := strings.TrimSpace(req.Header.Get(k)) sortedHeader = append(sortedHeader, fmt.Sprintf("%s:%s", strings.ToLower(k), strings.ToLower(stringMinifier(v)))) } } } return strings.Join(sortedHeader, "\t") } // signingKey is derived from the client secret. // The signing key is computed as the base64 encoding of the SHA–256 HMAC of the timestamp string // (the field value included in the HTTP authorization header described above) with the client secret as the key. func (c *Config) signingKey(timestamp string) string { key := createSignature(timestamp, c.ClientSecret) return key } // The content hash is the base64-encoded SHA–256 hash of the POST body. // For any other request methods, this field is empty. But the tac separator (\t) must be included. // The size of the POST body must be less than or equal to the value specified by the service. // Any request that does not meet this criteria SHOULD be rejected during the signing process, // as the request will be rejected by EdgeGrid. func (c *Config) createContentHash(req *http.Request) string { var ( contentHash string preparedBody string bodyBytes []byte ) if req.Body != nil { bodyBytes, _ = ioutil.ReadAll(req.Body) req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) preparedBody = string(bodyBytes) } log.Debugf("Body is %s", preparedBody) if req.Method == "POST" && len(preparedBody) > 0 { log.Debugf("Signing content: %s", preparedBody) if len(preparedBody) > c.MaxBody { log.Debugf("Data length %d is larger than maximum %d", len(preparedBody), c.MaxBody) preparedBody = preparedBody[0:c.MaxBody] log.Debugf("Data truncated to %d for computing the hash", len(preparedBody)) } contentHash = createHash(preparedBody) } log.Debugf("Content hash is '%s'", contentHash) return contentHash } // The data to sign includes the information from the HTTP request that is relevant to ensuring that the request is authentic. // This data set comprised of the request data combined with the authorization header value (excluding the signature field, // but including the ; right before the signature field). func (c *Config) signingData(req *http.Request, authHeader string) string { dataSign := []string{ req.Method, req.URL.Scheme, req.URL.Host, concatPathQuery(req.URL.Path, req.URL.RawQuery), c.canonicalizeHeaders(req), c.createContentHash(req), authHeader, } log.Debugf("Data to sign %s", strings.Join(dataSign, "\t")) return strings.Join(dataSign, "\t") } func (c *Config) signingRequest(req *http.Request, authHeader string, timestamp string) string { return createSignature(c.signingData(req, authHeader), c.signingKey(timestamp)) } // The Authorization header starts with the signing algorithm moniker (name of the algorithm) used to sign the request. // The moniker below identifies EdgeGrid V1, hash message authentication code, SHA–256 as the hash standard. // This moniker is then followed by a space and an ordered list of name value pairs with each field separated by a semicolon. func (c *Config) createAuthHeader(req *http.Request, timestamp string, nonce string) string { authHeader := fmt.Sprintf("EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;", c.ClientToken, c.AccessToken, timestamp, nonce, ) log.Debugf("Unsigned authorization header: '%s'", authHeader) signedAuthHeader := fmt.Sprintf("%ssignature=%s", authHeader, c.signingRequest(req, authHeader, timestamp)) log.Debugf("Signed authorization header: '%s'", signedAuthHeader) return signedAuthHeader } // AddRequestHeader sets the authorization header to use Akamai Open API // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid func AddRequestHeader(c Config, req *http.Request) *http.Request { return c.AddRequestHeader(req) } // AddRequestHeader set the authorization header to use Akamai OPEN API // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid func (c Config) AddRequestHeader(req *http.Request) *http.Request { if c.Debug { log.SetLevel(log.DebugLevel) } timestamp := makeEdgeTimeStamp() nonce := createNonce() req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", c.createAuthHeader(req, timestamp, nonce)) return req } // InitEdgeRc initializes Config using an .edgerc (INI) configuration file // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid func InitEdgeRc(filepath string, section string) (Config, error) { var ( c Config requiredOptions = []string{"host", "client_token", "client_secret", "access_token"} missing []string ) // Check if filepath is empty if filepath == "" { filepath = "~/.edgerc" } // Check if section is empty if section == "" { section = "default" } path, err := homedir.Expand(filepath) if err != nil { return c, fmt.Errorf("Fatal could not find home dir from user: %s", err) } edgerc, err := ini.Load(path) if err != nil { return c, fmt.Errorf("Fatal error config file: %s", err) } err = edgerc.Section(section).MapTo(&c) if err != nil { return c, fmt.Errorf("Could not map section: %s", err) } for _, opt := range requiredOptions { if !(edgerc.Section(section).HasKey(opt)) { missing = append(missing, opt) } } if len(missing) > 0 { return c, fmt.Errorf("Fatal missing required options: %s", missing) } if c.MaxBody == 0 { c.MaxBody = 131072 } return c, nil } // InitEnv initializes Config using ENV variables // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid func InitEnv(section string) (Config, error) { var ( c Config requiredOptions = []string{"HOST", "CLIENT_TOKEN", "CLIENT_SECRET", "ACCESS_TOKEN"} missing []string prefix string ) // Check if section is empty if section == "" { section = defaultSection } else { section = strings.ToUpper(section) } prefix = "AKAMAI_" _, ok := os.LookupEnv("AKAMAI_" + section + "_HOST") if ok { prefix = "AKAMAI_" + section + "_" } for _, opt := range requiredOptions { val, ok := os.LookupEnv(prefix + opt) if !ok { missing = append(missing, prefix+opt) } else { switch { case opt == "HOST": c.Host = val case opt == "CLIENT_TOKEN": c.ClientToken = val case opt == "CLIENT_SECRET": c.ClientSecret = val case opt == "ACCESS_TOKEN": c.AccessToken = val } } } if len(missing) > 0 { return c, fmt.Errorf("Fatal missing required environment variables: %s", missing) } c.MaxBody = 0 val, ok := os.LookupEnv(prefix + "MAX_BODY") if i, err := strconv.Atoi(val); err == nil { c.MaxBody = i } if !ok || c.MaxBody == 0 { c.MaxBody = 131072 } return c, nil } // InitConfig initializes Config using .edgerc files // // Deprecated: Backwards compatible wrapper around InitEdgeRc which should be used instead func InitConfig(filepath string, section string) Config { c, err := InitEdgeRc(filepath, section) if err != nil { log.Panic(err.Error()) } return c } // Init initializes Config using first ENV variables, with fallback to .edgerc file // // Deprecated: use github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid func Init(filepath string, section string) (Config, error) { if section == "" { section = defaultSection } else { section = strings.ToUpper(section) } _, exists := os.LookupEnv("AKAMAI_" + section + "_HOST") if !exists && section == defaultSection { _, exists := os.LookupEnv("AKAMAI_HOST") if exists { return InitEnv("") } } if exists { return InitEnv(section) } c, err := InitEdgeRc(filepath, strings.ToLower(section)) if err == nil { return c, nil } if section != defaultSection { _, ok := os.LookupEnv("AKAMAI_HOST") if ok { return InitEnv("") } } return c, fmt.Errorf("Unable to create instance using environment or .edgerc file") } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/000077500000000000000000000000001400161560600243525ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/README.md000066400000000000000000000002231400161560600256260ustar00rootroot00000000000000# Akamai Edgegrid A golang package which facilitates authenticating and signing requests made to [Akamai OPEN APIs](https://developer.akamai.com).golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/config.go000066400000000000000000000102341400161560600261460ustar00rootroot00000000000000package edgegrid import ( "fmt" "os" "strconv" "strings" "github.com/mitchellh/go-homedir" "gopkg.in/ini.v1" ) // Config struct provides all the necessary fields to // create authorization header, debug is optional type Config struct { Host string `ini:"host"` ClientToken string `ini:"client_token"` ClientSecret string `ini:"client_secret"` AccessToken string `ini:"access_token"` AccountKey string `ini:"account_key"` HeaderToSign []string `ini:"headers_to_sign"` MaxBody int `ini:"max_body"` Debug bool `ini:"debug"` } // Init initializes by first attempting to use ENV vars, with .edgerc as a fallback // // See: InitEnv() // See: InitEdgeRc() func Init(filepath string, section string) (Config, error) { if section == "" { section = defaultSection } else { section = strings.ToUpper(section) } _, exists := os.LookupEnv("AKAMAI_" + section + "_HOST") if !exists && section == defaultSection { _, exists := os.LookupEnv("AKAMAI_HOST") if exists { return InitEnv("") } } if exists { return InitEnv(section) } c, err := InitEdgeRc(filepath, strings.ToLower(section)) if err == nil { return c, nil } if section != defaultSection { _, ok := os.LookupEnv("AKAMAI_HOST") if ok { return InitEnv("") } } return c, fmt.Errorf("Unable to create instance using environment or .edgerc file") } // InitEdgeRc initializes using a configuration file in standard INI format // // By default, it uses the .edgerc found in the users home directory, and the // "default" section. func InitEdgeRc(filepath string, section string) (Config, error) { var ( c Config requiredOptions = []string{"host", "client_token", "client_secret", "access_token"} missing []string ) // Check if filepath is empty if filepath == "" { filepath = "~/.edgerc" } // Check if section is empty if section == "" { section = "default" } // Tilde seems to be not working when passing ~/.edgerc as file // Takes current user and use home dir instead path, err := homedir.Expand(filepath) if err != nil { return c, fmt.Errorf(errorMap[ErrHomeDirNotFound], err) } edgerc, err := ini.Load(path) if err != nil { return c, fmt.Errorf(errorMap[ErrConfigFile], err) } err = edgerc.Section(section).MapTo(&c) if err != nil { return c, fmt.Errorf(errorMap[ErrConfigFileSection], err) } for _, opt := range requiredOptions { if !(edgerc.Section(section).HasKey(opt)) { missing = append(missing, opt) } } if len(missing) > 0 { return c, fmt.Errorf(errorMap[ErrConfigMissingOptions], missing) } if c.MaxBody == 0 { c.MaxBody = 131072 } return c, nil } // InitEnv initializes using the Environment (ENV) // // By default, it uses AKAMAI_HOST, AKAMAI_CLIENT_TOKEN, AKAMAI_CLIENT_SECRET, // AKAMAI_ACCESS_TOKEN, and AKAMAI_MAX_BODY variables. // // You can define multiple configurations by prefixing with the section name specified, e.g. // passing "ccu" will cause it to look for AKAMAI_CCU_HOST, etc. // // If AKAMAI_{SECTION} does not exist, it will fall back to just AKAMAI_. func InitEnv(section string) (Config, error) { var ( c Config requiredOptions = []string{"HOST", "CLIENT_TOKEN", "CLIENT_SECRET", "ACCESS_TOKEN"} missing []string prefix string ) // Check if section is empty if section == "" { section = defaultSection } else { section = strings.ToUpper(section) } prefix = "AKAMAI_" _, ok := os.LookupEnv("AKAMAI_" + section + "_HOST") if ok { prefix = "AKAMAI_" + section + "_" } for _, opt := range requiredOptions { val, ok := os.LookupEnv(prefix + opt) if !ok { missing = append(missing, prefix+opt) } else { switch { case opt == "HOST": c.Host = val case opt == "CLIENT_TOKEN": c.ClientToken = val case opt == "CLIENT_SECRET": c.ClientSecret = val case opt == "ACCESS_TOKEN": c.AccessToken = val } } } if len(missing) > 0 { return c, fmt.Errorf(errorMap[ErrMissingEnvVariables], missing) } c.MaxBody = 0 val, ok := os.LookupEnv(prefix + "MAX_BODY") if i, err := strconv.Atoi(val); err == nil { c.MaxBody = i } if !ok || c.MaxBody == 0 { c.MaxBody = 131072 } return c, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/config_test.go000066400000000000000000000177151400161560600272200ustar00rootroot00000000000000package edgegrid import ( "os" "testing" "github.com/stretchr/testify/assert" ) func TestInitEdgeRc(t *testing.T) { var configDefault = []string{ "", "default", } for _, section := range configDefault { testConfigDefault, err := InitEdgeRc("../testdata/sample_edgerc", section) assert.Equal(t, err, nil) assert.Equal(t, testConfigDefault.ClientToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigDefault.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, testConfigDefault.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigDefault.MaxBody, 131072) assert.Equal(t, testConfigDefault.HeaderToSign, []string(nil)) } } func TestInitEdgeRc_ConfigBroken(t *testing.T) { testSample := "../testdata/sample_edgerc" testConfigBroken, err := InitEdgeRc(testSample, "broken") assert.Equal(t, err, nil) assert.Equal(t, testConfigBroken.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, testConfigBroken.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigBroken.MaxBody, 128*1024) assert.Equal(t, testConfigBroken.HeaderToSign, []string(nil)) } func TestInitEdgeRc_ConfigUnparsable(t *testing.T) { testSample := "../testdata/edgerc_that_doesnt_parse" _, err := InitEdgeRc(testSample, "") assert.Error(t, err) } func TestInitEdgeRc_ConfigNotFound(t *testing.T) { testSample := "edgerc_not_found" _, err := InitEdgeRc(testSample, "") assert.Error(t, err) } func TestInitEdgeRc_ConfigDashes(t *testing.T) { testSample := "../testdata/sample_edgerc" _, err := InitEdgeRc(testSample, "dashes") assert.Error(t, err) } func TestInitEdgeRc_ConfigSection(t *testing.T) { testConfigDefault, err := InitEdgeRc("../testdata/sample_edgerc", "test") assert.Equal(t, err, nil) assert.Equal(t, testConfigDefault.Host, "test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, testConfigDefault.ClientToken, "test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigDefault.ClientSecret, "testxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, testConfigDefault.AccessToken, "test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigDefault.MaxBody, 131072) assert.Equal(t, testConfigDefault.HeaderToSign, []string(nil)) } func TestInitEdgeRc_Broken(t *testing.T) { testSample := "../testdata/sample_edgerc" testConfigBroken, err := InitEdgeRc(testSample, "broken") assert.NoError(t, err) assert.Equal(t, testConfigBroken.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, testConfigBroken.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, testConfigBroken.MaxBody, 128*1024) assert.Equal(t, testConfigBroken.HeaderToSign, []string(nil)) } func TestInitEnv(t *testing.T) { os.Clearenv() err := os.Setenv("AKAMAI_HOST", "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_TOKEN", "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_SECRET", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.NoError(t, err) err = os.Setenv("AKAMAI_ACCESS_TOKEN", "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) c, err := InitEnv("") assert.NoError(t, err) assert.Equal(t, c.Host, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, c.ClientToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, c.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.MaxBody, 131072) assert.Equal(t, c.HeaderToSign, []string(nil)) } func TestInitEnv_Incomplete(t *testing.T) { os.Clearenv() err := os.Setenv("AKAMAI_HOST", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NoError(t, err) _, err = InitEnv("") assert.Error(t, err) assert.Equal(t, err.Error(), "Fatal missing required environment variables: [AKAMAI_CLIENT_TOKEN AKAMAI_CLIENT_SECRET AKAMAI_ACCESS_TOKEN]") } func TestInitEnv_MaxBody(t *testing.T) { os.Clearenv() err := os.Setenv("AKAMAI_HOST", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_TOKEN", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_SECRET", "envxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.NoError(t, err) err = os.Setenv("AKAMAI_ACCESS_TOKEN", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) err = os.Setenv("AKAMAI_MAX_BODY", "42") assert.NoError(t, err) c, err := InitEnv("") assert.NoError(t, err) assert.Equal(t, c.Host, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, c.ClientToken, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.ClientSecret, "envxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, c.AccessToken, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.MaxBody, 42) assert.Equal(t, c.HeaderToSign, []string(nil)) } func TestInit_WithEnv(t *testing.T) { os.Clearenv() err := os.Setenv("AKAMAI_HOST", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_TOKEN", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) err = os.Setenv("AKAMAI_CLIENT_SECRET", "envxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.NoError(t, err) err = os.Setenv("AKAMAI_ACCESS_TOKEN", "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) c, err := InitEnv("") assert.NoError(t, err) assert.Equal(t, c.Host, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, c.ClientToken, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.ClientSecret, "envxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, c.AccessToken, "env-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.MaxBody, 131072) assert.Equal(t, c.HeaderToSign, []string(nil)) } func TestInit_WithoutEnv(t *testing.T) { os.Clearenv() c, err := InitEnv("") assert.Error(t, err) assert.NotEqual(t, c.Host, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NotEqual(t, c.ClientToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NotEqual(t, c.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.NotEqual(t, c.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NotEqual(t, c.MaxBody, 131072) assert.Equal(t, c.HeaderToSign, []string(nil)) } func TestInit_WithSectionEnv(t *testing.T) { os.Clearenv() err := os.Setenv("AKAMAI_TEST_HOST", "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.NoError(t, err) err = os.Setenv("AKAMAI_TEST_CLIENT_TOKEN", "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) err = os.Setenv("AKAMAI_TEST_CLIENT_SECRET", "testenvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.NoError(t, err) err = os.Setenv("AKAMAI_TEST_ACCESS_TOKEN", "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.NoError(t, err) c, err := InitEnv("test") assert.NoError(t, err) assert.Equal(t, c.Host, "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, c.ClientToken, "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.ClientSecret, "testenvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, c.AccessToken, "testenv-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.MaxBody, 131072) assert.Equal(t, c.HeaderToSign, []string(nil)) } func TestInitEdgeRc_NoDefault(t *testing.T) { c, err := InitEdgeRc("../testdata/nodefault_edgerc", "nodefault") assert.NoError(t, err) assert.Equal(t, c.Host, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/") assert.Equal(t, c.ClientToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.ClientSecret, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=") assert.Equal(t, c.AccessToken, "xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx") assert.Equal(t, c.MaxBody, 131072) assert.Equal(t, c.HeaderToSign, []string(nil)) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/errors.go000066400000000000000000000012261400161560600262160ustar00rootroot00000000000000package edgegrid // Error constants const ( ErrUUIDGenerateFailed = 500 ErrHomeDirNotFound = 501 ErrConfigFile = 502 ErrConfigFileSection = 503 ErrConfigMissingOptions = 504 ErrMissingEnvVariables = 505 ) var ( errorMap = map[int]string{ ErrUUIDGenerateFailed: "Generate UUID failed: %s", ErrHomeDirNotFound: "Fatal could not find home dir from user: %s", ErrConfigFile: "Fatal error edgegrid file: %s", ErrConfigFileSection: "Could not map section: %s", ErrConfigMissingOptions: "Fatal missing required options: %s", ErrMissingEnvVariables: "Fatal missing required environment variables: %s", } ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/log.go000066400000000000000000000077041400161560600254720ustar00rootroot00000000000000// Copyright 2018. Akamai Technologies, Inc // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package edgegrid import ( "bufio" "bytes" "encoding/json" "fmt" "net/http" "net/http/httputil" "os" "strings" logstd "log" log "github.com/sirupsen/logrus" ) var logBuffer *bufio.Writer var LogFile *os.File var EdgegridLog *log.Logger func SetupLogging() { if EdgegridLog != nil { return // already configured } EdgegridLog = log.New() EdgegridLog.SetFormatter(&log.TextFormatter{ DisableLevelTruncation: true, EnvironmentOverrideColors: true, }) // Log file destination specified? If not, use default stdout if logFileName := os.Getenv("AKAMAI_LOG_FILE"); logFileName != "" { // If the file doesn't exist, create it, or append to the file LogFile, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatal(err) } EdgegridLog.SetOutput(LogFile) } EdgegridLog.SetLevel(log.PanicLevel) if logLevel := os.Getenv("AKAMAI_LOG"); logLevel != "" { level, err := log.ParseLevel(logLevel) if err == nil { EdgegridLog.SetLevel(level) } else { log.Warningln("[WARN] Unknown AKAMAI_LOG value. Allowed values: panic, fatal, error, warn, info, debug, trace") } } defer LogFile.Close() } func LogMultiline(f func(args ...interface{}), args ...string) { for _, str := range args { for _, str := range strings.Split(strings.Trim(str, "\n"), "\n") { f(str) } } } func LogMultilineln(f func(args ...interface{}), args ...string) { LogMultiline(f, args...) } func LogMultilinef(f func(formatter string, args ...interface{}), formatter string, args ...interface{}) { str := fmt.Sprintf(formatter, args...) for _, str := range strings.Split(strings.Trim(str, "\n"), "\n") { f(str) } } // Utility func to print http req func PrintHttpRequest(req *http.Request, body bool) { if req == nil { return } b, err := httputil.DumpRequestOut(req, body) if err == nil { LogMultiline(EdgegridLog.Traceln, string(b)) } } func PrintHttpRequestCorrelation(req *http.Request, body bool, correlationid string) { if req == nil { return } b, err := httputil.DumpRequestOut(req, body) if err == nil { LogMultiline(EdgegridLog.Traceln, string(b)) PrintfCorrelation("[DEBUG] REQUEST", correlationid, prettyPrintJsonLines(b)) } } // Utility func to print http response func PrintHttpResponse(res *http.Response, body bool) { if res == nil { return } b, err := httputil.DumpResponse(res, body) if err == nil { LogMultiline(EdgegridLog.Traceln, string(b)) } } func PrintHttpResponseCorrelation(res *http.Response, body bool, correlationid string) { if res == nil { return } b, err := httputil.DumpResponse(res, body) if err == nil { LogMultiline(EdgegridLog.Traceln, string(b)) PrintfCorrelation("[DEBUG] RESPONSE ", correlationid, prettyPrintJsonLines(b)) } } func PrintfCorrelation(level string, correlationid string, msg string) { if correlationid == "" { logstd.Printf("%s %s\n", level, msg) } else { logstd.SetFlags(0) logstd.Printf("%v %s\n", correlationid, msg) } } // prettyPrintJsonLines iterates through a []byte line-by-line, // transforming any lines that are complete json into pretty-printed json. func prettyPrintJsonLines(b []byte) string { parts := strings.Split(string(b), "\n") for i, p := range parts { if b := []byte(p); json.Valid(b) { var out bytes.Buffer json.Indent(&out, b, "", " ") parts[i] = out.String() } } return strings.Join(parts, "\n") } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/profilecache.go000066400000000000000000000006441400161560600273310ustar00rootroot00000000000000package edgegrid import ( "time" "github.com/patrickmn/go-cache" gocache "github.com/patrickmn/go-cache" ) // Config struct provides all the necessary fields to // create authorization header, debug is optional type ( profileCache gocache.Cache ) // Init initializes cache // // See: InitCache() func InitCache() (gocache.Cache, error) { cache := cache.New(5*time.Minute, 10*time.Minute) return *cache, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/signer.go000066400000000000000000000163531400161560600262000ustar00rootroot00000000000000// Package edgegrid allows you to sign http.Request's using the Akamai OPEN Edgegrid Signing Scheme package edgegrid import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/base64" "fmt" "io/ioutil" "net/http" "os" "sort" "strings" "time" "unicode" "github.com/google/uuid" "github.com/sirupsen/logrus" ) const defaultSection = "DEFAULT" // AddRequestHeader sets the Authorization header to use Akamai Open API func AddRequestHeader(config Config, req *http.Request) *http.Request { if EdgegridLog == nil { SetupLogging() if config.Debug { EdgegridLog.SetLevel(logrus.DebugLevel) } } timestamp := makeEdgeTimeStamp() EdgegridLog.Debugf("Timestamp: '%s'", timestamp) nonce := createNonce() EdgegridLog.Debugf("Nonce: '%s'", nonce) if req.Header.Get("Content-Type") == "" { req.Header.Set("Content-Type", "application/json") } _, AkamaiCliEnvOK := os.LookupEnv("AKAMAI_CLI") AkamaiCliVersionEnv, AkamaiCliVersionEnvOK := os.LookupEnv("AKAMAI_CLI_VERSION") AkamaiCliCommandEnv, AkamaiCliCommandEnvOK := os.LookupEnv("AKAMAI_CLI_COMMAND") AkamaiCliCommandVersionEnv, AkamaiCliCommandVersionEnvOK := os.LookupEnv("AKAMAI_CLI_COMMAND_VERSION") if AkamaiCliEnvOK && AkamaiCliVersionEnvOK { if req.Header.Get("User-Agent") != "" { req.Header.Set("User-Agent", req.Header.Get("User-Agent")+" AkamaiCLI/"+AkamaiCliVersionEnv) } else { req.Header.Set("User-Agent", "AkamaiCLI/"+AkamaiCliVersionEnv) } } if AkamaiCliCommandEnvOK && AkamaiCliCommandVersionEnvOK { if req.Header.Get("User-Agent") != "" { req.Header.Set("User-Agent", req.Header.Get("User-Agent")+" AkamaiCLI-"+AkamaiCliCommandEnv+"/"+AkamaiCliCommandVersionEnv) } else { req.Header.Set("User-Agent", "AkamaiCLI-"+AkamaiCliCommandEnv+"/"+AkamaiCliCommandVersionEnv) } } req.Header.Set("Authorization", createAuthHeader(config, req, timestamp, nonce)) return req } // Must be assigned the UTC time when the request is signed. // Format of “yyyyMMddTHH:mm:ss+0000” func makeEdgeTimeStamp() string { local := time.FixedZone("GMT", 0) t := time.Now().In(local) return fmt.Sprintf("%d%02d%02dT%02d:%02d:%02d+0000", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) } // Must be assigned a nonce (number used once) for the request. // It is a random string used to detect replayed request messages. // A GUID is recommended. func createNonce() string { uuid, err := uuid.NewRandom() if err != nil { EdgegridLog.Errorf(errorMap[ErrUUIDGenerateFailed], err) return "" } return uuid.String() } func stringMinifier(in string) (out string) { white := false for _, c := range in { if unicode.IsSpace(c) { if !white { out = out + " " } white = true } else { out = out + string(c) white = false } } return } func concatPathQuery(path, query string) string { if query == "" { return path } return fmt.Sprintf("%s?%s", path, query) } // createSignature is the base64-encoding of the SHA–256 HMAC of the data to sign with the signing key. func createSignature(message string, secret string) string { key := []byte(secret) h := hmac.New(sha256.New, key) h.Write([]byte(message)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } func createHash(data string) string { h := sha256.Sum256([]byte(data)) return base64.StdEncoding.EncodeToString(h[:]) } func canonicalizeHeaders(config Config, req *http.Request) string { var unsortedHeader []string var sortedHeader []string for k := range req.Header { unsortedHeader = append(unsortedHeader, k) } sort.Strings(unsortedHeader) for _, k := range unsortedHeader { for _, sign := range config.HeaderToSign { if sign == k { v := strings.TrimSpace(req.Header.Get(k)) sortedHeader = append(sortedHeader, fmt.Sprintf("%s:%s", strings.ToLower(k), strings.ToLower(stringMinifier(v)))) } } } return strings.Join(sortedHeader, "\t") } // signingKey is derived from the client secret. // The signing key is computed as the base64 encoding of the SHA–256 HMAC of the timestamp string // (the field value included in the HTTP authorization header described above) with the client secret as the key. func signingKey(config Config, timestamp string) string { key := createSignature(timestamp, config.ClientSecret) return key } // The content hash is the base64-encoded SHA–256 hash of the POST body. // For any other request methods, this field is empty. But the tac separator (\t) must be included. // The size of the POST body must be less than or equal to the value specified by the service. // Any request that does not meet this criteria SHOULD be rejected during the signing process, // as the request will be rejected by EdgeGrid. func createContentHash(config Config, req *http.Request) string { var ( contentHash string preparedBody string bodyBytes []byte ) if req.Body != nil { bodyBytes, _ = ioutil.ReadAll(req.Body) req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) preparedBody = string(bodyBytes) } EdgegridLog.Debugf("Body is %s", preparedBody) if req.Method == "POST" && len(preparedBody) > 0 { EdgegridLog.Debugf("Signing content: %s", preparedBody) if len(preparedBody) > config.MaxBody { EdgegridLog.Debugf("Data length %d is larger than maximum %d", len(preparedBody), config.MaxBody) preparedBody = preparedBody[0:config.MaxBody] EdgegridLog.Debugf("Data truncated to %d for computing the hash", len(preparedBody)) } contentHash = createHash(preparedBody) } EdgegridLog.Debugf("Content hash is '%s'", contentHash) return contentHash } // The data to sign includes the information from the HTTP request that is relevant to ensuring that the request is authentic. // This data set comprised of the request data combined with the authorization header value (excluding the signature field, // but including the ; right before the signature field). func signingData(config Config, req *http.Request, authHeader string) string { dataSign := []string{ req.Method, req.URL.Scheme, req.URL.Host, concatPathQuery(req.URL.EscapedPath(), req.URL.RawQuery), canonicalizeHeaders(config, req), createContentHash(config, req), authHeader, } EdgegridLog.Debugf("Data to sign %s", strings.Join(dataSign, "\t")) return strings.Join(dataSign, "\t") } func signingRequest(config Config, req *http.Request, authHeader string, timestamp string) string { return createSignature(signingData(config, req, authHeader), signingKey(config, timestamp)) } // The Authorization header starts with the signing algorithm moniker (name of the algorithm) used to sign the request. // The moniker below identifies EdgeGrid V1, hash message authentication code, SHA–256 as the hash standard. // This moniker is then followed by a space and an ordered list of name value pairs with each field separated by a semicolon. func createAuthHeader(config Config, req *http.Request, timestamp string, nonce string) string { authHeader := fmt.Sprintf("EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;", config.ClientToken, config.AccessToken, timestamp, nonce, ) EdgegridLog.Debugf("Unsigned authorization header: '%s'", authHeader) signedAuthHeader := fmt.Sprintf("%ssignature=%s", authHeader, signingRequest(config, req, authHeader, timestamp)) EdgegridLog.Debugf("Signed authorization header: '%s'", signedAuthHeader) return signedAuthHeader } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/edgegrid/signer_test.go000066400000000000000000000050361400161560600272330ustar00rootroot00000000000000package edgegrid import ( "bytes" "fmt" "io/ioutil" "net/http" "net/url" "regexp" "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1" "github.com/stretchr/testify/assert" ) var ( testFile = "../testdata/testdata.json" timestamp = "20140321T19:34:21+0000" nonce = "nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" config = Config{ Host: "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: true, HeaderToSign: []string{ "X-Test1", "X-Test2", "X-Test3", }, } ) type JSONTests struct { Tests []Test `json:"tests"` } type Test struct { Name string `json:"testName"` Request struct { Method string `json:"method"` Path string `json:"path"` Headers []map[string]string `json:"headers"` Data string `json:"data"` } `json:"request"` ExpectedAuthorization string `json:"expectedAuthorization"` } func TestMakeEdgeTimeStamp(t *testing.T) { actual := makeEdgeTimeStamp() expected := regexp.MustCompile(`^\d{4}[0-1][0-9][0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9]\+0000$`) if assert.Regexp(t, expected, actual, "Fail: Regex do not match") { t.Log("Pass: Regex matches") } } func TestCreateNonce(t *testing.T) { actual := createNonce() for i := 0; i < 100; i++ { expected := createNonce() assert.NotEqual(t, actual, expected, "Fail: Nonce matches") } } func TestCreateAuthHeader(t *testing.T) { var edgegrid JSONTests byt, err := ioutil.ReadFile(testFile) if err != nil { t.Fatalf("Test file not found, err %s", err) } url, err := url.Parse(config.Host) if err != nil { t.Fatalf("URL is not parsable, err %s", err) } err = jsonhooks.Unmarshal(byt, &edgegrid) if err != nil { t.Fatalf("JSON is not parsable, err %s", err) } for _, edge := range edgegrid.Tests { url.Path = edge.Request.Path req, _ := http.NewRequest( edge.Request.Method, url.String(), bytes.NewBuffer([]byte(edge.Request.Data)), ) for _, header := range edge.Request.Headers { for k, v := range header { req.Header.Set(k, v) } } SetupLogging() actual := createAuthHeader(config, req, timestamp, nonce) if assert.Equal(t, edge.ExpectedAuthorization, actual, fmt.Sprintf("Fail: %s", edge.Name)) { t.Logf("Pass: %s\n", edge.Name) t.Logf("Expected: %s - Actual %s", edge.ExpectedAuthorization, actual) } } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/000077500000000000000000000000001400161560600244165ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/client/000077500000000000000000000000001400161560600256745ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/client/client.go000066400000000000000000000046461400161560600275130ustar00rootroot00000000000000//An example Diagnostic Tools v1 API Client package main import ( "fmt" "log" "math/rand" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func random(min int, max int) int { rand.Seed(time.Now().UTC().UnixNano()) random := rand.Intn(max-min) + min return random } //Location ghost location type type Location struct { ID string `json:"id"` Value string `json:"value"` } //LocationsResponse response type for ghost locations type LocationsResponse struct { Locations []Location `json:"locations"` } //DigResponse response type for dig API type DigResponse struct { Dig struct { Hostname string `json:"hostname"` QueryType string `json:"queryType"` Result string `json:"result"` ErrorString string `json:"errorString"` } `json:"digInfo"` } func main() { Example() } func Example() { config, err := edgegrid.InitEdgeRc("~/.edgerc", "default") config.Debug = false if err == nil { if err == nil { fmt.Println("Requesting locations that support the diagnostic-tools API.") req, err := client.NewRequest( config, "GET", "/diagnostic-tools/v2/ghost-locations/available", nil, ) if err != nil { log.Fatal(err.Error()) } res, err := client.Do(config, req) if err != nil { log.Fatal(err.Error()) return } locationsResponse := LocationsResponse{} client.BodyJSON(res, &locationsResponse) if err != nil { log.Fatal(err.Error()) } fmt.Printf("There are %d locations that can run dig in the Akamai Network\n", len(locationsResponse.Locations)) if len(locationsResponse.Locations) == 0 { log.Fatal("No locations found") } location := locationsResponse.Locations[random(0, len(locationsResponse.Locations))-1] fmt.Println("We will make our call from " + location.Value) fmt.Println("Running dig from " + location.Value) client.Client.Timeout = 5 * time.Minute req, err = client.NewRequest( config, "GET", "/diagnostic-tools/v2/ghost-locations/"+location.ID+"/dig-info?hostName=developer.akamai.com&queryType=A", nil, ) if err != nil { log.Fatal(err.Error()) return } res, err = client.Do(config, req) if err != nil { log.Fatal(err.Error()) return } digResponse := DigResponse{} client.BodyJSON(res, &digResponse) fmt.Println(digResponse.Dig.Result) } else { log.Fatal(err.Error()) } } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/edgegrid/000077500000000000000000000000001400161560600261705ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/edgegrid/edgegrid.go000066400000000000000000000022101400161560600302640ustar00rootroot00000000000000package main import ( "fmt" "io/ioutil" "net/http" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) func main() { client := http.Client{} /* Init will try to use the environment and fallback to .edgerc. This function will check in order: AKAMAI_{SECTION}_* environment variables if using the default section, AKAMAI_* environment variables the specified (or default if none) section in .edgerc if not using the default section, AKAMAI_* environment variables This new function is the recommended way for instantiating an instance. The environment variables are: AKAMAI_HOST or AKAMAI_{SECTION}_HOST AKAMAI_CLIENT_TOKEN or AKAMAI_{SECTION}_CLIENT_TOKEN AKAMAI_CLIENT_SECRET or AKAMAI_{SECTION}_CLIENT_SECRET AKAMAI_ACCESS_TOKEN or AKAMAI_{SECTION}_ACCESS_TOKEN */ config, err := edgegrid.InitEdgeRc("~/.edgerc", "default") if err == nil { req, _ := http.NewRequest("GET", fmt.Sprintf("https://%s/diagnostic-tools/v2/ghost-locations/available", config.Host), nil) req = edgegrid.AddRequestHeader(config, req) resp, _ := client.Do(req) byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/edgegrid_without_configfile/000077500000000000000000000000001400161560600321405ustar00rootroot00000000000000edgegrid_without_configfile.go000066400000000000000000000013241400161560600401320ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/examples/edgegrid_without_configfilepackage main import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "io/ioutil" "net/http" ) func main() { client := http.Client{} config := edgegrid.Config{ Host: "xxxxxx.luna.akamaiapis.net", ClientToken: "xxxx-xxxxxxxxxxx-xxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", AccessToken: "xxxx-xxxxxxxxxxx-xxxxxxxxxxx", MaxBody: 1024, HeaderToSign: []string{ "X-Test1", "X-Test2", "X-Test3", }, Debug: false, } req, _ := http.NewRequest("GET", fmt.Sprintf("https://%s/siteshield/v1/maps", config.Host), nil) req = edgegrid.AddRequestHeader(config, req) resp, _ := client.Do(req) byt, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(byt)) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/go.mod000066400000000000000000000007131400161560600237070ustar00rootroot00000000000000module github.com/akamai/AkamaiOPEN-edgegrid-golang go 1.14 require ( github.com/google/go-querystring v1.0.0 github.com/google/uuid v1.1.1 github.com/mitchellh/go-homedir v1.1.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.4.2 github.com/smartystreets/goconvey v1.6.4 // indirect github.com/stretchr/testify v1.4.0 github.com/xeipuuv/gojsonschema v1.2.0 gopkg.in/h2non/gock.v1 v1.0.15 gopkg.in/ini.v1 v1.51.1 ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/go.sum000066400000000000000000000126021400161560600237340ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/jsonhooks-v1/000077500000000000000000000000001400161560600251415ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/jsonhooks-v1/README.md000066400000000000000000000000221400161560600264120ustar00rootroot00000000000000# Akamai JSONHooksgolang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/jsonhooks-v1/errors.go000066400000000000000000000000221400161560600267760ustar00rootroot00000000000000package jsonhooks golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/jsonhooks-v1/jsonhooks.go000066400000000000000000000032631400161560600275110ustar00rootroot00000000000000// Package jsonhooks adds hooks that are automatically called before JSON marshaling (PreMarshalJSON) and // after JSON unmarshaling (PostUnmarshalJSON). It does not do so recursively. package jsonhooks import ( "encoding/json" "reflect" ) // Marshal wraps encoding/json.Marshal, calls v.PreMarshalJSON() if it exists func Marshal(v interface{}) ([]byte, error) { if ImplementsPreJSONMarshaler(v) { err := v.(PreJSONMarshaler).PreMarshalJSON() if err != nil { return nil, err } } return json.Marshal(v) } // Unmarshal wraps encoding/json.Unmarshal, calls v.PostUnmarshalJSON() if it exists func Unmarshal(data []byte, v interface{}) error { err := json.Unmarshal(data, v) if err != nil { return err } if ImplementsPostJSONUnmarshaler(v) { err := v.(PostJSONUnmarshaler).PostUnmarshalJSON() if err != nil { return err } } return nil } // PreJSONMarshaler infers support for the PreMarshalJSON pre-hook type PreJSONMarshaler interface { PreMarshalJSON() error } // ImplementsPreJSONMarshaler checks for support for the PreMarshalJSON pre-hook func ImplementsPreJSONMarshaler(v interface{}) bool { value := reflect.ValueOf(v) if !value.IsValid() { return false } _, ok := value.Interface().(PreJSONMarshaler) return ok } // PostJSONUnmarshaler infers support for the PostUnmarshalJSON post-hook type PostJSONUnmarshaler interface { PostUnmarshalJSON() error } // ImplementsPostJSONUnmarshaler checks for support for the PostUnmarshalJSON post-hook func ImplementsPostJSONUnmarshaler(v interface{}) bool { value := reflect.ValueOf(v) if value.Kind() == reflect.Ptr && value.IsNil() { return false } _, ok := value.Interface().(PostJSONUnmarshaler) return ok } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/jsonhooks-v1/jsonhooks_test.go000066400000000000000000000103141400161560600305430ustar00rootroot00000000000000package jsonhooks import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" ) type Optionals struct { Sr string `json:"sr"` So string `json:"so,omitempty"` Sw string `json:"-"` Ir int `json:"omitempty"` // actually named omitempty, not an option Io int `json:"io,omitempty"` Slr []string `json:"slr,random"` Slo []string `json:"slo,omitempty"` Mr map[string]interface{} `json:"mr"` Mo map[string]interface{} `json:",omitempty"` Fr float64 `json:"fr"` Fo float64 `json:"fo,omitempty"` Br bool `json:"br"` Bo bool `json:"bo,omitempty"` Ur uint `json:"ur"` Uo uint `json:"uo,omitempty"` Str struct{} `json:"str"` Sto struct{} `json:"sto,omitempty"` } type MixedTypes struct { I int `json:"I"` B bool `json:"B"` F float64 `json:"F"` S string `json:"S"` St struct { Foo int `json:"Foo"` Bar string `json:"Bar"` } `json:"St"` A []string `json:"A"` } type WithHooks MixedTypes func (hooks *WithHooks) PreMarshalJSON() error { hooks.I *= 1000 hooks.B = !hooks.B hooks.F *= 1.1 hooks.S = strings.ToUpper(hooks.S) hooks.St.Foo *= 2000 hooks.St.Bar = strings.ToUpper(hooks.St.Bar) for key, val := range hooks.A { hooks.A[key] = strings.ToUpper(val) } return nil } func (hooks *WithHooks) PostUnmarshalJSON() error { hooks.I /= 1000 hooks.B = !hooks.B hooks.F /= 1.1 hooks.S = strings.ToLower(hooks.S) hooks.St.Foo /= 2000 hooks.St.Bar = strings.ToLower(hooks.St.Bar) for key, val := range hooks.A { hooks.A[key] = strings.ToLower(val) } return nil } func TestMarshalCompat(t *testing.T) { var o Optionals o.Sw = "something" o.Mr = map[string]interface{}{} o.Mo = map[string]interface{}{} expected, _ := json.Marshal(o) actual, err := Marshal(o) assert.NoError(t, err) assert.Equal( t, expected, actual, ) } func TestUnmarshalCompat(t *testing.T) { data := `{ "sr": "", "omitempty": 0, "slr": null, "mr": {}, "fr": 0, "br": false, "ur": 0, "str": {}, "sto": {} }` expected := &Optionals{} _ = json.Unmarshal([]byte(data), expected) actual := &Optionals{} err := Unmarshal([]byte(data), actual) assert.NoError(t, err) assert.Equal( t, expected, actual, ) } func TestImplementsPreJSONMarshaler(t *testing.T) { noHooks := &MixedTypes{} withHooks := &WithHooks{} assert.False(t, ImplementsPreJSONMarshaler(noHooks)) assert.True(t, ImplementsPreJSONMarshaler(withHooks)) } func TestImplementsPostJSONUnmarshaler(t *testing.T) { noHooks := &MixedTypes{} withHooks := &WithHooks{} assert.False(t, ImplementsPostJSONUnmarshaler(noHooks)) assert.True(t, ImplementsPostJSONUnmarshaler(withHooks)) } func TestPreJSONMarshal(t *testing.T) { noHooks := &MixedTypes{ I: 1, B: true, F: 1.0, S: "testing", St: struct { Foo int `json:"Foo"` Bar string `json:"Bar"` }{2, "test"}, A: []string{"one", "two", "three"}, } withHooks := (*WithHooks)(noHooks) expected, _ := json.Marshal(&MixedTypes{ I: 1 * 1000, B: !true, F: 1.0 * 1.1, S: "TESTING", St: struct { Foo int `json:"Foo"` Bar string `json:"Bar"` }{2 * 2000, "TEST"}, A: []string{"ONE", "TWO", "THREE"}, }) gojson, _ := json.Marshal(withHooks) actualNoHooks, _ := Marshal(noHooks) actualWithHooks, err := Marshal(withHooks) assert.NoError(t, err) assert.Equal(t, string(gojson), string(actualNoHooks)) assert.NotEqual(t, string(gojson), string(actualWithHooks)) assert.NotEqual(t, string(actualNoHooks), string(actualWithHooks)) assert.Equal(t, string(expected), string(actualWithHooks)) } func TestPostJSONUnmarshal(t *testing.T) { expected := &WithHooks{ I: 1, B: true, F: 1.0, S: "testing", St: struct { Foo int `json:"Foo"` Bar string `json:"Bar"` }{2, "test"}, A: []string{"one", "two", "three"}, } data := []byte(`{"I":1000,"B":false,"F":1.1,"S":"TESTING","St":{"Foo":4000,"Bar":"TEST"},"A":["ONE","TWO","THREE"]}`) gojson := &MixedTypes{} _ = json.Unmarshal( data, gojson, ) withHooks := &WithHooks{} err := Unmarshal(data, withHooks) assert.NoError(t, err) withoutHooks := &MixedTypes{} err = Unmarshal(data, withoutHooks) assert.NoError(t, err) assert.NotEqual(t, gojson, withHooks) assert.NotEqual(t, expected, withoutHooks) assert.Equal(t, expected, withHooks) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/000077500000000000000000000000001400161560600240555ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/README.md000066400000000000000000000002741400161560600253370ustar00rootroot00000000000000# Akamai Property Manager API (PAPI) A golang package which facilitates making requests to the [Akamai OPEN Property Manager API](https://developer.akamai.com/api/luna/papi/overview.html).golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/activations.go000066400000000000000000000370241400161560600267360ustar00rootroot00000000000000package papi import ( "encoding/json" "fmt" "io/ioutil" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // Activations is a collection of property activations type Activations struct { client.Resource AccountID string `json:"accountId"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` Activations struct { Items []*Activation `json:"items"` } `json:"activations"` } // NewActivations creates a new Activations func NewActivations() *Activations { activations := &Activations{} activations.Init() return activations } // GetActivations retrieves activation data for a given property // // See: Property.GetActivations() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listactivations // Endpoint: GET /papi/v1/properties/{propertyId}/activations/{?contractId,groupId} func (activations *Activations) GetActivations(property *Property) error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf("/papi/v1/properties/%s/activations?contractId=%s&groupId=%s", property.PropertyID, property.Contract.ContractID, property.Group.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, activations); err != nil { return err } return nil } // GetLatestProductionActivation retrieves the latest activation for the production network // // Pass in a status to check for, defaults to StatusActive func (activations *Activations) GetLatestProductionActivation(status StatusValue) (*Activation, error) { return activations.GetLatestActivation(NetworkProduction, status) } // GetLatestStagingActivation retrieves the latest activation for the staging network // // Pass in a status to check for, defaults to StatusActive func (activations *Activations) GetLatestStagingActivation(status StatusValue) (*Activation, error) { return activations.GetLatestActivation(NetworkStaging, status) } // GetLatestActivation gets the latest activation for the specified network // // Default to NetworkProduction. Pass in a status to check for, defaults to StatusActive // // This can return an activation OR a deactivation. Check activation.ActivationType and activation.Status for what you're looking for func (activations *Activations) GetLatestActivation(network NetworkValue, status StatusValue) (*Activation, error) { if network == "" { network = NetworkProduction } if status == "" { status = StatusActive } var latest *Activation for _, activation := range activations.Activations.Items { if activation.Network == network && activation.Status == status && (latest == nil || activation.PropertyVersion > latest.PropertyVersion) { latest = activation } } if latest == nil { return nil, fmt.Errorf("No activation found (network: %s, status: %s)", network, status) } return latest, nil } // Activation represents a property activation resource type Activation struct { client.Resource parent *Activations ActivationID string `json:"activationId,omitempty"` ActivationType ActivationValue `json:"activationType,omitempty"` AcknowledgeWarnings []string `json:"acknowledgeWarnings,omitempty"` ComplianceRecord *ActivationComplianceRecord `json:"complianceRecord,omitempty"` FastPush bool `json:"fastPush,omitempty"` IgnoreHTTPErrors bool `json:"ignoreHttpErrors,omitempty"` PropertyName string `json:"propertyName,omitempty"` PropertyID string `json:"propertyId,omitempty"` PropertyVersion int `json:"propertyVersion"` Network NetworkValue `json:"network"` Status StatusValue `json:"status,omitempty"` SubmitDate string `json:"submitDate,omitempty"` UpdateDate string `json:"updateDate,omitempty"` Note string `json:"note,omitempty"` NotifyEmails []string `json:"notifyEmails"` StatusChange chan bool `json:"-"` } type ActivationComplianceRecord struct { NoncomplianceReason string `json:"noncomplianceReason,omitempty"` } // NewActivation creates a new Activation func NewActivation(parent *Activations) *Activation { activation := &Activation{parent: parent} activation.Init() return activation } func (activation *Activation) Init() { activation.Complete = make(chan bool, 1) activation.StatusChange = make(chan bool, 1) } // GetActivation populates the Activation resource // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getanactivation // Endpoint: GET /papi/v1/properties/{propertyId}/activations/{activationId}{?contractId,groupId} func (activation *Activation) GetActivation(property *Property) (time.Duration, error) { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/activations/%s?contractId=%s&groupId=%s", property.PropertyID, activation.ActivationID, property.ContractID, property.GroupID, ), nil, ) if err != nil { return 0, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return 0, err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return 0, client.NewAPIError(res) } activations := NewActivations() if err := client.BodyJSON(res, activations); err != nil { return 0, err } activation.ActivationID = activations.Activations.Items[0].ActivationID activation.ActivationType = activations.Activations.Items[0].ActivationType activation.AcknowledgeWarnings = activations.Activations.Items[0].AcknowledgeWarnings activation.ComplianceRecord = activations.Activations.Items[0].ComplianceRecord activation.FastPush = activations.Activations.Items[0].FastPush activation.IgnoreHTTPErrors = activations.Activations.Items[0].IgnoreHTTPErrors activation.PropertyName = activations.Activations.Items[0].PropertyName activation.PropertyID = activations.Activations.Items[0].PropertyID activation.PropertyVersion = activations.Activations.Items[0].PropertyVersion activation.Network = activations.Activations.Items[0].Network activation.Status = activations.Activations.Items[0].Status activation.SubmitDate = activations.Activations.Items[0].SubmitDate activation.UpdateDate = activations.Activations.Items[0].UpdateDate activation.Note = activations.Activations.Items[0].Note activation.NotifyEmails = activations.Activations.Items[0].NotifyEmails //retry, _ := strconv.Atoi(res.Header.Get("Retry-After")) //retry *= int(time.Second) return time.Duration(30 * time.Second), nil } // Save activates a given property // // If acknowledgeWarnings is true and warnings are returned on the first attempt, // a second attempt is made, acknowledging the warnings. // // See: Property.Activate() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#activateaproperty // Endpoint: POST /papi/v1/properties/{propertyId}/activations/{?contractId,groupId} func (activation *Activation) Save(property *Property, acknowledgeWarnings bool) error { if activation.ComplianceRecord == nil { activation.ComplianceRecord = &ActivationComplianceRecord{ NoncomplianceReason: "NO_PRODUCTION_TRAFFIC", } } req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/papi/v1/properties/%s/activations?contractId=%s&groupId=%s", property.PropertyID, property.ContractID, property.GroupID, ), activation, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) && (!acknowledgeWarnings || (acknowledgeWarnings && res.StatusCode != 400)) { return client.NewAPIError(res) } if res.StatusCode == 400 && acknowledgeWarnings { warnings := &struct { Warnings []struct { Detail string `json:"detail"` MessageID string `json:"messageId"` } `json:"warnings,omitempty"` }{} body, err := ioutil.ReadAll(res.Body) if err != nil { return err } if err = json.Unmarshal(body, warnings); err != nil { return err } // Just in case we got a 400 for a different reason if len(warnings.Warnings) == 0 { jsonBody := &client.JSONBody{} if err = json.Unmarshal(body, jsonBody); err != nil { return err } return client.NewAPIErrorFromBody(res, body) } for _, warning := range warnings.Warnings { activation.AcknowledgeWarnings = append(activation.AcknowledgeWarnings, warning.MessageID) } // Don't acknowledgeWarnings again, halting a potential endless recursion return activation.Save(property, false) } var location client.JSONBody if err = client.BodyJSON(res, &location); err != nil { return err } req, err = client.NewRequest( Config, "GET", location["activationLink"].(string), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err = client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) activations := NewActivations() if err := client.BodyJSON(res, activations); err != nil { return err } activation.ActivationID = activations.Activations.Items[0].ActivationID activation.ActivationType = activations.Activations.Items[0].ActivationType activation.AcknowledgeWarnings = activations.Activations.Items[0].AcknowledgeWarnings activation.ComplianceRecord = activations.Activations.Items[0].ComplianceRecord activation.FastPush = activations.Activations.Items[0].FastPush activation.IgnoreHTTPErrors = activations.Activations.Items[0].IgnoreHTTPErrors activation.PropertyName = activations.Activations.Items[0].PropertyName activation.PropertyID = activations.Activations.Items[0].PropertyID activation.PropertyVersion = activations.Activations.Items[0].PropertyVersion activation.Network = activations.Activations.Items[0].Network activation.Status = activations.Activations.Items[0].Status activation.SubmitDate = activations.Activations.Items[0].SubmitDate activation.UpdateDate = activations.Activations.Items[0].UpdateDate activation.Note = activations.Activations.Items[0].Note activation.NotifyEmails = activations.Activations.Items[0].NotifyEmails return nil } // PollStatus will responsibly poll till the property is active or an error occurs // // The Activation.StatusChange is a channel that can be used to // block on status changes. If a new valid status is returned, true will // be sent to the channel, otherwise, false will be sent. // // go activation.PollStatus(property) // for activation.Status != edgegrid.StatusActive { // select { // case statusChanged := <-activation.StatusChange: // if statusChanged == false { // break // } // case <-time.After(time.Minute * 30): // break // } // } // // if activation.Status == edgegrid.StatusActive { // // Activation succeeded // } func (activation *Activation) PollStatus(property *Property) bool { currentStatus := activation.Status var retry time.Duration = 0 for currentStatus != StatusActive { time.Sleep(retry) var err error retry, err = activation.GetActivation(property) if err != nil { activation.StatusChange <- false return false } if activation.Network == NetworkStaging && retry > time.Minute { retry = time.Minute } if err != nil { activation.StatusChange <- false return false } if currentStatus != activation.Status { currentStatus = activation.Status activation.StatusChange <- true } } return true } // Cancel an activation in progress // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#cancelapendingactivation // Endpoint: DELETE /papi/v1/properties/{propertyId}/activations/{activationId}{?contractId,groupId} func (activation *Activation) Cancel(property *Property) error { req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf( "/papi/v1/properties/%s/activations?contractId=%s&groupId=%s", property.PropertyID, property.Contract.ContractID, property.Group.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newActivations := NewActivations() if err := client.BodyJSON(res, newActivations); err != nil { return err } activation.ActivationID = newActivations.Activations.Items[0].ActivationID activation.ActivationType = newActivations.Activations.Items[0].ActivationType activation.AcknowledgeWarnings = newActivations.Activations.Items[0].AcknowledgeWarnings activation.ComplianceRecord = newActivations.Activations.Items[0].ComplianceRecord activation.FastPush = newActivations.Activations.Items[0].FastPush activation.IgnoreHTTPErrors = newActivations.Activations.Items[0].IgnoreHTTPErrors activation.PropertyName = newActivations.Activations.Items[0].PropertyName activation.PropertyID = newActivations.Activations.Items[0].PropertyID activation.PropertyVersion = newActivations.Activations.Items[0].PropertyVersion activation.Network = newActivations.Activations.Items[0].Network activation.Status = newActivations.Activations.Items[0].Status activation.SubmitDate = newActivations.Activations.Items[0].SubmitDate activation.UpdateDate = newActivations.Activations.Items[0].UpdateDate activation.Note = newActivations.Activations.Items[0].Note activation.NotifyEmails = newActivations.Activations.Items[0].NotifyEmails activation.StatusChange = newActivations.Activations.Items[0].StatusChange return nil } // ActivationValue is used to create an "enum" of possible Activation.ActivationType values type ActivationValue string // NetworkValue is used to create an "enum" of possible Activation.Network values type NetworkValue string // StatusValue is used to create an "enum" of possible Activation.Status values type StatusValue string const ( // ActivationTypeActivate Activation.ActivationType value ACTIVATE ActivationTypeActivate ActivationValue = "ACTIVATE" // ActivationTypeDeactivate Activation.ActivationType value DEACTIVATE ActivationTypeDeactivate ActivationValue = "DEACTIVATE" // NetworkProduction Activation.Network value PRODUCTION NetworkProduction NetworkValue = "PRODUCTION" // NetworkStaging Activation.Network value STAGING NetworkStaging NetworkValue = "STAGING" // StatusActive Activation.Status value ACTIVE StatusActive StatusValue = "ACTIVE" // StatusInactive Activation.Status value INACTIVE StatusInactive StatusValue = "INACTIVE" // StatusPending Activation.Status value PENDING StatusPending StatusValue = "PENDING" // StatusZone1 Activation.Status value ZONE_1 StatusZone1 StatusValue = "ZONE_1" // StatusZone2 Activation.Status value ZONE_2 StatusZone2 StatusValue = "ZONE_2" // StatusZone3 Activation.Status value ZONE_3 StatusZone3 StatusValue = "ZONE_3" // StatusAborted Activation.Status value ABORTED StatusAborted StatusValue = "ABORTED" // StatusFailed Activation.Status value FAILED StatusFailed StatusValue = "FAILED" // StatusDeactivated Activation.Status value DEACTIVATED StatusDeactivated StatusValue = "DEACTIVATED" // StatusPendingDeactivation Activation.Status value PENDING_DEACTIVATION StatusPendingDeactivation StatusValue = "PENDING_DEACTIVATION" // StatusNew Activation.Status value NEW StatusNew StatusValue = "NEW" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/available.go000066400000000000000000000114431400161560600263270ustar00rootroot00000000000000package papi import ( "fmt" "io/ioutil" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/xeipuuv/gojsonschema" ) // AvailableCriteria represents a collection of available rule criteria type AvailableCriteria struct { client.Resource ContractID string `json:"contractId"` GroupID string `json:"groupId"` ProductID string `json:"productId"` RuleFormat string `json:"ruleFormat"` AvailableCriteria struct { Items []struct { Name string `json:"name"` SchemaLink string `json:"schemaLink"` } `json:"items"` } `json:"availableCriteria"` } // NewAvailableCriteria creates a new AvailableCriteria func NewAvailableCriteria() *AvailableCriteria { availableCriteria := &AvailableCriteria{} availableCriteria.Init() return availableCriteria } // GetAvailableCriteria retrieves criteria available for a given property // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listavailablecriteria // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/available-criteria{?contractId,groupId} func (availableCriteria *AvailableCriteria) GetAvailableCriteria(property *Property) error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/available-criteria?contractId=%s&groupId=%s", property.PropertyID, property.LatestVersion, property.Contract.ContractID, property.Group.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, availableCriteria); err != nil { return err } return nil } // AvailableBehaviors represents a collection of available rule behaviors type AvailableBehaviors struct { client.Resource ContractID string `json:"contractId"` GroupID string `json:"groupId"` ProductID string `json:"productId"` RuleFormat string `json:"ruleFormat"` Behaviors struct { Items []AvailableBehavior `json:"items"` } `json:"behaviors"` } // NewAvailableBehaviors creates a new AvailableBehaviors func NewAvailableBehaviors() *AvailableBehaviors { availableBehaviors := &AvailableBehaviors{} availableBehaviors.Init() return availableBehaviors } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (availableBehaviors *AvailableBehaviors) PostUnmarshalJSON() error { availableBehaviors.Init() for key := range availableBehaviors.Behaviors.Items { availableBehaviors.Behaviors.Items[key].parent = availableBehaviors } availableBehaviors.Complete <- true return nil } // GetAvailableBehaviors retrieves available behaviors for a given property // // See: Property.GetAvailableBehaviors // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listavailablebehaviors // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/available-behaviors{?contractId,groupId} func (availableBehaviors *AvailableBehaviors) GetAvailableBehaviors(property *Property) error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/available-behaviors?contractId=%s&groupId=%s", property.PropertyID, property.LatestVersion, property.Contract.ContractID, property.Group.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, availableBehaviors); err != nil { return err } return nil } // AvailableBehavior represents an available behavior resource type AvailableBehavior struct { client.Resource parent *AvailableBehaviors Name string `json:"name"` SchemaLink string `json:"schemaLink"` } // NewAvailableBehavior creates a new AvailableBehavior func NewAvailableBehavior(parent *AvailableBehaviors) *AvailableBehavior { availableBehavior := &AvailableBehavior{parent: parent} availableBehavior.Init() return availableBehavior } // GetSchema retrieves the JSON schema for an available behavior func (behavior *AvailableBehavior) GetSchema() (*gojsonschema.Schema, error) { req, err := client.NewRequest( Config, "GET", behavior.SchemaLink, nil, ) if err != nil { return nil, err } res, err := client.Do(Config, req) if err != nil { return nil, err } schemaBytes, _ := ioutil.ReadAll(res.Body) schemaBody := string(schemaBytes) loader := gojsonschema.NewStringLoader(schemaBody) schema, err := gojsonschema.NewSchema(loader) return schema, err } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/client_settings.go000066400000000000000000000035511400161560600276060ustar00rootroot00000000000000package papi import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // ClientSettings represents the PAPI client settings resource type ClientSettings struct { client.Resource RuleFormat string `json:"ruleFormat"` } // NewClientSettings creates a new ClientSettings func NewClientSettings() *ClientSettings { clientSettings := &ClientSettings{} clientSettings.Init() return clientSettings } // GetClientSettings populates ClientSettings // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getclientsettings // Endpoint: GET /papi/v1/client-settings func (clientSettings *ClientSettings) GetClientSettings() error { req, err := client.NewRequest(Config, "GET", "/papi/v1/client-settings", nil) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err := client.BodyJSON(res, clientSettings); err != nil { return err } return nil } // Save updates client settings // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#updateclientsettings // Endpoint: PUT /papi/v1/client-settings func (clientSettings *ClientSettings) Save() error { req, err := client.NewJSONRequest( Config, "PUT", "/papi/v1/client-settings", clientSettings, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newClientSettings := NewClientSettings() if err := client.BodyJSON(res, newClientSettings); err != nil { return err } clientSettings.RuleFormat = newClientSettings.RuleFormat return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/contracts.go000066400000000000000000000075211400161560600264110ustar00rootroot00000000000000package papi import ( "encoding/json" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) // Contracts represents a collection of property manager contracts type Contracts struct { client.Resource AccountID string `json:"accountId"` Contracts struct { Items []*Contract `json:"items"` } `json:"contracts"` } // NewContracts creates a new Contracts func NewContracts() *Contracts { contracts := &Contracts{} contracts.Init() return contracts } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (contracts *Contracts) PostUnmarshalJSON() error { contracts.Init() for key, contract := range contracts.Contracts.Items { contracts.Contracts.Items[key].parent = contracts if err := contract.PostUnmarshalJSON(); err != nil { return err } } contracts.Complete <- true return nil } // GetContracts populates Contracts with contract data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listcontracts // Endpoint: GET /papi/v1/contracts func (contracts *Contracts) GetContracts(correlationid string) error { cachecontracts, found := Profilecache.Get("contracts") if found { json.Unmarshal(cachecontracts.([]byte), contracts) return nil } else { req, err := client.NewRequest( Config, "GET", "/papi/v1/contracts", nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, contracts); err != nil { return err } if err != nil { return err } byt, _ := json.Marshal(contracts) Profilecache.Set("contracts", byt, cache.DefaultExpiration) return nil } } // FindContract finds a specific contract by ID func (contracts *Contracts) FindContract(id string) (*Contract, error) { var contract *Contract var contractFound bool for _, contract = range contracts.Contracts.Items { if contract.ContractID == id { contractFound = true break } } if !contractFound { return nil, fmt.Errorf("Unable to find contract: \"%s\"", id) } return contract, nil } // Contract represents a property contract resource type Contract struct { client.Resource parent *Contracts ContractID string `json:"contractId"` ContractTypeName string `json:"contractTypeName"` } // NewContract creates a new Contract func NewContract(parent *Contracts) *Contract { contract := &Contract{ parent: parent, } contract.Init() return contract } // GetContract populates a Contract func (contract *Contract) GetContract() error { contracts, err := GetContracts() if err != nil { return err } for _, c := range contracts.Contracts.Items { if c.ContractID == contract.ContractID { contract.parent = c.parent contract.ContractTypeName = c.ContractTypeName contract.Complete <- true return nil } } contract.Complete <- false return fmt.Errorf("contract \"%s\" not found", contract.ContractID) } // GetProducts gets products associated with a contract func (contract *Contract) GetProducts() (*Products, error) { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/products?contractId=%s", contract.ContractID, ), nil, ) if err != nil { return nil, err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return nil, client.NewAPIError(res) } products := NewProducts() if err = client.BodyJSON(res, products); err != nil { return nil, err } return products, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/cpcodes.go000066400000000000000000000173031400161560600260300ustar00rootroot00000000000000package papi import ( "encoding/json" "fmt" "strconv" "strings" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) // CpCodes represents a collection of CP Codes // // See: CpCodes.GetCpCodes() // API Docs: https://developer.akamai.com/api/luna/papi/data.html#cpcode type CpCodes struct { client.Resource AccountID string `json:"accountId"` Contract *Contract `json:"-"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` Group *Group `json:"-"` CpCodes struct { Items []*CpCode `json:"items"` } `json:"cpcodes"` } // NewCpCodes creates a new *CpCodes func NewCpCodes(contract *Contract, group *Group) *CpCodes { return &CpCodes{ Contract: contract, Group: group, } } // PostUnmarshalJSON is called after UnmarshalJSON to setup the // structs internal state. The cpcodes.Complete channel is utilized // to communicate full completion. func (cpcodes *CpCodes) PostUnmarshalJSON() error { cpcodes.Init() cpcodes.Contract = NewContract(NewContracts()) cpcodes.Contract.ContractID = cpcodes.ContractID cpcodes.Group = NewGroup(NewGroups()) cpcodes.Group.GroupID = cpcodes.GroupID go cpcodes.Group.GetGroup() go cpcodes.Contract.GetContract() go (func(cpcodes *CpCodes) { contractComplete := <-cpcodes.Contract.Complete groupComplete := <-cpcodes.Group.Complete cpcodes.Complete <- (contractComplete && groupComplete) })(cpcodes) for key, cpcode := range cpcodes.CpCodes.Items { cpcodes.CpCodes.Items[key].parent = cpcodes if err := cpcode.PostUnmarshalJSON(); err != nil { return err } } return nil } // GetCpCodes populates a *CpCodes with it's related CP Codes // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listcpcodes // Endpoint: GET /papi/v1/cpcodes/{?contractId,groupId} func (cpcodes *CpCodes) GetCpCodes(correlationid string) error { cachecpcodes, found := Profilecache.Get("cpcodes") if found { json.Unmarshal(cachecpcodes.([]byte), cpcodes) return nil } else { if cpcodes.Contract == nil { cpcodes.Contract = NewContract(NewContracts()) cpcodes.Contract.ContractID = cpcodes.Group.ContractIDs[0] } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/cpcodes?groupId=%s&contractId=%s", cpcodes.Group.GroupID, cpcodes.Contract.ContractID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, cpcodes); err != nil { return err } byt, _ := json.Marshal(cpcodes) Profilecache.Set("cpcodes", byt, cache.DefaultExpiration) return nil } } func (cpcodes *CpCodes) FindCpCode(nameOrId string, correlationid string) (*CpCode, error) { if len(cpcodes.CpCodes.Items) == 0 { err := cpcodes.GetCpCodes(correlationid) if err != nil { return nil, err } if len(cpcodes.CpCodes.Items) == 0 { return nil, nil } } for _, cpcode := range cpcodes.CpCodes.Items { if cpcode.CpcodeID == nameOrId || cpcode.CpcodeID == "cpc_"+nameOrId || cpcode.CpcodeName == nameOrId { return cpcode, nil } } return nil, nil } // NewCpCode creates a new *CpCode associated with this *CpCodes as it's parent. func (cpcodes *CpCodes) NewCpCode() *CpCode { cpcode := NewCpCode(cpcodes) cpcodes.AddCpCode(cpcode) return cpcode } func (cpcodes *CpCodes) AddCpCode(cpcode *CpCode) { var exists bool for _, cpc := range cpcodes.CpCodes.Items { if cpc == cpcode { exists = true } } if !exists { cpcodes.CpCodes.Items = append(cpcodes.CpCodes.Items, cpcode) } } // CpCode represents a single CP Code // // API Docs: https://developer.akamai.com/api/luna/papi/data.html#cpcode type CpCode struct { client.Resource parent *CpCodes CpcodeID string `json:"cpcodeId,omitempty"` CpcodeName string `json:"cpcodeName"` ProductID string `json:"productId,omitempty"` ProductIDs []string `json:"productIds,omitempty"` CreatedDate time.Time `json:"createdDate,omitempty"` } // NewCpCode creates a new *CpCode func NewCpCode(parent *CpCodes) *CpCode { cpcode := &CpCode{parent: parent} cpcode.Init() return cpcode } // GetCpCode populates the *CpCode with it's data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getacpcode // Endpoint: GET /papi/v1/cpcodes/{cpcodeId}{?contractId,groupId} func (cpcode *CpCode) GetCpCode() error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/cpcodes/%s?contractId=%s&groupId=%s", cpcode.CpcodeID, cpcode.parent.Contract.ContractID, cpcode.parent.Group.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newCpcodes := NewCpCodes(nil, nil) if err = client.BodyJSON(res, newCpcodes); err != nil { return err } if len(newCpcodes.CpCodes.Items) == 0 { return fmt.Errorf("CP Code \"%s\" not found", cpcode.CpcodeID) } cpcode.CpcodeID = newCpcodes.CpCodes.Items[0].CpcodeID cpcode.CpcodeName = newCpcodes.CpCodes.Items[0].CpcodeName cpcode.ProductID = newCpcodes.CpCodes.Items[0].ProductID cpcode.ProductIDs = newCpcodes.CpCodes.Items[0].ProductIDs cpcode.CreatedDate = newCpcodes.CpCodes.Items[0].CreatedDate cpcode.parent.AddCpCode(cpcode) return nil } // ID retrieves a CP Codes integer ID // // PAPI Behaviors require the integer ID, rather than the prefixed string returned func (cpcode *CpCode) ID() int { id, err := strconv.Atoi(strings.TrimPrefix(cpcode.CpcodeID, "cpc_")) if err != nil { return 0 } return id } // Save will create a new CP Code. You cannot update a CP Code; // trying to do so will result in an error. // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#createanewcpcode // Endpoint: POST /papi/v1/cpcodes/{?contractId,groupId} func (cpcode *CpCode) Save(correlationid string) error { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/papi/v1/cpcodes?contractId=%s&groupId=%s", cpcode.parent.ContractID, cpcode.parent.GroupID, ), client.JSONBody{"productId": cpcode.ProductID, "cpcodeName": cpcode.CpcodeName}, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } var location client.JSONBody if err = client.BodyJSON(res, &location); err != nil { return err } req, err = client.NewRequest( Config, "GET", location["cpcodeLink"].(string), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err = client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } cpcodes := NewCpCodes(nil, nil) if err != nil { return err } if err = client.BodyJSON(res, cpcodes); err != nil { return err } newCpcode := cpcodes.CpCodes.Items[0] newCpcode.parent = cpcode.parent //cpcode.parent.CpCodes.Items = append(cpcode.parent.CpCodes.Items, newCpcode) cpcode.CpcodeID = cpcodes.CpCodes.Items[0].CpcodeID cpcode.CpcodeName = cpcodes.CpCodes.Items[0].CpcodeName cpcode.ProductIDs = cpcodes.CpCodes.Items[0].ProductIDs cpcode.CreatedDate = cpcodes.CpCodes.Items[0].CreatedDate cpcode.parent.AddCpCode(cpcode) return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/custombehaviors.go000066400000000000000000000105071400161560600276240ustar00rootroot00000000000000package papi import ( "fmt" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // CustomBehaviors represents a collection of Custom Behaviors // // See: CustomBehaviors.GetCustomBehaviors() // API Docs: https://developer.akamai.com/api/luna/papi/data.html#custombehavior type CustomBehaviors struct { client.Resource AccountID string `json:"accountId"` CustomBehaviors struct { Items []*CustomBehavior `json:"items"` } `json:"customBehaviors"` } // NewCustomBehaviors creates a new *CustomBehaviors func NewCustomBehaviors() *CustomBehaviors { return &CustomBehaviors{} } // PostUnmarshalJSON is called after UnmarshalJSON to setup the // structs internal state. The cpcodes.Complete channel is utilized // to communicate full completion. func (behaviors *CustomBehaviors) PostUnmarshalJSON() error { behaviors.Init() for key, behavior := range behaviors.CustomBehaviors.Items { behaviors.CustomBehaviors.Items[key].parent = behaviors if err := behavior.PostUnmarshalJSON(); err != nil { return err } } return nil } // GetCustomBehaviors populates a *CustomBehaviors with it's related Custom Behaviors // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getcustombehaviors // Endpoint: GET /papi/v1/custom-behaviors func (behaviors *CustomBehaviors) GetCustomBehaviors() error { req, err := client.NewRequest( Config, "GET", "/papi/v1/custom-behaviors", nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, behaviors); err != nil { return err } return nil } func (behaviors *CustomBehaviors) AddCustomBehavior(behavior *CustomBehavior) { var exists bool for _, cb := range behaviors.CustomBehaviors.Items { if cb == behavior { exists = true } } if !exists { behaviors.CustomBehaviors.Items = append(behaviors.CustomBehaviors.Items, behavior) } } // CustomBehavior represents a single Custom Behavior // // API Docs: https://developer.akamai.com/api/luna/papi/data.html#custombehavior type CustomBehavior struct { client.Resource parent *CustomBehaviors BehaviorID string `json:"behaviorId,omitempty"` Description string `json:"description"` DisplayName string `json:"displayName"` Name string `json:"name"` Status string `json:"status",omitempty` UpdatedByUser string `json:"updatedByUser,omitempty"` UpdatedDate time.Time `json:"updatedDate,omitempty"` XML string `json:"xml,omitempty"` } // GetCustomBehavior populates the *CustomBehavior with it's data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getcustombehavior // Endpoint: GET /papi/v1/custom-behaviors/{behaviorId} func (behavior *CustomBehavior) GetCustomBehavior() error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/custom-behaviors/%s", behavior.BehaviorID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newCustomBehaviors := NewCustomBehaviors() if err = client.BodyJSON(res, newCustomBehaviors); err != nil { return err } if len(newCustomBehaviors.CustomBehaviors.Items) == 0 { return fmt.Errorf("Custom Behavior \"%s\" not found", behavior.BehaviorID) } behavior.Name = newCustomBehaviors.CustomBehaviors.Items[0].Name behavior.Description = newCustomBehaviors.CustomBehaviors.Items[0].Description behavior.DisplayName = newCustomBehaviors.CustomBehaviors.Items[0].DisplayName behavior.Status = newCustomBehaviors.CustomBehaviors.Items[0].Status behavior.UpdatedByUser = newCustomBehaviors.CustomBehaviors.Items[0].UpdatedByUser behavior.UpdatedDate = newCustomBehaviors.CustomBehaviors.Items[0].UpdatedDate behavior.XML = newCustomBehaviors.CustomBehaviors.Items[0].XML behavior.parent.AddCustomBehavior(behavior) return nil } // NewCustomBehavior creates a new *CustomBehavior func NewCustomBehavior(behaviors *CustomBehaviors) *CustomBehavior { return &CustomBehavior{parent: behaviors} } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/custombehaviors_test.go000066400000000000000000000060311400161560600306600ustar00rootroot00000000000000package papi import ( "testing" "time" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) func TestCustomBehaviors_GetCustomBehaviors(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/custom-behaviors") mock. Get("/papi/v1/custom-behaviors"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_1-1TJZFB", "customBehaviors": { "items": [ { "behaviorId": "cbe_12345", "name": "DLR", "status": "ACTIVE", "displayName": "Custom Download Receipt", "description": "Setting custom download receipt. Uses PMUSER_LOG variable.", "updatedDate": "2017-04-24T12:34:56Z", "updatedByUser": "jsikkela" } ] } }`) Init(config) behaviors := NewCustomBehaviors() err := behaviors.GetCustomBehaviors() assert.NoError(t, err) assert.Len(t, behaviors.CustomBehaviors.Items, 1) assert.Equal(t, "cbe_12345", behaviors.CustomBehaviors.Items[0].BehaviorID) assert.Equal(t, "DLR", behaviors.CustomBehaviors.Items[0].Name) assert.Equal(t, "ACTIVE", behaviors.CustomBehaviors.Items[0].Status) assert.Equal(t, "Custom Download Receipt", behaviors.CustomBehaviors.Items[0].DisplayName) assert.Equal(t, "Setting custom download receipt. Uses PMUSER_LOG variable.", behaviors.CustomBehaviors.Items[0].Description) time, _ := time.Parse("2006-01-02T15:04:05Z", "2017-04-24T12:34:56Z") assert.Equal(t, time, behaviors.CustomBehaviors.Items[0].UpdatedDate) assert.Equal(t, "jsikkela", behaviors.CustomBehaviors.Items[0].UpdatedByUser) } func TestCustomBehavior_GetCustomBehavior(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/custom-behaviors/cbe_12345") mock. Get("/papi/v1/custom-behaviors/cbe_12345"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_1-1TJZFB", "customBehaviors": { "items": [ { "behaviorId": "cbe_12345", "name": "DLR", "status": "ACTIVE", "displayName": "Custom Download Receipt", "description": "Setting custom download receipt. Uses PMUSER_LOG variable.", "updatedDate": "2017-04-24T12:34:56Z", "updatedByUser": "jsikkela" } ] } }`) Init(config) behavior := NewCustomBehavior(NewCustomBehaviors()) behavior.BehaviorID = "cbe_12345" err := behavior.GetCustomBehavior() assert.NoError(t, err) assert.Equal(t, "cbe_12345", behavior.BehaviorID) assert.Equal(t, "DLR", behavior.Name) assert.Equal(t, "ACTIVE", behavior.Status) assert.Equal(t, "Custom Download Receipt", behavior.DisplayName) assert.Equal(t, "Setting custom download receipt. Uses PMUSER_LOG variable.", behavior.Description) time, _ := time.Parse("2006-01-02T15:04:05Z", "2017-04-24T12:34:56Z") assert.Equal(t, time, behavior.UpdatedDate) assert.Equal(t, "jsikkela", behavior.UpdatedByUser) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/customoverrides.go000066400000000000000000000105451400161560600276460ustar00rootroot00000000000000package papi import ( "fmt" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // CustomOverrides represents a collection of Custom Overrides // // See: CustomerOverrides.GetCustomOverrides() // API Docs: https://developer.akamai.com/api/luna/papi/data.html#cpcode type CustomOverrides struct { client.Resource AccountID string `json:"accountId"` CustomOverrides struct { Items []*CustomOverride `json:"items"` } `json:"customOverrides"` } // NewCustomOverrides creates a new *CustomOverrides func NewCustomOverrides() *CustomOverrides { return &CustomOverrides{} } // PostUnmarshalJSON is called after UnmarshalJSON to setup the // structs internal state. The CustomOverrides.Complete channel is utilized // to communicate full completion. func (overrides *CustomOverrides) PostUnmarshalJSON() error { overrides.Init() for key, override := range overrides.CustomOverrides.Items { overrides.CustomOverrides.Items[key].parent = overrides if err := override.PostUnmarshalJSON(); err != nil { return err } } overrides.Complete <- true return nil } // GetCustomOverrides populates a *CustomOverrides with it's related Custom Overrides // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getcustomoverrides // Endpoint: GET /papi/v1/custom-overrides func (overrides *CustomOverrides) GetCustomOverrides() error { req, err := client.NewRequest( Config, "GET", "/papi/v1/custom-overrides", nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, overrides); err != nil { return err } return nil } func (overrides *CustomOverrides) AddCustomOverride(override *CustomOverride) { var exists bool for _, co := range overrides.CustomOverrides.Items { if co == override { exists = true } } if !exists { overrides.CustomOverrides.Items = append(overrides.CustomOverrides.Items, override) } } // CustomOverride represents a single Custom Override // // API Docs: https://developer.akamai.com/api/luna/papi/data.html#customoverride type CustomOverride struct { client.Resource parent *CustomOverrides Description string `json:"description"` DisplayName string `json:"displayName"` Name string `json:"name"` OverrideID string `json:"overrideId,omitempty"` Status string `json:"status",omitempty` UpdatedByUser string `json:"updatedByUser,omitempty"` UpdatedDate time.Time `json:"updatedDate,omitempty"` XML string `json:"xml,omitempty"` } // GetCustomOverride populates the *CustomOverride with it's data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getcustomoverride // Endpoint: GET /papi/v1/custom-overrides/{overrideId} func (override *CustomOverride) GetCustomOverride() error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/custom-overrides/%s", override.OverrideID, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newCustomOverrides := NewCustomOverrides() if err = client.BodyJSON(res, newCustomOverrides); err != nil { return err } if len(newCustomOverrides.CustomOverrides.Items) == 0 { return fmt.Errorf("Custom Override \"%s\" not found", override.OverrideID) } override.Name = newCustomOverrides.CustomOverrides.Items[0].Name override.Description = newCustomOverrides.CustomOverrides.Items[0].Description override.DisplayName = newCustomOverrides.CustomOverrides.Items[0].DisplayName override.Status = newCustomOverrides.CustomOverrides.Items[0].Status override.UpdatedByUser = newCustomOverrides.CustomOverrides.Items[0].UpdatedByUser override.UpdatedDate = newCustomOverrides.CustomOverrides.Items[0].UpdatedDate override.XML = newCustomOverrides.CustomOverrides.Items[0].XML override.parent.AddCustomOverride(override) return nil } // NewCustomOverride creates a new *CustomOverride func NewCustomOverride(overrides *CustomOverrides) *CustomOverride { return &CustomOverride{parent: overrides} } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/customoverrides_test.go000066400000000000000000000057051400161560600307070ustar00rootroot00000000000000package papi import ( "testing" "time" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) func TestCustomOverrides_GetCustomOverrides(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/custom-overrides") mock. Get("/papi/v1/custom-overrides"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_1-1TJZFB", "customOverrides": { "items": [ { "overrideId": "cbo_12345", "displayName": "MDC Behavior", "description": "Multiple Domain Configuration can be used to ...", "name": "mdc", "status": "ACTIVE", "updatedByUser": "jsikkela", "updatedDate": "2017-04-24T12:34:56Z" } ] } }`) Init(config) overrides := NewCustomOverrides() err := overrides.GetCustomOverrides() assert.NoError(t, err) assert.Len(t, overrides.CustomOverrides.Items, 1) assert.Equal(t, "cbo_12345", overrides.CustomOverrides.Items[0].OverrideID) assert.Equal(t, "mdc", overrides.CustomOverrides.Items[0].Name) assert.Equal(t, "ACTIVE", overrides.CustomOverrides.Items[0].Status) assert.Equal(t, "MDC Behavior", overrides.CustomOverrides.Items[0].DisplayName) assert.Equal(t, "Multiple Domain Configuration can be used to ...", overrides.CustomOverrides.Items[0].Description) time, _ := time.Parse("2006-01-02T15:04:05Z", "2017-04-24T12:34:56Z") assert.Equal(t, time, overrides.CustomOverrides.Items[0].UpdatedDate) assert.Equal(t, "jsikkela", overrides.CustomOverrides.Items[0].UpdatedByUser) } func TestCustomOverride_GetCustomOverride(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/custom-overrides/cbo_12345") mock. Get("/papi/v1/custom-overrides/cbo_12345"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_1-1TJZFB", "customOverrides": { "items": [ { "overrideId": "cbo_12345", "displayName": "MDC Behavior", "description": "Multiple Domain Configuration can be used to ...", "name": "mdc", "status": "ACTIVE", "updatedByUser": "jsikkela", "updatedDate": "2017-04-24T12:34:56Z" } ] } }`) Init(config) override := NewCustomOverride(NewCustomOverrides()) override.OverrideID = "cbo_12345" err := override.GetCustomOverride() assert.NoError(t, err) assert.Equal(t, "cbo_12345", override.OverrideID) assert.Equal(t, "mdc", override.Name) assert.Equal(t, "ACTIVE", override.Status) assert.Equal(t, "MDC Behavior", override.DisplayName) assert.Equal(t, "Multiple Domain Configuration can be used to ...", override.Description) time, _ := time.Parse("2006-01-02T15:04:05Z", "2017-04-24T12:34:56Z") assert.Equal(t, time, override.UpdatedDate) assert.Equal(t, "jsikkela", override.UpdatedByUser) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/edgehostnames.go000066400000000000000000000266421400161560600272440ustar00rootroot00000000000000package papi import ( "encoding/json" "errors" "fmt" "net/url" "strings" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) // EdgeHostnames is a collection for PAPI Edge Hostname resources type EdgeHostnames struct { client.Resource AccountID string `json:"accountId"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` EdgeHostnames struct { Items []*EdgeHostname `json:"items"` } `json:"edgeHostnames"` } // NewEdgeHostnames creates a new EdgeHostnames func NewEdgeHostnames() *EdgeHostnames { edgeHostnames := &EdgeHostnames{} edgeHostnames.Init() return edgeHostnames } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (edgeHostnames *EdgeHostnames) PostUnmarshalJSON() error { edgeHostnames.Init() for key, edgeHostname := range edgeHostnames.EdgeHostnames.Items { edgeHostnames.EdgeHostnames.Items[key].parent = edgeHostnames if err := edgeHostname.PostUnmarshalJSON(); err != nil { return err } } edgeHostnames.Complete <- true return nil } // NewEdgeHostname creates a new EdgeHostname within a given EdgeHostnames func (edgeHostnames *EdgeHostnames) NewEdgeHostname() *EdgeHostname { edgeHostname := NewEdgeHostname(edgeHostnames) edgeHostnames.EdgeHostnames.Items = append(edgeHostnames.EdgeHostnames.Items, edgeHostname) return edgeHostname } // GetEdgeHostnames will populate EdgeHostnames with Edge Hostname data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listedgehostnames // Endpoint: GET /papi/v1/edgehostnames/{?contractId,groupId,options} func (edgeHostnames *EdgeHostnames) GetEdgeHostnames(contract *Contract, group *Group, options string, correlationid string) error { if contract == nil && group == nil { return errors.New("function requires at least \"group\" argument") } cacheedgehostnames, found := Profilecache.Get("edgehostnames") if found { json.Unmarshal(cacheedgehostnames.([]byte), edgeHostnames) return nil } else { if contract == nil && group != nil { contract = NewContract(NewContracts()) contract.ContractID = group.ContractIDs[0] } if options != "" { options = fmt.Sprintf("&options=%s", options) } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/edgehostnames?groupId=%s&contractId=%s%s", group.GroupID, contract.ContractID, options, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, edgeHostnames); err != nil { return err } byt, _ := json.Marshal(edgeHostnames) Profilecache.Set("edgehostnames", byt, cache.DefaultExpiration) return nil } } func (edgeHostnames *EdgeHostnames) FindEdgeHostname(edgeHostname *EdgeHostname) (*EdgeHostname, error) { if edgeHostname.DomainSuffix == "" && edgeHostname.EdgeHostnameDomain != "" { edgeHostname.DomainSuffix = "edgesuite.net" if strings.HasSuffix(edgeHostname.EdgeHostnameDomain, "edgekey.net") { edgeHostname.DomainSuffix = "edgekey.net" } } if edgeHostname.DomainPrefix == "" && edgeHostname.EdgeHostnameDomain != "" { edgeHostname.DomainPrefix = strings.TrimSuffix(edgeHostname.EdgeHostnameDomain, "."+edgeHostname.DomainSuffix) } if len(edgeHostnames.EdgeHostnames.Items) == 0 { return nil, errors.New("no hostnames found, did you call GetHostnames()?") } for _, eHn := range edgeHostnames.EdgeHostnames.Items { if (eHn.DomainPrefix == edgeHostname.DomainPrefix && eHn.DomainSuffix == edgeHostname.DomainSuffix) || eHn.EdgeHostnameID == edgeHostname.EdgeHostnameID { return eHn, nil } } return nil, nil } func (edgeHostnames *EdgeHostnames) AddEdgeHostname(edgeHostname *EdgeHostname) { found, err := edgeHostnames.FindEdgeHostname(edgeHostname) if err != nil || found == nil { edgeHostnames.EdgeHostnames.Items = append(edgeHostnames.EdgeHostnames.Items, edgeHostname) } if err == nil && found != nil && found.EdgeHostnameID == edgeHostname.EdgeHostnameID { *found = *edgeHostname } } // EdgeHostname represents an Edge Hostname resource type EdgeHostname struct { client.Resource parent *EdgeHostnames EdgeHostnameID string `json:"edgeHostnameId,omitempty"` EdgeHostnameDomain string `json:"edgeHostnameDomain,omitempty"` ProductID string `json:"productId"` DomainPrefix string `json:"domainPrefix"` DomainSuffix string `json:"domainSuffix"` CertEnrollmentId int `json:"certEnrollmentId,omitempty"` SlotNumber int `json:"slotNumber,omitempty"` SecureNetwork string `json:"secureNetwork,omitempty"` Status StatusValue `json:"status,omitempty"` Secure bool `json:"secure,omitempty"` IPVersionBehavior string `json:"ipVersionBehavior,omitempty"` MapDetailsSerialNumber int `json:"mapDetails:serialNumber,omitempty"` MapDetailsSlotNumber int `json:"mapDetails:slotNumber,omitempty"` MapDetailsMapDomain string `json:"mapDetails:mapDomain,omitempty"` StatusChange chan bool `json:"-"` } // NewEdgeHostname creates a new EdgeHostname func NewEdgeHostname(edgeHostnames *EdgeHostnames) *EdgeHostname { edgeHostname := &EdgeHostname{parent: edgeHostnames} edgeHostname.Init() return edgeHostname } func (edgeHostname *EdgeHostname) Init() { edgeHostname.Complete = make(chan bool, 1) edgeHostname.StatusChange = make(chan bool, 1) } // GetEdgeHostname populates EdgeHostname with data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getanedgehostname // Endpoint: GET /papi/v1/edgehostnames/{edgeHostnameId}{?contractId,groupId,options} func (edgeHostname *EdgeHostname) GetEdgeHostname(options string, correlationid string) error { if options != "" { options = "&options=" + options } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/edgehostnames/%s?contractId=%s&groupId=%s%s", edgeHostname.EdgeHostnameID, edgeHostname.parent.ContractID, edgeHostname.parent.GroupID, options, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { if res.StatusCode == 404 { // Check collection for current hostname contract := NewContract(NewContracts()) contract.ContractID = edgeHostname.parent.ContractID group := NewGroup(NewGroups()) group.GroupID = edgeHostname.parent.GroupID edgeHostname.parent.GetEdgeHostnames(contract, group, "", correlationid) newEdgeHostname, err := edgeHostname.parent.FindEdgeHostname(edgeHostname) if err != nil || newEdgeHostname == nil { return client.NewAPIError(res) } edgeHostname.EdgeHostnameID = newEdgeHostname.EdgeHostnameID edgeHostname.EdgeHostnameDomain = newEdgeHostname.EdgeHostnameDomain edgeHostname.ProductID = newEdgeHostname.ProductID edgeHostname.DomainPrefix = newEdgeHostname.DomainPrefix edgeHostname.DomainSuffix = newEdgeHostname.DomainSuffix edgeHostname.Status = newEdgeHostname.Status edgeHostname.Secure = newEdgeHostname.Secure edgeHostname.IPVersionBehavior = newEdgeHostname.IPVersionBehavior edgeHostname.MapDetailsSerialNumber = newEdgeHostname.MapDetailsSerialNumber edgeHostname.MapDetailsSlotNumber = newEdgeHostname.MapDetailsSlotNumber edgeHostname.MapDetailsMapDomain = newEdgeHostname.MapDetailsMapDomain return nil } return client.NewAPIError(res) } newEdgeHostnames := NewEdgeHostnames() if err := client.BodyJSON(res, newEdgeHostnames); err != nil { return err } edgeHostname.EdgeHostnameID = newEdgeHostnames.EdgeHostnames.Items[0].EdgeHostnameID edgeHostname.EdgeHostnameDomain = newEdgeHostnames.EdgeHostnames.Items[0].EdgeHostnameDomain edgeHostname.ProductID = newEdgeHostnames.EdgeHostnames.Items[0].ProductID edgeHostname.DomainPrefix = newEdgeHostnames.EdgeHostnames.Items[0].DomainPrefix edgeHostname.DomainSuffix = newEdgeHostnames.EdgeHostnames.Items[0].DomainSuffix edgeHostname.Status = newEdgeHostnames.EdgeHostnames.Items[0].Status edgeHostname.Secure = newEdgeHostnames.EdgeHostnames.Items[0].Secure edgeHostname.IPVersionBehavior = newEdgeHostnames.EdgeHostnames.Items[0].IPVersionBehavior edgeHostname.MapDetailsSerialNumber = newEdgeHostnames.EdgeHostnames.Items[0].MapDetailsSerialNumber edgeHostname.MapDetailsSlotNumber = newEdgeHostnames.EdgeHostnames.Items[0].MapDetailsSlotNumber edgeHostname.MapDetailsMapDomain = newEdgeHostnames.EdgeHostnames.Items[0].MapDetailsMapDomain return nil } // Save creates a new Edge Hostname // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#createanewedgehostname // Endpoint: POST /papi/v1/edgehostnames/{?contractId,groupId,options} func (edgeHostname *EdgeHostname) Save(options string, correlationid string) error { if options != "" { options = "&options=" + options } req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/papi/v1/edgehostnames/?contractId=%s&groupId=%s%s", edgeHostname.parent.ContractID, edgeHostname.parent.GroupID, options, ), edgeHostname, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } var location client.JSONBody if err = client.BodyJSON(res, &location); err != nil { return err } // A 404 is returned until the hostname is valid, so just pull the new ID out for now url, _ := url.Parse(location["edgeHostnameLink"].(string)) for _, part := range strings.Split(url.Path, "/") { if strings.HasPrefix(part, "ehn_") { edgeHostname.EdgeHostnameID = part } } edgeHostname.parent.AddEdgeHostname(edgeHostname) return nil } // PollStatus will responsibly poll till the property is active or an error occurs // // The EdgeHostname.StatusChange is a channel that can be used to // block on status changes. If a new valid status is returned, true will // be sent to the channel, otherwise, false will be sent. // // go edgeHostname.PollStatus("") // for edgeHostname.Status != edgegrid.StatusActive { // select { // case statusChanged := <-edgeHostname.StatusChange: // if statusChanged == false { // break // } // case <-time.After(time.Minute * 30): // break // } // } // // if edgeHostname.Status == edgegrid.StatusActive { // // EdgeHostname activated successfully // } func (edgeHostname *EdgeHostname) PollStatus(options string, correlationid string) bool { currentStatus := edgeHostname.Status var retry time.Duration = 0 for currentStatus != StatusActive { time.Sleep(retry) if retry == 0 { retry = time.Minute * 3 } retry -= time.Minute err := edgeHostname.GetEdgeHostname(options, correlationid) if err != nil { edgeHostname.StatusChange <- false return false } if currentStatus != edgeHostname.Status { edgeHostname.StatusChange <- true } currentStatus = edgeHostname.Status } return true } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/errors.go000066400000000000000000000011161400161560600257170ustar00rootroot00000000000000package papi import "errors" // Error constants const ( ErrInvalidPath = iota ErrCriteriaNotFound ErrBehaviorNotFound ErrVariableNotFound ErrRuleNotFound ErrInvalidRules ) var ( ErrorMap = map[int]error{ ErrInvalidPath: errors.New("Invalid Path"), ErrCriteriaNotFound: errors.New("Criteria not found"), ErrBehaviorNotFound: errors.New("Behavior not found"), ErrVariableNotFound: errors.New("Variable not found"), ErrRuleNotFound: errors.New("Rule not found"), ErrInvalidRules: errors.New("Rule validation failed. See papi.Rules.Errors for details"), } ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/groups.go000066400000000000000000000124311400161560600257240ustar00rootroot00000000000000package papi import ( "encoding/json" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) // Groups represents a collection of PAPI groups type Groups struct { client.Resource AccountID string `json:"accountId"` AccountName string `json:"accountName"` Groups struct { Items []*Group `json:"items"` } `json:"groups"` } // NewGroups creates a new Groups func NewGroups() *Groups { groups := &Groups{} return groups } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (groups *Groups) PostUnmarshalJSON() error { groups.Init() for key, group := range groups.Groups.Items { groups.Groups.Items[key].parent = groups if err := group.PostUnmarshalJSON(); err != nil { return err } } groups.Complete <- true return nil } // GetGroups populates Groups with group data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listgroups // Endpoint: GET /papi/v1/groups/ func (groups *Groups) GetGroups(correlationid string) error { cachegroups, found := Profilecache.Get("groups") if found { json.Unmarshal(cachegroups.([]byte), groups) return nil } else { req, err := client.NewRequest( Config, "GET", "/papi/v1/groups", nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, groups); err != nil { return err } byt, _ := json.Marshal(groups) Profilecache.Set("groups", byt, cache.DefaultExpiration) return nil } } // AddGroup adds a group to a Groups collection func (groups *Groups) AddGroup(newGroup *Group) { if newGroup.GroupID != "" { for key, group := range groups.Groups.Items { if group.GroupID == newGroup.GroupID { groups.Groups.Items[key] = newGroup return } } } newGroup.parent = groups groups.Groups.Items = append(groups.Groups.Items, newGroup) } // FindGroup finds a specific group by ID func (groups *Groups) FindGroup(id string) (*Group, error) { var group *Group var groupFound bool if id == "" { goto err } for _, group = range groups.Groups.Items { if group.GroupID == id { groupFound = true break } } err: if !groupFound { return nil, fmt.Errorf("Unable to find group: \"%s\"", id) } return group, nil } // FindGroupId finds a specific group by name // Deprecated: When there are multiple groups with same name, // the first one is returned. Please use FindGroupsByName instead. func (groups *Groups) FindGroupId(name string) (*Group, error) { var group *Group var groupFound bool if name == "" { goto err } for _, group = range groups.Groups.Items { if group.GroupName == name { groupFound = true break } } err: if !groupFound { return nil, fmt.Errorf("Unable to find group: \"%s\"", name) } return group, nil } // FindGroupsByName finds groups by name func (groups *Groups) FindGroupsByName(name string) ([]*Group, error) { var group *Group var foundGroups []*Group var groupFound bool if name == "" { goto err } for _, group = range groups.Groups.Items { if group.GroupName == name { foundGroups = append(foundGroups, group) groupFound = true } } err: if !groupFound { return nil, fmt.Errorf("Unable to find group: \"%s\"", name) } return foundGroups, nil } // Group represents a group resource type Group struct { client.Resource parent *Groups GroupName string `json:"groupName"` GroupID string `json:"groupId"` ParentGroupID string `json:"parentGroupId,omitempty"` ContractIDs []string `json:"contractIds"` } // NewGroup creates a new Group func NewGroup(parent *Groups) *Group { group := &Group{ parent: parent, } group.Init() return group } // GetGroup populates a Group func (group *Group) GetGroup() { groups, err := GetGroups() if err != nil { return } for _, g := range groups.Groups.Items { if g.GroupID == group.GroupID { group.parent = groups group.ContractIDs = g.ContractIDs group.GroupName = g.GroupName group.ParentGroupID = g.ParentGroupID group.Complete <- true return } } group.Complete <- false } // GetProperties retrieves all properties associated with a given group and contract func (group *Group) GetProperties(contract *Contract) (*Properties, error) { return GetProperties(contract, group) } // GetCpCodes retrieves all CP codes associated with a given group and contract func (group *Group) GetCpCodes(contract *Contract) (*CpCodes, error) { return GetCpCodes(contract, group) } // GetEdgeHostnames retrieves all Edge hostnames associated with a given group/contract func (group *Group) GetEdgeHostnames(contract *Contract, options string, correlationid string) (*EdgeHostnames, error) { return GetEdgeHostnames(contract, group, options) } // NewProperty creates a property associated with a given group/contract func (group *Group) NewProperty(contract *Contract) (*Property, error) { property := NewProperty(NewProperties()) property.Contract = contract property.Group = group return property, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/hostnames.go000066400000000000000000000103611400161560600264060ustar00rootroot00000000000000package papi import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // Hostnames is a collection of Property Hostnames type Hostnames struct { client.Resource AccountID string `json:"accountId"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` PropertyID string `json:"propertyId"` PropertyVersion int `json:"propertyVersion"` Etag string `json:"etag"` Hostnames struct { Items []*Hostname `json:"items"` } `json:"hostnames"` } // NewHostnames creates a new Hostnames func NewHostnames() *Hostnames { hostnames := &Hostnames{} hostnames.Init() return hostnames } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (hostnames *Hostnames) PostUnmarshalJSON() error { hostnames.Init() for key, hostname := range hostnames.Hostnames.Items { hostnames.Hostnames.Items[key].parent = hostnames if err := hostname.PostUnmarshalJSON(); err != nil { return err } } hostnames.Complete <- true return nil } // GetHostnames retrieves hostnames assigned to a given property // // If no version is given, the latest version is used // // See: Property.GetHostnames() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listapropertyshostnames // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/hostnames/{?contractId,groupId} func (hostnames *Hostnames) GetHostnames(version *Version, correlationid string) error { if version == nil { property := NewProperty(NewProperties()) property.PropertyID = hostnames.PropertyID err := property.GetProperty(correlationid) if err != nil { return err } version, err = property.GetLatestVersion("", correlationid) if err != nil { return err } } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/hostnames/?contractId=%s&groupId=%s", hostnames.PropertyID, version.PropertyVersion, hostnames.ContractID, hostnames.GroupID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, hostnames); err != nil { return err } return nil } // NewHostname creates a new Hostname within a given Hostnames func (hostnames *Hostnames) NewHostname() *Hostname { hostname := NewHostname(hostnames) hostnames.Hostnames.Items = append(hostnames.Hostnames.Items, hostname) return hostname } // Save updates a properties hostnames func (hostnames *Hostnames) Save() error { req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/hostnames?contractId=%s&groupId=%s", hostnames.PropertyID, hostnames.PropertyVersion, hostnames.ContractID, hostnames.GroupID, ), hostnames.Hostnames.Items, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, hostnames); err != nil { return err } return nil } // Hostname represents a property hostname resource type Hostname struct { client.Resource parent *Hostnames CnameType CnameTypeValue `json:"cnameType"` EdgeHostnameID string `json:"edgeHostnameId,omitempty"` CnameFrom string `json:"cnameFrom"` CnameTo string `json:"cnameTo,omitempty"` CertEnrollmentId string `json:"certEnrollmentId,omitempty"` } // NewHostname creates a new Hostname func NewHostname(parent *Hostnames) *Hostname { hostname := &Hostname{parent: parent, CnameType: CnameTypeEdgeHostname} hostname.Init() return hostname } // CnameTypeValue is used to create an "enum" of possible Hostname.CnameType values type CnameTypeValue string const ( // CnameTypeEdgeHostname Hostname.CnameType value EDGE_HOSTNAME CnameTypeEdgeHostname CnameTypeValue = "EDGE_HOSTNAME" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/init.go000066400000000000000000000004231400161560600253460ustar00rootroot00000000000000// Package papi provides a simple wrapper for the Akamai Property Manager API package papi import "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" // Init sets the PAPI edgegrid Config func Init(config edgegrid.Config) { Config = config edgegrid.SetupLogging() } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/products.go000066400000000000000000000053051400161560600262520ustar00rootroot00000000000000package papi import ( "encoding/json" "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) // Products represents a collection of products type Products struct { client.Resource AccountID string `json:"accountId"` ContractID string `json:"contractId"` Products struct { Items []*Product `json:"items"` } `json:"products"` } // NewProducts creates a new Products func NewProducts() *Products { products := &Products{} products.Init() return products } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (products *Products) PostUnmarshalJSON() error { products.Init() for key, product := range products.Products.Items { products.Products.Items[key].parent = products if err := product.PostUnmarshalJSON(); err != nil { return err } } return nil } // GetProducts populates Products with product data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listproducts // Endpoint: GET /papi/v1/products/{?contractId} func (products *Products) GetProducts(contract *Contract, correlationid string) error { cacheproducts, found := Profilecache.Get("products") if found { json.Unmarshal(cacheproducts.([]byte), products) return nil } else { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/products?contractId=%s", contract.ContractID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, products); err != nil { return err } byt, _ := json.Marshal(products) Profilecache.Set("products", byt, cache.DefaultExpiration) return nil } } // FindProduct finds a specific product by ID func (products *Products) FindProduct(id string) (*Product, error) { var product *Product var productFound bool for _, product = range products.Products.Items { if product.ProductID == id { productFound = true break } } if !productFound { return nil, fmt.Errorf("Unable to find product: \"%s\"", id) } return product, nil } // Product represents a product resource type Product struct { client.Resource parent *Products ProductName string `json:"productName"` ProductID string `json:"productId"` } // NewProduct creates a new Product func NewProduct(parent *Products) *Product { product := &Product{parent: parent} product.Init() return product } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/properties.go000066400000000000000000000355441400161560600266130ustar00rootroot00000000000000package papi import ( "fmt" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // Properties is a collection of PAPI Property resources type Properties struct { client.Resource Properties struct { Items []*Property `json:"items"` } `json:"properties"` } // NewProperties creates a new Properties func NewProperties() *Properties { properties := &Properties{} properties.Init() return properties } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (properties *Properties) PostUnmarshalJSON() error { properties.Init() for key, property := range properties.Properties.Items { properties.Properties.Items[key].parent = properties if err := property.PostUnmarshalJSON(); err != nil { return err } } properties.Complete <- true return nil } // GetProperties populates Properties with property data // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listproperties // Endpoint: GET /papi/v1/properties/{?contractId,groupId} func (properties *Properties) GetProperties(contract *Contract, group *Group, correlationid string) error { if contract == nil { contract = NewContract(NewContracts()) contract.ContractID = group.ContractIDs[0] } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties?groupId=%s&contractId=%s", group.GroupID, contract.ContractID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return nil } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, properties); err != nil { return err } return nil } // AddProperty adds a property to the collection, if the property already exists // in the collection it will be replaced. func (properties *Properties) AddProperty(newProperty *Property) { if newProperty.PropertyID != "" { for key, property := range properties.Properties.Items { if property.PropertyID == newProperty.PropertyID { properties.Properties.Items[key] = newProperty return } } } newProperty.parent = properties properties.Properties.Items = append(properties.Properties.Items, newProperty) } // FindProperty finds a property by ID within the collection func (properties *Properties) FindProperty(id string) (*Property, error) { var property *Property var propertyFound bool for _, property = range properties.Properties.Items { if property.PropertyID == id { propertyFound = true break } } if !propertyFound { return nil, fmt.Errorf("Unable to find property: \"%s\"", id) } return property, nil } // NewProperty creates a new property associated with the collection func (properties *Properties) NewProperty(contract *Contract, group *Group) *Property { property := NewProperty(properties) properties.AddProperty(property) property.Contract = contract property.Group = group go property.Contract.GetContract() go property.Group.GetGroup() go (func(property *Property) { groupCompleted := <-property.Group.Complete contractCompleted := <-property.Contract.Complete property.Complete <- (groupCompleted && contractCompleted) })(property) return property } // Property represents a PAPI Property type Property struct { client.Resource parent *Properties AccountID string `json:"accountId,omitempty"` Contract *Contract `json:"-"` Group *Group `json:"-"` ContractID string `json:"contractId,omitempty"` GroupID string `json:"groupId,omitempty"` PropertyID string `json:"propertyId,omitempty"` PropertyName string `json:"propertyName"` LatestVersion int `json:"latestVersion,omitempty"` StagingVersion int `json:"stagingVersion,omitempty"` ProductionVersion int `json:"productionVersion,omitempty"` Note string `json:"note,omitempty"` ProductID string `json:"productId,omitempty"` RuleFormat string `json:"ruleFormat",omitempty` CloneFrom *ClonePropertyFrom `json:"cloneFrom"` } // NewProperty creates a new Property func NewProperty(parent *Properties) *Property { property := &Property{parent: parent, Group: &Group{}, Contract: &Contract{}} property.Init() return property } // PreMarshalJSON is called before JSON marshaling // // See: jsonhooks-v1/json.Marshal() func (property *Property) PreMarshalJSON() error { property.GroupID = property.Group.GroupID property.ContractID = property.Contract.ContractID return nil } // GetProperty populates a Property // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaproperty // Endpoint: GET /papi/v1/properties/{propertyId}{?contractId,groupId} func (property *Property) GetProperty(correlationid string) error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s", property.PropertyID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } newProperties := NewProperties() if err := client.BodyJSON(res, newProperties); err != nil { return err } property.AccountID = newProperties.Properties.Items[0].AccountID property.Contract = newProperties.Properties.Items[0].Contract property.Group = newProperties.Properties.Items[0].Group property.ContractID = newProperties.Properties.Items[0].ContractID property.GroupID = newProperties.Properties.Items[0].GroupID property.PropertyID = newProperties.Properties.Items[0].PropertyID property.PropertyName = newProperties.Properties.Items[0].PropertyName property.LatestVersion = newProperties.Properties.Items[0].LatestVersion property.StagingVersion = newProperties.Properties.Items[0].StagingVersion property.ProductionVersion = newProperties.Properties.Items[0].ProductionVersion property.Note = newProperties.Properties.Items[0].Note property.ProductID = newProperties.Properties.Items[0].ProductID property.RuleFormat = newProperties.Properties.Items[0].RuleFormat property.CloneFrom = newProperties.Properties.Items[0].CloneFrom return nil } // GetActivations retrieves activation data for a given property // // See: Activations.GetActivations() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listactivations // Endpoint: GET /papi/v1/properties/{propertyId}/activations/{?contractId,groupId} func (property *Property) GetActivations() (*Activations, error) { activations := NewActivations() if err := activations.GetActivations(property); err != nil { return nil, err } return activations, nil } // GetAvailableBehaviors retrieves available behaviors for a given property // // See: AvailableBehaviors.GetAvailableBehaviors // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listavailablebehaviors // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/available-behaviors{?contractId,groupId} func (property *Property) GetAvailableBehaviors() (*AvailableBehaviors, error) { behaviors := NewAvailableBehaviors() if err := behaviors.GetAvailableBehaviors(property); err != nil { return nil, err } return behaviors, nil } // GetRules retrieves rules for a property // // See: Rules.GetRules // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaruletree // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/rules/{?contractId,groupId} func (property *Property) GetRules(correlationid string) (*Rules, error) { rules := NewRules() if err := rules.GetRules(property, correlationid); err != nil { return nil, err } return rules, nil } // GetRulesDigest fetches the Etag for a rule tree // // See: Rules.GetRulesDigest() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaruletreesdigest // Endpoint: HEAD /papi/v1/properties/{propertyId}/versions/{propertyVersion}/rules/{?contractId,groupId} func (property *Property) GetRulesDigest(correlationid string) (string, error) { rules := NewRules() return rules.GetRulesDigest(property, correlationid) } // GetVersions retrieves all versions for a a given property // // See: Versions.GetVersions() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listversions // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{?contractId,groupId} func (property *Property) GetVersions(correlationid string) (*Versions, error) { versions := NewVersions() err := versions.GetVersions(property, correlationid) if err != nil { return nil, err } return versions, nil } // GetLatestVersion gets the latest active version, optionally of a given network // // See: Versions.GetLatestVersion() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getthelatestversion // Endpoint: GET /papi/v1/properties/{propertyId}/versions/latest{?contractId,groupId,activatedOn} func (property *Property) GetLatestVersion(activatedOn NetworkValue, correlationid string) (*Version, error) { versions := NewVersions() versions.PropertyID = property.PropertyID return versions.GetLatestVersion(activatedOn, correlationid) } // GetHostnames retrieves hostnames assigned to a given property // // If no version is given, the latest version is used // // See: Hostnames.GetHostnames() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getpropertyversionhostnames // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/hostnames/{?contractId,groupId} func (property *Property) GetHostnames(version *Version, correlationid string) (*Hostnames, error) { hostnames := NewHostnames() hostnames.PropertyID = property.PropertyID hostnames.ContractID = property.Contract.ContractID hostnames.GroupID = property.Group.GroupID if version == nil { var err error version, err = property.GetLatestVersion("", correlationid) if err != nil { return nil, err } } err := hostnames.GetHostnames(version, correlationid) if err != nil { return nil, err } return hostnames, nil } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (property *Property) PostUnmarshalJSON() error { property.Init() property.Contract = NewContract(NewContracts()) property.Contract.ContractID = property.ContractID property.Group = NewGroup(NewGroups()) property.Group.GroupID = property.GroupID go property.Group.GetGroup() go property.Contract.GetContract() go (func(property *Property) { contractComplete := <-property.Contract.Complete groupComplete := <-property.Group.Complete property.Complete <- (contractComplete && groupComplete) })(property) return nil } // Save will create a property, optionally cloned from another property // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#createorcloneaproperty // Endpoint: POST /papi/v1/properties/{?contractId,groupId} func (property *Property) Save(correlationid string) error { req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/papi/v1/properties?contractId=%s&groupId=%s", property.Contract.ContractID, property.Group.GroupID, ), property, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } var location client.JSONBody if err = client.BodyJSON(res, &location); err != nil { return err } req, err = client.NewRequest( Config, "GET", location["propertyLink"].(string), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err = client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } properties := NewProperties() if err = client.BodyJSON(res, properties); err != nil { return err } property.AccountID = properties.Properties.Items[0].AccountID property.Contract = properties.Properties.Items[0].Contract property.Group = properties.Properties.Items[0].Group property.ContractID = properties.Properties.Items[0].ContractID property.GroupID = properties.Properties.Items[0].GroupID property.PropertyID = properties.Properties.Items[0].PropertyID property.PropertyName = properties.Properties.Items[0].PropertyName property.LatestVersion = properties.Properties.Items[0].LatestVersion property.StagingVersion = properties.Properties.Items[0].StagingVersion property.ProductionVersion = properties.Properties.Items[0].ProductionVersion property.Note = properties.Properties.Items[0].Note property.ProductID = properties.Properties.Items[0].ProductID property.CloneFrom = properties.Properties.Items[0].CloneFrom return nil } // Activate activates a given property // // If acknowledgeWarnings is true and warnings are returned on the first attempt, // a second attempt is made, acknowledging the warnings. // // See: Activation.Save() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#activateaproperty // Endpoint: POST /papi/v1/properties/{propertyId}/activations/{?contractId,groupId} func (property *Property) Activate(activation *Activation, acknowledgeWarnings bool) error { return activation.Save(property, acknowledgeWarnings) } // Delete a property // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#removeaproperty // Endpoint: DELETE /papi/v1/properties/{propertyId}{?contractId,groupId} func (property *Property) Delete(correlationid string) error { // /papi/v1/properties/{propertyId}{?contractId,groupId} req, err := client.NewRequest( Config, "DELETE", fmt.Sprintf( "/papi/v1/properties/%s", property.PropertyID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } return nil } // ClonePropertyFrom represents type ClonePropertyFrom struct { client.Resource PropertyID string `json:"propertyId"` Version int `json:"version"` CopyHostnames bool `json:"copyHostnames,omitempty"` CloneFromVersionEtag string `json:"cloneFromVersionEtag,omitempty"` } // NewClonePropertyFrom creates a new ClonePropertyFrom func NewClonePropertyFrom() *ClonePropertyFrom { clonePropertyFrom := &ClonePropertyFrom{} clonePropertyFrom.Init() return clonePropertyFrom } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/ruleformats.go000066400000000000000000000051021400161560600267450ustar00rootroot00000000000000package papi import ( "fmt" "io/ioutil" "sort" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/xeipuuv/gojsonschema" ) // RuleFormats is a collection of available rule formats type RuleFormats struct { client.Resource RuleFormats struct { Items []string `json:"items"` } `json:"ruleFormats"` } // NewRuleFormats creates a new RuleFormats func NewRuleFormats() *RuleFormats { ruleFormats := &RuleFormats{} ruleFormats.Init() return ruleFormats } // GetRuleFormats populates RuleFormats // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listruleformats // Endpoint: GET /papi/v1/rule-formats func (ruleFormats *RuleFormats) GetRuleFormats(correlationid string) error { req, err := client.NewRequest( Config, "GET", "/papi/v1/rule-formats", nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err := client.BodyJSON(res, ruleFormats); err != nil { return err } sort.Strings(ruleFormats.RuleFormats.Items) return nil } func (ruleFormats *RuleFormats) GetLatest(correlationid string) (string, error) { if len(ruleFormats.RuleFormats.Items) == 0 { err := ruleFormats.GetRuleFormats(correlationid) if err != nil { return "", err } } return ruleFormats.RuleFormats.Items[len(ruleFormats.RuleFormats.Items)-1], nil } // GetSchema fetches the schema for a given product and rule format // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaruleformatsschema // Endpoint: /papi/v1/schemas/products/{productId}/{ruleFormat} func (ruleFormats *RuleFormats) GetSchema(product string, ruleFormat string, correlationid string) (*gojsonschema.Schema, error) { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/schemas/products/%s/%s", product, ruleFormat, ), nil, ) if err != nil { return nil, err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return nil, client.NewAPIError(res) } schemaBytes, _ := ioutil.ReadAll(res.Body) schemaBody := string(schemaBytes) loader := gojsonschema.NewStringLoader(schemaBody) schema, err := gojsonschema.NewSchema(loader) return schema, err } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/rules.go000066400000000000000000000334511400161560600255440ustar00rootroot00000000000000package papi import ( "fmt" "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // Rules is a collection of property rules type Rules struct { client.Resource AccountID string `json:"accountId"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` PropertyID string `json:"propertyId"` PropertyVersion int `json:"propertyVersion"` Etag string `json:"etag"` RuleFormat string `json:"ruleFormat"` Rule *Rule `json:"rules"` Errors []*RuleErrors `json:"errors,omitempty"` } // NewRules creates a new Rules func NewRules() *Rules { rules := &Rules{} rules.Rule = NewRule() rules.Rule.Name = "default" rules.Init() return rules } // PreMarshalJSON is called before JSON marshaling // // See: jsonhooks-v1/json.Marshal() func (rules *Rules) PreMarshalJSON() error { rules.Errors = nil return nil } // GetRules populates Rules with rule data for a given property // // See: Property.GetRules // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaruletree // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{propertyVersion}/rules/{?contractId,groupId} func (rules *Rules) GetRules(property *Property, correlationid string) error { req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/rules", property.PropertyID, property.LatestVersion, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, rules); err != nil { return err } return nil } // GetRulesDigest fetches the Etag for a rule tree // // See: Property.GetRulesDigest() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaruletreesdigest // Endpoint: HEAD /papi/v1/properties/{propertyId}/versions/{propertyVersion}/rules/{?contractId,groupId} func (rules *Rules) GetRulesDigest(property *Property, correlationid string) (string, error) { req, err := client.NewRequest( Config, "HEAD", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/rules", property.PropertyID, property.LatestVersion, ), nil, ) if err != nil { return "", err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return "", err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return "", client.NewAPIError(res) } return res.Header.Get("Etag"), nil } // Save creates/updates a rule tree for a property // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#putpropertyversionrules // Endpoint: PUT /papi/v1/properties/{propertyId}/versions/{propertyVersion}/rules{?contractId,groupId} func (rules *Rules) Save(correlationid string) error { rules.Errors = []*RuleErrors{} req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/rules", rules.PropertyID, rules.PropertyVersion, ), rules, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, rules); err != nil { return err } if len(rules.Errors) != 0 { return ErrorMap[ErrInvalidRules] } return nil } // Freeze pins a properties rule set to a specific rule set version func (rules *Rules) Freeze(format string) error { rules.Errors = []*RuleErrors{} req, err := client.NewJSONRequest( Config, "PUT", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d/rules", rules.PropertyID, rules.PropertyVersion, ), rules, ) if err != nil { return err } edge.PrintHttpRequest(req, true) req.Header.Set("Content-Type", fmt.Sprintf("application/vnd.akamai.papirules.%s+json", format)) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } if err = client.BodyJSON(res, rules); err != nil { return err } if len(rules.Errors) != 0 { return ErrorMap[ErrInvalidRules] } return nil } // Rule represents a property rule resource type Rule struct { client.Resource Depth int `json:"-"` Name string `json:"name"` Criteria []*Criteria `json:"criteria,omitempty"` Behaviors []*Behavior `json:"behaviors,omitempty"` Children []*Rule `json:"children,omitempty"` Comments string `json:"comments,omitempty"` CriteriaLocked bool `json:"criteriaLocked,omitempty"` CriteriaMustSatisfy RuleCriteriaMustSatisfyValue `json:"criteriaMustSatisfy,omitempty"` UUID string `json:"uuid,omitempty"` Variables []*Variable `json:"variables,omitempty"` AdvancedOverride string `json:"advancedOverride,omitempty"` Options struct { IsSecure bool `json:"is_secure,omitempty"` } `json:"options,omitempty"` CustomOverride *CustomOverride `json:"customOverride,omitempty"` } // NewRule creates a new Rule func NewRule() *Rule { rule := &Rule{} rule.Init() return rule } // MergeBehavior merges a behavior into a rule // // If the behavior already exists, it's options are merged with the existing // options. func (rule *Rule) MergeBehavior(behavior *Behavior) { for _, existingBehavior := range rule.Behaviors { if behavior.Name == "cpCode" || behavior.Name == "origin" { if existingBehavior.Name == behavior.Name { existingBehavior.MergeOptions(behavior.Options) return } } } rule.Behaviors = append(rule.Behaviors, behavior) } // AddBehavior adds a behavior to the rule // // If the behavior already exists it is replaced with the given behavior func (rule *Rule) AddBehavior(behavior *Behavior) { /*for key, existingBehavior := range rule.Behaviors { if existingBehavior.Name == behavior.Name { rule.Behaviors[key] = behavior return } }*/ rule.Behaviors = append(rule.Behaviors, behavior) } // MergeCriteria merges a criteria into a rule // // If the criteria already exists, it's options are merged with the existing // options. func (rule *Rule) MergeCriteria(criteria *Criteria) { /*for _, existingCriteria := range rule.Criteria { if existingCriteria.Name == criteria.Name { existingCriteria.MergeOptions(criteria.Options) return } }*/ rule.Criteria = append(rule.Criteria, criteria) } // AddCriteria add a criteria to a rule // // If the criteria already exists, it is replaced with the given criteria. func (rule *Rule) AddCriteria(criteria *Criteria) { /*for key, existingCriteria := range rule.Criteria { if existingCriteria.Name == criteria.Name { rule.Criteria[key] = criteria return } }*/ rule.Criteria = append(rule.Criteria, criteria) } // MergeChildRule adds a child rule to this rule // // If the rule already exists, criteria, behaviors, and child rules are added to // the existing rule. func (rule *Rule) MergeChildRule(childRule *Rule) { /*for key, existingChildRule := range rule.Children { if existingChildRule.Name == childRule.Name { for _, behavior := range childRule.Behaviors { rule.Children[key].MergeBehavior(behavior) } for _, criteria := range childRule.Criteria { rule.Children[key].MergeCriteria(criteria) } for _, child := range childRule.Children { rule.Children[key].MergeChildRule(child) } return } }*/ rule.Children = append(rule.Children, childRule) } // AddChildRule adds a rule as a child of this rule // // If the rule already exists, it is replaced by the given rule. func (rule *Rule) AddChildRule(childRule *Rule) { /*for key, existingChildRule := range rule.Children { if existingChildRule.Name == childRule.Name { rule.Children[key] = childRule return } }*/ rule.Children = append(rule.Children, childRule) } // AddVariable adds a variable as a child of this rule // // If the rule already exists, it is replaced by the given rule. func (rule *Rule) AddVariable(variable *Variable) { for key, existingVariable := range rule.Variables { if existingVariable.Name == variable.Name { rule.Variables[key] = variable return } } rule.Variables = append(rule.Variables, variable) } // FindBehavior locates a specific behavior by path func (rules *Rules) FindBehavior(path string) (*Behavior, error) { if len(path) <= 1 { return nil, ErrorMap[ErrInvalidPath] } rule, err := rules.FindParentRule(path) if err != nil { return nil, err } sep := "/" segments := strings.Split(path, sep) behaviorName := strings.ToLower(segments[len(segments)-1]) for _, behavior := range rule.Behaviors { if strings.ToLower(behavior.Name) == behaviorName { return behavior, nil } } return nil, ErrorMap[ErrBehaviorNotFound] } // FindCriteria locates a specific Critieria by path func (rules *Rules) FindCriteria(path string) (*Criteria, error) { if len(path) <= 1 { return nil, ErrorMap[ErrInvalidPath] } rule, err := rules.FindParentRule(path) if err != nil { return nil, err } sep := "/" segments := strings.Split(path, sep) criteriaName := strings.ToLower(segments[len(segments)-1]) for _, criteria := range rule.Criteria { if strings.ToLower(criteria.Name) == criteriaName { return criteria, nil } } return nil, ErrorMap[ErrCriteriaNotFound] } // FindVariable locates a specific Variable by path func (rules *Rules) FindVariable(path string) (*Variable, error) { if len(path) <= 1 { return nil, ErrorMap[ErrInvalidPath] } rule, err := rules.FindParentRule(path) if err != nil { return nil, err } sep := "/" segments := strings.Split(path, sep) variableName := strings.ToLower(segments[len(segments)-1]) for _, variable := range rule.Variables { if strings.ToLower(variable.Name) == variableName { return variable, nil } } return nil, ErrorMap[ErrVariableNotFound] } // FindRule locates a specific rule by path func (rules *Rules) FindRule(path string) (*Rule, error) { if path == "" { return rules.Rule, nil } sep := "/" segments := strings.Split(path, sep) currentRule := rules.Rule for _, segment := range segments { found := false for _, rule := range currentRule.Children { if strings.ToLower(rule.Name) == segment { currentRule = rule found = true } } if found != true { return nil, ErrorMap[ErrRuleNotFound] } } return currentRule, nil } // Find the parent rule for a given rule, criteria, or behavior path func (rules *Rules) FindParentRule(path string) (*Rule, error) { sep := "/" segments := strings.Split(strings.ToLower(strings.TrimPrefix(path, sep)), sep) parentPath := strings.Join(segments[0:len(segments)-1], sep) return rules.FindRule(parentPath) } // Criteria represents a rule criteria resource type Criteria struct { client.Resource Name string `json:"name"` Options OptionValue `json:"options"` UUID string `json:"uuid,omitempty"` Locked bool `json:"locked,omitempty"` } // NewCriteria creates a new Criteria func NewCriteria() *Criteria { criteria := &Criteria{Options: OptionValue{}} criteria.Init() return criteria } // MergeOptions merges the given options with the existing options /*func (criteria *Criteria) MergeOptions(newOptions OptionValue) { options := make(map[string]interface{}) for k, v := range criteria.Options { options[k] = v } for k, v := range newOptions { options[k] = v } criteria.Options = OptionValue(options) } */ // Behavior represents a rule behavior resource type Behavior struct { client.Resource Name string `json:"name"` Options OptionValue `json:"options"` Locked bool `json:"locked,omitempty"` UUID string `json:"uuid,omitempty"` } // NewBehavior creates a new Behavior func NewBehavior() *Behavior { behavior := &Behavior{Options: OptionValue{}} behavior.Init() return behavior } // MergeOptions merges the given options with the existing options func (behavior *Behavior) MergeOptions(newOptions OptionValue) { options := make(map[string]interface{}) for k, v := range behavior.Options { options[k] = v } for k, v := range newOptions { options[k] = v } behavior.Options = OptionValue(options) } // OptionValue represents a generic option value // // OptionValue is a map with string keys, and any // type of value. You can nest OptionValues as necessary // to create more complex values. type OptionValue map[string]interface{} type Variable struct { client.Resource Name string `json:"name"` Value string `json:"value"` Description string `json:"description"` Hidden bool `json:"hidden"` Sensitive bool `json:"sensitive"` } // NewVariable creates a new Variable func NewVariable() *Variable { variable := &Variable{} variable.Init() return variable } // RuleErrors represents an validate error returned for a rule type RuleErrors struct { client.Resource Type string `json:"type"` Title string `json:"title"` Detail string `json:"detail"` Instance string `json:"instance"` BehaviorName string `json:"behaviorName"` } // NewRuleErrors creates a new RuleErrors func NewRuleErrors() *RuleErrors { ruleErrors := &RuleErrors{} ruleErrors.Init() return ruleErrors } type RuleCriteriaMustSatisfyValue string const ( RuleCriteriaMustSatisfyAll RuleCriteriaMustSatisfyValue = "all" RuleCriteriaMustSatisfyAny RuleCriteriaMustSatisfyValue = "any" ) golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/rules_test.go000066400000000000000000001042421400161560600266000ustar00rootroot00000000000000package papi import ( "testing" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) func TestRule_AddBehavior(t *testing.T) { tests := []struct { Rule Rule Behavior Behavior Expected Rule }{ { Rule: Rule{}, Behavior: Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Behavior: Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Behavior: Behavior{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Behavior{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, }, }, }, } for _, test := range tests { test.Rule.AddBehavior(&test.Behavior) assert.Equal(t, len(test.Rule.Behaviors), len(test.Expected.Behaviors)) for key, behavior := range test.Rule.Behaviors { assert.Equal(t, behavior.Name, test.Expected.Behaviors[key].Name) assert.Equal(t, behavior.Options, test.Expected.Behaviors[key].Options) } } } func TestRule_MergeBehavior(t *testing.T) { tests := []struct { Rule Rule Behavior Behavior Expected Rule }{ { Rule: Rule{}, Behavior: Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Behavior: Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Behavior{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Behavior: Behavior{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Behavior{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", "otherkey": "won't change", }, }, }, }, Behavior: Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "newvalue", "bar": "baz", }, }, Expected: Rule{ Behaviors: []*Behavior{ &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", "otherkey": "won't change", }, }, &Behavior{ Name: "existing", Options: OptionValue{ "existingkey": "newvalue", "bar": "baz", }, }, }, }, }, } for _, test := range tests { test.Rule.MergeBehavior(&test.Behavior) assert.Equal(t, len(test.Rule.Behaviors), len(test.Expected.Behaviors)) for key, behavior := range test.Rule.Behaviors { assert.Equal(t, behavior.Name, test.Expected.Behaviors[key].Name) assert.Equal(t, behavior.Options, test.Expected.Behaviors[key].Options) } } } func TestRule_AddCriteria(t *testing.T) { tests := []struct { Rule Rule Criteria Criteria Expected Rule }{ { Rule: Rule{}, Criteria: Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Criteria: Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Criteria: Criteria{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Criteria{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, }, }, }, } for _, test := range tests { test.Rule.AddCriteria(&test.Criteria) assert.Equal(t, len(test.Rule.Criteria), len(test.Expected.Criteria)) for key, criteria := range test.Rule.Criteria { assert.Equal(t, criteria.Name, test.Expected.Criteria[key].Name) assert.Equal(t, criteria.Options, test.Expected.Criteria[key].Options) } } } func TestRule_MergeCriteria(t *testing.T) { tests := []struct { Rule Rule Criteria Criteria Expected Rule }{ { Rule: Rule{}, Criteria: Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Criteria: Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Criteria{ Name: "foo", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, }, }, Criteria: Criteria{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", }, }, &Criteria{ Name: "existing", Options: OptionValue{ "bar": "baz", }, }, }, }, }, { Rule: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", "otherkey": "won't change", }, }, }, }, Criteria: Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "newvalue", "bar": "baz", }, }, Expected: Rule{ Criteria: []*Criteria{ &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "existingvalue", "otherkey": "won't change", }, }, &Criteria{ Name: "existing", Options: OptionValue{ "existingkey": "newvalue", "bar": "baz", }, }, }, }, }, } for _, test := range tests { test.Rule.MergeCriteria(&test.Criteria) assert.Equal(t, len(test.Rule.Criteria), len(test.Expected.Criteria)) for key, criteria := range test.Rule.Criteria { assert.Equal(t, criteria.Name, test.Expected.Criteria[key].Name) assert.Equal(t, criteria.Options, test.Expected.Criteria[key].Options) } } } func TestRule_AddVariable(t *testing.T) { tests := []struct { ParentRule Rule Variables []*Variable Expected Rule }{ { ParentRule: Rule{ Name: "Parent Rule", }, Variables: []*Variable{ &Variable{ Name: "Test Variable", Description: "Test Description", Value: "Test Value", Hidden: true, Sensitive: true, }, }, Expected: Rule{ Name: "Parent Rule", Variables: []*Variable{ &Variable{ Name: "Test Variable", Description: "Test Description", Value: "Test Value", Hidden: true, Sensitive: true, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Variables: []*Variable{ &Variable{ Name: "Existing Variable", }, }, }, Variables: []*Variable{ &Variable{ Name: "Existing Variable", Description: "New Description", Value: "New Value", Hidden: true, Sensitive: true, }, }, Expected: Rule{ Name: "Parent Rule", Variables: []*Variable{ &Variable{ Name: "Existing Variable", Description: "New Description", Value: "New Value", Hidden: true, Sensitive: true, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Variables: []*Variable{ &Variable{ Name: "Existing Variable", }, }, }, Variables: []*Variable{ &Variable{ Name: "Existing Variable", Description: "Updated Description", }, &Variable{ Name: "New Variable", }, }, Expected: Rule{ Name: "Parent Rule", Variables: []*Variable{ &Variable{ Name: "Existing Variable", Description: "Updated Description", }, &Variable{ Name: "New Variable", }, }, }, }, } for _, test := range tests { for _, variable := range test.Variables { test.ParentRule.AddVariable(variable) } } } func TestRule_AddChildRule(t *testing.T) { tests := []struct { ParentRule Rule ChildRules []*Rule Expected Rule }{ { ParentRule: Rule{ Name: "Parent Rule", }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Existing Child Rule", }, }, }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Existing Child Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Sub-Child Existing Rule", }, }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Sub-Child Existing Rule", }, }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", }, }, }, }, } for _, test := range tests { for _, child := range test.ChildRules { test.ParentRule.AddChildRule(child) } assertRulesMatch(t, &test.ParentRule, &test.Expected) } } func TestRule_MergeChildRule(t *testing.T) { tests := []struct { ParentRule Rule ChildRules []*Rule Expected Rule }{ { ParentRule: Rule{ Name: "Parent Rule", }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Existing Child Rule", }, }, }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Existing Child Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Child Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Child Rule", }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Sub-Child Existing Rule", }, }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", }, }, }, &Rule{ Name: "Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Child Existing Rule", Children: []*Rule{ &Rule{ Name: "Sub-Sub-Child Existing Rule", }, }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", }, &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", }, }, }, }, { ParentRule: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, }, }, ChildRules: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option2": "Value2", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option2": "Value2", }, }, }, }, }, Expected: Rule{ Name: "Parent Rule", Children: []*Rule{ &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option": "Value", }, }, }, }, &Rule{ Name: "Existing Rule", }, &Rule{ Name: "Child Rule", Behaviors: []*Behavior{ &Behavior{ Name: "Behavior", Options: OptionValue{ "Option2": "Value2", }, }, }, Criteria: []*Criteria{ &Criteria{ Name: "Behavior", Options: OptionValue{ "Option2": "Value2", }, }, }, }, }, }, }, } for i, test := range tests { for _, child := range test.ChildRules { test.ParentRule.MergeChildRule(child) } if !assertRulesMatch(t, &test.ParentRule, &test.Expected) { t.Errorf("Data set %d failed!", i+1) } } } func TestRules_GetRules_Locked(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/properties/prp_123/versions/1/rules") mock. Get("/papi/v1/properties/prp_123/versions/1/rules"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_TEST", "contractId": "ctr_TEST", "groupId": "grp_123", "propertyId": "prp_1232", "propertyName": "example.org", "propertyVersion": 1, "etag": "3c98a3bd6ac66a91fc9986803f01f05dde494ef0", "rules": { "name": "default", "children": [ { "name": "Parent", "children": [], "behaviors": [ { "name": "testing", "options": { }, "uuid": "04d66607-a767-4b18-be0c-7aa9bbc3bbc4", "locked": true } ], "criteria": [ { "name": "matchAdvanced", "options": { }, "uuid": "0a16be91-4c7b-4e94-ae7b-565867f19ffb", "locked": true } ], "uuid": "44b00323-df7a-4e6b-8ed7-2a49c92f6e44", "criteriaMustSatisfy": "all" } ] } }`) Init(config) property := NewProperty(&Properties{}) property.PropertyID = "prp_123" property.LatestVersion = 1 rules, err := property.GetRules("") assert.NoError(t, err) assert.Equal(t, "44b00323-df7a-4e6b-8ed7-2a49c92f6e44", rules.Rule.Children[0].UUID) assert.Equal(t, "04d66607-a767-4b18-be0c-7aa9bbc3bbc4", rules.Rule.Children[0].Behaviors[0].UUID) assert.True(t, rules.Rule.Children[0].Behaviors[0].Locked) assert.Equal(t, "0a16be91-4c7b-4e94-ae7b-565867f19ffb", rules.Rule.Children[0].Criteria[0].UUID) assert.True(t, rules.Rule.Children[0].Criteria[0].Locked) } func TestRules_GetRules_CustomOverrides(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/properties/prp_123/versions/1/rules") mock. Get("/papi/v1/properties/prp_123/versions/1/rules"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "accountId": "act_TEST", "contractId": "ctr_TEST", "groupId": "grp_123", "propertyId": "prp_1232", "propertyName": "example.org", "propertyVersion": 1, "etag": "3c98a3bd6ac66a91fc9986803f01f05dde494ef0", "rules": { "name": "default", "children": [], "customOverride": { "overrideId": "cbo_12345", "name": "my_override" } } }`) Init(config) property := NewProperty(&Properties{}) property.PropertyID = "prp_123" property.LatestVersion = 1 rules, err := property.GetRules("") assert.NoError(t, err) assert.Equal(t, "cbo_12345", rules.Rule.CustomOverride.OverrideID) assert.Equal(t, "my_override", rules.Rule.CustomOverride.Name) } func TestRules_GetRules_Variables(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/properties/prp_123/versions/1/rules") mock. Get("/papi/v1/properties/prp_123/versions/1/rules"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "rules": { "name": "default", "options": { "is_secure": false }, "variables": [ { "name": "VAR_NAME", "value": "default value", "description": "This is a sample Property Manager variable.", "hidden": false, "sensitive": false } ], "criteriaMustSatisfy": "all", "criteria": [], "behaviors": [], "children": [] } }`) Init(config) property := NewProperty(&Properties{}) property.PropertyID = "prp_123" property.LatestVersion = 1 rules, err := property.GetRules("") assert.NoError(t, err) assert.Len(t, rules.Rule.Variables, 1) assert.Equal(t, "VAR_NAME", rules.Rule.Variables[0].Name) assert.Equal(t, "default value", rules.Rule.Variables[0].Value) assert.Equal(t, "This is a sample Property Manager variable.", rules.Rule.Variables[0].Description) assert.False(t, rules.Rule.Variables[0].Hidden) assert.False(t, rules.Rule.Variables[0].Sensitive) } func assertRulesMatch(t *testing.T, expected *Rule, actual *Rule) bool { valid := true if !assert.Equal(t, expected.Name, actual.Name) { valid = false } if !assert.Equal(t, expected.Criteria, actual.Criteria) { valid = false } if !assert.Equal(t, expected.Behaviors, actual.Behaviors) { valid = false } if !assert.Equal(t, expected.Variables, actual.Variables) { valid = false } if !assert.Equal(t, len(expected.Children), len(actual.Children)) { valid = false } if len(expected.Children) > 0 { for key := 0; key < len(expected.Children); key++ { if !assertRulesMatch(t, expected.Children[key], actual.Children[key]) { valid = false } } } return valid } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/search.go000066400000000000000000000035761400161560600256640ustar00rootroot00000000000000package papi import ( "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) type SearchKey string const ( SearchByPropertyName SearchKey = "propertyName" SearchByHostname SearchKey = "hostname" SearchByEdgeHostname SearchKey = "edgeHostname" ) type SearchResult struct { Versions struct { Items []struct { UpdatedByUser string `json:"updatedByUser"` StagingStatus string `json:"stagingStatus"` AssetID string `json:"assetId"` PropertyName string `json:"propertyName"` PropertyVersion int `json:"propertyVersion"` UpdatedDate time.Time `json:"updatedDate"` ContractID string `json:"contractId"` AccountID string `json:"accountId"` GroupID string `json:"groupId"` PropertyID string `json:"propertyId"` ProductionStatus string `json:"productionStatus"` } `json:"items"` } `json:"versions"` } // Search searches for properties // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#postfindbyvalue // Endpoint: POST /papi/v1/search/find-by-value func Search(searchBy SearchKey, propertyName string, correlationid string) (*SearchResult, error) { req, err := client.NewJSONRequest( Config, "POST", "/papi/v1/search/find-by-value", map[string]string{(string)(searchBy): propertyName}, ) if err != nil { return nil, err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return nil, client.NewAPIError(res) } results := &SearchResult{} if err = client.BodyJSON(res, results); err != nil { return nil, err } if len(results.Versions.Items) == 0 { return nil, nil } return results, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/service.go000066400000000000000000000053221400161560600260460ustar00rootroot00000000000000package papi import ( "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "github.com/patrickmn/go-cache" ) var ( Config edgegrid.Config Profilecache = cache.New(5*time.Minute, 10*time.Minute) ) // GetGroups retrieves all groups func GetGroups() (*Groups, error) { groups := NewGroups() if err := groups.GetGroups(""); err != nil { return nil, err } return groups, nil } // GetContracts retrieves all contracts func GetContracts() (*Contracts, error) { contracts := NewContracts() if err := contracts.GetContracts(""); err != nil { return nil, err } return contracts, nil } // GetProducts retrieves all products func GetProducts(contract *Contract) (*Products, error) { products := NewProducts() if err := products.GetProducts(contract, ""); err != nil { return nil, err } return products, nil } // GetEdgeHostnames retrieves all edge hostnames func GetEdgeHostnames(contract *Contract, group *Group, options string) (*EdgeHostnames, error) { edgeHostnames := NewEdgeHostnames() if err := edgeHostnames.GetEdgeHostnames(contract, group, options, ""); err != nil { return nil, err } return edgeHostnames, nil } // GetCpCodes creates a new CpCodes struct and populates it with all CP Codes associated with a contract/group // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listcpcodes func GetCpCodes(contract *Contract, group *Group) (*CpCodes, error) { cpcodes := NewCpCodes(contract, group) if err := cpcodes.GetCpCodes(""); err != nil { return nil, err } return cpcodes, nil } // GetProperties retrieves all properties for a given contract/group func GetProperties(contract *Contract, group *Group) (*Properties, error) { properties := NewProperties() if err := properties.GetProperties(contract, group, ""); err != nil { return nil, err } return properties, nil } // GetVersions retrieves all versions for a given property func GetVersions(property *Property) (*Versions, error) { versions := NewVersions() if err := versions.GetVersions(property, ""); err != nil { return nil, err } return versions, nil } // GetAvailableBehaviors retrieves all available behaviors for a property func GetAvailableBehaviors(property *Property) (*AvailableBehaviors, error) { availableBehaviors := NewAvailableBehaviors() if err := availableBehaviors.GetAvailableBehaviors(property); err != nil { return nil, err } return availableBehaviors, nil } // GetAvailableCriteria retrieves all available criteria for a property func GetAvailableCriteria(property *Property) (*AvailableCriteria, error) { availableCriteria := NewAvailableCriteria() if err := availableCriteria.GetAvailableCriteria(property); err != nil { return nil, err } return availableCriteria, nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/papi-v1/versions.go000066400000000000000000000224411400161560600262570ustar00rootroot00000000000000package papi import ( "errors" "fmt" "time" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" edge "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) // Versions contains a collection of Property Versions type Versions struct { client.Resource PropertyID string `json:"propertyId"` PropertyName string `json:"propertyName"` AccountID string `json:"accountId"` ContractID string `json:"contractId"` GroupID string `json:"groupId"` Versions struct { Items []*Version `json:"items"` } `json:"versions"` RuleFormat string `json:"ruleFormat,omitempty"` } // NewVersions creates a new Versions func NewVersions() *Versions { version := &Versions{} version.Init() return version } // PostUnmarshalJSON is called after JSON unmarshaling into EdgeHostnames // // See: jsonhooks-v1/jsonhooks.Unmarshal() func (versions *Versions) PostUnmarshalJSON() error { versions.Init() for key := range versions.Versions.Items { versions.Versions.Items[key].parent = versions } versions.Complete <- true return nil } // AddVersion adds or replaces a version within the collection func (versions *Versions) AddVersion(version *Version) { if version.PropertyVersion != 0 { for key, v := range versions.Versions.Items { if v.PropertyVersion == version.PropertyVersion { versions.Versions.Items[key] = version return } } } versions.Versions.Items = append(versions.Versions.Items, version) } // GetVersions retrieves all versions for a a given property // // See: Property.GetVersions() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#listversions // Endpoint: GET /papi/v1/properties/{propertyId}/versions/{?contractId,groupId} func (versions *Versions) GetVersions(property *Property, correlationid string) error { if property == nil { return errors.New("You must provide a property") } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions", property.PropertyID, ), nil, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if err = client.BodyJSON(res, versions); err != nil { return err } return nil } // GetLatestVersion retrieves the latest Version for a property // // See: Property.GetLatestVersion() // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#getthelatestversion // Endpoint: GET /papi/v1/properties/{propertyId}/versions/latest{?contractId,groupId,activatedOn} func (versions *Versions) GetLatestVersion(activatedOn NetworkValue, correlationid string) (*Version, error) { if activatedOn != "" { activatedOn = "?activatedOn=" + activatedOn } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/latest%s", versions.PropertyID, activatedOn, ), nil, ) if err != nil { return nil, err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return nil, err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return nil, client.NewAPIError(res) } newVersions := NewVersions() if err := client.BodyJSON(res, newVersions); err != nil { return nil, err } return newVersions.Versions.Items[0], nil } // NewVersion creates a new version associated with the Versions collection func (versions *Versions) NewVersion(createFromVersion *Version, useEtagStrict bool, correlationid string) *Version { if createFromVersion == nil { var err error createFromVersion, err = versions.GetLatestVersion("", correlationid) if err != nil { return nil } } version := NewVersion(versions) version.CreateFromVersion = createFromVersion.PropertyVersion versions.Versions.Items = append(versions.Versions.Items, version) if useEtagStrict { version.CreateFromVersionEtag = createFromVersion.Etag } return version } // Version represents a Property Version type Version struct { client.Resource parent *Versions PropertyVersion int `json:"propertyVersion,omitempty"` UpdatedByUser string `json:"updatedByUser,omitempty"` UpdatedDate time.Time `json:"updatedDate,omitempty"` ProductionStatus StatusValue `json:"productionStatus,omitempty"` StagingStatus StatusValue `json:"stagingStatus,omitempty"` Etag string `json:"etag,omitempty"` ProductID string `json:"productId,omitempty"` Note string `json:"note,omitempty"` CreateFromVersion int `json:"createFromVersion,omitempty"` CreateFromVersionEtag string `json:"createFromVersionEtag,omitempty"` RuleFormat string `json:"ruleFormat,omitempty"` } // NewVersion creates a new Version func NewVersion(parent *Versions) *Version { version := &Version{parent: parent} version.Init() return version } // GetVersion populates a Version // // Api Docs: https://developer.akamai.com/api/luna/papi/resources.html#getaversion // Endpoint: /papi/v1/properties/{propertyId}/versions/{propertyVersion}{?contractId,groupId} func (version *Version) GetVersion(property *Property, getVersion int) error { if getVersion == 0 { getVersion = property.LatestVersion } req, err := client.NewRequest( Config, "GET", fmt.Sprintf( "/papi/v1/properties/%s/versions/%d", property.PropertyID, getVersion, ), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } newVersions := NewVersions() if err := client.BodyJSON(res, newVersions); err != nil { return err } version.PropertyVersion = newVersions.Versions.Items[0].PropertyVersion version.UpdatedByUser = newVersions.Versions.Items[0].UpdatedByUser version.UpdatedDate = newVersions.Versions.Items[0].UpdatedDate version.ProductionStatus = newVersions.Versions.Items[0].ProductionStatus version.StagingStatus = newVersions.Versions.Items[0].StagingStatus version.Etag = newVersions.Versions.Items[0].Etag version.ProductID = newVersions.Versions.Items[0].ProductID version.Note = newVersions.Versions.Items[0].Note version.CreateFromVersion = newVersions.Versions.Items[0].CreateFromVersion version.CreateFromVersionEtag = newVersions.Versions.Items[0].CreateFromVersionEtag return nil } // HasBeenActivated determines if a given version has been activated, optionally on a specific network func (version *Version) HasBeenActivated(activatedOn NetworkValue) (bool, error) { properties := NewProperties() property := NewProperty(properties) property.PropertyID = version.parent.PropertyID property.Group = NewGroup(NewGroups()) property.Group.GroupID = version.parent.GroupID property.Contract = NewContract(NewContracts()) property.Contract.ContractID = version.parent.ContractID activations, err := property.GetActivations() if err != nil { return false, err } for _, activation := range activations.Activations.Items { if activation.PropertyVersion == version.PropertyVersion && (activatedOn == "" || activation.Network == activatedOn) { return true, nil } } return false, nil } // Save creates a new version // // API Docs: https://developer.akamai.com/api/luna/papi/resources.html#createanewversion // Endpoint: POST /papi/v1/properties/{propertyId}/versions/{?contractId,groupId} func (version *Version) Save(correlationid string) error { if version.PropertyVersion != 0 { return fmt.Errorf("version (%d) already exists", version.PropertyVersion) } req, err := client.NewJSONRequest( Config, "POST", fmt.Sprintf( "/papi/v1/properties/%s/versions", version.parent.PropertyID, ), version, ) if err != nil { return err } edge.PrintHttpRequestCorrelation(req, true, correlationid) res, err := client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponseCorrelation(res, true, correlationid) if client.IsError(res) { return client.NewAPIError(res) } var location client.JSONBody if err = client.BodyJSON(res, &location); err != nil { return err } req, err = client.NewRequest( Config, "GET", location["versionLink"].(string), nil, ) if err != nil { return err } edge.PrintHttpRequest(req, true) res, err = client.Do(Config, req) if err != nil { return err } edge.PrintHttpResponse(res, true) if client.IsError(res) { return client.NewAPIError(res) } versions := NewVersions() if err = client.BodyJSON(res, versions); err != nil { return err } version.PropertyVersion = versions.Versions.Items[0].PropertyVersion version.UpdatedByUser = versions.Versions.Items[0].UpdatedByUser version.UpdatedDate = versions.Versions.Items[0].UpdatedDate version.ProductionStatus = versions.Versions.Items[0].ProductionStatus version.StagingStatus = versions.Versions.Items[0].StagingStatus version.Etag = versions.Versions.Items[0].Etag version.ProductID = versions.Versions.Items[0].ProductID version.Note = versions.Versions.Items[0].Note version.CreateFromVersion = versions.Versions.Items[0].CreateFromVersion version.CreateFromVersionEtag = versions.Versions.Items[0].CreateFromVersionEtag version.parent.AddVersion(version) return nil } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/000077500000000000000000000000001400161560600253325ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/README.md000066400000000000000000000003341400161560600266110ustar00rootroot00000000000000# Akamai GTM Reports (Global Traffic Management) A golang package that talks to the [Akamai OPEN GTM Reporting API](https://developer.akamai.com/api/web_performance/global_traffic_management_reporting/v1.html#overview). golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/datacenter.go000066400000000000000000000047471400161560600300070ustar00rootroot00000000000000package reportsgtm import ( "strconv" "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/configgtm-v1_3" "fmt" ) // // Support gtm reports thru Edgegrid // Based on 1.0 Schema // // Datacenter Traffic Report Structs type DCTMeta struct { Uri string `json:uri"` Domain string `json:"domain"` Interval string `json:"interval,omitempty"` DatacenterId int `json:"datacenterId"` DatacenterNickname string `json:"datacenterNickname"` Start string `json:"start"` End string `json:"end"` } type DCTDRow struct { Name string `json:"name"` Requests int64 `json:"requests"` Status string `json:"status"` } type DCTData struct { Timestamp string `json:"timestamp"` Properties []*DCTDRow `json:"properties"` } // Response structure returned by the Datacenter Traffic API type DcTrafficResponse struct { Metadata *DCTMeta `json:"metadata"` DataRows []*DCTData `json:"dataRows"` DataSummary interface{} `json:"dataSummary"` Links []*configgtm.Link `json:"links"` } // GetTrafficPerDatacenter retrieves Report Traffic per datacenter. Opt args - start, end. func GetTrafficPerDatacenter(domainName string, datacenterID int, optArgs map[string]string) (*DcTrafficResponse, error) { stat := &DcTrafficResponse{} hostURL := fmt.Sprintf("/gtm-api/v1/reports/traffic/domains/%s/datacenters/%s", domainName, strconv.Itoa(datacenterID)) req, err := client.NewRequest( Config, "GET", hostURL, nil, ) if err != nil { return nil, err } // Look for and process optional query params q := req.URL.Query() for k, v := range optArgs { switch k { case "start": fallthrough case "end": q.Add(k, v) } } if optArgs != nil { // time stamps require urlencoded content header setEncodedHeader(req) req.URL.RawQuery = q.Encode() } // print/log the request if warranted printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // print/log the response if warranted printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { cErr := configgtm.CommonError{} cErr.SetItem("entityName", "Datacenter") cErr.SetItem("name", strconv.Itoa(datacenterID)) return nil, cErr } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } return stat, nil } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/datacenter_test.go000066400000000000000000000067341400161560600310440ustar00rootroot00000000000000package reportsgtm import ( "testing" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) // Verify GetTrafficPerDatacenter. func TestGetTrafficPerDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters/3200") mock. Get("/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters/3200"). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "metadata": { "domain": "gtmtest.akadns.net", "datacenterId": 3200, "datacenterNickname": "Winterfell", "start": "2016-11-23T00:00:00Z", "end": "2016-11-23T00:10:00Z", "interval": "FIVE_MINUTE", "uri": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters?start=2016-11-23T00:00:00Z&end=2016-11-23T00:10:00Z" }, "dataRows": [ { "timestamp": "2016-11-23T00:00:00Z", "properties": [ { "name": "www", "requests": 45, "status": "1" } ] }, { "timestamp": "2016-11-23T00:05:00Z", "properties": [ { "name": "www", "requests": 45, "status": "1" } ] } ], "links": [ { "rel": "self", "href": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters?start=2016-11-23T00:00:00Z&2016-11-23T00:10:00Z" } ] }`) Init(config) optArgs := make(map[string]string) optArgs["start"] = "2016-11-23T00:00:00Z" optArgs["end"] = "2016-11-23T00:10:00Z" testDCTraffic, err := GetTrafficPerDatacenter(gtmTestDomain, 3200, optArgs) assert.NoError(t, err) assert.Equal(t, "gtmtest.akadns.net", testDCTraffic.Metadata.Domain) assert.Equal(t, testDCTraffic.DataRows[0].Timestamp, "2016-11-23T00:00:00Z") } // Verify failed case for TrafficPerDatacenter. func TestGetBadTrafficPerDatacenter(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters/9999") mock. Get("/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/datacenters/9999"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/json"). BodyString(`{ }`) Init(config) optArgs := make(map[string]string) _, err := GetTrafficPerDatacenter(gtmTestDomain, 9999, optArgs) assert.Error(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/property.go000066400000000000000000000123461400161560600275530ustar00rootroot00000000000000package reportsgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/configgtm-v1_3" "fmt" ) // // Support gtm reports thru Edgegrid // Based on 1.0 Schema // // Property Traffic Report Structs type PropertyTMeta struct { Uri string `json:uri"` Domain string `json:"domain"` Interval string `json:"interval,omitempty"` Property string `json:"property"` Start string `json:"start"` End string `json:"end"` } type PropertyDRow struct { Nickname string `json:"nickname"` DatacenterId int `json:"datacenterId"` TrafficTargetName string `json:"trafficTargetName"` Requests int64 `json:"requests"` Status string `json:"status"` } type PropertyTData struct { Timestamp string `json:"timestamp"` Datacenters []*PropertyDRow `json:"datacenters"` } // The Property Traffic Response structure returned by the Reports API type PropertyTrafficResponse struct { Metadata *PropertyTMeta `json:"metadata"` DataRows []*PropertyTData `json:"dataRows"` DataSummary interface{} `json:"dataSummary"` Links []*configgtm.Link `json:"links"` } // // IP Status By Property Structs // // IP Availability Status Response structure returned by the Reports API. type IPStatusPerProperty struct { Metadata *IpStatPerPropMeta `json:"metadata"` DataRows []*IpStatPerPropData `json:"dataRows"` DataSummary interface{} `json:"dataSummary"` Links []*configgtm.Link `json:"links"` } type IpStatPerPropMeta struct { Uri string `json:uri"` Domain string `json:"domain"` Property string `json:"property"` Start string `json:"start"` End string `json:"end"` MostRecent bool `json:"mostRecent"` Ip string `json:"ip"` DatacenterId int `json:"datacenterId"` } type IpStatPerPropData struct { Timestamp string `json:"timestamp"` CutOff float64 `json:"cutOff"` Datacenters []*IpStatPerPropDRow `json:"datacenters"` } type IpStatPerPropDRow struct { Nickname string `json:"nickname"` DatacenterId int `json:"datacenterId"` TrafficTargetName string `json:"trafficTargetName"` IPs []*IpStatIp `json:"IPs"` } type IpStatIp struct { Ip string `json:"ip"` HandedOut bool `json:"handedOut"` Score float32 `json:"score"` Alive bool `json:"alive"` } // GetIpStatusPerProperty retrieves current IP Availability Status for specified property in the given domainname. func GetIpStatusPerProperty(domainName string, propertyName string, optArgs map[string]string) (*IPStatusPerProperty, error) { stat := &IPStatusPerProperty{} hostURL := fmt.Sprintf("/gtm-api/v1/reports/ip-availability/domains/%s/properties/%s", domainName, propertyName) req, err := client.NewRequest( Config, "GET", hostURL, nil, ) if err != nil { return nil, err } // Look for and process optional query params q := req.URL.Query() for k, v := range optArgs { switch k { case "start": fallthrough case "end": fallthrough case "ip": fallthrough case "mostRecent": fallthrough case "datacenterId": q.Add(k, v) } } if optArgs != nil { req.URL.RawQuery = q.Encode() } // time stamps require urlencoded content header setEncodedHeader(req) // print/log the request if warranted printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // print/log the response if warranted printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { cErr := configgtm.CommonError{} cErr.SetItem("entityName", "Property") cErr.SetItem("name", propertyName) return nil, cErr } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } return stat, nil } } // GetTrafficPerProperty retrieves report traffic for the specified property in the specified domain. func GetTrafficPerProperty(domainName string, propertyName string, optArgs map[string]string) (*PropertyTrafficResponse, error) { stat := &PropertyTrafficResponse{} hostURL := fmt.Sprintf("/gtm-api/v1/reports/traffic/domains/%s/properties/%s", domainName, propertyName) req, err := client.NewRequest( Config, "GET", hostURL, nil, ) if err != nil { return nil, err } // Look for and process optional query params q := req.URL.Query() for k, v := range optArgs { switch k { case "start": fallthrough case "end": q.Add(k, v) } } if optArgs != nil { req.URL.RawQuery = q.Encode() } // time stamps require urlencoded content header setEncodedHeader(req) // print/log the request if warranted printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } // print/log the response if warranted printHttpResponse(res, true) if client.IsError(res) && res.StatusCode != 404 { return nil, client.NewAPIError(res) } else if res.StatusCode == 404 { cErr := configgtm.CommonError{} cErr.SetItem("entityName", "Property") cErr.SetItem("name", propertyName) return nil, cErr } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } return stat, nil } } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/property_test.go000066400000000000000000000267241400161560600306170ustar00rootroot00000000000000package reportsgtm import ( "testing" "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" ) // // Important note: The test cases enclosed piggyback on the objects created in the configgtm test cases // // TODO: Add tests for Opt args // // var GtmTestProperty = "testproperty" // Verify GetIpStatusPerProperty. Property and domain names hardcoded. Should pass, e.g. no API errors and property returned // Depends on CreateProperty func TestGetIpStatusProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/ip-availability/domains/gtmtest.akadns.net/properties/" + GtmTestProperty) mock. Get("/gtm-api/v1/reports/ip-availability/domains/gtmtest.akadns.net/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "metadata": { "domain": "gtmtest.akadns.net", "property": "testproperty", "start" : "2017-02-23T21:00:00Z", "end" : "2017-03-23T22:00:00Z", "uri": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/ip-availability/domains/gtmtest.akadns.net/properties/testproperty" }, "dataRows": [ { "timestamp": "2017-02-23T21:42:35Z", "cutOff": 112.5, "datacenters": [ { "datacenterId": 3132, "nickname": "Winterfell", "trafficTargetName": "Winterfell - 1.2.3.4", "IPs": [ { "ip": "1.2.3.4", "score": 75.0, "handedOut": true, "alive": true } ] }, { "datacenterId": 3133, "nickname": "Braavos", "trafficTargetName": "Braavos - 1.2.3.5", "IPs": [ { "ip": "1.2.3.5", "score": 85.0, "handedOut": true, "alive": true } ] } ] }, { "timestamp": "2017-03-23T21:42:35Z", "cutOff": 112.5, "datacenters": [ { "datacenterId": 3132, "nickname": "Winterfell", "trafficTargetName": "Winterfell - 1.2.3.4", "IPs": [ { "ip": "1.2.3.4", "score": 115.0, "handedOut": false, "alive": false } ] }, { "datacenterId": 3133, "nickname": "Braavos", "trafficTargetName": "Braavos - 1.2.3.5", "IPs": [ { "ip": "1.2.3.5", "score": 75.0, "handedOut": true, "alive": true } ] } ] } ], "links": [ { "rel": "self", "href": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/ip-availability/domains/gtmtest.akadns.net/properties/testproperty" } ] }`) Init(config) optArgs := make(map[string]string) optArgs["start"] = "2017-02-23T21:00:00Z" optArgs["end"] = "2017-03-23T22:00:00Z" testPropertyIpStatus, err := GetIpStatusPerProperty(gtmTestDomain, GtmTestProperty, optArgs) assert.NoError(t, err) assert.Equal(t, testPropertyIpStatus.DataRows[0].Datacenters[0].DatacenterId, 3132) assert.Equal(t, testPropertyIpStatus.Metadata.Domain, gtmTestDomain) assert.Equal(t, testPropertyIpStatus.Metadata.Property, GtmTestProperty) } /* // TestGetIpStatus with mostRecent flag func TestGetIpStatusPropertyRecent(t *testing.T) { config, _ := edgegrid.InitEdgeRc("", "default") Init(config) // add mock ... optArgs := make(map[string]string) optArgs["mostRecent"] = "true" domDCs, err := configgtm.ListDatacenters(GtmObjectTestDomain) assert.NoError(t, err, "Failure retrieving DCs") if len(domDCs) > 0 { optArgs["datacenterId"] = strconv.Itoa(domDCs[0].DatacenterId) fmt.Println("dcid: "+optArgs["datacenterId"]) } testPropertyIpStatus, err := GetIpStatusPerProperty(GtmObjectTestDomain, GtmTestProperty, optArgs) assert.NoError(t, err) json, err := json.MarshalIndent(testPropertyIpStatus, "", " ") if err == nil { fmt.Println(string(json)) } else { t.Fatal("PropertyIP Status retrival failed. " + err.Error()) } } */ // Verify GetTrafficPerProperty. Domain name and property name hardcoded. func TestGetTrafficPerProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/" + GtmTestProperty) mock. Get("/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/"+GtmTestProperty). HeaderPresent("Authorization"). Reply(200). SetHeader("Content-Type", "application/json"). BodyString(`{ "metadata": { "domain": "gtmtest.akadns.net", "property": "testproperty", "start": "2016-11-24T01:40:00Z", "end": "2016-11-24T01:50:00Z", "interval": "FIVE_MINUTE", "uri": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/testproperty?start=2016-11-23T00:00:00Z&2016-11-24T01:50:00Z" }, "dataRows": [ { "timestamp": "2016-11-24T01:40:00Z", "datacenters": [ { "datacenterId": 3130, "nickname": "Winterfell", "trafficTargetName": "Winterfell - 1.2.3.4", "requests": 34, "status": "1" } ] }, { "timestamp": "2016-11-24T01:45:00Z", "datacenters": [ { "datacenterId": 3130, "nickname": "Winterfell", "trafficTargetName": "Winterfell - 1.2.3.4", "requests": 45, "status": "1" } ] } ], "links": [ { "rel": "self", "href": "https://akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/testproperty?start=2016-11-23T00:00:00Z&2016-11-24T01:50:00Z" } ] }`) Init(config) optArgs := make(map[string]string) optArgs["start"] = "2016-11-24T01:40:00Z" optArgs["end"] = "2016-11-24T01:50:00Z" testPropertyTraffic, err := GetTrafficPerProperty(gtmTestDomain, GtmTestProperty, optArgs) assert.NoError(t, err) assert.Equal(t, testPropertyTraffic.DataRows[0].Datacenters[0].DatacenterId, 3130) assert.Equal(t, testPropertyTraffic.Metadata.Domain, gtmTestDomain) assert.Equal(t, testPropertyTraffic.Metadata.Property, GtmTestProperty) } // Verify failed case for GetProperty. Should pass, e.g. no API errors and domain not found func TestGetBadTrafficPerProperty(t *testing.T) { defer gock.Off() mock := gock.New("https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/badproperty") mock. Get("/gtm-api/v1/reports/traffic/domains/gtmtest.akadns.net/properties/badproperty"). HeaderPresent("Authorization"). Reply(404). SetHeader("Content-Type", "application/json"). BodyString(`{ }`) Init(config) optArgs := make(map[string]string) _, err := GetTrafficPerProperty(gtmTestDomain, "badproperty", optArgs) assert.Error(t, err) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/service.go000066400000000000000000000011561400161560600273240ustar00rootroot00000000000000package reportsgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" "net/http" ) var ( // Config contains the Akamai OPEN Edgegrid API credentials // for automatic signing of requests Config edgegrid.Config ) // Init sets the GTM edgegrid Config func Init(config edgegrid.Config) { Config = config edgegrid.SetupLogging() } // Utility func to print http req func printHttpRequest(req *http.Request, body bool) { edgegrid.PrintHttpRequest(req, body) } // Utility func to print http response func printHttpResponse(res *http.Response, body bool) { edgegrid.PrintHttpResponse(res, body) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/service_test.go000066400000000000000000000007311400161560600303610ustar00rootroot00000000000000package reportsgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" ) var ( config = edgegrid.Config{ Host: "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/", AccessToken: "akab-access-token-xxx-xxxxxxxxxxxxxxxx", ClientToken: "akab-client-token-xxx-xxxxxxxxxxxxxxxx", ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", MaxBody: 2048, Debug: false, } ) var gtmTestDomain = "gtmtest.akadns.net" golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/reportsgtm-v1/util.go000066400000000000000000000102061400161560600266350ustar00rootroot00000000000000package reportsgtm import ( "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1" "github.com/akamai/AkamaiOPEN-edgegrid-golang/configgtm-v1_3" "net/http" "fmt" "time" ) // // Support gtm reports thru Edgegrid // Based on 1.0 Schema // type WindowResponse struct { StartTime time.Time EndTime time.Time } type APIWindowResponse struct { Start string `json:"start"` End string `json:"end"` } func setEncodedHeader(req *http.Request) { if req.Method == "GET" { req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } return } // Utility method to convert an RFC3339 formated time string to a time.Time object func convertRFC3339toDate(rfc3339Stamp string) (time.Time, error) { t, err := time.Parse(time.RFC3339, rfc3339Stamp) return t, err } func createTimeWindow(apiResponse *APIWindowResponse) (*WindowResponse, error) { var err error windowResponse := &WindowResponse{} windowResponse.StartTime, err = convertRFC3339toDate(apiResponse.Start) if err != nil { return nil, err } windowResponse.EndTime, err = convertRFC3339toDate(apiResponse.End) if err != nil { return nil, err } return windowResponse, nil } // Core function to retrieve all Window API requests func getWindowCore(hostURL string) (*WindowResponse, error) { stat := &APIWindowResponse{} req, err := client.NewRequest( Config, "GET", hostURL, nil, ) if err != nil { return nil, err } printHttpRequest(req, true) res, err := client.Do(Config, req) if err != nil { return nil, err } printHttpResponse(res, true) if client.IsError(res) { if res.StatusCode == 400 { // Get the body. Could be bad dates. var windRespErrBody map[string]interface{} err = client.BodyJSON(res, windRespErrBody) if err != nil { return nil, err } // are available dates present? if availEnd, ok := windRespErrBody["availableEndDate"]; ok { stat.End = availEnd.(string) } if availStart, ok := windRespErrBody["availableStartDate"]; ok { stat.Start = availStart.(string) } if stat.End == "" || stat.Start == "" { cErr := configgtm.CommonError{} cErr.SetItem("entityName", "Window") cErr.SetItem("name", "Data Window") cErr.SetItem("apiErrorMessage", "No available data window") return nil, cErr } } else if res.StatusCode == 404 { cErr := configgtm.CommonError{} cErr.SetItem("entityName", "Window") cErr.SetItem("name", "Data Window") return nil, cErr } else { return nil, client.NewAPIError(res) } } else { err = client.BodyJSON(res, stat) if err != nil { return nil, err } } timeWindow, err := createTimeWindow(stat) if err != nil { return nil, err } return timeWindow, nil } // GetDemandWindow is a utility function that retrieves the data window for Demand category of Report APIs func GetDemandWindow(domainName string, propertyName string) (*WindowResponse, error) { hostURL := fmt.Sprintf("/gtm-api/v1/reports/demand/domains/%s/properties/%s/window", domainName, propertyName) return getWindowCore(hostURL) } // GetLatencyDomainsWindow is a utility function that retrieves the data window for Latency category of Report APIs func GetLatencyDomainsWindow(domainName string) (*WindowResponse, error) { hostURL := fmt.Sprintf("/gtm-api/v1/reports/latency/domains/%s/window", domainName) return getWindowCore(hostURL) } // GetLivenessTestsWindow is a utility function that retrieves the data window for Liveness category of Report APIs func GetLivenessTestsWindow() (*WindowResponse, error) { hostURL := fmt.Sprintf("/gtm-api/v1/reports/liveness-tests/window") return getWindowCore(hostURL) } // GetDatacentersTrafficWindow is a utility function that retrieves the data window for Traffic category of Report APIs func GetDatacentersTrafficWindow() (*WindowResponse, error) { hostURL := fmt.Sprintf("/gtm-api/v1/reports/traffic/datacenters-window") return getWindowCore(hostURL) } // GetPropertiesTrafficWindow is a utility function that retrieves the data window for Traffic category of Report API func GetPropertiesTrafficWindow() (*WindowResponse, error) { hostURL := fmt.Sprintf("/gtm-api/v1/reports/traffic/properties-window") return getWindowCore(hostURL) } golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/scripts/000077500000000000000000000000001400161560600242675ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/scripts/semtag000077500000000000000000000424351400161560600255050ustar00rootroot00000000000000#!/usr/bin/env bash # this file has semantic versioning script from https://github.com/pnikosis/semtag PROG=semtag PROG_VERSION="v0.1.0" SEMVER_REGEX="^v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$" IDENTIFIER_REGEX="^\-([0-9A-Za-z-]+)\.([0-9A-Za-z-]+)*$" # Global variables FIRST_VERSION="v0.0.0" finalversion=$FIRST_VERSION lastversion=$FIRST_VERSION hasversiontag="false" scope="patch" displayonly="false" forcetag="false" forcedversion= versionname= identifier= HELP="\ Usage: $PROG $PROG getlast $PROG getfinal $PROG (final|alpha|beta|candidate) [-s (major|minor|patch|auto) | -o] $PROG --help $PROG --version Options: -s The scope that must be increased, can be major, minor or patch. The resulting version will match X.Y.Z(-PRERELEASE)(+BUILD) where X, Y and Z are positive integers, PRERELEASE is an optionnal string composed of alphanumeric characters describing if the build is a release candidate, alpha or beta version, with a number. BUILD is also an optional string composed of alphanumeric characters and hyphens. Setting the scope as 'auto', the script will chose the scope between 'minor' and 'patch', depending on the amount of lines added (<10% will choose patch). -v Specifies manually the version to be tagged, must be a valid semantic version in the format X.Y.Z where X, Y and Z are positive integers. -o Output the version only, shows the bumped version, but doesn't tag. -f Forces to tag, even if there are unstaged or uncommited changes. Commands: --help Print this help message. --version Prints the program's version. get Returns both current final version and last tagged version. getlast Returns the latest tagged version. getfinal Returns the latest tagged final version. getcurrent Returns the current version, based on the latest one, if there are uncommited or unstaged changes, they will be reflected in the version, adding the number of pending commits, current branch and commit hash. final Tags the current build as a final version, this only can be done on the master branch. candidate Tags the current build as a release candidate, the tag will contain all the commits from the last final version. alpha Tags the current build as an alpha version, the tag will contain all the commits from the last final version. beta Tags the current build as a beta version, the tag will contain all the commits from the last final version." # Commands and options ACTION="getlast" ACTION="$1" shift # We get the parameters while getopts "v:s:of" opt; do case $opt in v) forcedversion="$OPTARG" ;; s) scope="$OPTARG" ;; o) displayonly="true" ;; f) forcetag="true" ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done # Gets a string with the version and returns an array of maximum size of 5 with all the parts of the sematinc version # $1 The string containing the version in semantic format # $2 The variable to store the result array: # position 0: major number # position 1: minor number # position 2: patch number # position 3: identifier (or prerelease identifier) # position 4: build info function explode_version { local __version=$1 local __result=$2 if [[ $__version =~ $SEMVER_REGEX ]] ; then local __major=${BASH_REMATCH[1]} local __minor=${BASH_REMATCH[2]} local __patch=${BASH_REMATCH[3]} local __prere=${BASH_REMATCH[4]} local __build=${BASH_REMATCH[5]} eval "$__result=(\"$__major\" \"$__minor\" \"$__patch\" \"$__prere\" \"$__build\")" else eval "$__result=" fi } # Compare two versions and returns -1, 0 or 1 # $1 The first version to compare # $2 The second version to compare # $3 The variable where to store the result function compare_versions { local __first local __second explode_version $1 __first explode_version $2 __second local lv=$3 # Compares MAJOR, MINOR and PATCH for i in 0 1 2; do local __numberfirst=${__first[$i]} local __numbersecond=${__second[$i]} case $(($__numberfirst - $__numbersecond)) in 0) ;; -[0-9]*) eval "$lv=-1" return 0 ;; [0-9]*) eval "$lv=1" return 0 ;; esac done # Identifiers should compare with the ASCII order. local __identifierfirst=${__first[3]} local __identifiersecond=${__second[3]} if [[ -n "$__identifierfirst" ]] && [[ -n "$__identifiersecond" ]]; then if [[ "$__identifierfirst" > "$__identifiersecond" ]]; then eval "$lv=1" return 0 elif [[ "$__identifierfirst" < "$__identifiersecond" ]]; then eval "$lv=-1" return 0 fi elif [[ -z "$__identifierfirst" ]] && [[ -n "$__identifiersecond" ]]; then eval "$lv=1" return 0 elif [[ -n "$__identifierfirst" ]] && [[ -z "$__identifiersecond" ]]; then eval "$lv=-1" return 0 fi eval "$lv=0" } # Returns the last version of two # $1 The first version to compare # $2 The second version to compare # $3 The variable where to store the last one function get_latest_of_two { local __first=$1 local __second=$2 local __result local __latest=$3 compare_versions $__first $__second __result case $__result in 0) eval "$__latest=$__second" ;; -1) eval "$__latest=$__second" ;; 1) eval "$__latest=$__first" ;; esac } # Assigns a 2 size array with the identifier, having the identifier at pos 0, and the number in pos 1 # $1 The identifier in the format -id.# # $2 The vferiable where to store the 2 size array function explode_identifier { local __identifier=$1 local __result=$2 if [[ $__identifier =~ $IDENTIFIER_REGEX ]] ; then local __id=${BASH_REMATCH[1]} local __number=${BASH_REMATCH[2]} if [[ -z "$__number" ]]; then __number=1 fi eval "$__result=(\"$__id\" \"$__number\")" else eval "$__result=" fi } # Gets a list of tags and assigns the base and latest versions # Receives an array with the tags containing the versions # Assigns to the global variables finalversion and lastversion the final version and the latest version function get_latest { local __taglist=("$@") local __tagsnumber=${#__taglist[@]} local __current case $__tagsnumber in 0) finalversion=$FIRST_VERSION lastversion=$FIRST_VERSION ;; 1) __current=${__taglist[0]} explode_version $__current ver if [ -n "$ver" ]; then if [ -n "${ver[3]}" ]; then finalversion=$FIRST_VERSION else finalversion=$__current fi lastversion=$__current else finalversion=$FIRST_VERSION lastversion=$FIRST_VERSION fi ;; *) local __lastpos=$(($__tagsnumber-1)) for i in $(seq 0 $__lastpos) do __current=${__taglist[i]} explode_version ${__taglist[i]} ver if [ -n "$ver" ]; then if [ -z "${ver[3]}" ]; then get_latest_of_two $finalversion $__current finalversion get_latest_of_two $lastversion $finalversion lastversion else get_latest_of_two $lastversion $__current lastversion fi fi done ;; esac if git rev-parse -q --verify "refs/tags/$lastversion" >/dev/null; then hasversiontag="true" else hasversiontag="false" fi } # Gets the next version given the provided scope # $1 The version that is going to be bumped # $2 The scope to bump # $3 The variable where to stoer the result function get_next_version { local __exploded local __fromversion=$1 local __scope=$2 local __result=$3 explode_version $__fromversion __exploded case $__scope in major) __exploded[0]=$((${__exploded[0]}+1)) __exploded[1]=0 __exploded[2]=0 ;; minor) __exploded[1]=$((${__exploded[1]}+1)) __exploded[2]=0 ;; patch) __exploded[2]=$((${__exploded[2]}+1)) ;; esac eval "$__result=v${__exploded[0]}.${__exploded[1]}.${__exploded[2]}" } function bump_version { ## First we try to get the next version based on the existing last one if [ "$scope" == "auto" ]; then get_scope_auto scope fi local __candidatefromlast=$FIRST_VERSION local __explodedlast explode_version $lastversion __explodedlast if [[ -n "${__explodedlast[3]}" ]]; then # Last version is not final local __idlast explode_identifier ${__explodedlast[3]} __idlast # We get the last, given the desired id based on the scope __candidatefromlast="v${__explodedlast[0]}.${__explodedlast[1]}.${__explodedlast[2]}" if [[ -n "$identifier" ]]; then local __nextid="$identifier.1" if [ "$identifier" == "${__idlast[0]}" ]; then # We target the same identifier as the last so we increase one __nextid="$identifier.$(( ${__idlast[1]}+1 ))" __candidatefromlast="$__candidatefromlast-$__nextid" else # Different identifiers, we make sure we are assigning a higher identifier, if not, we increase the version __candidatefromlast="$__candidatefromlast-$__nextid" local __comparedwithlast compare_versions $__candidatefromlast $lastversion __comparedwithlast if [ "$__comparedwithlast" == -1 ]; then get_next_version $__candidatefromlast $scope __candidatefromlast __candidatefromlast="$__candidatefromlast-$__nextid" fi fi fi fi # Then we try to get the version based on the latest final one local __candidatefromfinal=$FIRST_VERSION get_next_version $finalversion $scope __candidatefromfinal if [[ -n "$identifier" ]]; then __candidatefromfinal="$__candidatefromfinal-$identifier.1" fi # Finally we compare both candidates local __resultversion local __result compare_versions $__candidatefromlast $__candidatefromfinal __result case $__result in 0) __resultversion=$__candidatefromlast ;; -1) __resultversion="$__candidatefromfinal" ;; 1) __resultversion=$__candidatefromlast ;; esac eval "$1=$__resultversion" } function increase_version { local __version= if [ -z $forcedversion ]; then bump_version __version else if [[ $forcedversion =~ $SEMVER_REGEX ]] ; then compare_versions $forcedversion $lastversion __result if [ $__result -le 0 ]; then echo "Version can't be lower than last version: $lastversion" exit 1 fi else echo "Non valid version to bump" exit 1 fi __version=$forcedversion fi if [ "$displayonly" == "true" ]; then echo "$__version" else if [ "$forcetag" == "false" ]; then check_git_dirty_status fi local __commitlist if [ "$finalversion" == "$FIRST_VERSION" ] || [ "$hasversiontag" != "true" ]; then __commitlist="$(git log --pretty=oneline | cat)" else __commitlist="$(git log --pretty=oneline $finalversion... | cat)" fi # If we are forcing a bump, we add bump to the commit list if [[ -z $__commitlist && "$forcetag" == "true" ]]; then __commitlist="bump" fi if [[ -z $__commitlist ]]; then echo "No commits since the last final version, not bumping version" else if [[ -z $versionname ]]; then versionname=$(date -u +"%Y-%m-%dT%H:%M:%SZ") fi local __message="$versionname $__commitlist" # We check we have info on the user local __username=$(git config user.name) if [ -z "$__username" ]; then __username=$(id -u -n) git config user.name $__username fi local __useremail=$(git config user.email) if [ -z "$__useremail" ]; then __useremail=$(hostname) git config user.email "$__username@$__useremail" fi git tag -a $__version -m "$__message" # If we have a remote, we push there local __remotes=$(git remote) if [[ -n $__remotes ]]; then for __remote in $__remotes; do git push $__remote $__version > /dev/null if [ $? -eq 0 ]; then echo "$__version pushed to $__remote" else echo "Error pushing the tag $__version to $__remote" exit 1 fi done else echo "$__version" fi fi fi } function check_git_dirty_status { local __repostatus= get_work_tree_status __repostatus if [ "$__repostatus" == "uncommitted" ]; then echo "ERROR: You have uncommitted changes" git status --porcelain exit 1 fi if [ "$__repostatus" == "unstaged" ]; then echo "ERROR: You have unstaged changes" git status --porcelain exit 1 fi } # Get the total amount of lines of code in the repo function get_total_lines { local __empty_id="$(git hash-object -t tree /dev/null)" local __changes="$(git diff --numstat $__empty_id | cat)" local __added_deleted=$1 get_changed_lines "$__changes" $__added_deleted } # Get the total amount of lines of code since the provided tag function get_sincetag_lines { local __sincetag=$1 local __changes="$(git diff --numstat $__sincetag | cat)" local __added_deleted=$2 get_changed_lines "$__changes" $__added_deleted } function get_changed_lines { local __changes_numstat=$1 local __result=$2 IFS=$'\n' read -rd '' -a __changes_array <<<"$__changes_numstat" local __diff_regex="^([0-9]+)[[:space:]]+([0-9]+)[[:space:]]+.+$" local __total_added=0 local __total_deleted=0 for i in "${__changes_array[@]}" do if [[ $i =~ $__diff_regex ]] ; then local __added=${BASH_REMATCH[1]} local __deleted=${BASH_REMATCH[2]} __total_added=$(( $__total_added+$__added )) __total_deleted=$(( $__total_deleted+$__deleted )) fi done eval "$2=( $__total_added $__total_deleted )" } function get_scope_auto { local __verbose=$2 local __total=0 local __since=0 local __scope= get_total_lines __total get_sincetag_lines $finalversion __since local __percentage=0 if [ "$__total" != "0" ]; then local __percentage=$(( 100*$__since/$__total )) if [ $__percentage -gt "10" ]; then __scope="minor" else __scope="patch" fi fi eval "$1=$__scope" if [[ -n "$__verbose" ]]; then echo "[Auto Scope] Percentage of lines changed: $__percentage" echo "[Auto Scope] : $__scope" fi } function get_work_tree_status { # Update the index git update-index -q --ignore-submodules --refresh > /dev/null eval "$1=" if ! git diff-files --quiet --ignore-submodules -- > /dev/null then eval "$1=unstaged" fi if ! git diff-index --cached --quiet HEAD --ignore-submodules -- > /dev/null then eval "$1=uncommitted" fi } function get_current { if [ "$hasversiontag" == "true" ]; then local __commitcount="$(git rev-list $lastversion.. --count)" else local __commitcount="$(git rev-list --count HEAD)" fi local __status= get_work_tree_status __status if [ "$__commitcount" == "0" ] && [ -z "$__status" ]; then eval "$1=$lastversion" else local __buildinfo="$(git rev-parse --short HEAD)" local __currentbranch="$(git rev-parse --abbrev-ref HEAD)" if [ "$__currentbranch" != "master" ]; then __buildinfo="$__currentbranch.$__buildinfo" fi local __suffix= if [ "$__commitcount" != "0" ]; then if [ -n "$__suffix" ]; then __suffix="$__suffix." fi __suffix="$__suffix$__commitcount" fi if [ -n "$__status" ]; then if [ -n "$__suffix" ]; then __suffix="$__suffix." fi __suffix="$__suffix$__status" fi __suffix="$__suffix+$__buildinfo" if [ "$lastversion" == "$finalversion" ]; then scope="patch" identifier= local __bumped= bump_version __bumped eval "$1=$__bumped-dev.$__suffix" else eval "$1=$lastversion.$__suffix" fi fi } function init { git fetch > /dev/null TAGS="$(git tag)" IFS=$'\n' read -rd '' -a TAG_ARRAY <<<"$TAGS" get_latest ${TAG_ARRAY[@]} currentbranch="$(git rev-parse --abbrev-ref HEAD)" } case $ACTION in --help) echo -e "$HELP" ;; --version) echo -e "${PROG}: $PROG_VERSION" ;; final) init diff=$(git diff master | cat) diff_dev=$(git diff develop | cat) diff_v2=$(git diff v2 | cat) if [ "$forcetag" == "false" ]; then if [ -n "$diff_dev" ] && [ -n "$diff" ] && [ -n "$diff_v2" ]; then echo "ERROR: Branch must be updated with develop, master, or v2 for final versions" if [ -n "$diff" ]; then echo "ERROR: Branch must be updated with master for final versions" exit 1 fi fi increase_version ;; alpha|beta) init identifier="$ACTION" increase_version ;; candidate) init identifier="rc" increase_version ;; getlast) init echo "$lastversion" ;; getfinal) init echo "$finalversion" ;; getcurrent) init get_current current echo "$current" ;; get) init echo "Current final version: $finalversion" echo "Last tagged version: $lastversion" ;; *) echo "'$ACTION' is not a valid command, see --help for available commands." ;; esac golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/testdata/000077500000000000000000000000001400161560600244115ustar00rootroot00000000000000golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/testdata/edgerc_that_doesnt_parse000066400000000000000000000002101400161560600313440ustar00rootroot00000000000000[default] client_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx access_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx max_body = 131072 golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/testdata/nodefault_edgerc000066400000000000000000000004111400161560600276220ustar00rootroot00000000000000[nodefault] host = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/ client_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= access_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx max_body = 131072golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/testdata/sample_edgerc000066400000000000000000000020231400161560600271230ustar00rootroot00000000000000[default] host = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/ client_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= access_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx max_body = 131072 [test] host = test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/ client_token = test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx client_secret = testxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= access_token = test-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx max_body = 131072 [broken] host = "https://xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/" client_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= access_token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx [dashes] host = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net/ client-token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx client-secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= access-token = xxxx-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx max-body = 131072 golang-github-akamai-akamaiopen-edgegrid-golang-1.0.1/testdata/testdata.json000066400000000000000000000306411400161560600271210ustar00rootroot00000000000000{ "tests": [ { "testName": "simple GET", "request": { "method": "GET", "path": "/", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=tL+y4hxyHxgWVD30X3pWnGKHcPzmrIF+LThiAOhMxYU=" }, { "testName": "GET with querystring", "request": { "method": "GET", "path": "/testapi/v1/t1?p1=1&p2=2", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=d6CRM7lMZvSlwqNU9he5VN1ey+gi5QKvrFHemBAfnjk=" }, { "testName": "POST inside limit", "request": { "method": "POST", "path": "/testapi/v1/t3", "data": "datadatadatadatadatadatadatadata", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hXm4iCxtpN22m4cbZb4lVLW5rhX8Ca82vCFqXzSTPe4=" }, { "testName": "POST too large", "request": { "method": "POST", "path": "/testapi/v1/t3", "data": "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=6Q6PiTipLae6n4GsSIDTCJ54bEbHUBp+4MUXrbQCBoY=" }, { "testName": "POST length equals max_body", "request": { "method": "POST", "path": "/testapi/v1/t3", "data": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=6Q6PiTipLae6n4GsSIDTCJ54bEbHUBp+4MUXrbQCBoY=" }, { "testName": "POST empty body", "request": { "method": "POST", "path": "/testapi/v1/t6", "data": "", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=1gEDxeQGD5GovIkJJGcBaKnZ+VaPtrc4qBUHixjsPCQ=" }, { "testName": "Simple header signing with GET", "request": { "method": "GET", "path": "/testapi/v1/t4", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test1": "test-simple-header"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=8F9AybcRw+PLxnvT+H0JRkjROrrUgsxJTnRXMzqvcwY=" }, { "testName": "Simple header signing with GET. Space in Path", "request": { "method": "GET", "path": "/testapi/v1/t 4", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test1": "test-simple-header"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=nks5K9Q96uegodgNmzAhLQMgAKaP48dAcKTX+T7Xu8k=" }, { "testName": "Header containing spaces", "request": { "method": "GET", "path": "/testapi/v1/t4", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test1": "\" test-header-with-spaces \""} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=ucq2AbjCNtobHfCTuS38fdkl5UDdWHZhQX46fYR8CqI=" }, { "testName": "Header with leading and interior spaces", "request": { "method": "GET", "path": "/testapi/v1/t4", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test1": " first-thing second-thing"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=WtnneL539UadAAOJwnsXvPqT4Kt6z7HMgBEwAFpt3+c=" }, { "testName": "Headers out of order", "request": { "method": "GET", "path": "/testapi/v1/t4", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test2": "t2"}, {"X-Test1": "t1"}, {"X-Test3": "t3"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=Wus73Nx8jOYM+kkBFF2q8D1EATRIMr0WLWwpLBgkBqY=" }, { "testName": "Extra header", "request": { "method": "GET", "path": "/testapi/v1/t5", "headers": [ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}, {"X-Test2": "t2"}, {"X-Test1": "t1"}, {"X-Test3": "t3"}, {"X-Extra": "this won't be included"} ] }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=Knd/jc0A5Ghhizjayr0AUUvl2MZjBpS3FDSzvtq4Ixc=" }, { "testName": "PUT test", "request": { "method": "PUT", "path": "/testapi/v1/t6", "data": "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" }, "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=GNBWEYSEWOLtu+7dD52da2C39aX/Jchpon3K/AmBqBU=" } ] }