pax_global_header00006660000000000000000000000064140026136420014510gustar00rootroot0000000000000052 comment=25345b053a01ef5d38b0aa004f2dfe4f7f9ad161 go-kong-0.15.0/000077500000000000000000000000001400261364200131345ustar00rootroot00000000000000go-kong-0.15.0/.ci/000077500000000000000000000000001400261364200136055ustar00rootroot00000000000000go-kong-0.15.0/.ci/setup_kong.sh000077500000000000000000000023641400261364200163270ustar00rootroot00000000000000#!/bin/bash set -e # download Kong deb sudo apt-get update sudo apt-get install openssl libpcre3 procps perl wget zlibc function setup_kong(){ SWITCH="1.3.100" URL="https://kong.bintray.com/kong-deb/kong-${KONG_VERSION}.xenial.all.deb" if [[ "$KONG_VERSION" > "$SWITCH" ]]; then URL="https://kong.bintray.com/kong-deb/kong-${KONG_VERSION}.xenial.amd64.deb" fi /usr/bin/curl -sL $URL -o kong.deb } function setup_kong_enterprise(){ KONG_VERSION="${KONG_VERSION#enterprise-}" URL="https://kong.bintray.com/kong-enterprise-edition-deb/dists/kong-enterprise-edition-${KONG_VERSION}.xenial.all.deb" RESPONSE_CODE=$(/usr/bin/curl -sL \ -w "%{http_code}" \ -u $KONG_ENTERPRISE_REPO_USERNAME:$KONG_ENTERPRISE_REPO_PASSSWORD \ $URL -o kong.deb) if [[ $RESPONSE_CODE != "200" ]]; then echo "error retrieving kong enterprise package from ${URL}. response code ${RESPONSE_CODE}" exit 1 fi } if [[ $KONG_VERSION == *"enterprise"* ]]; then setup_kong_enterprise else setup_kong fi sudo dpkg -i kong.deb echo $KONG_LICENSE_DATA | sudo tee /etc/kong/license.json export KONG_LICENSE_PATH=/tmp/license.json export KONG_PASSWORD=kong export KONG_ENFORCE_RBAC=on sudo kong migrations bootstrap sudo kong version sudo kong start go-kong-0.15.0/.editorconfig000066400000000000000000000000501400261364200156040ustar00rootroot00000000000000[*.go] end_of_line = lf indent_size = 2 go-kong-0.15.0/.github/000077500000000000000000000000001400261364200144745ustar00rootroot00000000000000go-kong-0.15.0/.github/workflows/000077500000000000000000000000001400261364200165315ustar00rootroot00000000000000go-kong-0.15.0/.github/workflows/test.yaml000066400000000000000000000063321400261364200204000ustar00rootroot00000000000000name: CI Test on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - name: Setup go uses: actions/setup-go@v2 with: go-version: '^1.14' - name: Checkout repository uses: actions/checkout@v2 - name: Setup golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.25.0 - name: Run golangci-lint run: golangci-lint run ./... - name: Verify Codegen run: ./hack/verify-deepcopy-gen.sh test: strategy: matrix: kong_version: [ '1.0.3', '1.1.2', '1.2.0', '1.3.0', '1.4.0', '2.0.4', '2.1.0'] env: KONG_VERSION: ${{ matrix.kong_version }} KONG_ENTERPRISE_REPO_USERNAME: ${{ secrets.KONG_ENTERPRISE_REPO_USERNAME }} KONG_ENTERPRISE_REPO_PASSSWORD: ${{ secrets.KONG_ENTERPRISE_REPO_PASSSWORD }} KONG_LICENSE_DATA: ${{ secrets.KONG_LICENSE_DATA }} KONG_ANONYMOUS_REPORTS: "off" runs-on: ubuntu-latest services: postgres: image: postgres:11.6-alpine ports: - 5432:5432 # needed because the postgres container does not provide a healthcheck options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Setup go uses: actions/setup-go@v2 with: go-version: '^1.14' - name: Checkout repository uses: actions/checkout@v2 - name: Setup Postgres run: | psql -c 'create database kong;' -U postgres -h 127.0.0.1 -p 5432 psql -c 'create user kong;' -U postgres -h 127.0.0.1 -p 5432 psql -c 'GRANT ALL PRIVILEGES ON DATABASE "kong" to kong;' -U postgres -h 127.0.0.1 -p 5432 - name: Setup Kong run: bash .ci/setup_kong.sh - name: Run tests run: go test -v ./... test-enterprise: strategy: matrix: kong_version: ['enterprise-1.3.0.2', 'enterprise-1.5.0.2'] env: KONG_VERSION: ${{ matrix.kong_version }} KONG_ENTERPRISE_REPO_USERNAME: ${{ secrets.KONG_ENTERPRISE_REPO_USERNAME }} KONG_ENTERPRISE_REPO_PASSSWORD: ${{ secrets.KONG_ENTERPRISE_REPO_PASSSWORD }} KONG_LICENSE_DATA: ${{ secrets.KONG_LICENSE_DATA }} KONG_ANONYMOUS_REPORTS: "off" KONG_ADMIN_TOKEN: kong runs-on: ubuntu-latest services: postgres: image: postgres:11.6-alpine ports: - 5432:5432 # needed because the postgres container does not provide a healthcheck options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Setup go uses: actions/setup-go@v2 with: go-version: '^1.14' - name: Checkout repository uses: actions/checkout@v2 - name: Setup Postgres run: | psql -c 'create database kong;' -U postgres -h 127.0.0.1 -p 5432 psql -c 'create user kong;' -U postgres -h 127.0.0.1 -p 5432 psql -c 'GRANT ALL PRIVILEGES ON DATABASE "kong" to kong;' -U postgres -h 127.0.0.1 -p 5432 - name: Setup Kong run: bash .ci/setup_kong.sh - name: Run tests run: go test -tags=enterprise -v ./... go-kong-0.15.0/.gitignore000066400000000000000000000004471400261364200151310ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test vendor # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof # for this repo only go-kong-0.15.0/.golangci.yml000066400000000000000000000003131400261364200155150ustar00rootroot00000000000000linters: enable: - megacheck - govet - bodyclose - unparam - unconvert - misspell - lll - gofmt - gochecknoinits - golint - gosec - nakedret - gomnd - maligned - errcheck go-kong-0.15.0/CHANGELOG.md000066400000000000000000000205731400261364200147540ustar00rootroot00000000000000# Table of Contents - [v0.14.0](#v0140---20210112) - [v0.13.0](#v0130---20200804) - [v0.12.0](#v0120---20200730) - [v0.11.0](#v0110---20200117) - [v0.10.0](#v0100---20191027) - [v0.9.0](#v090---20190824) - [v0.8.0](#v080---20190821) - [v0.7.0](#v070---20190813) - [v0.6.2](#v062---20190809) - [v0.6.1](#v061---20190809) - [v0.6.0](#v060---20190809) - [v0.5.1](#v051---20190805) - [v0.5.0](#v050---20190607) - [v0.4.1](#v041---20190411) - [v0.4.0](#v040---20190406) - [0.3.0](#030---20181219) - [0.2.0](#020---20181219) - [0.1.0](#010---20181201) ## [v0.14.0] - 2021/01/12 ### Breaking changes - HTTP error format changed to feature HTTP codes ### Added - RBACUser support - Support for auto-expiring key-auth key TTL - Support for RBAC roles - Support for RBAC permissions - DeepCopy annotations for enterprise entities ## [v0.13.0] - 2020/08/04 ### Summary This release renames the package from `github.com/hbagdi/go-kong` to `github.com/kong/go-kong`. ## [v0.12.0] - 2020/07/30 ### Summary This release adds support for Kong 2.1 series and a number of enterprise entities. ### Added - Added `HTTPClientWithHeaders` helper function to inject authn/authz related HTTP headers in requests to kong. - New fields in types: - `Service` struct has three new fields: - `TLSVerifyDepth` - `TLSVerify` - `CACertificates` - `ClientCertificate` field has been added to `Upstream` struct. - `Type` field has been added to `PassiveHealthcheck` struct. - Following new services for Kong Enterprise have been introduced: - WorkspaceService to manage workspaces in kong - AdminService to manage users of Kong Manager - MTLSAuthService to manage MTLS credentials ### Misc - Changed the branch name from `master` to `main` - Introduced linters to improve code health ## [v0.11.0] - 2020/01/17 ### Summary - This release adds support for Kong 2.0.0. ### Added - `Threshold` field has been added to Upstream struct. - `PathHandling` field has been added to Route struct. ## [v0.10.0] - 2019/10/27 ### Summary - This release adds support for Kong 1.4. ### Added - `HostHeader` field has been added to Upstream struct. - `Tags` field has been added to the following types: - `KeyAuth` - `Basicauth` - `HMACAuth` - `Oauth2Credential` - `ACLGroup` - `JWTAuth` ## [v0.9.0] - 2019/08/24 ### Breaking changes - `client.Do()` returns a response object even on errors so that clients can inspect the response directly when needed. The error condition has changed to include HTTP status codes 300 to 399 as success and not failure. [b1f9eda31](https://github.com/hbagdi/go-kong/commit/b1f9eda311e1d9c9d6b0f5a5e33a3d399d85faf6) - `String()` method has been dropped from all types defined in this package. ### Added - `NewRequest()` method helping with creating HTTP requests is now exported - URLs parsed inside the package are more robust. - New method `GetByCustomID` has been introduced to fetch Consumers by `custom_id`. ## [v0.8.0] - 2019/08/21 ### Added - Oauth2Credential type and service has been added which can be used to create Oauth2 credentials in Kong for some Oauth2 flows. ## [v0.7.0] - 2019/08/13 ### Summary This release brings support for CRUD methods for authentication credentials in Kong. ### Added - The following credentials and corresponding services have been added: - `key-auth` - `basic-auth` - `hmac-auth` - `jwt` - `acl` ## [v0.6.2] - 2019/08/09 ### Fix - Add missing omitempty tag to ClientCertificate field ## [v0.6.1] - 2019/08/09 ### Fix - Fix a typo in Service struct definition for YAML tag ## [v0.6.0] - 2019/08/09 ### Summary - This release adds support for Kong 1.3. ### Breaking change - `Validator` Interface has been dropped and Valid() method from all entities is dropped. [#8](https://github.com/hbagdi/go-kong/pull/8) ### Added - `Headers` field has been added to Route struct. [#5](https://github.com/hbagdi/go-kong/pull/5) - `ClientCertificate` field has been added to Service struct. [#5](https://github.com/hbagdi/go-kong/pull/5) - `CACertificate` is a new core entity in Kong. A struct to represent it and a corresponding new service is added. [#5](https://github.com/hbagdi/go-kong/pull/5) - `Algorithm` field has been added to Upstream struct. [#9](https://github.com/hbagdi/go-kong/pull/9) ## [v0.5.1] - 2019/08/05 ### Fix - Add missing healthchecks.active.unhealthy.interval field to Upstream [#6](https://github.com/hbagdi/go-kong/issues/6) ## [v0.5.0] - 2019/06/07 ### Summary - This release adds support for Kong 1.2. ### Added - Added HTTPSRedirectStatusCode property to Route struct. [#3](https://github.com/hbagdi/go-kong/pull/3) ### Breaking change - `Create()` for Custom Entities now supports HTTP PUT method. If `id` is specified in the object, it will be used to PUT the entity. This was always POST previously. [#3](https://github.com/hbagdi/go-kong/pull/3) ## [v0.4.1] - 2019/04/11 ### Fix - Add `omitempty` property to Upstream fields for Kong 1.0 compatibility ## [v0.4.0] - 2019/04/06 ### Summary - This release adds support for features released in Kong 1.1. This version is compatible with Kong 1.0 and Kong 1.1. ### Breaking Change - Please note that the version naming scheme for this library has changed from `x.y.z` to `vX.Y.Z`. This is to ensure compatibility with Go modules. ### Added - `Tags` field has been added to all Kong Core entity structs. - List methods now support tag based filtering introduced in Kong 1.1. Tags can be ANDed or ORed together. `ListOpt` struct can be used to specify the tags for filtering. - `Protocols` field has been added to Plugin struct. - New fields `Type`, `HTTPSSni` and `HTTPSVerifyCertificate` have been introduced for Active HTTPS healthchecks. - `TargetService` has two new methods `MarkHealthy()` and `MarkUnhealthy()` to change the health of a target. ## [0.3.0] - 2018/12/19 ### Summary - This release adds support for Kong 1.0. It is not compatible with 0.x.y versions of Kong due to breaking Admin API changes as the deprecated API entity is dropped. - The code and API for the library is same as 0.2.0, with the exception that struct defs and services related to `API` is dropped. ### Breaking changes - `API` struct definition is no longer available. - `APIService` is no longer available. Please ensure your code doesn't rely on these before upgrading. - `Plugin` struct has dropped the `API` field. ## [0.2.0] - 2018/12/19 ### Summary - This release adds support for Kong 0.15.x. It is not compatible with any other versions of Kong due to breaking Admin API changes in Kong for Plugins, Upstreams and Targets entities. ### Breaking changes - `Target` struct now has an `Upstream` member in place of `UpstreamID`. - `Plugin` struct now has `Consumer`, `API`, `Route`, `Service` members instead of `ConsumerID`, `APIID`, `RouteID` and `ServiceID`. ### Added - `RunOn` property has been added to `Plugin`. - New properties are added to `Route` for L4 proxy support. ## [0.1.0] - 2018/12/01 ### Summary - Debut release of this library - This release comes with support for Kong 0.14.x - The library is not expected to work with previous or later releases of Kong since every release of Kong is introducing breaking changes to the Admin API. [v0.14.0]: https://github.com/Kong/go-kong/compare/v0.13.0...v0.14.0 [v0.13.0]: https://github.com/Kong/go-kong/compare/v0.12.0...v0.13.0 [v0.12.0]: https://github.com/Kong/go-kong/compare/v0.11.0...v0.12.0 [v0.11.0]: https://github.com/Kong/go-kong/compare/v0.10.0...v0.11.0 [v0.10.0]: https://github.com/Kong/go-kong/compare/v0.9.0...v0.10.0 [v0.9.0]: https://github.com/Kong/go-kong/compare/v0.8.0...v0.9.0 [v0.8.0]: https://github.com/Kong/go-kong/compare/v0.7.0...v0.8.0 [v0.7.0]: https://github.com/Kong/go-kong/compare/v0.6.2...v0.7.0 [v0.6.2]: https://github.com/Kong/go-kong/compare/v0.6.1...v0.6.2 [v0.6.1]: https://github.com/Kong/go-kong/compare/v0.6.0...v0.6.1 [v0.6.0]: https://github.com/Kong/go-kong/compare/v0.5.1...v0.6.0 [v0.5.1]: https://github.com/Kong/go-kong/compare/v0.5.0...v0.5.1 [v0.5.0]: https://github.com/Kong/go-kong/compare/v0.4.1...v0.5.0 [v0.4.1]: https://github.com/Kong/go-kong/compare/v0.4.0...v0.4.1 [v0.4.0]: https://github.com/Kong/go-kong/compare/0.3.0...v0.4.0 [0.3.0]: https://github.com/Kong/go-kong/compare/0.2.0...0.3.0 [0.2.0]: https://github.com/Kong/go-kong/compare/0.1.0...0.2.0 [0.1.0]: https://github.com/Kong/go-kong/compare/87666c7fe73477d1874d35d690301241cd23059f...0.1.0 go-kong-0.15.0/LICENSE000066400000000000000000000261651400261364200141530ustar00rootroot00000000000000 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 2018-2020 Harry Bagdi Copyright 2020-2020 Kong 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. go-kong-0.15.0/README.md000066400000000000000000000024611400261364200144160ustar00rootroot00000000000000# go-kong Go bindings for Kong's Admin API [![GoDoc](https://godoc.org/github.com/kong/go-kong?status.svg)](https://godoc.org/github.com/kong/go-kong/kong) [![Build Status](https://github.com/kong/go-kong/workflows/CI%20Test/badge.svg)](https://github.com/kong/go-kong/actions?query=branch%3Amain+event%3Apush) [![Go Report Card](https://goreportcard.com/badge/github.com/kong/go-kong)](https://goreportcard.com/report/github.com/kong/go-kong) ## Importing ```shell go get github.com/kong/go-kong/kong ``` ## Compatibility `go-kong` is compatible with Kong 1.x and 2.x. Semantic versioning is followed for versioning `go-kong`. ## Generators Some code in this repo such as `kong/zz_generated.deepcopy.go` is generated from API types (see `kong/types.go`). After making a change to an API type you can run the generators with: ```shell ./hack/update-deepcopy-gen.sh ``` Note that the files generated will be placed in `$GOPATH/src/github.com/kong/go-kong/` and if you were in another directory when you ran the script you'll need to copy generated code from there, e.g.: ```shell cp $(go env GOPATH)/src/github.com/kong/go-kong/kong/zz_generated.deepcopy.go \ $(pwd)/kong/zz_generated.deepcopy.go ``` ## License go-kong is licensed with Apache License Version 2.0. Please read the LICENSE file for more details. go-kong-0.15.0/go.mod000066400000000000000000000006301400261364200142410ustar00rootroot00000000000000module github.com/kong/go-kong go 1.12 require ( github.com/blang/semver v0.0.0-20190414102917-ba2c2ddd8906 github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-querystring v1.0.0 github.com/kr/pretty v0.1.0 // indirect github.com/pkg/errors v0.9.1 github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.4.0 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) go-kong-0.15.0/go.sum000066400000000000000000000043651400261364200142770ustar00rootroot00000000000000github.com/blang/semver v0.0.0-20190414102917-ba2c2ddd8906 h1:KGe2go3VELJLcQfKBUlviUzERqg79dO6VYzCvQxF01w= github.com/blang/semver v0.0.0-20190414102917-ba2c2ddd8906/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= go-kong-0.15.0/hack/000077500000000000000000000000001400261364200140425ustar00rootroot00000000000000go-kong-0.15.0/hack/header-template.go.tmpl000066400000000000000000000010631400261364200204050ustar00rootroot00000000000000/* Copyright 2018-2020 Harry Bagdi 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. */ go-kong-0.15.0/hack/update-deepcopy-gen.sh000077500000000000000000000006061400261364200202420ustar00rootroot00000000000000#!/bin/bash -e VERSION="kubernetes-1.18.2" if [[ ! -d /tmp/code-generator ]]; then git clone https://github.com/kubernetes/code-generator.git /tmp/code-generator pushd /tmp/code-generator git checkout $VERSION popd fi /tmp/code-generator/generate-groups.sh \ deepcopy \ github.com/kong/go-kong/kong \ github.com/kong \ go-kong:kong \ --go-header-file hack/header-template.go.tmpl go-kong-0.15.0/hack/verify-deepcopy-gen.sh000077500000000000000000000002341400261364200202610ustar00rootroot00000000000000#!/bin/bash -e FILE_NAME="zz_generated.deepcopy.go" cp kong/${FILE_NAME} /tmp ./hack/update-deepcopy-gen.sh diff -nr /tmp/${FILE_NAME} kong/${FILE_NAME} go-kong-0.15.0/kong/000077500000000000000000000000001400261364200140725ustar00rootroot00000000000000go-kong-0.15.0/kong/acl_service.go000066400000000000000000000070751400261364200167110ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // ACLService handles consumer ACL groups in Kong. type ACLService service // Create adds a consumer to an ACL group in Kong // If an ID is specified, it will be used to // create the group association in Kong, otherwise an ID // is auto-generated. func (s *ACLService) Create(ctx context.Context, consumerUsernameOrID *string, aclGroup *ACLGroup) (*ACLGroup, error) { cred, err := s.client.credentials.Create(ctx, "acl", consumerUsernameOrID, aclGroup) if err != nil { return nil, err } var createdACLGroup ACLGroup err = json.Unmarshal(cred, &createdACLGroup) if err != nil { return nil, err } return &createdACLGroup, nil } // Get fetches an ACL group for a consumer in Kong. func (s *ACLService) Get(ctx context.Context, consumerUsernameOrID, groupOrID *string) (*ACLGroup, error) { cred, err := s.client.credentials.Get(ctx, "acl", consumerUsernameOrID, groupOrID) if err != nil { return nil, err } var aclGroup ACLGroup err = json.Unmarshal(cred, &aclGroup) if err != nil { return nil, err } return &aclGroup, nil } // Update updates an ACL group for a consumer in Kong func (s *ACLService) Update(ctx context.Context, consumerUsernameOrID *string, aclGroup *ACLGroup) (*ACLGroup, error) { cred, err := s.client.credentials.Update(ctx, "acl", consumerUsernameOrID, aclGroup) if err != nil { return nil, err } var updatedACLGroup ACLGroup err = json.Unmarshal(cred, &updatedACLGroup) if err != nil { return nil, err } return &updatedACLGroup, nil } // Delete deletes an ACL group association for a consumer in Kong func (s *ACLService) Delete(ctx context.Context, consumerUsernameOrID, groupOrID *string) error { return s.client.credentials.Delete(ctx, "acl", consumerUsernameOrID, groupOrID) } // List fetches a list of all ACL group and consumer associations in Kong. // opt can be used to control pagination. func (s *ACLService) List(ctx context.Context, opt *ListOpt) ([]*ACLGroup, *ListOpt, error) { data, next, err := s.client.list(ctx, "/acls", opt) if err != nil { return nil, nil, err } var aclGroups []*ACLGroup for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var aclGroup ACLGroup err = json.Unmarshal(b, &aclGroup) if err != nil { return nil, nil, err } aclGroups = append(aclGroups, &aclGroup) } return aclGroups, next, nil } // ListAll fetches all all ACL group associations in Kong. // This method can take a while if there // a lot of ACLGroup associations are present. func (s *ACLService) ListAll(ctx context.Context) ([]*ACLGroup, error) { var aclGroups, data []*ACLGroup var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } aclGroups = append(aclGroups, data...) } return aclGroups, nil } // ListForConsumer fetches a list of ACL groups // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *ACLService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*ACLGroup, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/acls", opt) if err != nil { return nil, nil, err } var aclGroups []*ACLGroup for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var aclGroup ACLGroup err = json.Unmarshal(b, &aclGroup) if err != nil { return nil, nil, err } aclGroups = append(aclGroups, &aclGroup) } return aclGroups, next, nil } go-kong-0.15.0/kong/acl_service_test.go000066400000000000000000000147541400261364200177520ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestACLGroupCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) acl, err := client.ACLs.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(acl) acl = &ACLGroup{} acl, err = client.ACLs.Create(defaultCtx, String(""), acl) assert.NotNil(err) assert.Nil(acl) acl, err = client.ACLs.Create(defaultCtx, String("does-not-exist"), acl) assert.NotNil(err) assert.Nil(acl) // consumer for the ACL group consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) acl = &ACLGroup{ Group: String("my-group"), } createdACL, err := client.ACLs.Create(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(createdACL) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestACLGroupCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() acl := &ACLGroup{ ID: String(uuid), Group: String("my-group"), } // consumer for the ACLGroup consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdACL, err := client.ACLs.Create(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(createdACL) assert.Equal(uuid, *createdACL.ID) assert.Equal("my-group", *createdACL.Group) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestACLGroupGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() acl := &ACLGroup{ ID: String(uuid), Group: String("my-group"), } // consumer for the ACLGroup consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdACL, err := client.ACLs.Create(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(createdACL) aclGroup, err := client.ACLs.Get(defaultCtx, consumer.ID, acl.ID) assert.Nil(err) assert.Equal("my-group", *aclGroup.Group) aclGroup, err = client.ACLs.Get(defaultCtx, consumer.ID, acl.Group) assert.Nil(err) assert.Equal("my-group", *aclGroup.Group) aclGroup, err = client.ACLs.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(aclGroup) assert.NotNil(err) aclGroup, err = client.ACLs.Get(defaultCtx, consumer.ID, String("")) assert.Nil(aclGroup) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestACLGroupUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() acl := &ACLGroup{ ID: String(uuid), Group: String("my-group"), } // consumer for the ACLGroup consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdACL, err := client.ACLs.Create(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(createdACL) aclGroup, err := client.ACLs.Get(defaultCtx, consumer.ID, acl.ID) assert.Nil(err) assert.Equal("my-group", *aclGroup.Group) acl.Group = String("my-new-group") updatedACLGroup, err := client.ACLs.Update(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(updatedACLGroup) assert.Equal("my-new-group", *updatedACLGroup.Group) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestACLGroupDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() acl := &ACLGroup{ ID: String(uuid), Group: String("my-group"), } // consumer for the ACLGroup consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdACL, err := client.ACLs.Create(defaultCtx, consumer.ID, acl) assert.Nil(err) assert.NotNil(createdACL) err = client.ACLs.Delete(defaultCtx, consumer.ID, acl.Group) assert.Nil(err) aclGroup, err := client.ACLs.Get(defaultCtx, consumer.ID, acl.ID) assert.NotNil(err) assert.Nil(aclGroup) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestACLGroupListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the ACLGroup consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures aclGroups := []*ACLGroup{ { Group: String("acl11"), Consumer: consumer1, }, { Group: String("acl12"), Consumer: consumer1, }, { Group: String("acl21"), Consumer: consumer2, }, { Group: String("acl22"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(aclGroups); i++ { acl, err := client.ACLs.Create(defaultCtx, aclGroups[i].Consumer.ID, aclGroups[i]) assert.Nil(err) assert.NotNil(acl) aclGroups[i] = acl } aclGroupsFromKong, next, err := client.ACLs.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(aclGroupsFromKong) assert.Equal(4, len(aclGroupsFromKong)) // first page page1, next, err := client.ACLs.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.ACLs.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) aclGroupsForConsumer, next, err := client.ACLs.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(aclGroupsForConsumer) assert.Equal(2, len(aclGroupsForConsumer)) aclGroups, err = client.ACLs.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(aclGroups) assert.Equal(4, len(aclGroups)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/admin_service.go000066400000000000000000000171641400261364200172420ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" "strings" ) // AdminService handles Admins in Kong. type AdminService service // Invite creates an Admin in Kong. func (s *AdminService) Invite(ctx context.Context, admin *Admin) (*Admin, error) { if admin == nil { return nil, errors.New("cannot create a nil admin") } endpoint := "/admins" method := "POST" req, err := s.client.NewRequest(method, endpoint, nil, admin) if err != nil { return nil, err } var createdAdmin struct { Admin Admin `json:"admin,omitempty" yaml:"admin,omitempty"` } _, err = s.client.Do(ctx, req, &createdAdmin) if err != nil { return nil, err } return &createdAdmin.Admin, nil } // Create aliases the Invite function as it performs // essentially the same operation. func (s *AdminService) Create(ctx context.Context, admin *Admin) (*Admin, error) { return s.Invite(ctx, admin) } // Get fetches a Admin in Kong. func (s *AdminService) Get(ctx context.Context, nameOrID *string) (*Admin, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/admins/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Admin Admin _, err = s.client.Do(ctx, req, &Admin) if err != nil { return nil, err } return &Admin, nil } // GenerateRegisterURL fetches an Admin in Kong // and returns a unique registration URL for the Admin func (s *AdminService) GenerateRegisterURL(ctx context.Context, nameOrID *string) (*Admin, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/admins/%v?generate_register_url=true", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Admin Admin _, err = s.client.Do(ctx, req, &Admin) if err != nil { return nil, err } return &Admin, nil } // Update updates an Admin in Kong. func (s *AdminService) Update(ctx context.Context, admin *Admin) (*Admin, error) { if admin == nil { return nil, errors.New("cannot update a nil Admin") } if isEmptyString(admin.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/admins/%v", *admin.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, admin) if err != nil { return nil, err } var updatedAdmin Admin _, err = s.client.Do(ctx, req, &updatedAdmin) if err != nil { return nil, err } return &updatedAdmin, nil } // Delete deletes an Admin in Kong func (s *AdminService) Delete(ctx context.Context, AdminOrID *string) error { if isEmptyString(AdminOrID) { return errors.New("AdminOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/admins/%v", *AdminOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of all Admins in Kong. func (s *AdminService) List(ctx context.Context, opt *ListOpt) ([]*Admin, *ListOpt, error) { data, next, err := s.client.list(ctx, "/admins/", opt) if err != nil { return nil, nil, err } var admins []*Admin for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var admin Admin err = json.Unmarshal(b, &admin) if err != nil { return nil, nil, err } admins = append(admins, &admin) } return admins, next, nil } // RegisterCredentials registers credentials for existing Kong Admins func (s *AdminService) RegisterCredentials(ctx context.Context, admin *Admin) error { if admin == nil { return errors.New("cannot register credentials for a nil Admin") } if isEmptyString(admin.Username) { return errors.New("Username cannot be nil for a registration operation") } if isEmptyString(admin.Email) { return errors.New("Email cannot be nil for a registration operation") } if isEmptyString(admin.Password) { return errors.New("Password cannot be nil for a registration operation") } req, err := s.client.NewRequest("POST", "/admins/register", nil, admin) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) if err != nil { return err } return nil } // ListWorkspaces lists the workspaces associated with an admin func (s *AdminService) ListWorkspaces(ctx context.Context, emailOrID *string) ([]*Workspace, error) { endpoint := fmt.Sprintf("/admins/%v/workspaces", *emailOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var workspaces []*Workspace _, err = s.client.Do(ctx, req, &workspaces) if err != nil { return nil, fmt.Errorf("error updating admin workspaces: %v", err) } return workspaces, nil } // ListRoles returns a slice of Kong RBAC roles associated with an Admin. func (s *AdminService) ListRoles(ctx context.Context, emailOrID *string, opt *ListOpt) ([]*RBACRole, error) { endpoint := fmt.Sprintf("/admins/%v/roles", *emailOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var listRoles struct { Roles []*RBACRole `json:"roles,omitempty" yaml:"roles,omitempty"` } _, err = s.client.Do(ctx, req, &listRoles) if err != nil { return nil, fmt.Errorf("error listing admin roles: %v", err) } return listRoles.Roles, nil } // UpdateRoles creates or updates roles associated with an Admin func (s *AdminService) UpdateRoles(ctx context.Context, emailOrID *string, roles []*RBACRole) ([]*RBACRole, error) { var updateRoles struct { NameOrID *string `json:"name_or_id,omitempty" yaml:"name_or_id,omitempty"` Roles *string `json:"roles,omitempty" yaml:"roles,omitempty"` } // Flatten roles var r []string for _, role := range roles { r = append(r, *role.Name) } updateRoles.NameOrID = emailOrID updateRoles.Roles = String(strings.Join(r, ",")) endpoint := fmt.Sprintf("/admins/%v/roles", *emailOrID) req, err := s.client.NewRequest("POST", endpoint, nil, updateRoles) if err != nil { return nil, err } var listRoles struct { Roles []*RBACRole `json:"roles,omitempty" yaml:"roles,omitempty"` } _, err = s.client.Do(ctx, req, &listRoles) if err != nil { return nil, fmt.Errorf("error updating admin roles: %v", err) } return listRoles.Roles, nil } // DeleteRoles deletes roles associated with an Admin func (s *AdminService) DeleteRoles(ctx context.Context, emailOrID *string, roles []*RBACRole) error { var updateRoles struct { NameOrID *string `json:"name_or_id,omitempty" yaml:"name_or_id,omitempty"` Roles *string `json:"roles,omitempty" yaml:"roles,omitempty"` } // Flatten roles var r []string for _, role := range roles { r = append(r, *role.Name) } updateRoles.NameOrID = emailOrID updateRoles.Roles = String(strings.Join(r, ",")) endpoint := fmt.Sprintf("/admins/%v/roles", *emailOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, updateRoles) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) if err != nil { return fmt.Errorf("error deleting admin roles: %v", err) } return nil } // GetConsumer fetches the Consumer that gets generated for an Admin when // the Admin is created. func (s *AdminService) GetConsumer(ctx context.Context, emailOrID *string) (*Consumer, error) { if isEmptyString(emailOrID) { return nil, errors.New("emailOrID cannot be nil for GetConsumer operation") } endpoint := fmt.Sprintf("/admins/%v/consumer", *emailOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var consumer Consumer _, err = s.client.Do(ctx, req, &consumer) if err != nil { return nil, err } return &consumer, nil } go-kong-0.15.0/kong/admin_service_test.go000066400000000000000000000105371400261364200202760ustar00rootroot00000000000000// +build enterprise package kong import ( "path" "testing" "github.com/stretchr/testify/assert" ) func TestAdminService(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", false) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) admin := &Admin{ Email: String("admin@test.com"), Username: String("newAdmin"), CustomID: String("admin123"), RBACTokenEnabled: Bool(true), } createdAdmin, err := client.Admins.Create(defaultCtx, admin) assert.Nil(err) assert.NotNil(createdAdmin) admin, err = client.Admins.Get(defaultCtx, createdAdmin.ID) assert.Nil(err) assert.NotNil(admin) admin.CustomID = String("admin321") admin, err = client.Admins.Update(defaultCtx, admin) assert.Nil(err) assert.NotNil(admin) assert.Equal("admin321", *admin.CustomID) err = client.Admins.Delete(defaultCtx, createdAdmin.ID) assert.Nil(err) } func TestAdminServiceWorkspace(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", false) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspace := Workspace{ Name: String("test-workspace"), } createdWorkspace, err := client.Workspaces.Create(defaultCtx, &workspace) assert.Nil(err) assert.NotNil(createdWorkspace) workspaceClient, err := NewTestClient(String(path.Join(defaultBaseURL, *createdWorkspace.Name)), nil) assert.Nil(err) assert.NotNil(workspaceClient) admin := &Admin{ Email: String("admin@test.com"), Username: String("newAdmin"), CustomID: String("admin123"), RBACTokenEnabled: Bool(true), } createdAdmin, err := client.Admins.Create(defaultCtx, admin) assert.Nil(err) assert.NotNil(createdAdmin) admin, err = client.Admins.Get(defaultCtx, createdAdmin.ID) assert.Nil(err) assert.NotNil(admin) admin.CustomID = String("admin321") admin, err = client.Admins.Update(defaultCtx, admin) assert.Nil(err) assert.NotNil(admin) assert.Equal("admin321", *admin.CustomID) err = client.Admins.Delete(defaultCtx, createdAdmin.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.Name) assert.Nil(err) } func TestAdminServiceList(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) runWhenEnterprise(T, ">=0.33.0", false) assert.Nil(err) assert.NotNil(client) admin1 := &Admin{ Email: String("admin1@test.com"), Username: String("newAdmin1"), CustomID: String("admin1"), RBACTokenEnabled: Bool(true), } admin2 := &Admin{ Email: String("admin2@test.com"), Username: String("newAdmin2"), CustomID: String("admin2"), RBACTokenEnabled: Bool(true), } createdAdmin1, err := client.Admins.Create(defaultCtx, admin1) assert.Nil(err) assert.NotNil(createdAdmin1) createdAdmin2, err := client.Admins.Create(defaultCtx, admin2) assert.Nil(err) assert.NotNil(createdAdmin2) admins, _, err := client.Admins.List(defaultCtx, nil) assert.Nil(err) assert.NotNil(admins) // Check if RBAC is enabled res, err := client.Root(defaultCtx) assert.Nil(err) rbac := res["configuration"].(map[string]interface{})["rbac"].(string) expectedAdmins := 3 if rbac == "off" { expectedAdmins = 2 } assert.Equal(expectedAdmins, len(admins)) err = client.Admins.Delete(defaultCtx, createdAdmin1.ID) assert.Nil(err) err = client.Admins.Delete(defaultCtx, createdAdmin2.ID) assert.Nil(err) } // XXX: // This test requires RBAC to be enabled. func TestAdminServiceRegisterCredentials(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) admin := &Admin{ Email: String("admin1@test.com"), Username: String("newAdmin1"), CustomID: String("admin1"), RBACTokenEnabled: Bool(true), } admin, err = client.Admins.Invite(defaultCtx, admin) assert.Nil(err) assert.NotNil(admin) // Generate a new registration URL for the Admin admin, err = client.Admins.GenerateRegisterURL(defaultCtx, admin.ID) assert.Nil(err) assert.NotNil(admin) admin.Password = String("bar") err = client.Admins.RegisterCredentials(defaultCtx, admin) assert.Nil(err) admin, err = client.Admins.Get(defaultCtx, admin.ID) assert.Nil(err) assert.NotNil(admin) err = client.Admins.Delete(defaultCtx, admin.ID) assert.Nil(err) } go-kong-0.15.0/kong/basic_auth_service.go000066400000000000000000000072571400261364200202560ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // BasicAuthService handles basic-auth credentials in Kong. type BasicAuthService service // Create creates a basic-auth credential in Kong // If an ID is specified, it will be used to // create a basic-auth in Kong, otherwise an ID // is auto-generated. func (s *BasicAuthService) Create(ctx context.Context, consumerUsernameOrID *string, basicAuth *BasicAuth) (*BasicAuth, error) { cred, err := s.client.credentials.Create(ctx, "basic-auth", consumerUsernameOrID, basicAuth) if err != nil { return nil, err } var createdBasicAuth BasicAuth err = json.Unmarshal(cred, &createdBasicAuth) if err != nil { return nil, err } return &createdBasicAuth, nil } // Get fetches a basic-auth credential from Kong. func (s *BasicAuthService) Get(ctx context.Context, consumerUsernameOrID, usernameOrID *string) (*BasicAuth, error) { cred, err := s.client.credentials.Get(ctx, "basic-auth", consumerUsernameOrID, usernameOrID) if err != nil { return nil, err } var basicAuth BasicAuth err = json.Unmarshal(cred, &basicAuth) if err != nil { return nil, err } return &basicAuth, nil } // Update updates a basic-auth credential in Kong func (s *BasicAuthService) Update(ctx context.Context, consumerUsernameOrID *string, basicAuth *BasicAuth) (*BasicAuth, error) { cred, err := s.client.credentials.Update(ctx, "basic-auth", consumerUsernameOrID, basicAuth) if err != nil { return nil, err } var updatedBasicAuth BasicAuth err = json.Unmarshal(cred, &updatedBasicAuth) if err != nil { return nil, err } return &updatedBasicAuth, nil } // Delete deletes a basic-auth credential in Kong func (s *BasicAuthService) Delete(ctx context.Context, consumerUsernameOrID, usernameOrID *string) error { return s.client.credentials.Delete(ctx, "basic-auth", consumerUsernameOrID, usernameOrID) } // List fetches a list of basic-auth credentials in Kong. // opt can be used to control pagination. func (s *BasicAuthService) List(ctx context.Context, opt *ListOpt) ([]*BasicAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/basic-auths", opt) if err != nil { return nil, nil, err } var basicAuths []*BasicAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var basicAuth BasicAuth err = json.Unmarshal(b, &basicAuth) if err != nil { return nil, nil, err } basicAuths = append(basicAuths, &basicAuth) } return basicAuths, next, nil } // ListAll fetches all basic-auth credentials in Kong. // This method can take a while if there // a lot of basic-auth credentials present. func (s *BasicAuthService) ListAll(ctx context.Context) ([]*BasicAuth, error) { var basicAuths, data []*BasicAuth var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } basicAuths = append(basicAuths, data...) } return basicAuths, nil } // ListForConsumer fetches a list of basic-auth credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *BasicAuthService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*BasicAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/basic-auth", opt) if err != nil { return nil, nil, err } var basicAuths []*BasicAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var basicAuth BasicAuth err = json.Unmarshal(b, &basicAuth) if err != nil { return nil, nil, err } basicAuths = append(basicAuths, &basicAuth) } return basicAuths, next, nil } go-kong-0.15.0/kong/basic_auth_service_test.go000066400000000000000000000200131400261364200212760ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestBasicAuthCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) basicAuth, err := client.BasicAuths.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(basicAuth) basicAuth = &BasicAuth{} basicAuth, err = client.BasicAuths.Create(defaultCtx, String(""), basicAuth) assert.NotNil(err) assert.Nil(basicAuth) basicAuth, err = client.BasicAuths.Create(defaultCtx, String("does-not-exist"), basicAuth) assert.NotNil(err) assert.Nil(basicAuth) // consumer for the basic-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) // no username is specified basicAuth = &BasicAuth{} basicAuth, err = client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.NotNil(err) assert.Nil(basicAuth) basicAuth = &BasicAuth{ Username: String("foo"), Password: String("bar"), } basicAuth, err = client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(basicAuth) assert.NotEmpty(*basicAuth.Password) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestBasicAuthCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() basicAuth := &BasicAuth{ ID: String(uuid), Username: String("my-username"), Password: String("my-password"), } // consumer for the basic-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdBasicAuth, err := client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(createdBasicAuth) assert.Equal(uuid, *createdBasicAuth.ID) assert.Equal("my-username", *createdBasicAuth.Username) // password is hashed assert.NotEqual("my-password", *createdBasicAuth.Password) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestBasicAuthGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() basicAuth := &BasicAuth{ ID: String(uuid), Username: String("my-username"), Password: String("my-password"), } // consumer for the basic-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdBasicAuth, err := client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(createdBasicAuth) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, basicAuth.ID) assert.Nil(err) assert.Equal("my-username", *basicAuth.Username) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, basicAuth.Username) assert.Nil(err) assert.Equal("my-username", *basicAuth.Username) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(basicAuth) assert.NotNil(err) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, String("")) assert.Nil(basicAuth) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestBasicAuthUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() basicAuth := &BasicAuth{ ID: String(uuid), Username: String("my-username"), Password: String("my-password"), } // consumer for the basic-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdBasicAuth, err := client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(createdBasicAuth) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, basicAuth.ID) assert.Nil(err) assert.Equal("my-username", *basicAuth.Username) basicAuth.Username = String("my-new-username") basicAuth.Password = String("my-new-password") updatedBasicAuth, err := client.BasicAuths.Update(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(updatedBasicAuth) assert.NotEqual("my-new-password", *updatedBasicAuth.Password) assert.Equal("my-new-username", *updatedBasicAuth.Username) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestBasicAuthDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() basicAuth := &BasicAuth{ ID: String(uuid), Username: String("my-username"), Password: String("my-password"), } // consumer for the basic-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdBasicAuth, err := client.BasicAuths.Create(defaultCtx, consumer.ID, basicAuth) assert.Nil(err) assert.NotNil(createdBasicAuth) err = client.BasicAuths.Delete(defaultCtx, consumer.ID, basicAuth.Username) assert.Nil(err) basicAuth, err = client.BasicAuths.Get(defaultCtx, consumer.ID, basicAuth.Username) assert.NotNil(err) assert.Nil(basicAuth) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestBasicAuthListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the basic-auth: consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures basicAuths := []*BasicAuth{ { Username: String("username11"), Password: String("password11"), Consumer: consumer1, }, { Username: String("username12"), Password: String("password12"), Consumer: consumer1, }, { Username: String("username21"), Password: String("password21"), Consumer: consumer2, }, { Username: String("username22"), Password: String("password22"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(basicAuths); i++ { basicAuth, err := client.BasicAuths.Create(defaultCtx, basicAuths[i].Consumer.ID, basicAuths[i]) assert.Nil(err) assert.NotNil(basicAuth) basicAuths[i] = basicAuth } basicAuthsFromKong, next, err := client.BasicAuths.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(basicAuthsFromKong) assert.Equal(4, len(basicAuthsFromKong)) // first page page1, next, err := client.BasicAuths.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page // XXX: This feels like a hack. I had to change the page size here // to accommodate for the super admin created during database bootstrapping for Kong EE // this super admin does not appear to effect basic-auth entities returned by a call // to /basic-auths but does appear to effect paging behavior. next.Size = 4 page2, next, err := client.BasicAuths.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) basicAuthsForConsumer, next, err := client.BasicAuths.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(basicAuthsForConsumer) assert.Equal(2, len(basicAuthsForConsumer)) basicAuths, err = client.BasicAuths.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(basicAuths) assert.Equal(4, len(basicAuths)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/bundled_custom_entities.go000066400000000000000000000015161400261364200213370ustar00rootroot00000000000000package kong import ( "github.com/kong/go-kong/kong/custom" ) var defaultCustomEntities = []custom.EntityCRUDDefinition{ { Name: "key-auth", CRUDPath: "/consumers/${consumer_id}/key-auth", PrimaryKey: "id", }, { Name: "basic-auth", CRUDPath: "/consumers/${consumer_id}/basic-auth", PrimaryKey: "id", }, { Name: "acl", CRUDPath: "/consumers/${consumer_id}/acls", PrimaryKey: "id", }, { Name: "hmac-auth", CRUDPath: "/consumers/${consumer_id}/hmac-auth", PrimaryKey: "id", }, { Name: "jwt", CRUDPath: "/consumers/${consumer_id}/jwt", PrimaryKey: "id", }, { Name: "oauth2", CRUDPath: "/consumers/${consumer_id}/oauth2", PrimaryKey: "id", }, { Name: "mtls-auth", CRUDPath: "/consumers/${consumer_id}/mtls-auth", PrimaryKey: "id", }, } go-kong-0.15.0/kong/ca_certificate.go000066400000000000000000000006171400261364200173520ustar00rootroot00000000000000package kong // CACertificate represents a CACertificate in Kong. // +k8s:deepcopy-gen=true type CACertificate struct { ID *string `json:"id,omitempty" yaml:"id,omitempty"` Cert *string `json:"cert,omitempty" yaml:"cert,omitempty"` CreatedAt *int64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } go-kong-0.15.0/kong/ca_certificate_service.go000066400000000000000000000067001400261364200210710ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // CACertificateService handles Certificates in Kong. type CACertificateService service // Create creates a CACertificate in Kong. // If an ID is specified, it will be used to // create a certificate in Kong, otherwise an ID // is auto-generated. func (s *CACertificateService) Create(ctx context.Context, certificate *CACertificate) (*CACertificate, error) { queryPath := "/ca_certificates" method := "POST" if certificate.ID != nil { queryPath = queryPath + "/" + *certificate.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, certificate) if err != nil { return nil, err } var createdCACertificate CACertificate _, err = s.client.Do(ctx, req, &createdCACertificate) if err != nil { return nil, err } return &createdCACertificate, nil } // Get fetches a CACertificate in Kong. func (s *CACertificateService) Get(ctx context.Context, ID *string) (*CACertificate, error) { if isEmptyString(ID) { return nil, errors.New("ID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/ca_certificates/%v", *ID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var certificate CACertificate _, err = s.client.Do(ctx, req, &certificate) if err != nil { return nil, err } return &certificate, nil } // Update updates a CACertificate in Kong func (s *CACertificateService) Update(ctx context.Context, certificate *CACertificate) (*CACertificate, error) { if isEmptyString(certificate.ID) { return nil, errors.New("ID cannot be nil for Update op eration") } endpoint := fmt.Sprintf("/ca_certificates/%v", *certificate.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, certificate) if err != nil { return nil, err } var updatedAPI CACertificate _, err = s.client.Do(ctx, req, &updatedAPI) if err != nil { return nil, err } return &updatedAPI, nil } // Delete deletes a CACertificate in Kong func (s *CACertificateService) Delete(ctx context.Context, ID *string) error { if isEmptyString(ID) { return errors.New("ID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/ca_certificates/%v", *ID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of certificate in Kong. // opt can be used to control pagination. func (s *CACertificateService) List(ctx context.Context, opt *ListOpt) ([]*CACertificate, *ListOpt, error) { data, next, err := s.client.list(ctx, "/ca_certificates", opt) if err != nil { return nil, nil, err } var certificates []*CACertificate for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var certificate CACertificate err = json.Unmarshal(b, &certificate) if err != nil { return nil, nil, err } certificates = append(certificates, &certificate) } return certificates, next, nil } // ListAll fetches all Certificates in Kong. // This method can take a while if there // a lot of Certificates present. func (s *CACertificateService) ListAll(ctx context.Context) ([]*CACertificate, error) { var certificates, data []*CACertificate var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } certificates = append(certificates, data...) } return certificates, nil } go-kong-0.15.0/kong/ca_certificate_service_test.go000066400000000000000000000222401400261364200221250ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) const ( caCert1 = `-----BEGIN CERTIFICATE----- MIIEvjCCAqagAwIBAgIJALabx/Nup200MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV BAMMCFlvbG80Mi4xMCAXDTE5MDkxNTE2Mjc1M1oYDzIxMTkwODIyMTYyNzUzWjAT MREwDwYDVQQDDAhZb2xvNDIuMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBANIW67Ay0AtTeBY2mORaGet/VPL5jnBRz0zkZ4Jt7fEq3lbxYaJBnFI8wtz3 bHLtLsxkvOFujEMY7HVd+iTqbJ7hLBtK0AdgXDjf+HMmoWM7x0PkZO+3XSqyRBbI YNoEaQvYBNIXrKKJbXIU6higQaXYszeN8r3+RIbcTIlZxy28msivEGfGTrNujQFc r/eyf+TLHbRqh0yg4Dy/U/T6fqamGhFrjupRmOMugwF/BHMH2JHhBYkkzuZLgV2u 7Yh1S5FRlh11am5vWuRSbarnx72hkJ99rUb6szOWnJKKew8RSn3CyhXbS5cb0QRc ugRc33p/fMucJ4mtCJ2Om1QQe83G1iV2IBn6XJuCvYlyWH8XU0gkRxWD7ZQsl0bB 8AFTkVsdzb94OM8Y6tWI5ybS8rwl8b3r3fjyToIWrwK4WDJQuIUx4nUHObDyw+KK +MmqwpAXQWbNeuAc27FjuJm90yr/163aGuInNY5Wiz6CM8WhFNAi/nkEY2vcxKKx irSdSTkbnrmLFAYrThaq0BWTbW2mwkOatzv4R2kZzBUOiSjRLPnbyiPhI8dHLeGs wMxiTXwyPi8iQvaIGyN4DPaSEiZ1GbexyYFdP7sJJD8tG8iccbtJYquq3cDaPTf+ qv5M6R/JuMqtUDheLSpBNK+8vIe5e3MtGFyrKqFXdynJtfHVAgMBAAGjEzARMA8G A1UdEwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggIBAK0BmL5B1fPSMbFy8Hbc /ESEunt4HGaRWmZZSa/aOtTjhKyDXLLJZz3C4McugfOf9BvvmAOZU4uYjfHTnNH2 Z3neBkdTpQuJDvrBPNoCtJns01X/nuqFaTK/Tt9ZjAcVeQmp51RwhyiD7nqOJ/7E Hp2rC6gH2ABXeexws4BDoZPoJktS8fzGWdFBCHzf4mCJcb4XkI+7GTYpglR818L3 dMNJwXeuUsmxxKScBVH6rgbgcEC/6YwepLMTHB9VcH3X5VCfkDIyPYLWmvE0gKV7 6OU91E2Rs8PzbJ3EuyQpJLxFUQp8ohv5zaNBlnMb76UJOPR6hXfst5V+e7l5Dgwv Dh4CeO46exmkEsB+6R3pQR8uOFtubH2snA0S3JA1ji6baP5Y9Wh9bJ5McQUgbAPE sCRBFoDLXOj3EgzibohC5WrxN3KIMxlQnxPl3VdQvp4gF899mn0Z9V5dAsGPbxRd quE+DwfXkm0Sa6Ylwqrzu2OvSVgbMliF3UnWbNsDD5KcHGIaFxVC1qkwK4cT3pyS 58i/HAB2+P+O+MltQUDiuw0OSUFDC0IIjkDfxLVffbF+27ef9C5NG81QlwTz7TuN zeigcsBKooMJTszxCl6dtxSyWTj7hJWXhy9pXsm1C1QulG6uT4RwCa3m0QZoO7G+ 6Wu6lP/kodPuoNubstIuPdi2 -----END CERTIFICATE-----` caCert2 = `-----BEGIN CERTIFICATE----- MIIEvjCCAqagAwIBAgIJAPf5iqimiR2BMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV BAMMCFlvbG80Mi4yMCAXDTE5MDkxNTE2Mjc1OVoYDzIxMTkwODIyMTYyNzU5WjAT MREwDwYDVQQDDAhZb2xvNDIuMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBANIW67Ay0AtTeBY2mORaGet/VPL5jnBRz0zkZ4Jt7fEq3lbxYaJBnFI8wtz3 bHLtLsxkvOFujEMY7HVd+iTqbJ7hLBtK0AdgXDjf+HMmoWM7x0PkZO+3XSqyRBbI YNoEaQvYBNIXrKKJbXIU6higQaXYszeN8r3+RIbcTIlZxy28msivEGfGTrNujQFc r/eyf+TLHbRqh0yg4Dy/U/T6fqamGhFrjupRmOMugwF/BHMH2JHhBYkkzuZLgV2u 7Yh1S5FRlh11am5vWuRSbarnx72hkJ99rUb6szOWnJKKew8RSn3CyhXbS5cb0QRc ugRc33p/fMucJ4mtCJ2Om1QQe83G1iV2IBn6XJuCvYlyWH8XU0gkRxWD7ZQsl0bB 8AFTkVsdzb94OM8Y6tWI5ybS8rwl8b3r3fjyToIWrwK4WDJQuIUx4nUHObDyw+KK +MmqwpAXQWbNeuAc27FjuJm90yr/163aGuInNY5Wiz6CM8WhFNAi/nkEY2vcxKKx irSdSTkbnrmLFAYrThaq0BWTbW2mwkOatzv4R2kZzBUOiSjRLPnbyiPhI8dHLeGs wMxiTXwyPi8iQvaIGyN4DPaSEiZ1GbexyYFdP7sJJD8tG8iccbtJYquq3cDaPTf+ qv5M6R/JuMqtUDheLSpBNK+8vIe5e3MtGFyrKqFXdynJtfHVAgMBAAGjEzARMA8G A1UdEwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggIBALNx2xaS5nv1QjEqtiCO EA/ZTXbs+il6cf6ZyUwFXs7d3OKx6Kk2Nr7wGgM1M5WuTyIGKtZspz9ThzYmsuN/ UBCSKLw3X7U2fLiHJDipXboU1txasTErUTPJs/Vq4v7PWh8sMLCQH/ha4FAOXR0M Uie+VgSJNKoQSj7G1hzU/LZv0KdvJ45mQBCnBXrUrGgeEcRqubbkDKgdBh7dJQzW Xgy6rPb6H1aXbsSuRuUVv/xFHJoCdZJmqPH4JTMYRbHNS2km9nHVJzmtL6pQFe32 24wfpue9geFndOE9bDU9/cqoRYA4Pce4V5qDL0wL9W4uPmyPDkulKNQtAvZnDA9V 6ccYYthlTBr62UEnw7zZOnSm0q4fB2o82/6bdPwrT7WhbHZQWN7SeqYNWAbYZ1EE 40f5IpTwZ7E5LaG62qPhKLXame7SPAaqaQ9aCTYxaWR7XSYBsvCBRanjRq0r9Tql T1I8lwssIgbA3XubokI+IMkLDEpCQ27niWXOZL5y2M3xyutd6PPjmEEmoHMkOrZL etlxzx2CCoUDXKkYW2gZKEozwBZ+eBgUj8WB5g/8jGDAI0qzYnfAgiahjGwlEUtP hJiPG/YFADw0m5b/8OMCZ6AXNhxjdweHniDxY2HE734Nwm9mG/7UbkdvhR05tqFh G4KCViLH0cXt/TgW1sYB2o9Z -----END CERTIFICATE-----` caCert3 = `-----BEGIN CERTIFICATE----- MIIEvjCCAqagAwIBAgIJAPOV4FBF2WzgMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV BAMMCFlvbG80Mi4zMCAXDTE5MDkxNTE2MjgwNloYDzIxMTkwODIyMTYyODA2WjAT MREwDwYDVQQDDAhZb2xvNDIuMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBANIW67Ay0AtTeBY2mORaGet/VPL5jnBRz0zkZ4Jt7fEq3lbxYaJBnFI8wtz3 bHLtLsxkvOFujEMY7HVd+iTqbJ7hLBtK0AdgXDjf+HMmoWM7x0PkZO+3XSqyRBbI YNoEaQvYBNIXrKKJbXIU6higQaXYszeN8r3+RIbcTIlZxy28msivEGfGTrNujQFc r/eyf+TLHbRqh0yg4Dy/U/T6fqamGhFrjupRmOMugwF/BHMH2JHhBYkkzuZLgV2u 7Yh1S5FRlh11am5vWuRSbarnx72hkJ99rUb6szOWnJKKew8RSn3CyhXbS5cb0QRc ugRc33p/fMucJ4mtCJ2Om1QQe83G1iV2IBn6XJuCvYlyWH8XU0gkRxWD7ZQsl0bB 8AFTkVsdzb94OM8Y6tWI5ybS8rwl8b3r3fjyToIWrwK4WDJQuIUx4nUHObDyw+KK +MmqwpAXQWbNeuAc27FjuJm90yr/163aGuInNY5Wiz6CM8WhFNAi/nkEY2vcxKKx irSdSTkbnrmLFAYrThaq0BWTbW2mwkOatzv4R2kZzBUOiSjRLPnbyiPhI8dHLeGs wMxiTXwyPi8iQvaIGyN4DPaSEiZ1GbexyYFdP7sJJD8tG8iccbtJYquq3cDaPTf+ qv5M6R/JuMqtUDheLSpBNK+8vIe5e3MtGFyrKqFXdynJtfHVAgMBAAGjEzARMA8G A1UdEwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggIBAAWkIoAl1g5crjJcdQcN 9gF2+FRDdo84V+srtA5q9bvGDYXt9S8/IDSqjDKz/03nlCdye4bBLacorhhZS97O jPBdZ30kAVn478z6ZcZQeHHE93uOcO+hZWcQEoFRid8HSVAbFimhC+wW9JQv1CKz S/3i1uPXAE9V2TlWmKYbqt8jJBJ1qJV1Gt8V9AAB+L5X/I5MQoMk7rmddkUf5fEj 2Lghp4egDnHNE9jqMxx38LY+06TpoAr++ICdJ0P2n/Cmg+Z3jQZklE+8SR9C1XfK N1W9jGpDFkRgZx6udkGf6NDwyr+W3O//U+P2TLMSlPFHbpqH1jJFWVHaohE4rjPl MpG0eqM6inuliNewymQPurwxP47wBeQedDw169ehxbwqCmRvNToAfp+GTwrhoIDt YP97asx55JPxsXniM+L8mSsRvS+k11A8fdq5E3luKJ0Pyfct2AzUoy5OzcUWotv1 M5l19WkET0gOKRTzJzUpZiFQ3S6HIk//kT08VD++7UegLDOn2s0TIPLBpU6uaihm 6VSxYPyCcVX+4FeMGU5T47xnT5ClyhjSgUiY50FVuXuyA2zrsdZj4O5KDktK9hGh Vlz21lz4fvd3gtPgtVXLmaBKlGQFWNLxARBTQFxJJ7JvYu6FnhzhWt6YO49vAnUG R+pHRocvtyc8EnkuMw6+jGHr -----END CERTIFICATE-----` ) func TestCACertificatesService(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &CACertificate{ Cert: String("bar"), } createdCertificate, err := client.CACertificates.Create(defaultCtx, certificate) assert.NotNil(err) // invalid cert and key assert.Nil(createdCertificate) certificate.Cert = String(caCert1) createdCertificate, err = client.CACertificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) certificate, err = client.CACertificates.Get(defaultCtx, createdCertificate.ID) assert.Nil(err) assert.NotNil(certificate) certificate.Cert = String(caCert2) certificate, err = client.CACertificates.Update(defaultCtx, certificate) assert.Nil(err) assert.NotNil(certificate) err = client.CACertificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() certificate = &CACertificate{ Cert: String(caCert3), ID: String(id), } createdCertificate, err = client.CACertificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) assert.Equal(id, *createdCertificate.ID) err = client.CACertificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) } func TestCACertificateWithTags(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &CACertificate{ Cert: String(caCert3), Tags: StringSlice("tag1", "tag2"), } createdCertificate, err := client.CACertificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) assert.Equal(StringSlice("tag1", "tag2"), createdCertificate.Tags) err = client.CACertificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) } func TestCACertificateListEndpoint(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures certificates := []*CACertificate{ { Cert: String(caCert1), }, { Cert: String(caCert2), }, { Cert: String(caCert3), }, } // create fixturs for i := 0; i < len(certificates); i++ { certificate, err := client.CACertificates.Create(defaultCtx, certificates[i]) assert.Nil(err) assert.NotNil(certificate) certificates[i] = certificate } certificatesFromKong, next, err := client.CACertificates.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(certificatesFromKong) assert.Equal(3, len(certificatesFromKong)) // check if we see all certificates assert.True(compareCACertificates(certificates, certificatesFromKong)) // Test pagination certificatesFromKong = []*CACertificate{} // first page page1, next, err := client.CACertificates.List(defaultCtx, &ListOpt{ Size: 1, }) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) certificatesFromKong = append(certificatesFromKong, page1...) // last page next.Size = 2 page2, next, err := client.CACertificates.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) certificatesFromKong = append(certificatesFromKong, page2...) assert.True(compareCACertificates(certificates, certificatesFromKong)) certificates, err = client.CACertificates.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(certificates) assert.Equal(3, len(certificates)) for i := 0; i < len(certificates); i++ { assert.Nil(client.CACertificates.Delete(defaultCtx, certificates[i].ID)) } } func compareCACertificates(expected, actual []*CACertificate) bool { var expectedUsernames, actualUsernames []string for _, certificate := range expected { expectedUsernames = append(expectedUsernames, *certificate.Cert) } for _, certificate := range actual { actualUsernames = append(actualUsernames, *certificate.Cert) } return (compareSlices(expectedUsernames, actualUsernames)) } go-kong-0.15.0/kong/certificate_service.go000066400000000000000000000067111400261364200204300ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // CertificateService handles Certificates in Kong. type CertificateService service // Create creates a Certificate in Kong. // If an ID is specified, it will be used to // create a certificate in Kong, otherwise an ID // is auto-generated. func (s *CertificateService) Create(ctx context.Context, certificate *Certificate) (*Certificate, error) { queryPath := "/certificates" method := "POST" if certificate.ID != nil { queryPath = queryPath + "/" + *certificate.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, certificate) if err != nil { return nil, err } var createdCertificate Certificate _, err = s.client.Do(ctx, req, &createdCertificate) if err != nil { return nil, err } return &createdCertificate, nil } // Get fetches a Certificate in Kong. func (s *CertificateService) Get(ctx context.Context, usernameOrID *string) (*Certificate, error) { if isEmptyString(usernameOrID) { return nil, errors.New("usernameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/certificates/%v", *usernameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var certificate Certificate _, err = s.client.Do(ctx, req, &certificate) if err != nil { return nil, err } return &certificate, nil } // Update updates a Certificate in Kong func (s *CertificateService) Update(ctx context.Context, certificate *Certificate) (*Certificate, error) { if isEmptyString(certificate.ID) { return nil, errors.New("ID cannot be nil for Update op eration") } endpoint := fmt.Sprintf("/certificates/%v", *certificate.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, certificate) if err != nil { return nil, err } var updatedAPI Certificate _, err = s.client.Do(ctx, req, &updatedAPI) if err != nil { return nil, err } return &updatedAPI, nil } // Delete deletes a Certificate in Kong func (s *CertificateService) Delete(ctx context.Context, usernameOrID *string) error { if isEmptyString(usernameOrID) { return errors.New("usernameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/certificates/%v", *usernameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of certificate in Kong. // opt can be used to control pagination. func (s *CertificateService) List(ctx context.Context, opt *ListOpt) ([]*Certificate, *ListOpt, error) { data, next, err := s.client.list(ctx, "/certificates", opt) if err != nil { return nil, nil, err } var certificates []*Certificate for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var certificate Certificate err = json.Unmarshal(b, &certificate) if err != nil { return nil, nil, err } certificates = append(certificates, &certificate) } return certificates, next, nil } // ListAll fetches all Certificates in Kong. // This method can take a while if there // a lot of Certificates present. func (s *CertificateService) ListAll(ctx context.Context) ([]*Certificate, error) { var certificates, data []*Certificate var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } certificates = append(certificates, data...) } return certificates, nil } go-kong-0.15.0/kong/certificate_service_test.go000066400000000000000000000457351400261364200215000ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) const ( key1 = `-----BEGIN PRIVATE KEY----- MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCg21YOXJB4rjZU vl8dCpLX6oon8qYT6BnpWIfflTU295U72oQGGga3eC2m4YpAWrEEzA6bGstqcmz7 BPzF3ND5kotj5DOSmHSOZ8k+s4z+Sz6+WQWgO2esy6Kxv+KnWYvEPMgBxgg3v2Kl 9v9B9XiHua9FTZVWhY5gF0oBFBlQdhp4FOQa+6CDPQik8++8QcPnWqlD9CCvheKf Sej79ao5Hy1LuSTuHUxgsQ4zYu92S5bYaAPgn09k8axZHIIwhbi8BaDEdEgySJTv efVpuluVYAKM/bBoClRTCT6i9eqgRln85oMf/yOJ41M+ev2xbLd23SdcQ6CsoTT4 Xc7Mvi3VC/fNw/6mwmO1lFsRSBE8jUoQRzLtt0w72z7625aMOTwtnjsbtvi5rkF4 bf1YW4iqkybIrFr7544cIA4OFdbQ8eWszKVXZnrhyOfsEo4Ir1KhJV1eunk6ZG/W hY8MbmKRmjrGabJRYxBL16PEDHTzh01nXsiV5rge86PoXCuzNCTxoIkhgwq1fSeA 8M6Z75u8jxi5N4FygkkjrpsYV6TqhOo20m0BuLiH4OmcgZD4jniHgGmTJ2h1Ymyv 15PCNoPwfEUqJ/cKTfcakwz7WNkSEwTJjjd54zEkz658ggdZkaChek3/pK7itRoL Lz/rtaHlOUvAlJc4rphP5t8HNDs+/wIDAQABAoICADIoswj/bD11dZOvWVFg/rE9 fZ8/VvJWKd5NsPDTQijFw09KsGiGrRmA7BthsQ6oORLZ3qQXEt86lykfQQMh/DgW rkiT3FEWISJW0rYunwScyg/pCowQeh+z0CPFRhQRJDgpC+Uhr2ZS05wVDTuwI8mO 6UyfCLZWJzNnj7gOYGZqrY5MVWTkmgTSf2OQfW0ixMfbyXRbJ+YTxbsN/Qy0akQt qJ44OX/Wuv5bt6Xmb+1fXMZWiP7+Lm+3vJp8/UvMJvLafmtEJ08muuqCCTjS18QY kDMO2HdY4TqTY2jFbkhUJ7No3fKYSKiyrj6Jc5pj4EG8bI2kuPGbwzy/Y8EMfJW3 +ixL/f6wBWxHA2rAtjekPnNiT6dlSKYtYOnIGNTpRBmzsNLVDePTHMN1yEnETAWS LTI87sHLOdU0KwuNfZJAjrZhfMQmoWp9v87zpoKG1R/gmyH3DL3e6mTEW4OEYS+1 Jc/AS16lv1y7ILkY6UOHb602u5TgIx/759oXoTNcdy9SDYuy519lBoG/8rZGMKFW rub3kLkLXa5OooLB10KkMIOLZmrI/vSkraX9xMKuObQchlJpemAXp2bRmo5UezxH 3lm5alTcjKvVGuhwMPsHy3IRtdAcQ4Ra4Q4F4M6KyiHA+r07vQ47GlHwtFGbakYV VH/Xt2tzOMIjV2nG82fhAoIBAQDMejDoZTjmSWM5O6MBuMAPcptzcvcFIAyinlYt gNyuihmtOyANPcG/8uhYUkPQDwawtEIiMJE/6A3ytwLYfrLeYZ6R4RD+5j46k5/e fWW2+YdGMs1itfKJAAKeEGOglypY79c/ibw3rgQ9bpseMbGXpX3Wg09jJBY+aKt0 GHwlFadpRCkkyLgQet63NNnmK6E3uR+1smp0vWmFUq26rbq0PuplKPtEdEm/xPs4 sxvIIDMmFJIBDrNV3+Jpi9jAj+gi9qiqB142otQw9CZk+w63VAPBrhH6Z77WMB7z d9anfOvYn7NpQ7c3AgPDKt8Tq5XaJLcuSMyedSx94A87lEZLAoIBAQDJY2cqVwDA Coi3oBXIdovk1jVUygOP2SmvF+j2zuvLhbIInn34MJw4qMZE7EalKHE/kBV4XXEx sy2eoVtnuKDHyoUuwGVtxjs+ByxXeQifKSoI6xloai2BPV+R6EmzbdnsFzY9tiZq 5S4Q/qPTBlI2XiVH0nvVANDzREhJl+mr9wpc/VgrHAeXZHGj0rHYWJy6VUG81uQG Pv3NebR3qQNGu7y4GhubYPvkSJ+9FPmmRXWyVzj45KMByH/zZndHCGq4rb2S7j2e JlJJXA6WcuSIQVwoVd9XBzkyzJJ74pWo8OS+b7xXjOrzsIsq3SZ91gWeQXqXEgCz CN1ok1+dSomdAoIBAAZP00ipLzt0knqGy75W3J7dc8z5hISE+77dUl2vN6CvpKFD TPb7rApnziJDz9IRVKyJs+zoQOOPHzcZzR2vs4fHzaRFJUgpBUy7l9i/WC9wvms9 UDe21BjEhlAow1qGsAj0xlkwwD2bwoe+7UzeTdQXiK3hecbeq00b4AcCZnqik3td XkPDamMf19Yh7IP9XsmgjkkGi+C0pBg4eCJmEHhV5NhgjnkLeedQhky2wqnHzKxl QCiGMqT49z040uUGzCygHo65EYBwQEqOjszZLxgboM4OuIFZSHvGGn57eYXMBl+2 dkxOic5J4qHYpfAugL6uGXV1S9OsXEY6b13wcscCggEARyWP/9xGzpGqJT0wFOcU mx62LqNDyOEOoeYPjoohsYAlGnhrxm/d8QJnMVhLyPNVtv//JcvVPpqvhjg5I5aN bqf0j0S3UKXUriA4oRqIWjpfuFDeZA4Gz37QMarfxr0LXSYCKqEcR2157dUYKWg1 STHPd+U7jE/Cgf7gjudVTUR0a8+xA2HeqLR6lUbNP8JmdEnEdKNyYWaFob7aa9/Q 4X9Xt665jBYiR08E5/buD7jAUOYRoZScpfeghGvxva2SjnYK4Eq8iA+/yFz2Zl5m sGBu320e/w71PSYaphuxhcK8/S5aWo/VPYxkThtdCt2+lF9LoO1iQ93g4p4WDGqV 3QKCAQB8YCLrdv243estEO/3Lev3HQybHlNYtXzfPEAkFIQn/zdRufpXaCP3r4mW V7fFazQD57GjluOutFOHyKXF7HtRSQD/mULSOWFhnaiQlfy1Ak5wqmCmdNVdUDzP 9JtLI9fkhn5UmEfiE3N34DpXRU+wy0vnJ9oJ0DXI1zy909en1WQx+0yQSMO79w9A HTO49k9pw7NYFNOPb9ZSEbQ2XPemF2XDsqrg1uLLpE+yWouG9jzVB4gQm6o2IcKE HnTxx8vfvwHmI/3sUJsZKEY56RC2lxieYERwaHRUYkBqrnU+mYqH+5K9ic0sEb+q x0lR9WSCCs7krwrfYJM0jr7NRhGn -----END PRIVATE KEY-----` cert1 = `-----BEGIN CERTIFICATE----- MIIEpDCCAowCCQDpoxYguQp6+jANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls b2NhbGhvc3QwHhcNMTgxMjAyMjE0MTI1WhcNMTkxMjAyMjE0MTI1WjAUMRIwEAYD VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCg 21YOXJB4rjZUvl8dCpLX6oon8qYT6BnpWIfflTU295U72oQGGga3eC2m4YpAWrEE zA6bGstqcmz7BPzF3ND5kotj5DOSmHSOZ8k+s4z+Sz6+WQWgO2esy6Kxv+KnWYvE PMgBxgg3v2Kl9v9B9XiHua9FTZVWhY5gF0oBFBlQdhp4FOQa+6CDPQik8++8QcPn WqlD9CCvheKfSej79ao5Hy1LuSTuHUxgsQ4zYu92S5bYaAPgn09k8axZHIIwhbi8 BaDEdEgySJTvefVpuluVYAKM/bBoClRTCT6i9eqgRln85oMf/yOJ41M+ev2xbLd2 3SdcQ6CsoTT4Xc7Mvi3VC/fNw/6mwmO1lFsRSBE8jUoQRzLtt0w72z7625aMOTwt njsbtvi5rkF4bf1YW4iqkybIrFr7544cIA4OFdbQ8eWszKVXZnrhyOfsEo4Ir1Kh JV1eunk6ZG/WhY8MbmKRmjrGabJRYxBL16PEDHTzh01nXsiV5rge86PoXCuzNCTx oIkhgwq1fSeA8M6Z75u8jxi5N4FygkkjrpsYV6TqhOo20m0BuLiH4OmcgZD4jniH gGmTJ2h1Ymyv15PCNoPwfEUqJ/cKTfcakwz7WNkSEwTJjjd54zEkz658ggdZkaCh ek3/pK7itRoLLz/rtaHlOUvAlJc4rphP5t8HNDs+/wIDAQABMA0GCSqGSIb3DQEB CwUAA4ICAQACRx7PKUGhp0jQLquD0C79086GM4QwCFRlDkewzQiecLE+qz6qYqJK gSEdL2YHQw2wZOh0GhMMlFk06zDc34gwUdg/aK6oLYJpUZ4jwJKYWQRQY8YWU1gs Hkq3wKHrPG/YDS07aZBgKvEMHAtlTJeWFcWqKORMxaTpwgQkevUJJaL/Miashz5N NyUiILKp01kQGBO62BKKVxtxy1EYosdgr8x4TUnW0XuPjLkKuzjJt7v83Ptblu2d Vhrln5+RLGXldBOnMus8+r2gCbQb5H3fcRizNVnJTTdfq0DoyZSoZx11bKvhZMkx FiGN/CtLNNBnBJgDSoyesLDs9ZMS6njdCLegxxK5nOL67gKjlbHF+JfAbR4ojyhh xgsFNDNiVgxssvnR2MOD5rlyqn4UYGQWol90Z52CpQXO1sYRGTA7flf0nSHDaKw9 wuXog4MC3f1dIgvKZYxY0rC/2fMCoop2TK5MqBrIVFcV6IH/T9bEVlUXGk6kvQrf ZbD+Nn2FKejW43Xfl6Ftd1JGXJr6vzVYG4jEGRNSlZhxnX5gG/fIvor7NZGlWD5b OsnC3clA3dYwN/mdRAAi6yV/Cdv0ccxcKu1+Ub48zTajwnKliTP59GqjrSFtSoT5 EMP/MtSXGWJ/G5wCCKf/zrmm3J5om8RFywSFLi9ycjmtqi8I1ajJ0w== -----END CERTIFICATE-----` key2 = `-----BEGIN PRIVATE KEY----- MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC97UR6/nUVRvwW G7ggOCY5p/2FfvFNSuKYeU756rmla5kWndmNeAH4Z3bYrd5g8b1LWBbfmVCemwPe xeBzbDIXfVKRw+AxpJNXxeRs3Bq8hTXo3f53uxLsUYajbzDiLnAw/nS3v2Qeuy13 Sf/V+LmAwJV4PPirQ1ITgnVth/w2oKALBVFwt5t3QyTjiHa8EmxRiBArfuOGPjtW ARbXLQ3IXkyLNMpVuktlwgMqPUbLPdBNkKeTXw5shnA6vAOLeyRCmdXsH4LDMOGx 4HTh6NKtnzG2r7q2bnVChjb2onh+YWeNG7c/oQDlfOIcmcdc0QFn2xui1dbmKUuO LTxBahhcQhwk2TqxO4ZssnbAgvVwejYWewll9rvumd6wYhpmkjsjvrR6KNAvEgzB UxOvDAbEepviY2FGgKgMBA7AE6Us92Z9Ie7u0T7wnbhUu+/Ngfr3mGjdFIYQ5dv6 WpClVFsyw5Ynumr3FoBCiuxol//J8zjLcFowDT59ec3DlWdXsSiTALuuN83DL1LC ZmJ3axmtjxAX/FP3LYOvpHuaBF8FF3m+IIuuMci9JMA/kXV3tfEsF0/mzZ9o6TW/ ze7KpFtnuuOwxLf3DQK9N3BgIIy9RQ73lZg4yfYtU4knec0MVAhEHYE9pmPQBb8X 2/YKegDqNxndVTtl2NFSdyhIajulvwIDAQABAoICAC4TUIiyEH9v8BoA8YNHe+aC 3Zs0N5/zqdMposI4cn8yAjqdYrjSQ1Aa8ZcRXyCPpMeRgEMQc6F2o9K4mIIH3oMa URyxs0L31RL3HDpYj1fqzTBIIsKzLJ0ODia6A9brQyZvpKsrEEPwTtBgsGMdawtU LS61Q/Jwa4n2HTzMP6CVCR6DVMWOlXWyYVGduohXw9Vnt9yFdPcNQ+HSc9MRyAUy 80jWLrvrbP0ruw7VPMZzoYQfsreq2Nn1J2boU8fTwPEzVtVos5Vc13QKqvBfRjT+ qNXT/eziESppWw4sTiUCxldSQPt7uLbzu/sKR3Y58iha3HJ9hBvkKsM8MCECdxQH dNwnp7TkwgjutuylFzvtJ0Gihhzjor7WZSYH+mwyfpYt29BacwxOEjY7xWz/MKvp m718UV4C9KkMPprRpXiqtmERILnJHJJnyNotGDASbKPtp8UBjo1zSrQIqXgwscJX FSzM7MgCmHIWBHFOFzV/G8cVSpUGHy21ST2b/aQQ5FKsoxc507iFyCFVPfG2WpWa HMXo+zjOhPpn0kiLdj6ideJCpHEPm/nr2fa3T7q1VcpShykHtkYZV5AKBcwTA+OO cfEggnrkRZdu95bGDrkkPqDdkRPoBMaBAYzIX24EnC6ugxPDLK4aL5WnSj+Gi2wY aoqAvQPcMWDThxcpxeHBAoIBAQDrExB0vp7fqkPCsQEeWE7CZ+FqmpvSW0ATiCLI t3/5n9SemrndR8eCWC66r5svX4gZth9lQVEg1GoVARY919J6EXsJbMdp9keIVKI4 Wudr9ilW1fLphRe0qQJzxHPwUJSX8P4nQ5z3+LCkEV+RgNmW4mu6w3Bm9ezxg9eA ga/V4Tg/f0qJL/1/rVzbA7gP70oJOFsfINHtK4MBSu/lko41DsK9WZAxSwAUNvMn qharq8OfjgzNi1IsD/DZKooh3oDo7kj6/U5/5J4Ba1dHzEO1Bls8Iu1cHO+bhNij pXQlAmYHSGzz9RRSay68heemw9c29FtNukZ3Jk0Y3d8xj8VhAoIBAQDO1V4QueSn ps3WaifcN/889o+4UANCOEqMIom3dPbHlCIMuv1VBr3x2kccbgxZQMupmh1aqdDB BX/Q4m3y+UHynZ0x1vJRp1BPOO6XDwsLp2kVs6eheH7rOAj+4KkWdu7bvZMJ+Xah EwgINa6rpGHCatohBj9XH+DjYGbaWPVo2qzn8rHCoanGHQvN0S6+Erx1Aq4zDTal MUYlS97TOJG7CoFkmfYiKLq7jb/fqtp6SD9a7XIhc8ivLUofzxY61hA2S8gRjH0Q kE2r3gIjU5/ikwjnUIboMamzL3rX9GKMaMJVHmuTG5RyZRf7CKdccQYfMkMAw/uq K37jkLc8bB8fAoIBAFg5K2/lKpMev5eN/rF4yvZDLmJn7BsijAXIjeVumOUCizWL ND5L9iCBH+iIh2FcJSQhKd9CiEQd9EI1yjcjjKarcNW0sZKfD3Gm8crcswXduN4S JbxmauMumvD/xdNnKp1roLbztTGLcB/jNU7SYNcz2uKY/tJlcauio3pjMa6/e/C4 wSyDikwksDiySJ4SXGLhd7FTC/ZK4jvV9/rc6eoXxBZ0Sp11XG45wUAdoayEJkL3 eO6bXxeSU/3s7TKQ4yiIZXNtJczx7Cr0MimMC80guZT0NsjfQz3GudeQ/On24HvT PrDARgQ4na27Q5le3qKNSsb9Jf0Jrt2qR12+a4ECggEBAKIemjmQC8rhMwwybwXt GnIFbQdyJ+u6xavr0nhrBJfQ45OI6dLAkxfEGOMO2z0GTdylgQa0fn0dO19WbAn8 GBX8Nt9+9LbN52QBYvoif2zmDrdE90rYcNscM+jb3Y1PMdApWtyBnduJWE1fDodZ NIs4R7uE8xbuVM7EnDnfapSCeu7fyzeckb9IuxzbLsErXG526GX5oHCBG9NWEdUL zSaHiH57M3L468zgwZmmiNM6V/aEkWXpJE8yt5wRLQJ3EYQNiEdBEDJweYESZiic foEQ8PSmqOfNLY/W0nn9A1W9Mz2Wt4k6H/Q+izpoQQ5zRPIk6mHqPBPZPf9PSmDg +s8CggEBALWHq/myEl2Mqv+caaWpdrR8N34CWAl+rkDEqg45LqcoszCWcF7FQZ3B JKiAVOxiOuE4u1UDR/iBXAPysx4L5HxL1sEPHkaoXOz14FDxZ3g9Lk1X89TQhBel R8L8nkoEET/Jzxqoq40sFdPzBI+unULqp8nz4IDM5stDz3NuLoF6M86b9kLUOBsN F1fCPuxuDd2Dkadp5+EXEtP9hhI9bYMWG+76Hqwq9dtnIWJ6yAyAmrbDyVgV3wIa qtIUUf22cNCK7BG3UWpTxhI0VGX59j4CSHPWFMTAOzlASoyksbeWt3SQyE+yibtr N3a/2nCyY29O/S8NtCgE9AI7j+wElcI= -----END PRIVATE KEY-----` cert2 = `-----BEGIN CERTIFICATE----- MIIEpDCCAowCCQD/wY+0qczvfjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls b2NhbGhvc3QwHhcNMTgxMjAyMjE0OTI1WhcNMTkxMjAyMjE0OTI1WjAUMRIwEAYD VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9 7UR6/nUVRvwWG7ggOCY5p/2FfvFNSuKYeU756rmla5kWndmNeAH4Z3bYrd5g8b1L WBbfmVCemwPexeBzbDIXfVKRw+AxpJNXxeRs3Bq8hTXo3f53uxLsUYajbzDiLnAw /nS3v2Qeuy13Sf/V+LmAwJV4PPirQ1ITgnVth/w2oKALBVFwt5t3QyTjiHa8EmxR iBArfuOGPjtWARbXLQ3IXkyLNMpVuktlwgMqPUbLPdBNkKeTXw5shnA6vAOLeyRC mdXsH4LDMOGx4HTh6NKtnzG2r7q2bnVChjb2onh+YWeNG7c/oQDlfOIcmcdc0QFn 2xui1dbmKUuOLTxBahhcQhwk2TqxO4ZssnbAgvVwejYWewll9rvumd6wYhpmkjsj vrR6KNAvEgzBUxOvDAbEepviY2FGgKgMBA7AE6Us92Z9Ie7u0T7wnbhUu+/Ngfr3 mGjdFIYQ5dv6WpClVFsyw5Ynumr3FoBCiuxol//J8zjLcFowDT59ec3DlWdXsSiT ALuuN83DL1LCZmJ3axmtjxAX/FP3LYOvpHuaBF8FF3m+IIuuMci9JMA/kXV3tfEs F0/mzZ9o6TW/ze7KpFtnuuOwxLf3DQK9N3BgIIy9RQ73lZg4yfYtU4knec0MVAhE HYE9pmPQBb8X2/YKegDqNxndVTtl2NFSdyhIajulvwIDAQABMA0GCSqGSIb3DQEB CwUAA4ICAQC21//GuU+cdj7+dOiPfyODoZVSaHFsTUEOX2kuQ5LnM1chI13Bmzd0 kmw+57Dc5fxzb0mo7uLeU4lXxGhvN3B/2JwVgoVQ+4qqp2w7cFsEpff8gUvTwglI tkVWMCm+0isRIdFsqsgf4lnPcvMTcymYNR2j8KFbG+vRbDGdG+VSClMxjd/qg3nU Op5OiyZlzIvoIxcSG5mySeDUimL9REqjD1WCBFgpRVrO5gDlEyDjPOAYoNulXRzR 1PRXHY/lVonO6g1aiOJBZ+BjuE8J81mvZYCOVCliVLEQoeDQ3+qQUGzFzSUQ1+i2 J09JYK3j0MNmI6Uo8x34Ufz+oS1RPRtnPBdTqSx0J6QGdkFe6D4IGwufWeHKe8o5 +OyrctPnx0cnwFC/LE6V/jzFatM6Bpvp54Rt7e3dDLtpQrZrR+4WpjYsNpYwBVWr lYtlHuS+pOQGOwQyQqh3laQ9CmacR3MMmmtouswhBd81CTh7C2BR965Khl/J/Tmc K8vpSehmQyvfmJhZgTE21q7M4gGeotd5F6CfoJzqSu2XloDRHXJ7aqUKHNAbR1c7 5+/4rz5abr4xa7usKu2hh5wy7bzYCY3tRFS2mv6Pi/qDmaMSw4JsbB8kisPiP/nL E7ieP1vQrPWs17eoyI4J84XswdAjyh5OpAX0QVbgQseXrBv8TRECgw== -----END CERTIFICATE-----` key3 = `-----BEGIN PRIVATE KEY----- MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCvUGZCdSIXNOPP MatV0aIgbcYMFEQ0b01px517jeYe0jcSQ7JzVkrbUP8TAb+u2ub85yjY1iXh2kBj eNMDpGdzG93pZARFQU5f23qpwbs8i924a/EpoDew7qdTwrRFGdOwLg4NnKh1XwPw u6K7IlCYo0vevcxbtIiQxoDDMb0Zq53Knu+LiU865FtAbOaKTy6ZREffXnhgsrlA 2i+1iZ8eKZ34wS5/ZWTDSFrW3cJb4Yd/LD+ymPr/5NkFUP4Cwxq/pRVicDL3SCVT uHgF+jRGUL5uLwJCZfEQtzN/vkbWWSpYqnc4bQBcZNMC3QT5nJ3JqoXq3/NKCe5V B00PaVy/jV4cpTSUW/JfHKQx9u8OVZMr9jhjSrXCNPn0100/1VazxLC7jY5/+y5m DyanGawl+a0bFcZg2jm1AHRCiUfhKWjx2GVosMYfimcHLJttaWEGnGxFqNzJ0FOw dJK8GKz88n7T1HIb4v3hMsvzxORkb4M39/b34E/8xswYZ0p7M7zq1iRN77BK87Yy SkC2KPbuD8KuY+ElMmUuuX2093kKcRqheoGZ01HWV1cLzlNNurnsvrPVqkFgeKd6 hg2k4UeX8F8+ay6HGgBUtwdCCD9G1gr8QA35Vvf4UWZ+8T+wnhKXhqLOLIOPyHXu 5ziZe7m+/+IaOeAMC+9KZ4mT5kaaEQIDAQABAoICAETh3CwEhe6EU3YXV/CSO5du SkB4vgu0J8CGM/RV3rMBea3td3Il16ewfWhkaYI0dEmuMbhw+9VvwZjT4mUt9Y+e xWRsbdkgPcEgJWQJwJ2bfvR1RP5L+1XDj28zs0zrRueUUOU8RlxHhu7RarEIXI58 qtTL0j2+A2KO/Ay1wE0Txx3TsN8shjrneosnvrVdQzvpPiwfnECyOGOo1tIHTsO1 KmKQ1MotdpfcGAUQgMtFI83t/uEXhpeAvVx/ZC6Fpj7iiDJzTzMl37SzaEVA98Ug +JGmWsbn8v3UXaG1i3Ow+Rh5cfpzqY6j9tzLJqdEyCJyo8eTUq4mlMRH6BlEFrJu SOmq5bVYWjQeYqUe2eb7wSKOw+IDmTdn4dkTa9zzoltIOPJ2UAm15zn1+92Z99Fz 7M/npIqJ/BAbW7zwt97PylZul+n8yiV9Xik/gslV1z0XZifJozLR2QRuuUBykBus aUn36zw0j4mCli/0gmQ0OeMtoyl+/ggGDyfKK4+fQOAM1J6+9wQZFQqWcb5ZFqZP QcybmRbi/6306Rw62T9XJ9XCyMOUBr7SDQ27v/XkVQCDjs9Okfr6DEmVE6bwslde nV2sKeGqD+7K56zwTTCZ3Y6sV8SocmkbM6VEfFxOvszWIGaDIb4337vrJCjbYI1U rbxCVaWzvWR7VNa3C/B5AoIBAQDT44Dq137etlhpbHF4z/y5ugxBNV9VlHsJU+W3 7HHmE8gKVER5U0by13j3XLCRQPQi+YTShU9t9/aNjDw68+Yz9oBzwYG3E+wk8Efw 13juNCFVzJYii2fp01i/9uoW2y4m5ft3nuAnOLegNx41U4U+qioMzyGWRRQ72WVg GfEbQ+5S5qX59DqGaBmbGrg9BA8TiyMKMqWNgATHdn969zKkbe2Eo1PLsV3ZtorH BRIo7PCEfYZD4zhSbE/oer2qZHWa7iiHYBpTvrlS53shYOGbFsiZQRjOpIVB9DX0 ofk45xWpqMqF8UZ8SAzlzzHVqZI9PuFu58fMPqZc4J3FqkNrAoIBAQDTz6ud5Yq9 1ycLbunlJcBUFmG9vHsf3gWkughPTtN3nAJ4DCYe7HbKknVsCXmbRihRKUyHun6o VrhZshPm2KXNF42jaLQL97sGyDkzu2+7koLJXYBnIXqBeZRVNfcmvNkmQZe1l8zi kL+xFe6vxhKu1CtAX3W2q7xhcIDywX3/ktJsFvyl2FkKX5PJurZpkA5ZQDHrnA/R hypB+BYNC6dRzYWBpN3F1EI9mnYqBnTzTO1ZVieor7Qb5iX4F1O8LGd1i9iIuXgr EdGGia2SC2H/qOXJ7heq1UXy05wyqcIFmU7faPUzNHFTrQAFWQ+HlnDon9UTkLud kaj8RWeBFDNzAoIBADttioHTUO0L/X4MAUNeKka5DKjZXFS3YU67bimIsmVSVP+4 pL/WgIapsm7GW2tR6WdJzlvxMdbo/gizNU1fjMg0MdDFjCkZ+Fhf3/2HoY5FprfW uqETsmBde33TtdIVRTt5s27Ya4v0l2PjMaDJPQzXUxXmnkf0NfmXPpyWig4YnmY3 9INHYYbC+bOL6fKLCeN0Wa6Jh+9I4Y5ECPsnC9gcUMqruFvf8i+WyBOLs40w70Bp qFewCeLsJ/lPO5Tnuihq9YkKhjfIvVeoPtucvYnu+PIq1NdYQ1u9L8jeCPVRsryz 76Fji15eIuftlc+UUMTGtxmQ/nOleqmAAiAnYeMCggEBALr5S0lq43qJfpH9KsN4 +7o+t7FBvH55AwpSnhtEPjALq7JFJzGNE5/mgXkJNCv5VoWuqzv1SPFY/AtRw3e4 L0RIUmO5fZZC7PojrTsZbpxpzMHso/hl+TpqFKLTrISpmBbJOB65DcfCdzTfY4AO nVdvO27r1YGXQAfTxECGxa7h8JYyBHxx6sfZbyBYjcXJwKDQpkCR1vTjGE57rRt+ +gigIAY9fvevU3oF6+FVKc/MTIjcIM4rrBYkp8fE78ngeMOu20p2TrnWVNsqlemh 2rRQZ+hFIOdQtRqR6gRfDkLa/mEAydKVrKRsxuPxpl/OUYVH8lP/I18Iwd9PdPrg 1jkCggEBAIMRe0jLkDO6dKTD+FmqestCHz+RZwFNMiEMXZyvmF5eg3JhYFQYrHfY SAeq50xHKTCw1kRmT5LQXAshWV/u2KhfljjU1bPH43hO+J/GRZ0m2Ck48qpvG5ST CqJzohYc9Nws4upCAGmHhhagEDu4DaQXi9v4iRTjyhE+8bXGNRDxpGHlxjuGviyj CSbIm8IP+6uBuO2+XZ2yGyKVdzHNVi+tlyhgS4N7rSDzL/8COS8NyQ+fnSa6yf07 1PwYcSf1+IA77lyFjmZzDPZcBxAKiIJDNgsIKuvXR7YyP84Wnfiubbwcg7J2Sczw Kwauzj8I4U9WySIj91DC4rv4ALBfSkU= -----END PRIVATE KEY-----` cert3 = `-----BEGIN CERTIFICATE----- MIIE+zCCAuOgAwIBAgIJALZU5ftU71m6MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV BAMMCWxvY2FsaG9zdDAeFw0xODEyMDIyMTU2MjdaFw0xOTEyMDIyMTU2MjdaMBQx EjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAK9QZkJ1Ihc0488xq1XRoiBtxgwURDRvTWnHnXuN5h7SNxJDsnNWSttQ/xMB v67a5vznKNjWJeHaQGN40wOkZ3Mb3elkBEVBTl/beqnBuzyL3bhr8SmgN7Dup1PC tEUZ07AuDg2cqHVfA/C7orsiUJijS969zFu0iJDGgMMxvRmrncqe74uJTzrkW0Bs 5opPLplER99eeGCyuUDaL7WJnx4pnfjBLn9lZMNIWtbdwlvhh38sP7KY+v/k2QVQ /gLDGr+lFWJwMvdIJVO4eAX6NEZQvm4vAkJl8RC3M3++RtZZKliqdzhtAFxk0wLd BPmcncmqherf80oJ7lUHTQ9pXL+NXhylNJRb8l8cpDH27w5Vkyv2OGNKtcI0+fTX TT/VVrPEsLuNjn/7LmYPJqcZrCX5rRsVxmDaObUAdEKJR+EpaPHYZWiwxh+KZwcs m21pYQacbEWo3MnQU7B0krwYrPzyftPUchvi/eEyy/PE5GRvgzf39vfgT/zGzBhn SnszvOrWJE3vsErztjJKQLYo9u4Pwq5j4SUyZS65fbT3eQpxGqF6gZnTUdZXVwvO U026uey+s9WqQWB4p3qGDaThR5fwXz5rLocaAFS3B0IIP0bWCvxADflW9/hRZn7x P7CeEpeGos4sg4/Ide7nOJl7ub7/4ho54AwL70pniZPmRpoRAgMBAAGjUDBOMB0G A1UdDgQWBBTOQKJ21L/ciHTkRi1n7rRTInXJ4zAfBgNVHSMEGDAWgBTOQKJ21L/c iHTkRi1n7rRTInXJ4zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQB5 tZqWk0RyeAsCK6sX9tWZFAKFiQrVRGlhcW21nUdZn+jLruup27UontAML0mWHIVi FUaok3BZ6qEMC0q6DAzfCN7Zmk/K7MeaHc0staCv8qj6XC/CAWgkx3k9WgDp72K1 lyp1hwW8I9tUMoM4C+6LFjp2959v/4mUnLz69atzdomVZiPf2HiUrBAb4eMOXntZ E4tVyAG3A713QAsOXFMtz8LzlHOTUOPiWcyk92/XfBtsVTmFYpxOKSBrhHIXz+WV 6pKJ557iBpGbu5/CscT5+VN5CYAFxzw0LsRXgJoVqgM5XQS8zztCi8XK9kchpt2u eULB8qUFnUHqewkBypxDDNQ/mOjY4K5dm9RwM6WUeAlVZGWWn0vHaToUN91f7usr UfbR/OrU4lizCkznqNqH9IYIB11LSJngr/FMSymRKAQOUSUmqJCUlLvALKEColhW Ti/feroXva50o6DojtMRBn5G2aTyfIqeiYHBdrBd6NQXKxNSd/qeR3sKRZ4kp6c8 +tCIfUQuN9no4J2cnYULhs2mwInqIny5AgOytXRfDxR61wUezV7OEfUAhhovmuwf Nez1wdrqpD+3AI7Rv+GU/zCBOCoKl0LlqYchcWWEFgBHcmjgTvGI9yfhoDiezibT StncqiK5F5CsWRrwQCpoNDkOAQE/l7QZgBzYrXw4vQ== -----END CERTIFICATE-----` ) func TestCertificatesService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &Certificate{ Key: String("foo"), Cert: String("bar"), SNIs: StringSlice("host1.com", "host2.com"), } createdCertificate, err := client.Certificates.Create(defaultCtx, certificate) assert.NotNil(err) // invalid cert and key assert.Nil(createdCertificate) certificate.Key = String(key1) certificate.Cert = String(cert1) createdCertificate, err = client.Certificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) certificate, err = client.Certificates.Get(defaultCtx, createdCertificate.ID) assert.Nil(err) assert.NotNil(certificate) assert.Equal(2, len(createdCertificate.SNIs)) certificate.Key = String(key2) certificate.Cert = String(cert2) certificate, err = client.Certificates.Update(defaultCtx, certificate) assert.Nil(err) assert.NotNil(certificate) assert.Equal(key2, *certificate.Key) err = client.Certificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() certificate = &Certificate{ Key: String(key3), Cert: String(cert3), ID: String(id), } createdCertificate, err = client.Certificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) assert.Equal(id, *createdCertificate.ID) err = client.Certificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) } func TestCertificateWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &Certificate{ Key: String(key3), Cert: String(cert3), Tags: StringSlice("tag1", "tag2"), } createdCertificate, err := client.Certificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) assert.Equal(StringSlice("tag1", "tag2"), createdCertificate.Tags) err = client.Certificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) } func TestCertificateListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures certificates := []*Certificate{ { Cert: String(cert1), Key: String(key1), }, { Cert: String(cert2), Key: String(key2), }, { Cert: String(cert3), Key: String(key3), }, } // create fixturs for i := 0; i < len(certificates); i++ { certificate, err := client.Certificates.Create(defaultCtx, certificates[i]) assert.Nil(err) assert.NotNil(certificate) certificates[i] = certificate } certificatesFromKong, next, err := client.Certificates.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(certificatesFromKong) assert.Equal(3, len(certificatesFromKong)) // check if we see all certificates assert.True(compareCertificates(certificates, certificatesFromKong)) // Test pagination certificatesFromKong = []*Certificate{} // first page page1, next, err := client.Certificates.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) certificatesFromKong = append(certificatesFromKong, page1...) // last page next.Size = 2 page2, next, err := client.Certificates.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) certificatesFromKong = append(certificatesFromKong, page2...) assert.True(compareCertificates(certificates, certificatesFromKong)) certificates, err = client.Certificates.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(certificates) assert.Equal(3, len(certificates)) for i := 0; i < len(certificates); i++ { assert.Nil(client.Certificates.Delete(defaultCtx, certificates[i].ID)) } } func compareCertificates(expected, actual []*Certificate) bool { var expectedUsernames, actualUsernames []string for _, certificate := range expected { expectedUsernames = append(expectedUsernames, *certificate.Cert) } for _, certificate := range actual { actualUsernames = append(actualUsernames, *certificate.Cert) } return (compareSlices(expectedUsernames, actualUsernames)) } go-kong-0.15.0/kong/consumer_service.go000066400000000000000000000077521400261364200200070ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" "net/http" ) // ConsumerService handles Consumers in Kong. type ConsumerService service // Create creates a Consumer in Kong. // If an ID is specified, it will be used to // create a consumer in Kong, otherwise an ID // is auto-generated. func (s *ConsumerService) Create(ctx context.Context, consumer *Consumer) (*Consumer, error) { queryPath := "/consumers" method := "POST" if consumer.ID != nil { queryPath = queryPath + "/" + *consumer.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, consumer) if err != nil { return nil, err } var createdConsumer Consumer _, err = s.client.Do(ctx, req, &createdConsumer) if err != nil { return nil, err } return &createdConsumer, nil } // Get fetches a Consumer in Kong. func (s *ConsumerService) Get(ctx context.Context, usernameOrID *string) (*Consumer, error) { if isEmptyString(usernameOrID) { return nil, errors.New("usernameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/consumers/%v", *usernameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var consumer Consumer _, err = s.client.Do(ctx, req, &consumer) if err != nil { return nil, err } return &consumer, nil } // GetByCustomID fetches a Consumer in Kong. func (s *ConsumerService) GetByCustomID(ctx context.Context, customID *string) (*Consumer, error) { if isEmptyString(customID) { return nil, errors.New("customID cannot be nil for Get operation") } type QS struct { CustomID string `url:"custom_id,omitempty"` } req, err := s.client.NewRequest("GET", "/consumers", &QS{CustomID: *customID}, nil) if err != nil { return nil, err } type Response struct { Data []Consumer } var resp Response _, err = s.client.Do(ctx, req, &resp) if err != nil { return nil, err } if len(resp.Data) == 0 { return nil, &APIError{httpCode: http.StatusNotFound, message: "Not found"} } return &resp.Data[0], nil } // Update updates a Consumer in Kong func (s *ConsumerService) Update(ctx context.Context, consumer *Consumer) (*Consumer, error) { if isEmptyString(consumer.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/consumers/%v", *consumer.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, consumer) if err != nil { return nil, err } var updatedAPI Consumer _, err = s.client.Do(ctx, req, &updatedAPI) if err != nil { return nil, err } return &updatedAPI, nil } // Delete deletes a Consumer in Kong func (s *ConsumerService) Delete(ctx context.Context, usernameOrID *string) error { if isEmptyString(usernameOrID) { return errors.New("usernameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/consumers/%v", *usernameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Consumers in Kong. // opt can be used to control pagination. func (s *ConsumerService) List(ctx context.Context, opt *ListOpt) ([]*Consumer, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers", opt) if err != nil { return nil, nil, err } var consumers []*Consumer for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var consumer Consumer err = json.Unmarshal(b, &consumer) if err != nil { return nil, nil, err } consumers = append(consumers, &consumer) } return consumers, next, nil } // ListAll fetches all Consumers in Kong. // This method can take a while if there // a lot of Consumers present. func (s *ConsumerService) ListAll(ctx context.Context) ([]*Consumer, error) { var consumers, data []*Consumer var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } consumers = append(consumers, data...) } return consumers, nil } go-kong-0.15.0/kong/consumer_service_test.go000066400000000000000000000151601400261364200210360ustar00rootroot00000000000000package kong import ( "reflect" "sort" "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestConsumersService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) consumer := &Consumer{ Username: String("foo"), CustomID: String("custom_id_foo"), } createdConsumer, err := client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(createdConsumer) consumer, err = client.Consumers.Get(defaultCtx, createdConsumer.ID) assert.Nil(err) assert.NotNil(consumer) consumer, err = client.Consumers.GetByCustomID(defaultCtx, String("does-not-exist")) assert.NotNil(err) assert.Nil(consumer) consumer, err = client.Consumers.GetByCustomID(defaultCtx, String("custom_id_foo")) assert.Nil(err) assert.NotNil(consumer) consumer.Username = String("bar") consumer, err = client.Consumers.Update(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) assert.Equal("bar", *consumer.Username) err = client.Consumers.Delete(defaultCtx, createdConsumer.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() consumer = &Consumer{ Username: String("foo"), ID: String(id), } createdConsumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(createdConsumer) assert.Equal(id, *createdConsumer.ID) err = client.Consumers.Delete(defaultCtx, createdConsumer.ID) assert.Nil(err) } func TestConsumerWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) consumer := &Consumer{ Username: String("foo"), Tags: StringSlice("tag1", "tag2"), } createdConsumer, err := client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(createdConsumer) assert.Equal(StringSlice("tag1", "tag2"), createdConsumer.Tags) err = client.Consumers.Delete(defaultCtx, createdConsumer.ID) assert.Nil(err) } func TestConsumerListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures consumers := []*Consumer{ { Username: String("foo1"), }, { Username: String("foo2"), }, { Username: String("foo3"), }, } // create fixturs for i := 0; i < len(consumers); i++ { consumer, err := client.Consumers.Create(defaultCtx, consumers[i]) assert.Nil(err) assert.NotNil(consumer) consumers[i] = consumer } consumersFromKong, next, err := client.Consumers.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(consumersFromKong) assert.Equal(3, len(consumersFromKong)) // check if we see all consumers assert.True(compareConsumers(consumers, consumersFromKong)) // Test pagination consumersFromKong = []*Consumer{} // first page page1, next, err := client.Consumers.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) consumersFromKong = append(consumersFromKong, page1...) // last page next.Size = 2 page2, next, err := client.Consumers.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) consumersFromKong = append(consumersFromKong, page2...) assert.True(compareConsumers(consumers, consumersFromKong)) consumers, err = client.Consumers.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(consumers) assert.Equal(3, len(consumers)) for i := 0; i < len(consumers); i++ { assert.Nil(client.Consumers.Delete(defaultCtx, consumers[i].ID)) } } func TestConsumerListWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures consumers := []*Consumer{ { Username: String("user1"), Tags: StringSlice("tag1", "tag2"), }, { Username: String("user2"), Tags: StringSlice("tag2", "tag3"), }, { Username: String("user3"), Tags: StringSlice("tag1", "tag3"), }, { Username: String("user4"), Tags: StringSlice("tag1", "tag2"), }, { Username: String("user5"), Tags: StringSlice("tag2", "tag3"), }, { Username: String("user6"), Tags: StringSlice("tag1", "tag3"), }, } // create fixtures for i := 0; i < len(consumers); i++ { consumer, err := client.Consumers.Create(defaultCtx, consumers[i]) assert.Nil(err) assert.NotNil(consumer) consumers[i] = consumer } consumersFromKong, next, err := client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag1"), }) assert.Nil(err) assert.Nil(next) assert.Equal(4, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag2"), }) assert.Nil(err) assert.Nil(next) assert.Equal(4, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag1", "tag2"), }) assert.Nil(err) assert.Nil(next) assert.Equal(6, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag1", "tag2"), MatchAllTags: true, }) assert.Nil(err) assert.Nil(next) assert.Equal(2, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag1", "tag2"), Size: 3, }) assert.Nil(err) assert.NotNil(next) assert.Equal(3, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.Equal(3, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, &ListOpt{ Tags: StringSlice("tag1", "tag2"), MatchAllTags: true, Size: 1, }) assert.Nil(err) assert.NotNil(next) assert.Equal(1, len(consumersFromKong)) consumersFromKong, next, err = client.Consumers.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.Equal(1, len(consumersFromKong)) for i := 0; i < len(consumers); i++ { assert.Nil(client.Consumers.Delete(defaultCtx, consumers[i].Username)) } } func compareConsumers(expected, actual []*Consumer) bool { var expectedUsernames, actualUsernames []string for _, consumer := range expected { expectedUsernames = append(expectedUsernames, *consumer.Username) } for _, consumer := range actual { actualUsernames = append(actualUsernames, *consumer.Username) } return (compareSlices(expectedUsernames, actualUsernames)) } func compareSlices(expected, actual []string) bool { sort.Strings(expected) sort.Strings(actual) return (reflect.DeepEqual(expected, actual)) } go-kong-0.15.0/kong/credentials.go000066400000000000000000000106531400261364200167230ustar00rootroot00000000000000package kong type id interface { id() *string } // KeyAuth represents a key-auth credential in Kong. // +k8s:deepcopy-gen=true type KeyAuth struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Key *string `json:"key,omitempty" yaml:"key,omitempty"` TTL *int `json:"ttl,omitempty" yaml:"ttl,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c KeyAuth) id() *string { return c.ID } // BasicAuth represents a basic-auth credential in Kong. // +k8s:deepcopy-gen=true type BasicAuth struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Username *string `json:"username,omitempty" yaml:"username,omitempty"` Password *string `json:"password,omitempty" yaml:"password,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c BasicAuth) id() *string { return c.ID } // HMACAuth represents a hmac-auth credential in Kong. // +k8s:deepcopy-gen=true type HMACAuth struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Username *string `json:"username,omitempty" yaml:"username,omitempty"` Secret *string `json:"secret,omitempty" yaml:"secret,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c HMACAuth) id() *string { return c.ID } // Oauth2Credential represents a Oauth2 credential in Kong. // +k8s:deepcopy-gen=true type Oauth2Credential struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` ClientID *string `json:"client_id,omitempty" yaml:"client_id,omitempty"` ClientSecret *string `json:"client_secret,omitempty" yaml:"client_secret,omitempty"` RedirectURIs []*string `json:"redirect_uris,omitempty" yaml:"redirect_uris,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c Oauth2Credential) id() *string { return c.ID } // JWTAuth represents a JWT credential in Kong. // +k8s:deepcopy-gen=true type JWTAuth struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Algorithm *string `json:"algorithm,omitempty" yaml:"algorithm,omitempty"` Key *string `json:"key,omitempty" yaml:"key,omitempty"` RSAPublicKey *string `json:"rsa_public_key,omitempty" yaml:"rsa_public_key,omitempty"` Secret *string `json:"secret,omitempty" yaml:"secret,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c JWTAuth) id() *string { return c.ID } // MTLSAuth represents a MTLS credential in Kong. // +k8s:deepcopy-gen=true type MTLSAuth struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` SubjectName *string `json:"subject_name,omitempty" yaml:"subject_name,omitempty"` CACertificate *CACertificate `json:"ca_certificate,omitempty" yaml:"ca_certificate,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c MTLSAuth) id() *string { return c.ID } // ACLGroup represents an ACL group for a consumer in Kong. // +k8s:deepcopy-gen=true type ACLGroup struct { Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Group *string `json:"group,omitempty" yaml:"group,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } func (c ACLGroup) id() *string { return c.ID } go-kong-0.15.0/kong/credentials_service.go000066400000000000000000000100461400261364200204370ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" "reflect" ) // credentialService handles key-auth credentials in Kong. type credentialService service var ( credPath = map[string]string{ "key-auth": "key-auth", "basic-auth": "basic-auth", "hmac-auth": "hmac-auth", "jwt-auth": "jwt", "acl": "acls", "oauth2": "oauth2", "mtls-auth": "mtls-auth", } ) // Create creates a credential in Kong of type credType. // If an ID is specified in the credential, it will be used to // create a credential in Kong, otherwise an ID // is auto-generated. func (s *credentialService) Create(ctx context.Context, credType string, consumerUsernameOrID *string, credential interface{}) (json.RawMessage, error) { if isEmptyString(consumerUsernameOrID) { return nil, errors.New("consumerUsernameOrID cannot be nil") } subPath, ok := credPath[credType] if !ok { return nil, fmt.Errorf("unknown credential type: %v", credType) } endpoint := "/consumers/" + *consumerUsernameOrID + "/" + subPath method := "POST" if credential != nil { if id, ok := credential.(id); ok { if !reflect.ValueOf(id).IsNil() { uuid := id.id() if !isEmptyString(uuid) { endpoint = endpoint + "/" + *uuid method = "PUT" } } } } req, err := s.client.NewRequest(method, endpoint, nil, credential) if err != nil { return nil, err } var createdCredential json.RawMessage _, err = s.client.Do(ctx, req, &createdCredential) if err != nil { return nil, err } return createdCredential, nil } // Get fetches a credential of credType with credIdentifier from Kong. func (s *credentialService) Get(ctx context.Context, credType string, consumerUsernameOrID *string, credIdentifier *string) (json.RawMessage, error) { if isEmptyString(credIdentifier) { return nil, errors.New("credIdentifier cannot be nil for Get operation") } if isEmptyString(consumerUsernameOrID) { return nil, errors.New("consumerUsernameOrID cannot be nil") } subPath, ok := credPath[credType] if !ok { return nil, fmt.Errorf("unknown credential type: %v", credType) } endpoint := "/consumers/" + *consumerUsernameOrID + "/" + subPath + "/" + *credIdentifier req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var cred json.RawMessage _, err = s.client.Do(ctx, req, &cred) if err != nil { return nil, err } return cred, nil } // Update updates credential in Kong func (s *credentialService) Update(ctx context.Context, credType string, consumerUsernameOrID *string, credential interface{}) (json.RawMessage, error) { if isEmptyString(consumerUsernameOrID) { return nil, errors.New("consumerUsernameOrID cannot be nil") } subPath, ok := credPath[credType] if !ok { return nil, fmt.Errorf("unknown credential type: %v", credType) } endpoint := "/consumers/" + *consumerUsernameOrID + "/" + subPath + "/" credID := "" if credential != nil { if id, ok := credential.(id); ok { if !reflect.ValueOf(id).IsNil() { uuid := id.id() if !isEmptyString(uuid) { credID = *uuid } } } } if credID == "" { return nil, errors.New("cannot update a credential without an ID") } endpoint = endpoint + credID req, err := s.client.NewRequest("PATCH", endpoint, nil, credential) if err != nil { return nil, err } var updatedCred json.RawMessage _, err = s.client.Do(ctx, req, &updatedCred) if err != nil { return nil, err } return updatedCred, nil } // Delete deletes a credential in Kong func (s *credentialService) Delete(ctx context.Context, credType string, consumerUsernameOrID, credIdentifier *string) error { if isEmptyString(credIdentifier) { return errors.New("credIdentifier cannot be nil for Delete operation") } subPath, ok := credPath[credType] if !ok { return fmt.Errorf("unknown credential type: %v", credType) } endpoint := "/consumers/" + *consumerUsernameOrID + "/" + subPath + "/" + *credIdentifier req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } go-kong-0.15.0/kong/custom/000077500000000000000000000000001400261364200154045ustar00rootroot00000000000000go-kong-0.15.0/kong/custom/doc.go000066400000000000000000000001411400261364200164740ustar00rootroot00000000000000// Package custom defines interfaces to interact // with custom entities in Kong. package custom go-kong-0.15.0/kong/custom/entity.go000066400000000000000000000040551400261364200172530ustar00rootroot00000000000000package custom // Type represents type of a custom entity in Kong. type Type string // Object is an instance of a custom entity definition // in Kong. type Object map[string]interface{} // Entity represents an instance of a custom entity // alongwith it's relations to other entities. type Entity interface { // Type returns the type of the entity. Type() Type // Object returns the object, an instance // of a custom entity in Kong. Object() Object SetObject(Object) // AddRelation adds a foreign // relation with another entity's ID. AddRelation(string, string) // GetRelation should return foreign // entity's ID that is associated with Entity. GetRelation(string) string // GetAllRelations should return all // relationship of current Entity. GetAllRelations() map[string]string } // EntityObject is a default implmentation of Entity interface. type EntityObject struct { ref map[string]string object Object typ Type } // NewEntityObject creates a new EntityObject // of type typ with content of object and // foreign references as defined in ref. func NewEntityObject(typ Type) *EntityObject { return &EntityObject{ typ: typ, ref: make(map[string]string), } } // Type returns the type of the entity. // Type() Type func (E *EntityObject) Type() Type { return E.typ } // Object returns the object, an instance // of a custom entity in Kong. func (E *EntityObject) Object() Object { return E.object } // SetObject sets the internal object // to newObject. func (E *EntityObject) SetObject(newObject Object) { E.object = newObject } // AddRelation adds a foreign // relation with another entity's ID. func (E *EntityObject) AddRelation(k, v string) { E.ref[k] = v } // GetRelation should return foreign // entity's ID that is associated with Entity. func (E *EntityObject) GetRelation(k string) string { return E.ref[k] } // GetAllRelations should return all // relationship of current Entity. func (E *EntityObject) GetAllRelations() map[string]string { res := make(map[string]string) for k, v := range E.ref { res[k] = v } return res } go-kong-0.15.0/kong/custom/entity_crud.go000066400000000000000000000064661400261364200203000ustar00rootroot00000000000000package custom import ( "errors" "regexp" "strings" ) // EntityCRUD defines endpoints on Kong's // Admin API to interact with the Custom entity in Kong. // Various *Endpoint methods can render // the endpoint to interact with a custom // entity in Kong. The RESTful endpoints are dynamically // generated since based on foreign relations, // the URLs change. type EntityCRUD interface { // Type return the type of custom entitiy // (like key-auth, basic-auth, acl). Type() Type // GetEndpoint returns the URL to get // an existing entity e. // This is useful when one has the foreign relations // and the primary key for that entity. GetEndpoint(e Entity) (string, error) // PostEndpoint returns the URL to create // an entity e of a Type. PostEndpoint(e Entity) (string, error) // PatchEndpoint returns the URL to use for updating // custom entity e. PatchEndpoint(e Entity) (string, error) // DeleteEndpoint returns the URL to use // to delete entity e. DeleteEndpoint(e Entity) (string, error) // ListEndpoint returns the list URL. // This can be used to list all // instances of a type. ListEndpoint(e Entity) (string, error) } // EntityCRUDDefinition implements the EntityCRUD interface. type EntityCRUDDefinition struct { Name Type `yaml:"name" json:"name"` CRUDPath string `yaml:"crud" json:"curd"` PrimaryKey string `yaml:"primary_key" json:"primary_key"` } var r = regexp.MustCompile(`(?:\$\{)(\w+)(?:\})`) func render(template string, entity Entity) (string, error) { result := template matches := r.FindAllStringSubmatch(template, -1) for _, m := range matches { if v := entity.GetRelation(m[1]); v != "" { result = strings.Replace(result, m[0], v, 1) } else { return "", errors.New("cannot substitute '" + m[1] + "' in URL: " + template) } } return result, nil } func (e EntityCRUDDefinition) renderWithPK(entity Entity) (string, error) { endpoint, err := render(e.CRUDPath, entity) if err != nil { return "", err } p, ok := entity.Object()[e.PrimaryKey] if !ok { return "", errors.New("primary key not found in entity") } key, ok := p.(string) if !ok { return "", errors.New("primary key can't be converted to string") } return endpoint + "/" + key, nil } // Type return the type of custom entitiy in Kong. func (e *EntityCRUDDefinition) Type() Type { return e.Name } // GetEndpoint returns the URL to get // an existing entity e. // This is useful when one has the foreign relations // and the primary key for that entity. func (e *EntityCRUDDefinition) GetEndpoint(entity Entity) (string, error) { return e.renderWithPK(entity) } // PostEndpoint returns the URL to create // an entity e of a Type. func (e *EntityCRUDDefinition) PostEndpoint(entity Entity) (string, error) { return render(e.CRUDPath, entity) } // PatchEndpoint returns the URL to use for updating // custom entity e. func (e *EntityCRUDDefinition) PatchEndpoint(entity Entity) (string, error) { return e.renderWithPK(entity) } // DeleteEndpoint returns the URL to use // to delete entity e. func (e *EntityCRUDDefinition) DeleteEndpoint(entity Entity) (string, error) { return e.renderWithPK(entity) } // ListEndpoint returns the list URL. // This can be used to list all // instances of a type. func (e EntityCRUDDefinition) ListEndpoint(entity Entity) (string, error) { return render(e.CRUDPath, entity) } go-kong-0.15.0/kong/custom/entity_crud_test.go000066400000000000000000000040611400261364200213240ustar00rootroot00000000000000package custom import ( "testing" "github.com/stretchr/testify/assert" ) func TestRender(t *testing.T) { assert := assert.New(t) entity := NewEntityObject("key-auth") entity.AddRelation("consumer_id", "bob") result, err := render("/consumers/${consumer_id}/key-auths", entity) assert.Nil(err) assert.Equal(result, "/consumers/bob/key-auths") result, err = render("/consumers/${random_id}/key-auths", entity) assert.NotNil(err) assert.Equal(result, "") } func TestEntityCRUDDefinition(t *testing.T) { assert := assert.New(t) var typ Type = "foo" e := EntityCRUDDefinition{ Name: typ, CRUDPath: "/consumers/${consumer_id}/foo", PrimaryKey: "id", } var object Object = map[string]interface{}{ "id": "unique-id", "key1": "value1", "key2": "value2", } entity := NewEntityObject(typ) entity.SetObject(object) entity.AddRelation("consumer_id", "gopher") assert.Equal(typ, e.Type()) url, err := e.GetEndpoint(entity) assert.Nil(err) assert.Equal("/consumers/gopher/foo/unique-id", url) url, err = e.PatchEndpoint(entity) assert.Nil(err) assert.Equal("/consumers/gopher/foo/unique-id", url) url, err = e.DeleteEndpoint(entity) assert.Nil(err) assert.Equal("/consumers/gopher/foo/unique-id", url) url, err = e.PostEndpoint(entity) assert.Nil(err) assert.Equal("/consumers/gopher/foo", url) url, err = e.ListEndpoint(entity) assert.Nil(err) assert.Equal("/consumers/gopher/foo", url) entity = NewEntityObject(typ) entity.SetObject(object) url, err = e.GetEndpoint(entity) assert.NotNil(err) assert.Empty(url) object = map[string]interface{}{ "key1": "value1", "key2": "value2", } entity = NewEntityObject(typ) entity.AddRelation("consumer_id", "gopher") entity.SetObject(object) url, err = e.GetEndpoint(entity) assert.NotNil(err) assert.Empty(url) object = map[string]interface{}{ "id": -1, "key1": "value1", "key2": "value2", } entity = NewEntityObject(typ) entity.SetObject(object) entity.AddRelation("consumer_id", "gopher") url, err = e.GetEndpoint(entity) assert.NotNil(err) assert.Empty(url) } go-kong-0.15.0/kong/custom/entity_test.go000066400000000000000000000011441400261364200203060ustar00rootroot00000000000000package custom import ( "testing" "github.com/stretchr/testify/assert" ) func TestEntityObject(t *testing.T) { assert := assert.New(t) var typ Type = "foo" var object Object = map[string]interface{}{ "id": "unique", "key": "value", } e := NewEntityObject(typ) assert.NotNil(e) assert.Equal(typ, e.Type()) e.SetObject(object) assert.Equal(object, e.Object()) e.AddRelation("bar", "baz") e.AddRelation("yo", "yoyo") assert.Equal("baz", e.GetRelation("bar")) assert.Equal("yoyo", e.GetRelation("yo")) assert.Equal(2, len(e.GetAllRelations())) assert.Equal("", e.GetRelation("none")) } go-kong-0.15.0/kong/custom/registry.go000066400000000000000000000032231400261364200176030ustar00rootroot00000000000000package custom import "errors" // Registry is a store of EntityCRUD objects type Registry interface { // Register puts EntityCRUD in the internal // store and returns an error if the entity // of Type is already registered Register(Type, EntityCRUD) error // Lookup returns the EntityCRUD object associated // with typ, or nil if one is not Registered yet. Lookup(Type) EntityCRUD // Unregister unregisters the entity // registered with Type from the store. // It returns an // error if the Type was not registered // before this call. Unregister(Type) error } // defaultRegistry is an out of the box implementation // of Registry object. type defaultRegistry struct { store map[Type]EntityCRUD } // NewDefaultRegistry returns a default registry func NewDefaultRegistry() Registry { return &defaultRegistry{ store: make(map[Type]EntityCRUD), } } // Register puts EntityCRUD in the internal // store and returns an error if the entity // of Type is already registered. func (r *defaultRegistry) Register(typ Type, def EntityCRUD) error { if _, ok := r.store[typ]; ok { return errors.New("type already registered") } r.store[typ] = def return nil } // Lookup returns the EntityCRUD object associated // with typ, or nil if one is not Registered yet. func (r *defaultRegistry) Lookup(typ Type) EntityCRUD { return r.store[typ] } // Unregister unregisters the entity // registered with Type from the store. // It returns an // error if the Type was not registered // before this call. func (r *defaultRegistry) Unregister(typ Type) error { if _, ok := r.store[typ]; !ok { return errors.New("type not registered") } delete(r.store, typ) return nil } go-kong-0.15.0/kong/custom/registry_test.go000066400000000000000000000010761400261364200206460ustar00rootroot00000000000000package custom import ( "testing" "github.com/stretchr/testify/assert" ) func TestDefaultRegistry(t *testing.T) { assert := assert.New(t) r := NewDefaultRegistry() assert.NotNil(r) var typ Type = "foo" entitiy := EntityCRUDDefinition{ Name: typ, } err := r.Register(typ, &entitiy) assert.Nil(err) err = r.Register(typ, &entitiy) assert.NotNil(err) e := r.Lookup(typ) assert.NotNil(e) assert.Equal(e, &entitiy) e = r.Lookup("NotExists") assert.Nil(e) err = r.Unregister("NotExists)") assert.NotNil(err) err = r.Unregister(typ) assert.Nil(err) } go-kong-0.15.0/kong/custom_entity_service.go000066400000000000000000000110021400261364200210410ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "github.com/kong/go-kong/kong/custom" ) // CustomEntityService handles custom entities in Kong. type CustomEntityService service // Get fetches a custom entity. The primary key and all relations of the // entity must be populated in entity. func (s *CustomEntityService) Get(ctx context.Context, entity custom.Entity) (custom.Entity, error) { def := s.client.Lookup(entity.Type()) if def == nil { return nil, errors.New("entity '" + string(entity.Type()) + "' not registered") } queryPath, err := def.GetEndpoint(entity) if err != nil { return nil, err } req, err := s.client.NewRequest("GET", queryPath, nil, nil) if err != nil { return nil, err } var object custom.Object _, err = s.client.Do(ctx, req, &object) if err != nil { return nil, err } entity.SetObject(object) return entity, nil } // Create creates a custom entity based on entity. // All required fields must be present in entity. func (s *CustomEntityService) Create(ctx context.Context, entity custom.Entity) (custom.Entity, error) { def := s.client.Lookup(entity.Type()) if def == nil { return nil, errors.New("entity '" + string(entity.Type()) + "' not registered") } method := "POST" queryPath, err := def.PostEndpoint(entity) if err != nil { return nil, err } if entity.Object() != nil { if _, ok := entity.Object()["id"]; ok { queryPath, err = def.PatchEndpoint(entity) if err != nil { return nil, err } method = "PUT" } } o := entity.Object() // Necessary to Marshal an empty map // as {} and not null if o == nil || len(o) == 0 { o = make(map[string]interface{}) } req, err := s.client.NewRequest(method, queryPath, nil, o) if err != nil { return nil, err } var object custom.Object _, err = s.client.Do(ctx, req, &object) if err != nil { return nil, err } entity.SetObject(object) return entity, nil } // Update updates a custom entity in Kong. func (s *CustomEntityService) Update(ctx context.Context, entity custom.Entity) (custom.Entity, error) { def := s.client.Lookup(entity.Type()) if def == nil { return nil, errors.New("entity '" + string(entity.Type()) + "' not registered") } queryPath, err := def.PatchEndpoint(entity) if err != nil { return nil, err } o := entity.Object() // Necessary to Marshal an empty map // as {} and not null if o == nil || len(o) == 0 { o = make(map[string]interface{}) } req, err := s.client.NewRequest("PATCH", queryPath, nil, o) if err != nil { return nil, err } var object custom.Object _, err = s.client.Do(ctx, req, &object) if err != nil { return nil, err } entity.SetObject(object) return entity, nil } // Delete deletes a custom entity in Kong. func (s *CustomEntityService) Delete(ctx context.Context, entity custom.Entity) error { def := s.client.Lookup(entity.Type()) if def == nil { return errors.New("entity '" + string(entity.Type()) + "' not registered") } queryPath, err := def.PatchEndpoint(entity) if err != nil { return err } req, err := s.client.NewRequest("DELETE", queryPath, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches all custom entities based on relations func (s *CustomEntityService) List(ctx context.Context, opt *ListOpt, entity custom.Entity) ([]custom.Entity, *ListOpt, error) { def := s.client.Lookup(entity.Type()) if def == nil { return nil, nil, errors.New("entity '" + string(entity.Type()) + "' not registered") } queryPath, err := def.ListEndpoint(entity) if err != nil { return nil, nil, err } data, next, err := s.client.list(ctx, queryPath, opt) if err != nil { return nil, nil, err } var entities []custom.Entity for _, o := range data { b, err := o.MarshalJSON() if err != nil { return nil, nil, err } var object custom.Object err = json.Unmarshal(b, &object) if err != nil { return nil, nil, err } e := custom.NewEntityObject(entity.Type()) e.SetObject(object) for k, v := range entity.GetAllRelations() { e.AddRelation(k, v) } entities = append(entities, e) } return entities, next, nil } // ListAll fetches all custom entities based on relations func (s *CustomEntityService) ListAll(ctx context.Context, entity custom.Entity) ([]custom.Entity, error) { var entities, data []custom.Entity var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt, entity) if err != nil { return nil, err } entities = append(entities, data...) } return entities, nil } go-kong-0.15.0/kong/custom_entity_service_test.go000066400000000000000000000045441400261364200221150ustar00rootroot00000000000000package kong import ( "sort" "testing" "github.com/kong/go-kong/kong/custom" "github.com/stretchr/testify/assert" ) func TestCustomEntityService(T *testing.T) { T.Skip() assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixture consumer consumer, err := client.Consumers.Create(defaultCtx, &Consumer{Username: String("foo")}) assert.Nil(err) assert.NotNil(consumer) // create a key associated with the consumer k1 := custom.NewEntityObject("key-auth") k1.AddRelation("consumer_id", *consumer.ID) e1, err := client.CustomEntities.Create(defaultCtx, k1) assert.NotNil(e1) assert.Nil(err) // look up the key se := custom.NewEntityObject("key-auth") se.AddRelation("consumer_id", *consumer.ID) se.SetObject(map[string]interface{}{"id": e1.Object()["id"]}) gotE, err := client.CustomEntities.Get(defaultCtx, se) assert.NotNil(gotE) assert.Equal(e1.Object()["key"], gotE.Object()["key"]) assert.Nil(err) gotE.Object()["key"] = "my-secret" e1, err = client.CustomEntities.Update(defaultCtx, gotE) assert.NotNil(e1) assert.Nil(err) assert.Equal("my-secret", e1.Object()["key"]) // PUT request k2 := custom.NewEntityObject("key-auth") id := "fc3898d9-4b4d-4491-a834-8358646e2d20" k2.SetObject(map[string]interface{}{ "id": id, "key": "super-secret", }) k2.AddRelation("consumer_id", *consumer.ID) e2, err := client.CustomEntities.Create(defaultCtx, k2) assert.NotNil(e2) assert.Nil(err) assert.Equal("super-secret", e2.Object()["key"]) assert.Equal(id, e2.Object()["id"]) se = custom.NewEntityObject("key-auth") se.AddRelation("consumer_id", *consumer.ID) keyAuths, _, err := client.CustomEntities.List(defaultCtx, nil, se) assert.Nil(err) assert.Equal(2, len(keyAuths)) // list endpoint keyAuths, err = client.CustomEntities.ListAll(defaultCtx, se) assert.Nil(err) assert.Equal(2, len(keyAuths)) expectedKeys := []string{e1.Object()["key"].(string), e2.Object()["key"].(string)} actualKeys := []string{keyAuths[0].Object()["key"].(string), keyAuths[1].Object()["key"].(string)} sort.Strings(expectedKeys) sort.Strings(actualKeys) assert.Equal(expectedKeys, actualKeys) assert.Nil(client.CustomEntities.Delete(defaultCtx, e1)) assert.Nil(client.CustomEntities.Delete(defaultCtx, e2)) // delete fixture consumer assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } go-kong-0.15.0/kong/doc.go000066400000000000000000000001221400261364200151610ustar00rootroot00000000000000// Package kong provides Go bindings to Kong's RESTful // Admin API. package kong go-kong-0.15.0/kong/endpoint_permission_service.go000066400000000000000000000101611400261364200222300ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // RBACEndpointPermissionService handles RBACEndpointPermissions in Kong. type RBACEndpointPermissionService service // Create creates a RBACEndpointPermission in Kong. func (s *RBACEndpointPermissionService) Create(ctx context.Context, ep *RBACEndpointPermission) (*RBACEndpointPermission, error) { if ep == nil { return nil, errors.New("cannot create a nil endpointpermission") } if ep.Role == nil || ep.Role.ID == nil { return nil, errors.New("cannot create endpoint permission with role or role id undefined") } method := "POST" endpoint := fmt.Sprintf("/rbac/roles/%v/endpoints", *ep.Role.ID) req, err := s.client.NewRequest(method, endpoint, nil, ep) if err != nil { return nil, err } var createdEndpointPermission RBACEndpointPermission _, err = s.client.Do(ctx, req, &createdEndpointPermission) if err != nil { return nil, err } return &createdEndpointPermission, nil } // Get fetches a RBACEndpointPermission in Kong. func (s *RBACEndpointPermissionService) Get(ctx context.Context, roleNameOrID *string, workspaceNameOrID *string, endpointName *string) (*RBACEndpointPermission, error) { if isEmptyString(endpointName) { return nil, errors.New("endpointName cannot be nil for Get operation") } if *endpointName == "*" { endpointName = String("/" + *endpointName) } endpoint := fmt.Sprintf("/rbac/roles/%v/endpoints/%v%v", *roleNameOrID, *workspaceNameOrID, *endpointName) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var EndpointPermission RBACEndpointPermission _, err = s.client.Do(ctx, req, &EndpointPermission) if err != nil { return nil, err } return &EndpointPermission, nil } // Update updates a RBACEndpointPermission in Kong. func (s *RBACEndpointPermissionService) Update(ctx context.Context, ep *RBACEndpointPermission) (*RBACEndpointPermission, error) { if ep == nil { return nil, errors.New("cannot update a nil EndpointPermission") } if ep.Workspace == nil { return nil, errors.New("cannot update an EndpointPermission with workspace as nil") } if ep.Role == nil || ep.Role.ID == nil { return nil, errors.New("cannot create endpoint permission with role or role id undefined") } if isEmptyString(ep.Endpoint) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/rbac/roles/%v/endpoints/%v/%v", *ep.Role.ID, *ep.Workspace, *ep.Endpoint) req, err := s.client.NewRequest("PATCH", endpoint, nil, ep) if err != nil { return nil, err } var updatedEndpointPermission RBACEndpointPermission _, err = s.client.Do(ctx, req, &updatedEndpointPermission) if err != nil { return nil, err } return &updatedEndpointPermission, nil } // Delete deletes a EndpointPermission in Kong func (s *RBACEndpointPermissionService) Delete(ctx context.Context, roleNameOrID *string, workspaceNameOrID *string, endpoint *string) error { if endpoint == nil { return errors.New("cannot update a nil EndpointPermission") } if workspaceNameOrID == nil { return errors.New("cannot update an EndpointPermission with workspace as nil") } if roleNameOrID == nil { return errors.New("cannot update an EndpointPermission with role as nil") } reqEndpoint := fmt.Sprintf("/rbac/roles/%v/endpoints/%v/%v", *roleNameOrID, *workspaceNameOrID, *endpoint) req, err := s.client.NewRequest("DELETE", reqEndpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // ListAllForRole fetches a list of all RBACEndpointPermissions in Kong for a given role. func (s *RBACEndpointPermissionService) ListAllForRole(ctx context.Context, roleNameOrID *string) ([]*RBACEndpointPermission, error) { data, _, err := s.client.list(ctx, fmt.Sprintf("/rbac/roles/%v/endpoints", *roleNameOrID), nil) if err != nil { return nil, err } var eps []*RBACEndpointPermission for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, err } var ep RBACEndpointPermission err = json.Unmarshal(b, &ep) if err != nil { return nil, err } eps = append(eps, &ep) } return eps, nil } go-kong-0.15.0/kong/endpoint_permission_service_test.go000066400000000000000000000033141400261364200232710ustar00rootroot00000000000000package kong import ( "testing" "github.com/stretchr/testify/assert" ) func TestRBACEndpointPermissionservice(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // Create Workspace workspace := &Workspace{ Name: String("endpoint-test-workspace"), } createdWorkspace, err := client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) // Use new client in workspace context. role := &RBACRole{ Name: String("test-role-endpoint-perm"), } createdRole, err := client.RBACRoles.Create(defaultCtx, role) assert.Nil(err) assert.NotNil(createdRole) // Add Endpoint Permission to Role ep := &RBACEndpointPermission{ Role: &RBACRole{ ID: createdRole.ID, }, Endpoint: String("/rbac"), Actions: []*string{ String("create"), String("read"), }, } createdEndpointPermission, err := client.RBACEndpointPermissions.Create(defaultCtx, ep) assert.Nil(err) assert.NotNil(createdEndpointPermission) ep, err = client.RBACEndpointPermissions.Get( defaultCtx, createdRole.ID, createdWorkspace.ID, createdEndpointPermission.Endpoint) assert.Nil(err) assert.NotNil(ep) ep.Comment = String("new comment") ep, err = client.RBACEndpointPermissions.Update(defaultCtx, ep) assert.Nil(err) assert.NotNil(ep) assert.Equal("new comment", *ep.Comment) err = client.RBACEndpointPermissions.Delete( defaultCtx, createdRole.ID, createdWorkspace.ID, createdEndpointPermission.Endpoint) assert.Nil(err) err = client.RBACRoles.Delete(defaultCtx, createdRole.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) } go-kong-0.15.0/kong/entity_permission_service.go000066400000000000000000000072051400261364200217310ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // RBACEntityPermissionService handles RBACEntityPermissions in Kong. type RBACEntityPermissionService service // Create creates an RBACEntityPermission in Kong. func (s *RBACEntityPermissionService) Create(ctx context.Context, ep *RBACEntityPermission) (*RBACEntityPermission, error) { if ep == nil { return nil, errors.New("cannot create a nil entitypermission") } if ep.Role == nil || ep.Role.ID == nil { return nil, errors.New("cannot create entity permission with role or role id undefined") } method := "POST" entity := fmt.Sprintf("/rbac/roles/%v/entities", *ep.Role.ID) req, err := s.client.NewRequest(method, entity, nil, ep) if err != nil { return nil, err } var createdEntityPermission RBACEntityPermission _, err = s.client.Do(ctx, req, &createdEntityPermission) if err != nil { return nil, err } return &createdEntityPermission, nil } // Get fetches an EntityPermission in Kong. func (s *RBACEntityPermissionService) Get(ctx context.Context, roleNameOrID *string, entityName *string) (*RBACEntityPermission, error) { if isEmptyString(entityName) { return nil, errors.New("entityName cannot be nil for Get operation") } entity := fmt.Sprintf("/rbac/roles/%v/entities/%v", *roleNameOrID, *entityName) req, err := s.client.NewRequest("GET", entity, nil, nil) if err != nil { return nil, err } var EntityPermission RBACEntityPermission _, err = s.client.Do(ctx, req, &EntityPermission) if err != nil { return nil, err } return &EntityPermission, nil } // Update updates an EntityPermission in Kong. func (s *RBACEntityPermissionService) Update(ctx context.Context, ep *RBACEntityPermission) (*RBACEntityPermission, error) { if ep == nil { return nil, errors.New("cannot update a nil EntityPermission") } if ep.Role == nil || ep.Role.ID == nil { return nil, errors.New("cannot create entity permission with role or role id undefined") } if isEmptyString(ep.EntityID) { return nil, errors.New("ID cannot be nil for Update operation") } entity := fmt.Sprintf("/rbac/roles/%v/entities/%v", *ep.Role.ID, *ep.EntityID) req, err := s.client.NewRequest("PATCH", entity, nil, ep) if err != nil { return nil, err } var updatedEntityPermission RBACEntityPermission _, err = s.client.Do(ctx, req, &updatedEntityPermission) if err != nil { return nil, err } return &updatedEntityPermission, nil } // Delete deletes an EntityPermission in Kong func (s *RBACEntityPermissionService) Delete(ctx context.Context, roleNameOrID *string, entityID *string) error { if roleNameOrID == nil { return errors.New("cannot update an EntityPermission with role as nil") } if entityID == nil { return errors.New("cannot update an EntityPermission with entity ID as nil") } endpoint := fmt.Sprintf("/rbac/roles/%v/entities/%v", *roleNameOrID, *entityID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // ListAllForRole fetches a list of all RBACEntityPermissions in Kong for a given role. func (s *RBACEntityPermissionService) ListAllForRole(ctx context.Context, roleNameOrID *string) ([]*RBACEntityPermission, error) { endpoint := fmt.Sprintf("/rbac/roles/%v/entities", *roleNameOrID) data, _, err := s.client.list(ctx, endpoint, nil) if err != nil { return nil, err } var eps []*RBACEntityPermission for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, err } var ep RBACEntityPermission err = json.Unmarshal(b, &ep) if err != nil { return nil, err } eps = append(eps, &ep) } return eps, nil } go-kong-0.15.0/kong/entity_permission_service_test.go000066400000000000000000000072551400261364200227750ustar00rootroot00000000000000package kong import ( "net/url" "path" "testing" "github.com/stretchr/testify/assert" ) func TestRBACEntityPermissionservice(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // Create Workspace workspace := &Workspace{ Name: String("entity-test-workspace"), } createdWorkspace, err := client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) // Create new workspace client url, err := url.Parse(defaultBaseURL) assert.Nil(err) url.Path = path.Join(url.Path, *createdWorkspace.Name) workspaceClient, err := NewTestClient(String(url.String()), nil) assert.Nil(err) assert.NotNil(workspaceClient) // Use new client in workspace context. role := &RBACRole{ Name: String("test-role-entity-perm"), } createdRole, err := workspaceClient.RBACRoles.Create(defaultCtx, role) assert.Nil(err) assert.NotNil(createdRole) // Add Entity Permission to Role ep := &RBACEntityPermission{ Role: &RBACRole{ ID: createdRole.ID, }, EntityID: String("*"), Actions: []*string{ String("create"), String("read"), }, } createdEntityPermission, err := workspaceClient.RBACEntityPermissions.Create(defaultCtx, ep) assert.Nil(err) assert.NotNil(createdEntityPermission) ep, err = workspaceClient.RBACEntityPermissions.Get(defaultCtx, createdRole.ID, createdEntityPermission.EntityID) assert.Nil(err) assert.NotNil(ep) ep.Comment = String("new comment") ep, err = workspaceClient.RBACEntityPermissions.Update(defaultCtx, ep) assert.Nil(err) assert.NotNil(ep) assert.Equal("new comment", *ep.Comment) err = workspaceClient.RBACEntityPermissions.Delete(defaultCtx, createdRole.ID, createdEntityPermission.EntityID) assert.Nil(err) err = workspaceClient.RBACRoles.Delete(defaultCtx, createdRole.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) } func TestRBACEntityPermissionserviceList(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // Create a workspace workspace := &Workspace{ Name: String("entity-test-list-workspace"), } createdWorkspace, err := client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) // Create a role role := &RBACRole{ Name: String("test-role-entity-perm"), } createdRole, err := client.RBACRoles.Create(defaultCtx, role) assert.Nil(err) assert.NotNil(createdRole) ep1 := &RBACEntityPermission{ Role: &RBACRole{ ID: createdRole.ID, }, EntityID: String("*"), Actions: []*string{ String("create"), String("read"), }, } ep2 := &RBACEntityPermission{ Role: &RBACRole{ ID: createdRole.ID, }, EntityID: createdWorkspace.ID, Actions: []*string{ String("update"), String("delete"), }, } createdEntityPermissionA, err := client.RBACEntityPermissions.Create(defaultCtx, ep1) assert.Nil(err) createdEntityPermissionB, err := client.RBACEntityPermissions.Create(defaultCtx, ep2) assert.Nil(err) eps, err := client.RBACEntityPermissions.ListAllForRole(defaultCtx, createdRole.ID) assert.Nil(err) assert.NotNil(eps) // Counts default ep assert.Equal(2, len(eps)) err = client.RBACEntityPermissions.Delete(defaultCtx, createdRole.ID, createdEntityPermissionA.EntityID) assert.Nil(err) err = client.RBACEntityPermissions.Delete(defaultCtx, createdRole.ID, createdEntityPermissionB.EntityID) assert.Nil(err) err = client.RBACRoles.Delete(defaultCtx, createdRole.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) } go-kong-0.15.0/kong/error.go000066400000000000000000000011031400261364200155450ustar00rootroot00000000000000package kong import ( "fmt" ) // APIError is used for Kong Admin API errors. type APIError struct { httpCode int message string } func (e *APIError) Error() string { return fmt.Sprintf("HTTP status %d (message: %q)", e.httpCode, e.message) } // Code returns the HTTP status code for the error. func (e *APIError) Code() int { return e.httpCode } // IsNotFoundErr returns true if the error or it's cause is // a 404 response from Kong. func IsNotFoundErr(e error) bool { switch e := e.(type) { case *APIError: return e.httpCode == 404 default: return false } } go-kong-0.15.0/kong/error_test.go000066400000000000000000000017321400261364200166140ustar00rootroot00000000000000package kong import ( "errors" "testing" "github.com/stretchr/testify/assert" ) func TestIsNotFoundErr(T *testing.T) { assert := assert.New(T) var e error = &APIError{httpCode: 404} assert.True(IsNotFoundErr(e)) assert.False(IsNotFoundErr(nil)) err := errors.New("not a 404") assert.False(IsNotFoundErr(err)) } func TestIsNotFoundErrE2E(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) consumer, err := client.Consumers.Get(defaultCtx, String("does-not-exists")) assert.Nil(consumer) assert.NotNil(err) assert.True(IsNotFoundErr(err)) } func TestAPIError_Code(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) consumer, err := client.Consumers.Get(defaultCtx, String("does-not-exists")) assert.Nil(consumer) assert.NotNil(err) kongErr, ok := err.(*APIError) assert.True(ok) assert.True(kongErr.Code() == 404) } go-kong-0.15.0/kong/hmac_auth_service.go000066400000000000000000000071471400261364200201030ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // HMACAuthService handles hmac-auth credentials in Kong. type HMACAuthService service // Create creates a hmac-auth credential in Kong // If an ID is specified, it will be used to // create a hmac-auth in Kong, otherwise an ID // is auto-generated. func (s *HMACAuthService) Create(ctx context.Context, consumerUsernameOrID *string, hmacAuth *HMACAuth) (*HMACAuth, error) { cred, err := s.client.credentials.Create(ctx, "hmac-auth", consumerUsernameOrID, hmacAuth) if err != nil { return nil, err } var createdHMACAuth HMACAuth err = json.Unmarshal(cred, &createdHMACAuth) if err != nil { return nil, err } return &createdHMACAuth, nil } // Get fetches a hmac-auth credential from Kong. func (s *HMACAuthService) Get(ctx context.Context, consumerUsernameOrID, usernameOrID *string) (*HMACAuth, error) { cred, err := s.client.credentials.Get(ctx, "hmac-auth", consumerUsernameOrID, usernameOrID) if err != nil { return nil, err } var hmacAuth HMACAuth err = json.Unmarshal(cred, &hmacAuth) if err != nil { return nil, err } return &hmacAuth, nil } // Update updates a hmac-auth credential in Kong func (s *HMACAuthService) Update(ctx context.Context, consumerUsernameOrID *string, hmacAuth *HMACAuth) (*HMACAuth, error) { cred, err := s.client.credentials.Update(ctx, "hmac-auth", consumerUsernameOrID, hmacAuth) if err != nil { return nil, err } var updatedHMACAuth HMACAuth err = json.Unmarshal(cred, &updatedHMACAuth) if err != nil { return nil, err } return &updatedHMACAuth, nil } // Delete deletes a hmac-auth credential in Kong func (s *HMACAuthService) Delete(ctx context.Context, consumerUsernameOrID, usernameOrID *string) error { return s.client.credentials.Delete(ctx, "hmac-auth", consumerUsernameOrID, usernameOrID) } // List fetches a list of hmac-auth credentials in Kong. // opt can be used to control pagination. func (s *HMACAuthService) List(ctx context.Context, opt *ListOpt) ([]*HMACAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/hmac-auths", opt) if err != nil { return nil, nil, err } var hmacAuths []*HMACAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var hmacAuth HMACAuth err = json.Unmarshal(b, &hmacAuth) if err != nil { return nil, nil, err } hmacAuths = append(hmacAuths, &hmacAuth) } return hmacAuths, next, nil } // ListAll fetches all hmac-auth credentials in Kong. // This method can take a while if there // a lot of hmac-auth credentials present. func (s *HMACAuthService) ListAll(ctx context.Context) ([]*HMACAuth, error) { var hmacAuths, data []*HMACAuth var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } hmacAuths = append(hmacAuths, data...) } return hmacAuths, nil } // ListForConsumer fetches a list of hmac-auth credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *HMACAuthService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*HMACAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/hmac-auth", opt) if err != nil { return nil, nil, err } var hmacAuths []*HMACAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var hmacAuth HMACAuth err = json.Unmarshal(b, &hmacAuth) if err != nil { return nil, nil, err } hmacAuths = append(hmacAuths, &hmacAuth) } return hmacAuths, next, nil } go-kong-0.15.0/kong/hmac_auth_service_test.go000066400000000000000000000162601400261364200211360ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestHMACAuthCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) hmacAuth, err := client.HMACAuths.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(hmacAuth) hmacAuth = &HMACAuth{} hmacAuth, err = client.HMACAuths.Create(defaultCtx, String(""), hmacAuth) assert.NotNil(err) assert.Nil(hmacAuth) // consumer for the hmac-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) // no username is specified hmacAuth = &HMACAuth{} hmacAuth, err = client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.NotNil(err) assert.Nil(hmacAuth) hmacAuth = &HMACAuth{ Username: String("foo"), } hmacAuth, err = client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(hmacAuth) assert.NotNil(hmacAuth.Secret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestHMACAuthCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() hmacAuth := &HMACAuth{ ID: String(uuid), Username: String("my-username"), Secret: String("my-secret"), } // consumer for the hmac-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdHMACAuth, err := client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(createdHMACAuth) assert.Equal(uuid, *createdHMACAuth.ID) assert.Equal("my-username", *createdHMACAuth.Username) assert.Equal("my-secret", *createdHMACAuth.Secret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestHMACAuthGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() hmacAuth := &HMACAuth{ ID: String(uuid), Username: String("my-username"), } // consumer for the hmac-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdHMACAuth, err := client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(createdHMACAuth) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, hmacAuth.ID) assert.Nil(err) assert.Equal("my-username", *hmacAuth.Username) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, hmacAuth.Username) assert.Nil(err) assert.Equal("my-username", *hmacAuth.Username) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(hmacAuth) assert.NotNil(err) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, String("")) assert.Nil(hmacAuth) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestHMACAuthUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() hmacAuth := &HMACAuth{ ID: String(uuid), Username: String("my-username"), Secret: String("secret"), } // consumer for the hmac-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdHMACAuth, err := client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(createdHMACAuth) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, hmacAuth.ID) assert.Nil(err) assert.Equal("my-username", *hmacAuth.Username) hmacAuth.Username = String("my-new-username") hmacAuth.Secret = String("my-new-secret") updatedHMACAuth, err := client.HMACAuths.Update(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(updatedHMACAuth) assert.Equal("my-new-secret", *updatedHMACAuth.Secret) assert.Equal("my-new-username", *updatedHMACAuth.Username) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestHMACAuthDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() hmacAuth := &HMACAuth{ ID: String(uuid), Username: String("my-username"), } // consumer for the hmac-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdHMACAuth, err := client.HMACAuths.Create(defaultCtx, consumer.ID, hmacAuth) assert.Nil(err) assert.NotNil(createdHMACAuth) err = client.HMACAuths.Delete(defaultCtx, consumer.ID, hmacAuth.Username) assert.Nil(err) hmacAuth, err = client.HMACAuths.Get(defaultCtx, consumer.ID, hmacAuth.Username) assert.NotNil(err) assert.Nil(hmacAuth) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestHMACAuthListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the hmac-auth: consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures hmacAuths := []*HMACAuth{ { Username: String("username11"), Consumer: consumer1, }, { Username: String("username12"), Consumer: consumer1, }, { Username: String("username21"), Consumer: consumer2, }, { Username: String("username22"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(hmacAuths); i++ { hmacAuth, err := client.HMACAuths.Create(defaultCtx, hmacAuths[i].Consumer.ID, hmacAuths[i]) assert.Nil(err) assert.NotNil(hmacAuth) hmacAuths[i] = hmacAuth } hmacAuthsFromKong, next, err := client.HMACAuths.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(hmacAuthsFromKong) assert.Equal(4, len(hmacAuthsFromKong)) // first page page1, next, err := client.HMACAuths.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.HMACAuths.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) hmacAuthsForConsumer, next, err := client.HMACAuths.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(hmacAuthsForConsumer) assert.Equal(2, len(hmacAuthsForConsumer)) hmacAuths, err = client.HMACAuths.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(hmacAuths) assert.Equal(4, len(hmacAuths)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/jwt_auth_service.go000066400000000000000000000066071400261364200177770ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // JWTAuthService handles JWT credentials in Kong. type JWTAuthService service // Create creates a JWT credential in Kong // If an ID is specified, it will be used to // create a JWT in Kong, otherwise an ID // is auto-generated. func (s *JWTAuthService) Create(ctx context.Context, consumerUsernameOrID *string, jwtAuth *JWTAuth) (*JWTAuth, error) { cred, err := s.client.credentials.Create(ctx, "jwt-auth", consumerUsernameOrID, jwtAuth) if err != nil { return nil, err } var createdJWT JWTAuth err = json.Unmarshal(cred, &createdJWT) if err != nil { return nil, err } return &createdJWT, nil } // Get fetches a JWT credential from Kong. func (s *JWTAuthService) Get(ctx context.Context, consumerUsernameOrID, keyOrID *string) (*JWTAuth, error) { cred, err := s.client.credentials.Get(ctx, "jwt-auth", consumerUsernameOrID, keyOrID) if err != nil { return nil, err } var jwtAuth JWTAuth err = json.Unmarshal(cred, &jwtAuth) if err != nil { return nil, err } return &jwtAuth, nil } // Update updates a JWT credential in Kong func (s *JWTAuthService) Update(ctx context.Context, consumerUsernameOrID *string, jwtAuth *JWTAuth) (*JWTAuth, error) { cred, err := s.client.credentials.Update(ctx, "jwt-auth", consumerUsernameOrID, jwtAuth) if err != nil { return nil, err } var updatedJWT JWTAuth err = json.Unmarshal(cred, &updatedJWT) if err != nil { return nil, err } return &updatedJWT, nil } // Delete deletes a JWT credential in Kong func (s *JWTAuthService) Delete(ctx context.Context, consumerUsernameOrID, keyOrID *string) error { return s.client.credentials.Delete(ctx, "jwt-auth", consumerUsernameOrID, keyOrID) } // List fetches a list of JWT credentials in Kong. // opt can be used to control pagination. func (s *JWTAuthService) List(ctx context.Context, opt *ListOpt) ([]*JWTAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/jwts", opt) if err != nil { return nil, nil, err } var jwts []*JWTAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var jwtAuth JWTAuth err = json.Unmarshal(b, &jwtAuth) if err != nil { return nil, nil, err } jwts = append(jwts, &jwtAuth) } return jwts, next, nil } // ListAll fetches all JWT credentials in Kong. // This method can take a while if there // a lot of JWT credentials present. func (s *JWTAuthService) ListAll(ctx context.Context) ([]*JWTAuth, error) { var jwts, data []*JWTAuth var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } jwts = append(jwts, data...) } return jwts, nil } // ListForConsumer fetches a list of jwt credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *JWTAuthService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*JWTAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/jwt", opt) if err != nil { return nil, nil, err } var jwts []*JWTAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var jwtAuth JWTAuth err = json.Unmarshal(b, &jwtAuth) if err != nil { return nil, nil, err } jwts = append(jwts, &jwtAuth) } return jwts, next, nil } go-kong-0.15.0/kong/jwt_auth_service_test.go000066400000000000000000000151631400261364200210330ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestJWTCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) jwt, err := client.JWTAuths.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(jwt) jwt = &JWTAuth{} jwt, err = client.JWTAuths.Create(defaultCtx, String(""), jwt) assert.NotNil(err) assert.Nil(jwt) jwt, err = client.JWTAuths.Create(defaultCtx, String("does-not-exist"), jwt) assert.NotNil(err) assert.Nil(jwt) // consumer for the JWT consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) jwt = &JWTAuth{ Key: String("foo"), RSAPublicKey: String("bar"), } jwt, err = client.JWTAuths.Create(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(jwt) assert.NotEmpty(*jwt.Secret) assert.Equal("bar", *jwt.RSAPublicKey) assert.NotEmpty(*jwt.Algorithm) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestJWTCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() jwt := &JWTAuth{ ID: String(uuid), Key: String("my-key"), Secret: String("my-secret"), } // consumer for the jwt consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdJWT, err := client.JWTAuths.Create(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(createdJWT) assert.Equal(uuid, *createdJWT.ID) assert.Equal("my-key", *createdJWT.Key) assert.Equal("my-secret", *createdJWT.Secret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestJWTGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() jwt := &JWTAuth{ ID: String(uuid), Key: String("my-key"), } // consumer for the jwt consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdJWT, err := client.JWTAuths.Create(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(createdJWT) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, jwt.ID) assert.Nil(err) assert.Equal("my-key", *jwt.Key) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, jwt.Key) assert.Nil(err) assert.Equal("my-key", *jwt.Key) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(jwt) assert.NotNil(err) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, String("")) assert.Nil(jwt) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestJWTUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() jwt := &JWTAuth{ ID: String(uuid), Key: String("my-key"), } // consumer for the jwt consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdJWT, err := client.JWTAuths.Create(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(createdJWT) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, jwt.ID) assert.Nil(err) assert.Equal("my-key", *jwt.Key) jwt.Key = String("my-new-key") jwt.Secret = String("my-new-secret") updatedJWT, err := client.JWTAuths.Update(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(updatedJWT) assert.Equal("my-new-secret", *updatedJWT.Secret) assert.Equal("my-new-key", *updatedJWT.Key) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestJWTDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() jwt := &JWTAuth{ ID: String(uuid), Key: String("my-key"), } // consumer for the jwt consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdJWT, err := client.JWTAuths.Create(defaultCtx, consumer.ID, jwt) assert.Nil(err) assert.NotNil(createdJWT) err = client.JWTAuths.Delete(defaultCtx, consumer.ID, jwt.Key) assert.Nil(err) jwt, err = client.JWTAuths.Get(defaultCtx, consumer.ID, jwt.Key) assert.NotNil(err) assert.Nil(jwt) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestJWTListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the JWT consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures jwts := []*JWTAuth{ { Key: String("username11"), Consumer: consumer1, }, { Key: String("username12"), Consumer: consumer1, }, { Key: String("username21"), Consumer: consumer2, }, { Key: String("username22"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(jwts); i++ { jwt, err := client.JWTAuths.Create(defaultCtx, jwts[i].Consumer.ID, jwts[i]) assert.Nil(err) assert.NotNil(jwt) jwts[i] = jwt } jwtsFromKong, next, err := client.JWTAuths.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(jwtsFromKong) assert.Equal(4, len(jwtsFromKong)) // first page page1, next, err := client.JWTAuths.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.JWTAuths.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) jwtsForConsumer, next, err := client.JWTAuths.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(jwtsForConsumer) assert.Equal(2, len(jwtsForConsumer)) jwts, err = client.JWTAuths.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(jwts) assert.Equal(4, len(jwts)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/key_auth_service.go000066400000000000000000000070131400261364200177530ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // KeyAuthService handles key-auth credentials in Kong. type KeyAuthService service // Create creates a key-auth credential in Kong // If an ID is specified, it will be used to // create a key-auth in Kong, otherwise an ID // is auto-generated. func (s *KeyAuthService) Create(ctx context.Context, consumerUsernameOrID *string, keyAuth *KeyAuth) (*KeyAuth, error) { cred, err := s.client.credentials.Create(ctx, "key-auth", consumerUsernameOrID, keyAuth) if err != nil { return nil, err } var createdKeyAuth KeyAuth err = json.Unmarshal(cred, &createdKeyAuth) if err != nil { return nil, err } return &createdKeyAuth, nil } // Get fetches a key-auth credential from Kong. func (s *KeyAuthService) Get(ctx context.Context, consumerUsernameOrID, keyOrID *string) (*KeyAuth, error) { cred, err := s.client.credentials.Get(ctx, "key-auth", consumerUsernameOrID, keyOrID) if err != nil { return nil, err } var keyAuth KeyAuth err = json.Unmarshal(cred, &keyAuth) if err != nil { return nil, err } return &keyAuth, nil } // Update updates a key-auth credential in Kong func (s *KeyAuthService) Update(ctx context.Context, consumerUsernameOrID *string, keyAuth *KeyAuth) (*KeyAuth, error) { cred, err := s.client.credentials.Update(ctx, "key-auth", consumerUsernameOrID, keyAuth) if err != nil { return nil, err } var updatedKeyAuth KeyAuth err = json.Unmarshal(cred, &updatedKeyAuth) if err != nil { return nil, err } return &updatedKeyAuth, nil } // Delete deletes a key-auth credential in Kong func (s *KeyAuthService) Delete(ctx context.Context, consumerUsernameOrID, keyOrID *string) error { return s.client.credentials.Delete(ctx, "key-auth", consumerUsernameOrID, keyOrID) } // List fetches a list of key-auth credentials in Kong. // opt can be used to control pagination. func (s *KeyAuthService) List(ctx context.Context, opt *ListOpt) ([]*KeyAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/key-auths", opt) if err != nil { return nil, nil, err } var keyAuths []*KeyAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var keyAuth KeyAuth err = json.Unmarshal(b, &keyAuth) if err != nil { return nil, nil, err } keyAuths = append(keyAuths, &keyAuth) } return keyAuths, next, nil } // ListAll fetches all key-auth credentials in Kong. // This method can take a while if there // a lot of key-auth credentials present. func (s *KeyAuthService) ListAll(ctx context.Context) ([]*KeyAuth, error) { var keyAuths, data []*KeyAuth var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } keyAuths = append(keyAuths, data...) } return keyAuths, nil } // ListForConsumer fetches a list of key-auth credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *KeyAuthService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*KeyAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/key-auth", opt) if err != nil { return nil, nil, err } var keyAuths []*KeyAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var keyAuth KeyAuth err = json.Unmarshal(b, &keyAuth) if err != nil { return nil, nil, err } keyAuths = append(keyAuths, &keyAuth) } return keyAuths, next, nil } go-kong-0.15.0/kong/key_auth_service_test.go000066400000000000000000000167021400261364200210170ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestKeyAuthCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) keyAuth, err := client.KeyAuths.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(keyAuth) keyAuth = &KeyAuth{} keyAuth, err = client.KeyAuths.Create(defaultCtx, String(""), keyAuth) assert.NotNil(err) assert.Nil(keyAuth) keyAuth, err = client.KeyAuths.Create(defaultCtx, String("does-not-exist"), keyAuth) assert.NotNil(err) assert.Nil(keyAuth) // consumer for the key-auth consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) keyAuth = &KeyAuth{} createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestKeyAuthCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() keyAuth := &KeyAuth{ ID: String(uuid), Key: String("my-apikey"), } // consumer for the key-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) assert.Equal(uuid, *createdKeyAuth.ID) assert.Equal("my-apikey", *createdKeyAuth.Key) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestKeyAuthGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() keyAuth := &KeyAuth{ ID: String(uuid), Key: String("my-apikey"), } // consumer for the key-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) searchKeyAuth, err := client.KeyAuths.Get(defaultCtx, consumer.ID, keyAuth.ID) assert.Nil(err) assert.Equal("my-apikey", *searchKeyAuth.Key) searchKeyAuth, err = client.KeyAuths.Get(defaultCtx, consumer.ID, keyAuth.Key) assert.Nil(err) assert.Equal("my-apikey", *searchKeyAuth.Key) searchKeyAuth, err = client.KeyAuths.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(searchKeyAuth) assert.NotNil(err) searchKeyAuth, err = client.KeyAuths.Get(defaultCtx, consumer.ID, String("")) assert.Nil(searchKeyAuth) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestKeyAuthUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() keyAuth := &KeyAuth{ ID: String(uuid), Key: String("my-apikey"), } // consumer for the key-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) searchKeyAuth, err := client.KeyAuths.Get(defaultCtx, consumer.ID, keyAuth.ID) assert.Nil(err) assert.Equal("my-apikey", *searchKeyAuth.Key) keyAuth.Key = String("my-new-apikey") updatedKeyAuth, err := client.KeyAuths.Update(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(updatedKeyAuth) assert.Equal("my-new-apikey", *updatedKeyAuth.Key) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestKeyAuthDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() keyAuth := &KeyAuth{ ID: String(uuid), Key: String("my-apikey"), } // consumer for the key-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) err = client.KeyAuths.Delete(defaultCtx, consumer.ID, keyAuth.Key) assert.Nil(err) searchKeyAuth, err := client.KeyAuths.Get(defaultCtx, consumer.ID, keyAuth.ID) assert.NotNil(err) assert.Nil(searchKeyAuth) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestKeyAuthListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the key-auth: consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures keyAuths := []*KeyAuth{ { Key: String("key11"), Consumer: consumer1, }, { Key: String("key12"), Consumer: consumer1, }, { Key: String("key21"), Consumer: consumer2, }, { Key: String("key22"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(keyAuths); i++ { keyAuth, err := client.KeyAuths.Create(defaultCtx, keyAuths[i].Consumer.ID, keyAuths[i]) assert.Nil(err) assert.NotNil(keyAuth) keyAuths[i] = keyAuth } keyAuthsFromKong, next, err := client.KeyAuths.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(keyAuthsFromKong) assert.Equal(4, len(keyAuthsFromKong)) // first page page1, next, err := client.KeyAuths.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.KeyAuths.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) keyAuthsForConsumer, next, err := client.KeyAuths.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(keyAuthsForConsumer) assert.Equal(2, len(keyAuthsForConsumer)) keyAuths, err = client.KeyAuths.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(keyAuths) assert.Equal(4, len(keyAuths)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } func TestKeyAuthCreateWithTTL(T *testing.T) { runWhenKong(T, ">=1.4.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) keyAuth := &KeyAuth{ TTL: Int(10), Key: String("my-apikey"), } // consumer for the key-auth: consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdKeyAuth, err := client.KeyAuths.Create(defaultCtx, consumer.ID, keyAuth) assert.Nil(err) assert.NotNil(createdKeyAuth) assert.True(*createdKeyAuth.TTL < 10) assert.Equal("my-apikey", *createdKeyAuth.Key) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } go-kong-0.15.0/kong/kong.go000066400000000000000000000150601400261364200153610ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "io" "net/http" "net/http/httputil" "net/url" "os" "github.com/pkg/errors" "github.com/kong/go-kong/kong/custom" ) const defaultBaseURL = "http://localhost:8001" var pageSize = 1000 type service struct { client *Client } var ( defaultCtx = context.Background() ) // Client talks to the Admin API or control plane of a // Kong cluster type Client struct { client *http.Client baseURL string common service Consumers *ConsumerService Services *Svcservice Routes *RouteService CACertificates *CACertificateService Certificates *CertificateService Plugins *PluginService SNIs *SNIService Upstreams *UpstreamService Targets *TargetService Workspaces *WorkspaceService Admins *AdminService RBACUsers *RBACUserService RBACRoles *RBACRoleService RBACEndpointPermissions *RBACEndpointPermissionService RBACEntityPermissions *RBACEntityPermissionService credentials *credentialService KeyAuths *KeyAuthService BasicAuths *BasicAuthService HMACAuths *HMACAuthService JWTAuths *JWTAuthService MTLSAuths *MTLSAuthService ACLs *ACLService Oauth2Credentials *Oauth2Service logger io.Writer debug bool CustomEntities *CustomEntityService custom.Registry } // Status respresents current status of a Kong node. type Status struct { Database struct { Reachable bool `json:"reachable"` } `json:"database"` Server struct { ConnectionsAccepted int `json:"connections_accepted"` ConnectionsActive int `json:"connections_active"` ConnectionsHandled int `json:"connections_handled"` ConnectionsReading int `json:"connections_reading"` ConnectionsWaiting int `json:"connections_waiting"` ConnectionsWriting int `json:"connections_writing"` TotalRequests int `json:"total_requests"` } `json:"server"` } // NewClient returns a Client which talks to Admin API of Kong func NewClient(baseURL *string, client *http.Client) (*Client, error) { if client == nil { client = http.DefaultClient } kong := new(Client) kong.client = client var rootURL string if baseURL != nil { rootURL = *baseURL } else { rootURL = defaultBaseURL } url, err := url.ParseRequestURI(rootURL) if err != nil { return nil, errors.Wrap(err, "parsing URL") } kong.baseURL = url.String() kong.common.client = kong kong.Consumers = (*ConsumerService)(&kong.common) kong.Services = (*Svcservice)(&kong.common) kong.Routes = (*RouteService)(&kong.common) kong.Plugins = (*PluginService)(&kong.common) kong.Certificates = (*CertificateService)(&kong.common) kong.CACertificates = (*CACertificateService)(&kong.common) kong.SNIs = (*SNIService)(&kong.common) kong.Upstreams = (*UpstreamService)(&kong.common) kong.Targets = (*TargetService)(&kong.common) kong.Workspaces = (*WorkspaceService)(&kong.common) kong.Admins = (*AdminService)(&kong.common) kong.RBACUsers = (*RBACUserService)(&kong.common) kong.RBACRoles = (*RBACRoleService)(&kong.common) kong.RBACEndpointPermissions = (*RBACEndpointPermissionService)(&kong.common) kong.RBACEntityPermissions = (*RBACEntityPermissionService)(&kong.common) kong.credentials = (*credentialService)(&kong.common) kong.KeyAuths = (*KeyAuthService)(&kong.common) kong.BasicAuths = (*BasicAuthService)(&kong.common) kong.HMACAuths = (*HMACAuthService)(&kong.common) kong.JWTAuths = (*JWTAuthService)(&kong.common) kong.MTLSAuths = (*MTLSAuthService)(&kong.common) kong.ACLs = (*ACLService)(&kong.common) kong.Oauth2Credentials = (*Oauth2Service)(&kong.common) kong.CustomEntities = (*CustomEntityService)(&kong.common) kong.Registry = custom.NewDefaultRegistry() for i := 0; i < len(defaultCustomEntities); i++ { err := kong.Register(defaultCustomEntities[i].Type(), &defaultCustomEntities[i]) if err != nil { return nil, err } } kong.logger = os.Stderr return kong, nil } // Do executes a HTTP request and returns a response func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) { var err error if req == nil { return nil, errors.New("request cannot be nil") } if ctx == nil { ctx = defaultCtx } req = req.WithContext(ctx) // log the request err = c.logRequest(req) if err != nil { return nil, err } //Make the request resp, err := c.client.Do(req) if err != nil { return nil, errors.Wrap(err, "making HTTP request") } // log the response err = c.logResponse(resp) if err != nil { return nil, err } response := newResponse(resp) ///check for API errors if err = hasError(resp); err != nil { return response, err } // Call Close on exit defer func() { e := resp.Body.Close() if e != nil { err = e } }() // response if v != nil { if writer, ok := v.(io.Writer); ok { _, err = io.Copy(writer, resp.Body) if err != nil { return nil, err } } else { err = json.NewDecoder(resp.Body).Decode(v) if err != nil { return nil, err } } } return response, err } // SetDebugMode enables or disables logging of // the request to the logger set by SetLogger(). // By default, debug logging is disabled. func (c *Client) SetDebugMode(enableDebug bool) { c.debug = enableDebug } func (c *Client) logRequest(r *http.Request) error { if !c.debug { return nil } dump, err := httputil.DumpRequestOut(r, true) if err != nil { return err } _, err = c.logger.Write(append(dump, '\n')) return err } func (c *Client) logResponse(r *http.Response) error { if !c.debug { return nil } dump, err := httputil.DumpResponse(r, true) if err != nil { return err } _, err = c.logger.Write(append(dump, '\n')) return err } // SetLogger sets the debug logger, defaults to os.StdErr func (c *Client) SetLogger(w io.Writer) { if w == nil { return } c.logger = w } // Status returns the status of a Kong node func (c *Client) Status(ctx context.Context) (*Status, error) { req, err := c.NewRequest("GET", "/status", nil, nil) if err != nil { return nil, err } var s Status _, err = c.Do(ctx, req, &s) if err != nil { return nil, err } return &s, nil } // Root returns the response of GET request on root of // Admin API (GET /). func (c *Client) Root(ctx context.Context) (map[string]interface{}, error) { req, err := c.NewRequest("GET", "/", nil, nil) if err != nil { return nil, err } var root map[string]interface{} _, err = c.Do(ctx, req, &root) if err != nil { return nil, err } return root, nil } go-kong-0.15.0/kong/kong_test.go000066400000000000000000000100741400261364200164200ustar00rootroot00000000000000//nolint:unparam package kong import ( "context" "io/ioutil" "net/http" "os" "regexp" "strings" "testing" "github.com/blang/semver" "github.com/stretchr/testify/assert" ) func TestNewTestClient(t *testing.T) { assert := assert.New(t) client, err := NewTestClient(String("foo/bar"), nil) assert.Nil(client) assert.NotNil(err) } func TestKongStatus(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) status, err := client.Status(defaultCtx) assert.Nil(err) assert.NotNil(status) } func TestRoot(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) root, err := client.Root(defaultCtx) assert.Nil(err) assert.NotNil(root) assert.NotNil(root["version"]) } func TestDo(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) req, err := client.NewRequest("GET", "/does-not-exist", nil, nil) assert.Nil(err) assert.NotNil(req) resp, err := client.Do(context.Background(), req, nil) assert.True(IsNotFoundErr(err)) assert.NotNil(resp) assert.Equal(404, resp.StatusCode) req, err = client.NewRequest("POST", "/", nil, nil) assert.Nil(err) assert.NotNil(req) resp, err = client.Do(context.Background(), req, nil) assert.NotNil(err) assert.NotNil(resp) body, err := ioutil.ReadAll(resp.Body) assert.Nil(err) assert.Empty(body) assert.Equal(405, resp.StatusCode) } func TestMain(m *testing.M) { // to test ListAll code for pagination pageSize = 1 os.Exit(m.Run()) } var currentVersion semver.Version var r = regexp.MustCompile(`^[0-9]+\.[0-9]+`) func cleanVersionString(version string) string { res := r.FindString(version) if res == "" { panic("unexpected version of kong") } res += ".0" if strings.Contains(version, "enterprise") { res += "-enterprise" } return res } // runWhenKong skips the current test if the version of Kong doesn't // fall in the semverRange. // This helper function can be used in tests to write version specific // tests for Kong. func runWhenKong(t *testing.T, semverRange string) { if currentVersion.Major == 0 { client, err := NewTestClient(nil, nil) if err != nil { t.Error(err) } res, err := client.Root(defaultCtx) if err != nil { t.Error(err) } v := res["version"].(string) currentVersion, err = semver.Parse(cleanVersionString(v)) if err != nil { t.Error(err) } } r, err := semver.ParseRange(semverRange) if err != nil { t.Error(err) } if !r(currentVersion) { t.Skip() } } // runWhenEnterprise skips a test if the version // of Kong running is not enterprise edition. Skips // the current test if the version of Kong doesn't // fall within the semver range. If a test requires // RBAC and RBAC is not enabled on Kong the test // will be skipped func runWhenEnterprise(t *testing.T, semverRange string, rbacRequired bool) { client, err := NewTestClient(nil, nil) if err != nil { t.Error(err) } res, err := client.Root(defaultCtx) if err != nil { t.Error(err) } v := res["version"].(string) if !strings.Contains(v, "enterprise-edition") { t.Skip() } r := res["configuration"].(map[string]interface{})["rbac"].(string) if rbacRequired && r != "on" { t.Skip() } runWhenKong(t, semverRange) } func TestRunWhenEnterprise(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", false) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) root, err := client.Root(defaultCtx) assert.Nil(err) assert.NotNil(root) v := root["version"].(string) assert.Contains(v, "enterprise") } func NewTestClient(baseURL *string, client *http.Client) (*Client, error) { if value, exists := os.LookupEnv("KONG_ADMIN_TOKEN"); exists { c := &http.Client{} defaultTransport := http.DefaultTransport.(*http.Transport) c.Transport = defaultTransport c.Transport = &headerRoundTripper{ headers: http.Header{ "kong-admin-token": []string{value}, }, rt: defaultTransport, } return NewClient(baseURL, c) } return NewClient(baseURL, client) } go-kong-0.15.0/kong/list.go000066400000000000000000000037041400261364200154000ustar00rootroot00000000000000package kong import ( "bytes" "context" "encoding/json" ) // ListOpt aids in paginating through list endpoints type ListOpt struct { // Size of the page Size int `url:"size,omitempty"` // Offset for the current page Offset string `url:"offset,omitempty"` // Tags to use for filtering the list. Tags []*string `url:"tags,omitempty"` // Tags are ORed by default, meaning entities // containing even a single tag in the list are listed. // If true, tags are ANDed, meaning only entities // matching each tag in the Tags array are listed. MatchAllTags bool } // qs is used to construct query string for list endpoints type qs struct { Size int `url:"size,omitempty"` Offset string `url:"offset,omitempty"` Tags string `url:"tags,omitempty"` } // list fetches a list of an entity in Kong. // opt can be used to control pagination. func (c *Client) list(ctx context.Context, endpoint string, opt *ListOpt) ([]json.RawMessage, *ListOpt, error) { q := constructQueryString(opt) req, err := c.NewRequest("GET", endpoint, &q, nil) if err != nil { return nil, nil, err } var list struct { Data []json.RawMessage `json:"data"` Next *string `json:"offset"` } _, err = c.Do(ctx, req, &list) if err != nil { return nil, nil, err } // convinient for end user to use this opt till it's nil var next *ListOpt if list.Next != nil { next = &ListOpt{ Offset: *list.Next, } if opt != nil && next != nil { next.Size = opt.Size next.Tags = opt.Tags next.MatchAllTags = opt.MatchAllTags } } return list.Data, next, nil } func constructQueryString(opt *ListOpt) qs { var q qs if opt == nil { return q } q.Size = opt.Size q.Offset = opt.Offset var tagQS bytes.Buffer tagCount := len(opt.Tags) for i := 0; i < tagCount; i++ { tagQS.WriteString(*opt.Tags[i]) if i+1 < tagCount { if opt.MatchAllTags { tagQS.WriteByte(',') } else { tagQS.WriteByte('/') } } } q.Tags = tagQS.String() return q } go-kong-0.15.0/kong/list_test.go000066400000000000000000000021111400261364200164260ustar00rootroot00000000000000package kong import ( "reflect" "testing" ) func TestConstructQueryString(t *testing.T) { } func Test_constructQueryString(t *testing.T) { type args struct { opt *ListOpt } tests := []struct { name string args args want qs }{ { "nil opt", args{}, qs{}, }, { "empty opt", args{opt: &ListOpt{}}, qs{}, }, { "size", args{opt: &ListOpt{Size: 42}}, qs{Size: 42}, }, { "offset", args{opt: &ListOpt{Offset: "42"}}, qs{Offset: "42"}, }, { "Single tag", args{opt: &ListOpt{Tags: StringSlice("tag1")}}, qs{Tags: "tag1"}, }, { "Multiple AND tags", args{opt: &ListOpt{Tags: StringSlice("tag1", "tag2", "tag3")}}, qs{Tags: "tag1/tag2/tag3"}, }, { "Multiple AND tags", args{opt: &ListOpt{Tags: StringSlice("tag1", "tag2", "tag3"), MatchAllTags: true}}, qs{Tags: "tag1,tag2,tag3"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := constructQueryString(tt.args.opt); !reflect.DeepEqual(got, tt.want) { t.Errorf("constructQueryString() = %v, want %v", got, tt.want) } }) } } go-kong-0.15.0/kong/mtls_auth_service.go000066400000000000000000000067351400261364200201540ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // MTLSAuthService handles MTLS credentials in Kong. type MTLSAuthService service // Create creates an MTLS credential in Kong // If an ID is specified, it will be used to // create a MTLS in Kong, otherwise an ID // is auto-generated. func (s *MTLSAuthService) Create(ctx context.Context, consumerUsernameOrID *string, mtlsAuth *MTLSAuth) (*MTLSAuth, error) { cred, err := s.client.credentials.Create(ctx, "mtls-auth", consumerUsernameOrID, mtlsAuth) if err != nil { return nil, err } var createdMTLS MTLSAuth err = json.Unmarshal(cred, &createdMTLS) if err != nil { return nil, err } return &createdMTLS, nil } // Get fetches an MTLS credential from Kong. func (s *MTLSAuthService) Get(ctx context.Context, consumerUsernameOrID, keyOrID *string) (*MTLSAuth, error) { cred, err := s.client.credentials.Get(ctx, "mtls-auth", consumerUsernameOrID, keyOrID) if err != nil { return nil, err } var mtlsAuth MTLSAuth err = json.Unmarshal(cred, &mtlsAuth) if err != nil { return nil, err } return &mtlsAuth, nil } // Update updates an MTLS credential in Kong func (s *MTLSAuthService) Update(ctx context.Context, consumerUsernameOrID *string, mtlsAuth *MTLSAuth) (*MTLSAuth, error) { cred, err := s.client.credentials.Update(ctx, "mtls-auth", consumerUsernameOrID, mtlsAuth) if err != nil { return nil, err } var updatedMTLS MTLSAuth err = json.Unmarshal(cred, &updatedMTLS) if err != nil { return nil, err } return &updatedMTLS, nil } // Delete deletes an MTLS credential in Kong func (s *MTLSAuthService) Delete(ctx context.Context, consumerUsernameOrID, keyOrID *string) error { return s.client.credentials.Delete(ctx, "mtls-auth", consumerUsernameOrID, keyOrID) } // List fetches a list of MTLS credentials in Kong. // opt can be used to control pagination. func (s *MTLSAuthService) List(ctx context.Context, opt *ListOpt) ([]*MTLSAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/mtls-auths", opt) if err != nil { return nil, nil, err } var mtlss []*MTLSAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var mtlsAuth MTLSAuth err = json.Unmarshal(b, &mtlsAuth) if err != nil { return nil, nil, err } mtlss = append(mtlss, &mtlsAuth) } return mtlss, next, nil } // ListAll fetches all MTLS credentials in Kong. // This method can take a while if there // a lot of MTLS credentials present. func (s *MTLSAuthService) ListAll(ctx context.Context) ([]*MTLSAuth, error) { var mtlss, data []*MTLSAuth var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } mtlss = append(mtlss, data...) } return mtlss, nil } // ListForConsumer fetches a list of mtls credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *MTLSAuthService) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*MTLSAuth, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/mtls-auth", opt) if err != nil { return nil, nil, err } var mtlss []*MTLSAuth for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var mtlsAuth MTLSAuth err = json.Unmarshal(b, &mtlsAuth) if err != nil { return nil, nil, err } mtlss = append(mtlss, &mtlsAuth) } return mtlss, next, nil } go-kong-0.15.0/kong/mtls_auth_service_test.go000066400000000000000000000165141400261364200212070ustar00rootroot00000000000000// +build enterprise package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestMTLSCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) mtls, err := client.MTLSAuths.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(mtls) mtls = &MTLSAuth{} mtls, err = client.MTLSAuths.Create(defaultCtx, String(""), mtls) assert.NotNil(err) assert.Nil(mtls) mtls, err = client.MTLSAuths.Create(defaultCtx, String("does-not-exist"), mtls) assert.NotNil(err) assert.Nil(mtls) // consumer for the MTLS consumer := &Consumer{ Username: String("foo"), } // without a CA certificate attached consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) mtls = &MTLSAuth{ SubjectName: String("test@example.com"), } mtls, err = client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(mtls) assert.Equal("test@example.com", *mtls.SubjectName) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) // with a CA certificate attached consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) certificate := &CACertificate{ Cert: String(caCert1), } createdCertificate, err := client.CACertificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) mtls = &MTLSAuth{ SubjectName: String("test@example.com"), CACertificate: createdCertificate, } mtls, err = client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(mtls) assert.Equal("test@example.com", *mtls.SubjectName) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestMTLSCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() mtls := &MTLSAuth{ ID: String(uuid), SubjectName: String("test@example.com"), } // consumer for the mtls consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdMTLS, err := client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(createdMTLS) assert.Equal(uuid, *createdMTLS.ID) assert.Equal("test@example.com", *mtls.SubjectName) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestMTLSGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() mtls := &MTLSAuth{ ID: String(uuid), SubjectName: String("test@example.com"), } // consumer for the mtls consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdMTLS, err := client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(createdMTLS) mtls, err = client.MTLSAuths.Get(defaultCtx, consumer.ID, mtls.ID) assert.Nil(err) assert.Equal("test@example.com", *mtls.SubjectName) mtls, err = client.MTLSAuths.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(mtls) assert.NotNil(err) mtls, err = client.MTLSAuths.Get(defaultCtx, consumer.ID, String("")) assert.Nil(mtls) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestMTLSUpdate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() mtls := &MTLSAuth{ ID: String(uuid), SubjectName: String("test@example.com"), } // consumer for the mtls consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdMTLS, err := client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(createdMTLS) mtls, err = client.MTLSAuths.Get(defaultCtx, consumer.ID, mtls.ID) assert.Nil(err) assert.Equal("test@example.com", *mtls.SubjectName) mtls.SubjectName = String("different@example.com") updatedMTLS, err := client.MTLSAuths.Update(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(updatedMTLS) assert.Equal("different@example.com", *updatedMTLS.SubjectName) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestMTLSDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() mtls := &MTLSAuth{ ID: String(uuid), SubjectName: String("test@example.com"), } // consumer for the mtls consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdMTLS, err := client.MTLSAuths.Create(defaultCtx, consumer.ID, mtls) assert.Nil(err) assert.NotNil(createdMTLS) err = client.MTLSAuths.Delete(defaultCtx, consumer.ID, mtls.ID) assert.Nil(err) mtls, err = client.MTLSAuths.Get(defaultCtx, consumer.ID, mtls.ID) assert.NotNil(err) assert.Nil(mtls) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestMTLSListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the MTLS consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures mtlss := []*MTLSAuth{ { SubjectName: String("username11@example.com"), Consumer: consumer1, }, { SubjectName: String("username12@example.com"), Consumer: consumer1, }, { SubjectName: String("username21@example.com"), Consumer: consumer2, }, { SubjectName: String("username22@example.com"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(mtlss); i++ { mtls, err := client.MTLSAuths.Create(defaultCtx, mtlss[i].Consumer.ID, mtlss[i]) assert.Nil(err) assert.NotNil(mtls) mtlss[i] = mtls } mtlssFromKong, next, err := client.MTLSAuths.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(mtlssFromKong) assert.Equal(4, len(mtlssFromKong)) // first page page1, next, err := client.MTLSAuths.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.MTLSAuths.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) mtlssForConsumer, next, err := client.MTLSAuths.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(mtlssForConsumer) assert.Equal(2, len(mtlssForConsumer)) mtlss, err = client.MTLSAuths.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(mtlss) assert.Equal(4, len(mtlss)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/oauth2_auth_service.go000066400000000000000000000073621400261364200203740ustar00rootroot00000000000000package kong import ( "context" "encoding/json" ) // Oauth2Service handles oauth2 credentials in Kong. type Oauth2Service service // Create creates an oauth2 credential in Kong // If an ID is specified, it will be used to // create a oauth2 credential in Kong, otherwise an ID // is auto-generated. func (s *Oauth2Service) Create(ctx context.Context, consumerUsernameOrID *string, oauth2Cred *Oauth2Credential) (*Oauth2Credential, error) { cred, err := s.client.credentials.Create(ctx, "oauth2", consumerUsernameOrID, oauth2Cred) if err != nil { return nil, err } var createdOauth2Cred Oauth2Credential err = json.Unmarshal(cred, &createdOauth2Cred) if err != nil { return nil, err } return &createdOauth2Cred, nil } // Get fetches an oauth2 credential from Kong. func (s *Oauth2Service) Get(ctx context.Context, consumerUsernameOrID, clientIDorID *string) (*Oauth2Credential, error) { cred, err := s.client.credentials.Get(ctx, "oauth2", consumerUsernameOrID, clientIDorID) if err != nil { return nil, err } var oauth2Cred Oauth2Credential err = json.Unmarshal(cred, &oauth2Cred) if err != nil { return nil, err } return &oauth2Cred, nil } // Update updates an oauth2 credential in Kong. func (s *Oauth2Service) Update(ctx context.Context, consumerUsernameOrID *string, oauth2Cred *Oauth2Credential) (*Oauth2Credential, error) { cred, err := s.client.credentials.Update(ctx, "oauth2", consumerUsernameOrID, oauth2Cred) if err != nil { return nil, err } var updatedHMACAuth Oauth2Credential err = json.Unmarshal(cred, &updatedHMACAuth) if err != nil { return nil, err } return &updatedHMACAuth, nil } // Delete deletes an oauth2 credential in Kong. func (s *Oauth2Service) Delete(ctx context.Context, consumerUsernameOrID, clientIDorID *string) error { return s.client.credentials.Delete(ctx, "oauth2", consumerUsernameOrID, clientIDorID) } // List fetches a list of oauth2 credentials in Kong. // opt can be used to control pagination. func (s *Oauth2Service) List(ctx context.Context, opt *ListOpt) ([]*Oauth2Credential, *ListOpt, error) { data, next, err := s.client.list(ctx, "/oauth2", opt) if err != nil { return nil, nil, err } var oauth2Creds []*Oauth2Credential for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var oauth2Cred Oauth2Credential err = json.Unmarshal(b, &oauth2Cred) if err != nil { return nil, nil, err } oauth2Creds = append(oauth2Creds, &oauth2Cred) } return oauth2Creds, next, nil } // ListAll fetches all oauth2 credentials in Kong. // This method can take a while if there // a lot of oauth2 credentials present. func (s *Oauth2Service) ListAll( ctx context.Context) ([]*Oauth2Credential, error) { var oauth2Creds, data []*Oauth2Credential var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } oauth2Creds = append(oauth2Creds, data...) } return oauth2Creds, nil } // ListForConsumer fetches a list of oauth2 credentials // in Kong associated with a specific consumer. // opt can be used to control pagination. func (s *Oauth2Service) ListForConsumer(ctx context.Context, consumerUsernameOrID *string, opt *ListOpt) ([]*Oauth2Credential, *ListOpt, error) { data, next, err := s.client.list(ctx, "/consumers/"+*consumerUsernameOrID+"/oauth2", opt) if err != nil { return nil, nil, err } var oauth2Creds []*Oauth2Credential for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var oauth2Cred Oauth2Credential err = json.Unmarshal(b, &oauth2Cred) if err != nil { return nil, nil, err } oauth2Creds = append(oauth2Creds, &oauth2Cred) } return oauth2Creds, next, nil } go-kong-0.15.0/kong/oauth2_auth_service_test.go000066400000000000000000000207331400261364200214300ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestOauth2CredentialCreate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) oauth2Cred, err := client.Oauth2Credentials.Create(defaultCtx, String("foo"), nil) assert.NotNil(err) assert.Nil(oauth2Cred) oauth2Cred = &Oauth2Credential{} oauth2Cred, err = client.Oauth2Credentials.Create(defaultCtx, String(""), oauth2Cred) assert.NotNil(err) assert.Nil(oauth2Cred) // consumer for the oauth2 cred consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) oauth2Cred = &Oauth2Credential{ ClientID: String("foo"), Name: String("name-foo"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), } oauth2Cred, err = client.Oauth2Credentials.Create(defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(oauth2Cred) assert.NotNil(oauth2Cred.ClientSecret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestOauth2CredentialCreateWithID(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() oauth2Cred := &Oauth2Credential{ ID: String(uuid), Name: String("name"), ClientSecret: String("my-client-secret"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), ClientID: String("my-clientid"), } // consumer for the oauth2 cred consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdOauth2Credential, err := client.Oauth2Credentials.Create( defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(createdOauth2Credential) assert.Equal(uuid, *createdOauth2Credential.ID) assert.Equal("my-clientid", *createdOauth2Credential.ClientID) assert.Equal("my-client-secret", *createdOauth2Credential.ClientSecret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestOauth2CredentialGet(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() oauth2Cred := &Oauth2Credential{ ID: String(uuid), Name: String("name-foo"), ClientID: String("foo-clientid"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), } // consumer for the oauth2 cred consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdOauth2Credential, err := client.Oauth2Credentials.Create(defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(createdOauth2Credential) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, oauth2Cred.ID) assert.Nil(err) assert.Equal("foo-clientid", *oauth2Cred.ClientID) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, String("foo-clientid")) assert.Nil(err) assert.NotNil(oauth2Cred) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, String("does-not-exists")) assert.Nil(oauth2Cred) assert.NotNil(err) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, String("")) assert.Nil(oauth2Cred) assert.NotNil(err) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestOauth2CredentialUpdate(T *testing.T) { runWhenKong(T, "<2.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() oauth2Cred := &Oauth2Credential{ ID: String(uuid), ClientID: String("client-id"), Name: String("foo-name"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), } // consumer for the oauth2 cred consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdOauth2Credential, err := client.Oauth2Credentials.Create( defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(createdOauth2Credential) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, oauth2Cred.ID) assert.Nil(err) assert.Equal("foo-name", *oauth2Cred.Name) oauth2Cred.Name = String("new-foo-name") oauth2Cred.ClientSecret = String("my-new-secret") updatedOauth2Credential, err := client.Oauth2Credentials.Update(defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(updatedOauth2Credential) assert.Equal("new-foo-name", *updatedOauth2Credential.Name) assert.Equal("my-new-secret", *updatedOauth2Credential.ClientSecret) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestOauth2CredentialDelete(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) uuid := uuid.NewV4().String() oauth2Cred := &Oauth2Credential{ ID: String(uuid), ClientID: String("my-client-id"), Name: String("my-name"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), } // consumer for the oauth2 cred consumer := &Consumer{ Username: String("foo"), } consumer, err = client.Consumers.Create(defaultCtx, consumer) assert.Nil(err) assert.NotNil(consumer) createdOauth2Credential, err := client.Oauth2Credentials.Create(defaultCtx, consumer.ID, oauth2Cred) assert.Nil(err) assert.NotNil(createdOauth2Credential) err = client.Oauth2Credentials.Delete(defaultCtx, consumer.ID, oauth2Cred.ClientID) assert.Nil(err) oauth2Cred, err = client.Oauth2Credentials.Get(defaultCtx, consumer.ID, oauth2Cred.ClientID) assert.NotNil(err) assert.Nil(oauth2Cred) assert.Nil(client.Consumers.Delete(defaultCtx, consumer.ID)) } func TestOauth2CredentialListMethods(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // consumer for the oauth2 cred consumer1 := &Consumer{ Username: String("foo"), } consumer1, err = client.Consumers.Create(defaultCtx, consumer1) assert.Nil(err) assert.NotNil(consumer1) consumer2 := &Consumer{ Username: String("bar"), } consumer2, err = client.Consumers.Create(defaultCtx, consumer2) assert.Nil(err) assert.NotNil(consumer2) // fixtures oauth2Creds := []*Oauth2Credential{ { ClientID: String("clientid11"), Name: String("name11"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), Consumer: consumer1, }, { ClientID: String("clientid12"), Name: String("name12"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), Consumer: consumer1, }, { ClientID: String("clientid21"), Name: String("name21"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), Consumer: consumer2, }, { ClientID: String("clientid22"), Name: String("name22"), RedirectURIs: StringSlice("http://foo.com", "http://bar.com"), Consumer: consumer2, }, } // create fixturs for i := 0; i < len(oauth2Creds); i++ { oauth2Cred, err := client.Oauth2Credentials.Create(defaultCtx, oauth2Creds[i].Consumer.ID, oauth2Creds[i]) assert.Nil(err) assert.NotNil(oauth2Cred) oauth2Creds[i] = oauth2Cred } oauth2CredsFromKong, next, err := client.Oauth2Credentials.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(oauth2CredsFromKong) assert.Equal(4, len(oauth2CredsFromKong)) // first page page1, next, err := client.Oauth2Credentials.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // last page next.Size = 3 page2, next, err := client.Oauth2Credentials.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(3, len(page2)) oauth2CredsForConsumer, next, err := client.Oauth2Credentials.ListForConsumer(defaultCtx, consumer1.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(oauth2CredsForConsumer) assert.Equal(2, len(oauth2CredsForConsumer)) oauth2Creds, err = client.Oauth2Credentials.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(oauth2Creds) assert.Equal(4, len(oauth2Creds)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer1.ID)) assert.Nil(client.Consumers.Delete(defaultCtx, consumer2.ID)) } go-kong-0.15.0/kong/plugin_service.go000066400000000000000000000113311400261364200174360ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // PluginService handles Plugins in Kong. type PluginService service // Create creates a Plugin in Kong. // If an ID is specified, it will be used to // create a plugin in Kong, otherwise an ID // is auto-generated. func (s *PluginService) Create(ctx context.Context, plugin *Plugin) (*Plugin, error) { queryPath := "/plugins" method := "POST" if plugin.ID != nil { queryPath = queryPath + "/" + *plugin.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, plugin) if err != nil { return nil, err } var createdPlugin Plugin _, err = s.client.Do(ctx, req, &createdPlugin) if err != nil { return nil, err } return &createdPlugin, nil } // Get fetches a Plugin in Kong. func (s *PluginService) Get(ctx context.Context, usernameOrID *string) (*Plugin, error) { if isEmptyString(usernameOrID) { return nil, errors.New("usernameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/plugins/%v", *usernameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var plugin Plugin _, err = s.client.Do(ctx, req, &plugin) if err != nil { return nil, err } return &plugin, nil } // Update updates a Plugin in Kong func (s *PluginService) Update(ctx context.Context, plugin *Plugin) (*Plugin, error) { if isEmptyString(plugin.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/plugins/%v", *plugin.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, plugin) if err != nil { return nil, err } var updatedAPI Plugin _, err = s.client.Do(ctx, req, &updatedAPI) if err != nil { return nil, err } return &updatedAPI, nil } // Delete deletes a Plugin in Kong func (s *PluginService) Delete(ctx context.Context, usernameOrID *string) error { if isEmptyString(usernameOrID) { return errors.New("usernameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/plugins/%v", *usernameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // listByPath fetches a list of Plugins in Kong // on a specific path. // This is a helper method for listing all plugins // or plugins for specific entities. func (s *PluginService) listByPath(ctx context.Context, path string, opt *ListOpt) ([]*Plugin, *ListOpt, error) { data, next, err := s.client.list(ctx, path, opt) if err != nil { return nil, nil, err } var plugins []*Plugin for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var plugin Plugin err = json.Unmarshal(b, &plugin) if err != nil { return nil, nil, err } plugins = append(plugins, &plugin) } return plugins, next, nil } // ListAll fetches all Plugins in Kong. // This method can take a while if there // a lot of Plugins present. func (s *PluginService) listAllByPath(ctx context.Context, path string) ([]*Plugin, error) { var plugins, data []*Plugin var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.listByPath(ctx, path, opt) if err != nil { return nil, err } plugins = append(plugins, data...) } return plugins, nil } // List fetches a list of Plugins in Kong. // opt can be used to control pagination. func (s *PluginService) List(ctx context.Context, opt *ListOpt) ([]*Plugin, *ListOpt, error) { return s.listByPath(ctx, "/plugins", opt) } // ListAll fetches all Plugins in Kong. // This method can take a while if there // a lot of Plugins present. func (s *PluginService) ListAll(ctx context.Context) ([]*Plugin, error) { return s.listAllByPath(ctx, "/plugins") } // ListAllForConsumer fetches all Plugins in Kong enabled for a consumer. func (s *PluginService) ListAllForConsumer(ctx context.Context, consumerIDorName *string) ([]*Plugin, error) { if isEmptyString(consumerIDorName) { return nil, errors.New("consumerIDorName cannot be nil") } return s.listAllByPath(ctx, "/consumers/"+*consumerIDorName+"/plugins") } // ListAllForService fetches all Plugins in Kong enabled for a service. func (s *PluginService) ListAllForService(ctx context.Context, serviceIDorName *string) ([]*Plugin, error) { if isEmptyString(serviceIDorName) { return nil, errors.New("serviceIDorName cannot be nil") } return s.listAllByPath(ctx, "/services/"+*serviceIDorName+"/plugins") } // ListAllForRoute fetches all Plugins in Kong enabled for a service. func (s *PluginService) ListAllForRoute(ctx context.Context, routeID *string) ([]*Plugin, error) { if isEmptyString(routeID) { return nil, errors.New("routeID cannot be nil") } return s.listAllByPath(ctx, "/routes/"+*routeID+"/plugins") } go-kong-0.15.0/kong/plugin_service_test.go000066400000000000000000000153151400261364200205030ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestPluginsService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) plugin := &Plugin{ Name: String("key-auth"), } createdPlugin, err := client.Plugins.Create(defaultCtx, plugin) assert.Nil(err) assert.NotNil(createdPlugin) plugin, err = client.Plugins.Get(defaultCtx, createdPlugin.ID) assert.Nil(err) assert.NotNil(plugin) plugin.Config["key_in_body"] = true plugin, err = client.Plugins.Update(defaultCtx, plugin) assert.Nil(err) assert.NotNil(plugin) assert.Equal(true, plugin.Config["key_in_body"]) err = client.Plugins.Delete(defaultCtx, createdPlugin.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() plugin = &Plugin{ Name: String("prometheus"), ID: String(id), } createdPlugin, err = client.Plugins.Create(defaultCtx, plugin) assert.Nil(err) assert.NotNil(createdPlugin) assert.Equal(id, *createdPlugin.ID) err = client.Plugins.Delete(defaultCtx, createdPlugin.ID) assert.Nil(err) } func TestPluginWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) plugin := &Plugin{ Name: String("key-auth"), Tags: StringSlice("tag1", "tag2"), } createdPlugin, err := client.Plugins.Create(defaultCtx, plugin) assert.Nil(err) assert.NotNil(createdPlugin) assert.Equal(StringSlice("tag1", "tag2"), createdPlugin.Tags) err = client.Plugins.Delete(defaultCtx, createdPlugin.ID) assert.Nil(err) } func TestUnknownPlugin(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) plugin, err := client.Plugins.Create(defaultCtx, &Plugin{ Name: String("plugin-not-present"), }) assert.NotNil(err) assert.Nil(plugin) } func TestPluginListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures plugins := []*Plugin{ { Name: String("key-auth"), }, { Name: String("basic-auth"), }, { Name: String("jwt"), }, } // create fixturs for i := 0; i < len(plugins); i++ { plugin, err := client.Plugins.Create(defaultCtx, plugins[i]) assert.Nil(err) assert.NotNil(plugin) plugins[i] = plugin } pluginsFromKong, next, err := client.Plugins.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(pluginsFromKong) assert.Equal(3, len(pluginsFromKong)) // check if we see all plugins assert.True(comparePlugins(plugins, pluginsFromKong)) // Test pagination pluginsFromKong = []*Plugin{} // first page page1, next, err := client.Plugins.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) pluginsFromKong = append(pluginsFromKong, page1...) // second page page2, next, err := client.Plugins.List(defaultCtx, next) assert.Nil(err) assert.NotNil(next) assert.NotNil(page2) assert.Equal(1, len(page2)) pluginsFromKong = append(pluginsFromKong, page2...) // last page page3, next, err := client.Plugins.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page3) assert.Equal(1, len(page3)) pluginsFromKong = append(pluginsFromKong, page3...) assert.True(comparePlugins(plugins, pluginsFromKong)) plugins, err = client.Plugins.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(plugins) assert.Equal(3, len(plugins)) for i := 0; i < len(plugins); i++ { assert.Nil(client.Plugins.Delete(defaultCtx, plugins[i].ID)) } } func TestPluginListAllForEntityEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures createdService, err := client.Services.Create(defaultCtx, &Service{ Name: String("foo"), Host: String("upstream"), Port: Int(42), Path: String("/path"), }) assert.Nil(err) assert.NotNil(createdService) createdRoute, err := client.Routes.Create(defaultCtx, &Route{ Hosts: StringSlice("host1.com", "host2.com"), Service: createdService, }) assert.Nil(err) assert.NotNil(createdRoute) createdConsumer, err := client.Consumers.Create(defaultCtx, &Consumer{ Username: String("foo"), }) assert.Nil(err) assert.NotNil(createdConsumer) plugins := []*Plugin{ // global { Name: String("key-auth"), }, { Name: String("basic-auth"), }, { Name: String("jwt"), }, // specific to route { Name: String("key-auth"), Route: createdRoute, }, { Name: String("jwt"), Route: createdRoute, }, // specific to service { Name: String("key-auth"), Service: createdService, }, { Name: String("jwt"), Service: createdService, }, // specific to consumer { Name: String("rate-limiting"), Consumer: createdConsumer, Config: map[string]interface{}{ "second": 1, }, }, } // create fixturs for i := 0; i < len(plugins); i++ { plugin, err := client.Plugins.Create(defaultCtx, plugins[i]) assert.Nil(err) assert.NotNil(plugin) plugins[i] = plugin } pluginsFromKong, err := client.Plugins.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(pluginsFromKong) assert.Equal(len(plugins), len(pluginsFromKong)) // check if we see all plugins assert.True(comparePlugins(plugins, pluginsFromKong)) assert.True(comparePlugins(plugins, pluginsFromKong)) pluginsFromKong, err = client.Plugins.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(pluginsFromKong) assert.Equal(8, len(pluginsFromKong)) pluginsFromKong, err = client.Plugins.ListAllForConsumer(defaultCtx, createdConsumer.ID) assert.Nil(err) assert.NotNil(pluginsFromKong) assert.Equal(1, len(pluginsFromKong)) pluginsFromKong, err = client.Plugins.ListAllForService(defaultCtx, createdService.ID) assert.Nil(err) assert.NotNil(pluginsFromKong) assert.Equal(2, len(pluginsFromKong)) pluginsFromKong, err = client.Plugins.ListAllForRoute(defaultCtx, createdRoute.ID) assert.Nil(err) assert.NotNil(pluginsFromKong) assert.Equal(2, len(pluginsFromKong)) for i := 0; i < len(plugins); i++ { assert.Nil(client.Plugins.Delete(defaultCtx, plugins[i].ID)) } assert.Nil(client.Consumers.Delete(defaultCtx, createdConsumer.ID)) assert.Nil(client.Routes.Delete(defaultCtx, createdRoute.ID)) assert.Nil(client.Services.Delete(defaultCtx, createdService.ID)) } func comparePlugins(expected, actual []*Plugin) bool { var expectedNames, actualNames []string for _, plugin := range expected { expectedNames = append(expectedNames, *plugin.Name) } for _, plugin := range actual { actualNames = append(actualNames, *plugin.Name) } return (compareSlices(expectedNames, actualNames)) } go-kong-0.15.0/kong/rbac_role_service.go000066400000000000000000000052341400261364200200750ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // RBACRoleService handles Roles in Kong. type RBACRoleService service // Create creates a Role in Kong. func (s *RBACRoleService) Create(ctx context.Context, role *RBACRole) (*RBACRole, error) { if role == nil { return nil, errors.New("cannot create a nil role") } endpoint := "/rbac/roles" method := "POST" if role.ID != nil { endpoint = endpoint + "/" + *role.ID method = "PUT" } req, err := s.client.NewRequest(method, endpoint, nil, role) if err != nil { return nil, err } var createdRole RBACRole _, err = s.client.Do(ctx, req, &createdRole) if err != nil { return nil, err } return &createdRole, nil } // Get fetches a Role in Kong. func (s *RBACRoleService) Get(ctx context.Context, nameOrID *string) (*RBACRole, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/rbac/roles/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Role RBACRole _, err = s.client.Do(ctx, req, &Role) if err != nil { return nil, err } return &Role, nil } // Update updates a Role in Kong. func (s *RBACRoleService) Update(ctx context.Context, role *RBACRole) (*RBACRole, error) { if role == nil { return nil, errors.New("cannot update a nil Role") } if isEmptyString(role.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/rbac/roles/%v", *role.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, role) if err != nil { return nil, err } var updatedRole RBACRole _, err = s.client.Do(ctx, req, &updatedRole) if err != nil { return nil, err } return &updatedRole, nil } // Delete deletes a Role in Kong func (s *RBACRoleService) Delete(ctx context.Context, RoleOrID *string) error { if isEmptyString(RoleOrID) { return errors.New("RoleOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/rbac/roles/%v", *RoleOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of all Roles in Kong. func (s *RBACRoleService) List(ctx context.Context) ([]*RBACRole, error) { data, _, err := s.client.list(ctx, "/rbac/roles/", nil) if err != nil { return nil, err } var roles []*RBACRole for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, err } var role RBACRole err = json.Unmarshal(b, &role) if err != nil { return nil, err } roles = append(roles, &role) } return roles, nil } go-kong-0.15.0/kong/rbac_role_service_test.go000066400000000000000000000036121400261364200211320ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestRBACRoleService(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) role := &RBACRole{ Name: String("roleA"), } createdRole, err := client.RBACRoles.Create(defaultCtx, role) assert.Nil(err) assert.NotNil(createdRole) role, err = client.RBACRoles.Get(defaultCtx, createdRole.ID) assert.Nil(err) assert.NotNil(role) role.Comment = String("new comment") role, err = client.RBACRoles.Update(defaultCtx, role) assert.Nil(err) assert.NotNil(role) assert.Equal("roleA", *role.Name) err = client.RBACRoles.Delete(defaultCtx, createdRole.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() role = &RBACRole{ Name: String("teamB"), ID: String(id), } createdRole, err = client.RBACRoles.Create(defaultCtx, role) assert.Nil(err) assert.NotNil(createdRole) assert.Equal(id, *createdRole.ID) err = client.RBACRoles.Delete(defaultCtx, createdRole.ID) assert.Nil(err) } func TestRBACRoleServiceList(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) roleA := &RBACRole{ Name: String("roleA"), } roleB := &RBACRole{ Name: String("roleB"), } createdRoleA, err := client.RBACRoles.Create(defaultCtx, roleA) assert.Nil(err) createdRoleB, err := client.RBACRoles.Create(defaultCtx, roleB) assert.Nil(err) roles, err := client.RBACRoles.List(defaultCtx) assert.Nil(err) assert.NotNil(roles) // Counts default roles (super-admin, admin, read-only) assert.Equal(5, len(roles)) err = client.RBACRoles.Delete(defaultCtx, createdRoleA.ID) assert.Nil(err) err = client.RBACRoles.Delete(defaultCtx, createdRoleB.ID) assert.Nil(err) } go-kong-0.15.0/kong/rbac_user_service.go000066400000000000000000000141171400261364200201120ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" "strings" ) // RBACUserService handles Users in Kong. type RBACUserService service // Create creates an RBAC User in Kong. func (s *RBACUserService) Create(ctx context.Context, user *RBACUser) (*RBACUser, error) { if user == nil { return nil, errors.New("cannot create a nil user") } endpoint := "/rbac/users" method := "POST" if user.ID != nil { endpoint = endpoint + "/" + *user.ID method = "PUT" } req, err := s.client.NewRequest(method, endpoint, nil, user) if err != nil { return nil, err } var createdUser RBACUser _, err = s.client.Do(ctx, req, &createdUser) if err != nil { return nil, err } return &createdUser, nil } // Get fetches a User in Kong. func (s *RBACUserService) Get(ctx context.Context, nameOrID *string) (*RBACUser, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/rbac/users/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var RBACUser RBACUser _, err = s.client.Do(ctx, req, &RBACUser) if err != nil { return nil, err } return &RBACUser, nil } // Update updates a User in Kong. func (s *RBACUserService) Update(ctx context.Context, user *RBACUser) (*RBACUser, error) { if user == nil { return nil, errors.New("cannot update a nil User") } if isEmptyString(user.ID) && isEmptyString(user.Name) { return nil, errors.New("ID and Name cannot both be nil for Update operation") } endpoint := fmt.Sprintf("/rbac/users/%v", *user.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, user) if err != nil { return nil, err } var updatedUser RBACUser _, err = s.client.Do(ctx, req, &updatedUser) if err != nil { return nil, err } return &updatedUser, nil } // Delete deletes a User in Kong func (s *RBACUserService) Delete(ctx context.Context, userOrID *string) error { if isEmptyString(userOrID) { return errors.New("UserOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/rbac/users/%v", *userOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Users in Kong. // opt can be used to control pagination. func (s *RBACUserService) List(ctx context.Context, opt *ListOpt) ([]*RBACUser, *ListOpt, error) { data, next, err := s.client.list(ctx, "/rbac/users/", opt) if err != nil { return nil, nil, err } var users []*RBACUser for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var user RBACUser err = json.Unmarshal(b, &user) if err != nil { return nil, nil, err } users = append(users, &user) } return users, next, nil } // ListAll fetches all users in Kong. func (s *RBACUserService) ListAll(ctx context.Context) ([]*RBACUser, error) { var users, data []*RBACUser var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } users = append(users, data...) } return users, nil } // AddRoles adds a comma separated list of roles to a User. func (s *RBACUserService) AddRoles(ctx context.Context, nameOrID *string, roles []*RBACRole) ([]*RBACRole, error) { var updateRoles struct { NameOrID *string `json:"name_or_id,omitempty" yaml:"name_or_id,omitempty"` Roles *string `json:"roles,omitempty" yaml:"roles,omitempty"` } // Flatten roles var r []string for _, role := range roles { r = append(r, *role.Name) } updateRoles.NameOrID = nameOrID updateRoles.Roles = String(strings.Join(r, ",")) endpoint := fmt.Sprintf("/rbac/users/%v/roles", *nameOrID) req, err := s.client.NewRequest("POST", endpoint, nil, updateRoles) if err != nil { return nil, err } var listRoles struct { Roles []*RBACRole `json:"roles,omitempty" yaml:"roles,omitempty"` User *RBACUser `json:"user,omitempty" yaml:"user,omitempty"` } _, err = s.client.Do(ctx, req, &listRoles) if err != nil { return nil, fmt.Errorf("error updating roles: %v", err) } return listRoles.Roles, nil } // DeleteRoles deletes roles associated with a User func (s *RBACUserService) DeleteRoles(ctx context.Context, nameOrID *string, roles []*RBACRole) error { var updateRoles struct { NameOrID *string `json:"name_or_id,omitempty" yaml:"name_or_id,omitempty"` Roles *string `json:"roles,omitempty" yaml:"roles,omitempty"` } // Flatten roles var r []string for _, role := range roles { r = append(r, *role.Name) } updateRoles.NameOrID = nameOrID updateRoles.Roles = String(strings.Join(r, ",")) endpoint := fmt.Sprintf("/rbac/users/%v/roles", *nameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, updateRoles) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) if err != nil { return fmt.Errorf("error deleting roles: %v", err) } return nil } // ListRoles returns a slice of Kong RBAC roles associated with a User. func (s *RBACUserService) ListRoles(ctx context.Context, nameOrID *string) ([]*RBACRole, error) { endpoint := fmt.Sprintf("/rbac/users/%v/roles", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var listRoles struct { Roles []*RBACRole `json:"roles,omitempty" yaml:"roles,omitempty"` } _, err = s.client.Do(ctx, req, &listRoles) if err != nil { return nil, fmt.Errorf("error retrieving list of roles: %v", err) } return listRoles.Roles, nil } // ListPermissions returns the entity and endpoint permissions associated with a user. func (s *RBACUserService) ListPermissions(ctx context.Context, nameOrID *string) (*RBACPermissionsList, error) { endpoint := fmt.Sprintf("/rbac/users/%v/permissions", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var permissionsList RBACPermissionsList _, err = s.client.Do(ctx, req, &permissionsList) if err != nil { return nil, fmt.Errorf("error retrieving list of permissions for role: %v", err) } return &permissionsList, nil } go-kong-0.15.0/kong/rbac_user_service_test.go000066400000000000000000000101351400261364200211450ustar00rootroot00000000000000package kong import ( "net/url" "path" "testing" "github.com/stretchr/testify/assert" ) func TestRBACUserService(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) user := &RBACUser{ Name: String("newUser"), Enabled: Bool(true), Comment: String("testing"), UserToken: String("foo"), } createdUser, err := client.RBACUsers.Create(defaultCtx, user) assert.Nil(err) assert.NotNil(createdUser) user, err = client.RBACUsers.Get(defaultCtx, createdUser.ID) assert.Nil(err) assert.NotNil(user) user.Comment = String("new comment") user, err = client.RBACUsers.Update(defaultCtx, user) assert.Nil(err) assert.NotNil(user) assert.Equal("new comment", *user.Comment) err = client.RBACUsers.Delete(defaultCtx, createdUser.ID) assert.Nil(err) } func TestRBACUserServiceWorkspace(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspace := Workspace{ Name: String("test-workspace"), } createdWorkspace, err := client.Workspaces.Create(defaultCtx, &workspace) assert.Nil(err) assert.NotNil(createdWorkspace) // Setup Workspace aware client url, err := url.Parse(defaultBaseURL) assert.Nil(err) url.Path = path.Join(url.Path, *createdWorkspace.Name) workspaceClient, err := NewTestClient(String(url.String()), nil) assert.Nil(err) assert.NotNil(workspaceClient) user := &RBACUser{ Name: String("newUser"), Enabled: Bool(true), Comment: String("testing"), UserToken: String("foo"), } createdUser, err := workspaceClient.RBACUsers.Create(defaultCtx, user) assert.Nil(err) assert.NotNil(createdUser) user, err = workspaceClient.RBACUsers.Get(defaultCtx, createdUser.ID) assert.Nil(err) assert.NotNil(user) user.Comment = String("new comment") user, err = workspaceClient.RBACUsers.Update(defaultCtx, user) assert.Nil(err) assert.NotNil(user) assert.Equal("new comment", *user.Comment) err = workspaceClient.RBACUsers.Delete(defaultCtx, createdUser.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.Name) assert.Nil(err) } func TestUserRoles(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", true) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) roleA := &RBACRole{ Name: String("roleA"), } roleB := &RBACRole{ Name: String("roleB"), } createdRoleA, err := client.RBACRoles.Create(defaultCtx, roleA) assert.Nil(err) createdRoleB, err := client.RBACRoles.Create(defaultCtx, roleB) assert.Nil(err) ep := &RBACEndpointPermission{ Role: &RBACRole{ ID: createdRoleA.ID, }, Endpoint: String("/rbac"), Actions: []*string{ String("create"), String("read"), }, } createdEndpointPermission, err := client.RBACEndpointPermissions.Create(defaultCtx, ep) assert.Nil(err) assert.NotNil(createdEndpointPermission) user := &RBACUser{ Name: String("newUser"), Enabled: Bool(true), Comment: String("testing"), UserToken: String("foo"), } createdUser, err := client.RBACUsers.Create(defaultCtx, user) assert.Nil(err) assert.NotNil(createdUser) roles := []*RBACRole{ createdRoleA, createdRoleB, } updatedUser, err := client.RBACUsers.AddRoles(defaultCtx, createdUser.ID, roles) assert.Nil(err) assert.NotNil(updatedUser) roleList, err := client.RBACUsers.ListRoles(defaultCtx, createdUser.ID) assert.Nil(err) assert.NotNil(roleList) assert.Equal(2, len(roleList)) permissionsList, err := client.RBACUsers.ListPermissions(defaultCtx, createdUser.ID) assert.Nil(err) assert.NotNil(permissionsList) assert.Equal(1, len(permissionsList.Endpoints)) err = client.RBACEndpointPermissions.Delete( defaultCtx, createdRoleA.ID, String("default"), createdEndpointPermission.Endpoint) assert.Nil(err) err = client.RBACUsers.Delete(defaultCtx, createdUser.ID) assert.Nil(err) err = client.RBACRoles.Delete(defaultCtx, createdRoleA.ID) assert.Nil(err) err = client.RBACRoles.Delete(defaultCtx, createdRoleB.ID) assert.Nil(err) } go-kong-0.15.0/kong/request.go000066400000000000000000000020361400261364200161120ustar00rootroot00000000000000package kong import ( "bytes" "encoding/json" "errors" "net/http" "github.com/google/go-querystring/query" ) // NewRequest creates a request based on the inputs. // endpoint should be relative to the baseURL specified during // client creation. // body is always marshaled into JSON. func (c *Client) NewRequest(method, endpoint string, qs interface{}, body interface{}) (*http.Request, error) { if endpoint == "" { return nil, errors.New("endpoint can't be nil") } //body to be sent in JSON var buf []byte if body != nil { var err error buf, err = json.Marshal(body) if err != nil { return nil, err } } //Create a new request req, err := http.NewRequest(method, c.baseURL+endpoint, bytes.NewBuffer(buf)) if err != nil { return nil, err } // add body if needed if body != nil { req.Header.Add("Content-Type", "application/json") } // add query string if any if qs != nil { values, err := query.Values(qs) if err != nil { return nil, err } req.URL.RawQuery = values.Encode() } return req, nil } go-kong-0.15.0/kong/response.go000066400000000000000000000014051400261364200162570ustar00rootroot00000000000000package kong import ( "encoding/json" "fmt" "io/ioutil" "net/http" ) // Response is a Kong Admin API response. It wraps http.Response. type Response struct { *http.Response //other Kong specific fields } func newResponse(res *http.Response) *Response { return &Response{Response: res} } func messageFromBody(b []byte) string { s := struct { Message string }{} if err := json.Unmarshal(b, &s); err != nil { return fmt.Sprintf("", err) } return s.Message } func hasError(res *http.Response) error { if res.StatusCode >= 200 && res.StatusCode <= 399 { return nil } body, _ := ioutil.ReadAll(res.Body) // TODO error in error? return &APIError{ httpCode: res.StatusCode, message: messageFromBody(body), } } go-kong-0.15.0/kong/response_test.go000066400000000000000000000031331400261364200173160ustar00rootroot00000000000000package kong import ( "io/ioutil" "net/http" "strings" "testing" "github.com/stretchr/testify/assert" ) func TestHasError(T *testing.T) { for _, tt := range []struct { name string response http.Response want error }{ { name: "code 200", response: http.Response{ StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader("")), }, }, { name: "code 404", response: http.Response{ StatusCode: 404, Body: ioutil.NopCloser(strings.NewReader(`{"message": "potayto pohtato", "some": "other field"}`)), }, want: &APIError{ httpCode: 404, message: "potayto pohtato", }, }, { name: "code 404, message field missing", response: http.Response{ StatusCode: 404, Body: ioutil.NopCloser(strings.NewReader(`{"nothing": "nothing"}`)), }, want: &APIError{ httpCode: 404, message: "", }, }, { name: "code 404, empty body", response: http.Response{ StatusCode: 404, Body: ioutil.NopCloser(strings.NewReader(``)), }, want: &APIError{ httpCode: 404, message: "", }, }, { name: "code 404, unparseable json", response: http.Response{ StatusCode: 404, Body: ioutil.NopCloser(strings.NewReader(`This is not json`)), }, want: &APIError{ httpCode: 404, message: "", }, }, } { T.Run(tt.name, func(T *testing.T) { got := hasError(&tt.response) assert.Equal(T, tt.want, got) }) } } go-kong-0.15.0/kong/route_service.go000066400000000000000000000104451400261364200173030ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // RouteService handles routes in Kong. type RouteService service // Create creates a Route in Kong // If an ID is specified, it will be used to // create a route in Kong, otherwise an ID // is auto-generated. func (s *RouteService) Create(ctx context.Context, route *Route) (*Route, error) { if route == nil { return nil, errors.New("cannot create a nil route") } endpoint := "/routes" method := "POST" if route.ID != nil { endpoint = endpoint + "/" + *route.ID method = "PUT" } req, err := s.client.NewRequest(method, endpoint, nil, route) if err != nil { return nil, err } var createdRoute Route _, err = s.client.Do(ctx, req, &createdRoute) if err != nil { return nil, err } return &createdRoute, nil } // CreateInService creates a route associated with serviceID func (s *RouteService) CreateInService(ctx context.Context, serviceID *string, route *Route) (*Route, error) { if isEmptyString(serviceID) { return nil, errors.New("serviceID cannot be nil for creating a route") } if route == nil { return nil, errors.New("cannot create a nil route") } r := *route r.Service = &Service{ID: serviceID} return s.Create(ctx, &r) } // Get fetches a Route in Kong. func (s *RouteService) Get(ctx context.Context, nameOrID *string) (*Route, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/routes/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var route Route _, err = s.client.Do(ctx, req, &route) if err != nil { return nil, err } return &route, nil } // Update updates a Route in Kong func (s *RouteService) Update(ctx context.Context, route *Route) (*Route, error) { if route == nil { return nil, errors.New("cannot update a nil route") } if isEmptyString(route.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/routes/%v", *route.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, route) if err != nil { return nil, err } var updatedRoute Route _, err = s.client.Do(ctx, req, &updatedRoute) if err != nil { return nil, err } return &updatedRoute, nil } // Delete deletes a Route in Kong func (s *RouteService) Delete(ctx context.Context, nameOrID *string) error { if isEmptyString(nameOrID) { return errors.New("nameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/routes/%v", *nameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Routes in Kong. // opt can be used to control pagination. func (s *RouteService) List(ctx context.Context, opt *ListOpt) ([]*Route, *ListOpt, error) { data, next, err := s.client.list(ctx, "/routes", opt) if err != nil { return nil, nil, err } var routes []*Route for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var route Route err = json.Unmarshal(b, &route) if err != nil { return nil, nil, err } routes = append(routes, &route) } return routes, next, nil } // ListAll fetches all Routes in Kong. // This method can take a while if there // a lot of Routes present. func (s *RouteService) ListAll(ctx context.Context) ([]*Route, error) { var routes, data []*Route var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } routes = append(routes, data...) } return routes, nil } // ListForService fetches a list of Routes in Kong associated with a service. // opt can be used to control pagination. func (s *RouteService) ListForService(ctx context.Context, serviceNameOrID *string, opt *ListOpt) ([]*Route, *ListOpt, error) { data, next, err := s.client.list(ctx, "/services/"+*serviceNameOrID+"/routes", opt) if err != nil { return nil, nil, err } var routes []*Route for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var route Route err = json.Unmarshal(b, &route) if err != nil { return nil, nil, err } routes = append(routes, &route) } return routes, next, nil } go-kong-0.15.0/kong/route_service_test.go000066400000000000000000000154571400261364200203520ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestRoutesRoute(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) route := &Route{} routeNotCreated, err := client.Routes.Create(defaultCtx, route) assert.NotNil(err) assert.Nil(routeNotCreated) // service for the route service := &Service{ Name: String("foo2"), Host: String("upstream"), Port: Int(42), Path: String("/path"), } service, err = client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(service) route = &Route{ Hosts: StringSlice("host1.com", "host2.com"), Service: service, } createdRoute, err := client.Routes.Create(defaultCtx, route) assert.Nil(err) assert.NotNil(createdRoute) route, err = client.Routes.Get(defaultCtx, createdRoute.ID) assert.Nil(err) assert.NotNil(route) assert.Empty(route.Methods) assert.Empty(route.Paths) route.Hosts = StringSlice("newHost.com") route.Methods = StringSlice("GET", "POST") route, err = client.Routes.Update(defaultCtx, route) assert.Nil(err) assert.NotNil(route) assert.Equal(1, len(route.Hosts)) assert.Equal("newHost.com", *route.Hosts[0]) err = client.Routes.Delete(defaultCtx, createdRoute.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() route = &Route{ ID: String(id), Name: String("new-route"), SNIs: StringSlice("snihost1.com", "snihost2.com"), Protocols: StringSlice("tcp", "tls"), Destinations: []*CIDRPort{ { IP: String("10.0.0.0/8"), Port: Int(80), }, }, Service: service, } createdRoute, err = client.Routes.Create(defaultCtx, route) assert.Nil(err) assert.NotNil(createdRoute) assert.Equal(id, *createdRoute.ID) assert.Equal(2, len(createdRoute.SNIs)) assert.Equal("snihost1.com", *createdRoute.SNIs[0]) assert.Equal("snihost2.com", *createdRoute.SNIs[1]) assert.Equal("10.0.0.0/8", *createdRoute.Destinations[0].IP) assert.Equal(80, *createdRoute.Destinations[0].Port) err = client.Routes.Delete(defaultCtx, createdRoute.ID) assert.Nil(err) err = client.Services.Delete(defaultCtx, service.ID) assert.Nil(err) _, err = client.Routes.Create(defaultCtx, nil) assert.NotNil(err) _, err = client.Routes.Update(defaultCtx, nil) assert.NotNil(err) } func TestRouteWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) route := &Route{ Name: String("key-auth"), Paths: StringSlice("/"), Tags: StringSlice("tag1", "tag2"), } createdRoute, err := client.Routes.Create(defaultCtx, route) assert.Nil(err) assert.NotNil(createdRoute) assert.Equal(StringSlice("tag1", "tag2"), createdRoute.Tags) err = client.Routes.Delete(defaultCtx, createdRoute.ID) assert.Nil(err) } func TestCreateInRoute(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) service := &Service{ Name: String("foo"), Host: String("upstream"), Port: Int(42), Path: String("/path"), } createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) route := &Route{ Hosts: StringSlice("host1.com", "host2.com"), } // specifying name won't work routeNotCreated, err := client.Routes.CreateInService(defaultCtx, createdService.Name, route) assert.Nil(routeNotCreated) assert.NotNil(err) createdRoute, err := client.Routes.CreateInService(defaultCtx, createdService.ID, route) assert.Nil(err) assert.NotNil(createdRoute) assert.Nil(client.Routes.Delete(defaultCtx, createdRoute.ID)) assert.Nil(client.Services.Delete(defaultCtx, createdService.ID)) } func TestRouteListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) service := &Service{ Name: String("foo"), Host: String("upstream"), Port: Int(42), Path: String("/path"), } createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) // fixtures routes := []*Route{ { Paths: StringSlice("/foo1"), Service: createdService, }, { Paths: StringSlice("/foo2"), Service: createdService, }, { Paths: StringSlice("/foo3"), Service: createdService, }, } // create fixturs for i := 0; i < len(routes); i++ { route, err := client.Routes.Create(defaultCtx, routes[i]) assert.Nil(err) assert.NotNil(route) routes[i] = route } routesFromKong, next, err := client.Routes.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(routesFromKong) assert.Equal(3, len(routesFromKong)) // check if we see all routes assert.True(compareRoutes(routes, routesFromKong)) // Test pagination routesFromKong = []*Route{} // first page page1, next, err := client.Routes.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) routesFromKong = append(routesFromKong, page1...) // last page next.Size = 2 page2, next, err := client.Routes.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) routesFromKong = append(routesFromKong, page2...) assert.True(compareRoutes(routes, routesFromKong)) routesForService, next, err := client.Routes.ListForService(defaultCtx, createdService.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(routesForService) assert.True(compareRoutes(routes, routesForService)) routes, err = client.Routes.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(routes) assert.Equal(3, len(routes)) for i := 0; i < len(routes); i++ { assert.Nil(client.Routes.Delete(defaultCtx, routes[i].ID)) } assert.Nil(client.Services.Delete(defaultCtx, createdService.ID)) } func compareRoutes(expected, actual []*Route) bool { var expectedUsernames, actualUsernames []string for _, route := range expected { expectedUsernames = append(expectedUsernames, *route.Paths[0]) } for _, route := range actual { actualUsernames = append(actualUsernames, *route.Paths[0]) } return (compareSlices(expectedUsernames, actualUsernames)) } func TestRouteWithHeaders(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) route := &Route{ Name: String("route-by-header"), Headers: map[string][]string{ "foo": {"bar"}, }, Tags: StringSlice("tag1", "tag2"), } createdRoute, err := client.Routes.Create(defaultCtx, route) assert.Nil(err) assert.NotNil(createdRoute) assert.Equal(StringSlice("tag1", "tag2"), createdRoute.Tags) assert.Equal(map[string][]string{"foo": {"bar"}}, createdRoute.Headers) err = client.Routes.Delete(defaultCtx, createdRoute.ID) assert.Nil(err) } go-kong-0.15.0/kong/service_service.go000066400000000000000000000075271400261364200176140ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // Svcservice handles services in Kong. type Svcservice service // Create creates an Service in Kong // If an ID is specified, it will be used to // create a service in Kong, otherwise an ID // is auto-generated. func (s *Svcservice) Create(ctx context.Context, service *Service) (*Service, error) { if service == nil { return nil, errors.New("cannot create a nil service") } endpoint := "/services" method := "POST" if service.ID != nil { endpoint = endpoint + "/" + *service.ID method = "PUT" } req, err := s.client.NewRequest(method, endpoint, nil, service) if err != nil { return nil, err } var createdService Service _, err = s.client.Do(ctx, req, &createdService) if err != nil { return nil, err } return &createdService, nil } // Get fetches an Service in Kong. func (s *Svcservice) Get(ctx context.Context, nameOrID *string) (*Service, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/services/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Service Service _, err = s.client.Do(ctx, req, &Service) if err != nil { return nil, err } return &Service, nil } // GetForRoute fetches a Service associated with routeID in Kong. func (s *Svcservice) GetForRoute(ctx context.Context, routeID *string) (*Service, error) { if isEmptyString(routeID) { return nil, errors.New("routeID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/routes/%v/service", *routeID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Service Service _, err = s.client.Do(ctx, req, &Service) if err != nil { return nil, err } return &Service, nil } // Update updates an Service in Kong func (s *Svcservice) Update(ctx context.Context, service *Service) (*Service, error) { if service == nil { return nil, errors.New("cannot update a nil service") } if isEmptyString(service.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/services/%v", *service.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, service) if err != nil { return nil, err } var updatedService Service _, err = s.client.Do(ctx, req, &updatedService) if err != nil { return nil, err } return &updatedService, nil } // Delete deletes an Service in Kong func (s *Svcservice) Delete(ctx context.Context, nameOrID *string) error { if isEmptyString(nameOrID) { return errors.New("nameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/services/%v", *nameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Services in Kong. // opt can be used to control pagination. func (s *Svcservice) List(ctx context.Context, opt *ListOpt) ([]*Service, *ListOpt, error) { data, next, err := s.client.list(ctx, "/services", opt) if err != nil { return nil, nil, err } var services []*Service for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var service Service err = json.Unmarshal(b, &service) if err != nil { return nil, nil, err } services = append(services, &service) } return services, next, nil } // ListAll fetches all Services in Kong. // This method can take a while if there // a lot of Services present. func (s *Svcservice) ListAll(ctx context.Context) ([]*Service, error) { var services, data []*Service var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } services = append(services, data...) } return services, nil } go-kong-0.15.0/kong/service_service_test.go000066400000000000000000000125261400261364200206460ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestServicesService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) service := &Service{ Name: String("foo"), Host: String("upstream"), Port: Int(42), Path: String("/path"), } createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) service, err = client.Services.Get(defaultCtx, createdService.ID) assert.Nil(err) assert.NotNil(service) service.Name = String("bar") service.Host = String("newUpstream") service, err = client.Services.Update(defaultCtx, service) assert.Nil(err) assert.NotNil(service) assert.Equal("bar", *service.Name) assert.Equal("newUpstream", *service.Host) assert.Equal(42, *service.Port) route, err := client.Routes.CreateInService(defaultCtx, service.ID, &Route{ Paths: StringSlice("/route"), }) assert.Nil(err) assert.NotNil(route) serviceForRoute, err := client.Services.GetForRoute(defaultCtx, route.ID) assert.Nil(err) assert.NotNil(serviceForRoute) assert.Equal(*service.ID, *serviceForRoute.ID) err = client.Routes.Delete(defaultCtx, route.ID) assert.Nil(err) err = client.Services.Delete(defaultCtx, service.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() service = &Service{ Name: String("fizz"), ID: String(id), Host: String("buzz"), } createdService, err = client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) assert.Equal(id, *createdService.ID) assert.Equal("buzz", *createdService.Host) err = client.Services.Delete(defaultCtx, createdService.ID) assert.Nil(err) _, err = client.Services.Create(defaultCtx, nil) assert.NotNil(err) _, err = client.Services.Update(defaultCtx, nil) assert.NotNil(err) } func TestServiceWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) service := &Service{ Name: String("key-auth"), Host: String("example.com"), Tags: StringSlice("tag1", "tag2"), } createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) assert.Equal(StringSlice("tag1", "tag2"), createdService.Tags) err = client.Services.Delete(defaultCtx, createdService.ID) assert.Nil(err) } func TestServiceListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures services := []*Service{ { Name: String("foo1"), Host: String("upstream1.com"), }, { Name: String("foo2"), Host: String("upstream2.com"), }, { Name: String("foo3"), Host: String("upstream3.com"), }, } // create fixturs for i := 0; i < len(services); i++ { service, err := client.Services.Create(defaultCtx, services[i]) assert.Nil(err) assert.NotNil(service) services[i] = service } servicesFromKong, next, err := client.Services.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(servicesFromKong) assert.Equal(3, len(servicesFromKong)) // check if we see all services assert.True(compareServices(services, servicesFromKong)) // Test pagination servicesFromKong = []*Service{} // first page page1, next, err := client.Services.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) servicesFromKong = append(servicesFromKong, page1...) // last page next.Size = 2 page2, next, err := client.Services.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) servicesFromKong = append(servicesFromKong, page2...) assert.True(compareServices(services, servicesFromKong)) services, err = client.Services.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(services) assert.Equal(3, len(services)) for i := 0; i < len(services); i++ { assert.Nil(client.Services.Delete(defaultCtx, services[i].ID)) } } func compareServices(expected, actual []*Service) bool { var expectedUsernames, actualUsernames []string for _, service := range expected { expectedUsernames = append(expectedUsernames, *service.Name) } for _, service := range actual { actualUsernames = append(actualUsernames, *service.Name) } return (compareSlices(expectedUsernames, actualUsernames)) } func TestServiceWithClientCert(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &Certificate{ Key: String(key1), Cert: String(cert1), } createdCertificate, err := client.Certificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) service := &Service{ Name: String("foo"), Host: String("example.com"), Protocol: String("https"), ClientCertificate: createdCertificate, } createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) assert.Equal(*createdCertificate.ID, *createdService.ClientCertificate.ID) err = client.Services.Delete(defaultCtx, createdService.ID) assert.Nil(err) err = client.Certificates.Delete(defaultCtx, createdCertificate.ID) assert.Nil(err) } go-kong-0.15.0/kong/sni_service.go000066400000000000000000000071671400261364200167450ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // SNIService handles SNIs in Kong. type SNIService service // Create creates a SNI in Kong. // If an ID is specified, it will be used to // create a sni in Kong, otherwise an ID // is auto-generated. func (s *SNIService) Create(ctx context.Context, sni *SNI) (*SNI, error) { queryPath := "/snis" method := "POST" if sni.ID != nil { queryPath = queryPath + "/" + *sni.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, sni) if err != nil { return nil, err } var createdSNI SNI _, err = s.client.Do(ctx, req, &createdSNI) if err != nil { return nil, err } return &createdSNI, nil } // Get fetches a SNI in Kong. func (s *SNIService) Get(ctx context.Context, usernameOrID *string) (*SNI, error) { if isEmptyString(usernameOrID) { return nil, errors.New( "usernameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/snis/%v", *usernameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var sni SNI _, err = s.client.Do(ctx, req, &sni) if err != nil { return nil, err } return &sni, nil } // Update updates a SNI in Kong func (s *SNIService) Update(ctx context.Context, sni *SNI) (*SNI, error) { if isEmptyString(sni.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/snis/%v", *sni.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, sni) if err != nil { return nil, err } var updatedAPI SNI _, err = s.client.Do(ctx, req, &updatedAPI) if err != nil { return nil, err } return &updatedAPI, nil } // Delete deletes a SNI in Kong func (s *SNIService) Delete(ctx context.Context, usernameOrID *string) error { if isEmptyString(usernameOrID) { return errors.New("usernameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/snis/%v", *usernameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of SNIs in Kong. // opt can be used to control pagination. func (s *SNIService) List(ctx context.Context, opt *ListOpt) ([]*SNI, *ListOpt, error) { data, next, err := s.client.list(ctx, "/snis", opt) if err != nil { return nil, nil, err } var snis []*SNI for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var sni SNI err = json.Unmarshal(b, &sni) if err != nil { return nil, nil, err } snis = append(snis, &sni) } return snis, next, nil } // ListForCertificate fetches a list of SNIs // in Kong associated with certificateID. // opt can be used to control pagination. func (s *SNIService) ListForCertificate(ctx context.Context, certificateID *string, opt *ListOpt) ([]*SNI, *ListOpt, error) { data, next, err := s.client.list(ctx, "/certificates/"+*certificateID+"/snis", opt) if err != nil { return nil, nil, err } var snis []*SNI for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var sni SNI err = json.Unmarshal(b, &sni) if err != nil { return nil, nil, err } snis = append(snis, &sni) } return snis, next, nil } // ListAll fetches all SNIs in Kong. // This method can take a while if there // a lot of SNIs present. func (s *SNIService) ListAll(ctx context.Context) ([]*SNI, error) { var snis, data []*SNI var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } snis = append(snis, data...) } return snis, nil } go-kong-0.15.0/kong/sni_service_test.go000066400000000000000000000110511400261364200177670ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestSNIsCertificate(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) sni := &SNI{ Name: String("host1.com"), } // cert is required badSNI, err := client.SNIs.Create(defaultCtx, sni) assert.NotNil(err) assert.Nil(badSNI) // create a cert fixtureCertificate, err := client.Certificates.Create(defaultCtx, &Certificate{ Key: String(key1), Cert: String(cert1), }) assert.Nil(err) assert.NotNil(fixtureCertificate) assert.NotNil(fixtureCertificate.ID) createdSNI, err := client.SNIs.Create(defaultCtx, &SNI{ Name: String("host1.com"), Certificate: fixtureCertificate, }) assert.Nil(err) assert.NotNil(createdSNI) sni, err = client.SNIs.Get(defaultCtx, createdSNI.ID) assert.Nil(err) assert.NotNil(sni) sni.Name = String("host2.com") sni, err = client.SNIs.Update(defaultCtx, sni) assert.Nil(err) assert.NotNil(sni) assert.Equal("host2.com", *sni.Name) err = client.SNIs.Delete(defaultCtx, createdSNI.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() sni = &SNI{ Name: String("host3.com"), ID: String(id), Certificate: fixtureCertificate, } createdSNI, err = client.SNIs.Create(defaultCtx, sni) assert.Nil(err) assert.NotNil(createdSNI) assert.Equal(id, *createdSNI.ID) err = client.Certificates.Delete(defaultCtx, fixtureCertificate.ID) assert.Nil(err) } func TestSNIWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) fixtureCertificate, err := client.Certificates.Create(defaultCtx, &Certificate{ Key: String(key1), Cert: String(cert1), }) assert.Nil(err) createdSNI, err := client.SNIs.Create(defaultCtx, &SNI{ Name: String("host1.com"), Certificate: fixtureCertificate, Tags: StringSlice("tag1", "tag2"), }) assert.Nil(err) assert.NotNil(createdSNI) assert.Equal(StringSlice("tag1", "tag2"), createdSNI.Tags) err = client.Certificates.Delete(defaultCtx, fixtureCertificate.ID) assert.Nil(err) } func TestSNIListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) certificate := &Certificate{ Cert: String(cert2), Key: String(key2), } createdCertificate, err := client.Certificates.Create(defaultCtx, certificate) assert.Nil(err) assert.NotNil(createdCertificate) // fixtures snis := []*SNI{ { Name: String("sni1"), Certificate: createdCertificate, }, { Name: String("sni2"), Certificate: createdCertificate, }, { Name: String("sni3"), Certificate: createdCertificate, }, } // create fixturs for i := 0; i < len(snis); i++ { sni, err := client.SNIs.Create(defaultCtx, snis[i]) assert.Nil(err) assert.NotNil(sni) snis[i] = sni } snisFromKong, next, err := client.SNIs.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(snisFromKong) assert.Equal(3, len(snisFromKong)) // check if we see all snis assert.True(compareSNIs(snis, snisFromKong)) // Test pagination snisFromKong = []*SNI{} // first page page1, next, err := client.SNIs.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) snisFromKong = append(snisFromKong, page1...) // last page next.Size = 2 page2, next, err := client.SNIs.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) snisFromKong = append(snisFromKong, page2...) assert.True(compareSNIs(snis, snisFromKong)) snisForCert, next, err := client.SNIs.ListForCertificate(defaultCtx, createdCertificate.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(snisForCert) assert.True(compareSNIs(snis, snisForCert)) snis, err = client.SNIs.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(snis) assert.Equal(3, len(snis)) for i := 0; i < len(snis); i++ { assert.Nil(client.SNIs.Delete(defaultCtx, snis[i].ID)) } assert.Nil(client.Certificates.Delete(defaultCtx, createdCertificate.ID)) } func compareSNIs(expected, actual []*SNI) bool { var expectedUsernames, actualUsernames []string for _, sni := range expected { expectedUsernames = append(expectedUsernames, *sni.Name) } for _, sni := range actual { actualUsernames = append(actualUsernames, *sni.Name) } return (compareSlices(expectedUsernames, actualUsernames)) } go-kong-0.15.0/kong/target_service.go000066400000000000000000000110041400261364200174230ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // TargetService handles Targets in Kong. type TargetService service // TODO foreign key can be read directly from the embedded key itself // upstreamNameOrID need not be an explicit parameter. // Create creates a Target in Kong under upstreamID. // If an ID is specified, it will be used to // create a target in Kong, otherwise an ID // is auto-generated. func (s *TargetService) Create(ctx context.Context, upstreamNameOrID *string, target *Target) (*Target, error) { if isEmptyString(upstreamNameOrID) { return nil, errors.New("upstreamNameOrID can not be nil") } queryPath := "/upstreams/" + *upstreamNameOrID + "/targets" method := "POST" // if target.ID != nil { // queryPath = queryPath + "/" + *target.ID // method = "PUT" // } req, err := s.client.NewRequest(method, queryPath, nil, target) if err != nil { return nil, err } var createdTarget Target _, err = s.client.Do(ctx, req, &createdTarget) if err != nil { return nil, err } return &createdTarget, nil } // Delete deletes a Target in Kong func (s *TargetService) Delete(ctx context.Context, upstreamNameOrID *string, targetOrID *string) error { if isEmptyString(upstreamNameOrID) { return errors.New("upstreamNameOrID cannot be nil for Get operation") } if isEmptyString(targetOrID) { return errors.New("targetOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/upstreams/%v/targets/%v", *upstreamNameOrID, *targetOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Targets in Kong. // opt can be used to control pagination. func (s *TargetService) List(ctx context.Context, upstreamNameOrID *string, opt *ListOpt) ([]*Target, *ListOpt, error) { if isEmptyString(upstreamNameOrID) { return nil, nil, errors.New( "upstreamNameOrID cannot be nil for Get operation") } data, next, err := s.client.list(ctx, "/upstreams/"+*upstreamNameOrID+"/targets", opt) if err != nil { return nil, nil, err } var targets []*Target for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var target Target err = json.Unmarshal(b, &target) if err != nil { return nil, nil, err } targets = append(targets, &target) } return targets, next, nil } // ListAll fetches all Targets in Kong for an upstream. func (s *TargetService) ListAll(ctx context.Context, upstreamNameOrID *string) ([]*Target, error) { var targets, data []*Target var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, upstreamNameOrID, opt) if err != nil { return nil, err } targets = append(targets, data...) } return targets, nil } // MarkHealthy marks target belonging to upstreamNameOrID as healthy in // Kong's load balancer. func (s *TargetService) MarkHealthy(ctx context.Context, upstreamNameOrID *string, target *Target) error { if target == nil { return errors.New("cannot set health status for a nil target") } if isEmptyString(target.ID) && isEmptyString(target.Target) { return errors.New("need at least one of target or ID to" + " set health status") } if isEmptyString(upstreamNameOrID) { return errors.New("upstreamNameOrID cannot be nil " + "for updating health check") } tid := target.ID if target.ID == nil { tid = target.Target } endpoint := fmt.Sprintf("/upstreams/%v/targets/%v/healthy", *upstreamNameOrID, *tid) req, err := s.client.NewRequest("POST", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // MarkUnhealthy marks target belonging to upstreamNameOrID as unhealthy in // Kong's load balancer. func (s *TargetService) MarkUnhealthy(ctx context.Context, upstreamNameOrID *string, target *Target) error { if target == nil { return errors.New("cannot set health status for a nil target") } if isEmptyString(target.ID) && isEmptyString(target.Target) { return errors.New("need at least one of target or ID to" + " set health status") } if isEmptyString(upstreamNameOrID) { return errors.New("upstreamNameOrID cannot be nil " + "for updating health check") } tid := target.ID if target.ID == nil { tid = target.Target } endpoint := fmt.Sprintf("/upstreams/%v/targets/%v/unhealthy", *upstreamNameOrID, *tid) req, err := s.client.NewRequest("POST", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } go-kong-0.15.0/kong/target_service_test.go000066400000000000000000000135131400261364200204710ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestTargetsUpstream(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) target := &Target{ Target: String("10.0.0.1"), } // upstream is required badTarget, err := client.Targets.Create(defaultCtx, nil, target) assert.NotNil(err) assert.Nil(badTarget) // create a upstream fixtureUpstream, err := client.Upstreams.Create(defaultCtx, &Upstream{ Name: String("vhost.com"), }) assert.Nil(err) assert.NotNil(fixtureUpstream) assert.NotNil(fixtureUpstream.ID) createdTarget, err := client.Targets.Create(defaultCtx, fixtureUpstream.ID, &Target{ Target: String("10.0.0.1:80"), }) assert.Nil(err) assert.NotNil(createdTarget) err = client.Targets.Delete(defaultCtx, fixtureUpstream.ID, createdTarget.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() target = &Target{ ID: String(id), Target: String("10.0.0.3"), Upstream: fixtureUpstream, } createdTarget, err = client.Targets.Create(defaultCtx, fixtureUpstream.ID, target) assert.Nil(err) assert.NotNil(createdTarget) assert.Equal(id, *createdTarget.ID) err = client.Upstreams.Delete(defaultCtx, fixtureUpstream.ID) assert.Nil(err) } func TestTargetWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) fixtureUpstream, err := client.Upstreams.Create(defaultCtx, &Upstream{ Name: String("vhost.com"), }) assert.Nil(err) createdTarget, err := client.Targets.Create(defaultCtx, fixtureUpstream.ID, &Target{ Target: String("10.0.0.1:80"), Tags: StringSlice("tag1", "tag2"), }) assert.Nil(err) assert.NotNil(createdTarget) assert.Equal(StringSlice("tag1", "tag2"), createdTarget.Tags) err = client.Upstreams.Delete(defaultCtx, fixtureUpstream.ID) assert.Nil(err) } func TestTargetListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("vhost2.com"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) // fixtures targets := []*Target{ { Target: String("10.42.1.2"), Upstream: createdUpstream, }, { Target: String("10.42.1.3"), Upstream: createdUpstream, }, { Target: String("10.42.1.4"), Upstream: createdUpstream, }, } // create fixturs for i := 0; i < len(targets); i++ { target, err := client.Targets.Create(defaultCtx, createdUpstream.ID, targets[i]) assert.Nil(err) assert.NotNil(target) targets[i] = target } targetsFromKong, next, err := client.Targets.List(defaultCtx, createdUpstream.ID, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(targetsFromKong) assert.Equal(3, len(targetsFromKong)) // check if we see all targets assert.True(compareTargets(targets, targetsFromKong)) // Test pagination targetsFromKong = []*Target{} // first page page1, next, err := client.Targets.List(defaultCtx, createdUpstream.ID, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) targetsFromKong = append(targetsFromKong, page1...) // last page next.Size = 2 page2, next, err := client.Targets.List(defaultCtx, createdUpstream.ID, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page2) assert.Equal(2, len(page2)) targetsFromKong = append(targetsFromKong, page2...) assert.True(compareTargets(targets, targetsFromKong)) targets, err = client.Targets.ListAll(defaultCtx, createdUpstream.ID) assert.Nil(err) assert.NotNil(targets) assert.Equal(3, len(targets)) assert.Nil(client.Upstreams.Delete(defaultCtx, createdUpstream.ID)) } func compareTargets(expected, actual []*Target) bool { var expectedUsernames, actualUsernames []string for _, target := range expected { expectedUsernames = append(expectedUsernames, *target.Target) } for _, target := range actual { actualUsernames = append(actualUsernames, *target.Target) } return (compareSlices(expectedUsernames, actualUsernames)) } func TestTargetMarkHealthy(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("vhost1.com"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) createdTarget, err := client.Targets.Create(defaultCtx, createdUpstream.ID, &Target{ Target: String("10.0.0.1:80"), }) assert.Nil(err) assert.NotNil(createdTarget) assert.NotNil(client.Targets.MarkHealthy(defaultCtx, createdTarget.Upstream.ID, nil)) assert.NotNil(client.Targets.MarkHealthy(defaultCtx, nil, createdTarget)) assert.Nil(client.Targets.MarkHealthy(defaultCtx, createdTarget.Upstream.ID, createdTarget)) assert.Nil(client.Upstreams.Delete(defaultCtx, createdUpstream.ID)) } func TestTargetMarkUnhealthy(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("vhost1.com"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) createdTarget, err := client.Targets.Create(defaultCtx, createdUpstream.ID, &Target{ Target: String("10.0.0.1:80"), }) assert.Nil(err) assert.NotNil(createdTarget) assert.NotNil(client.Targets.MarkUnhealthy(defaultCtx, createdTarget.Upstream.ID, nil)) assert.NotNil(client.Targets.MarkUnhealthy(defaultCtx, nil, createdTarget)) assert.Nil(client.Targets.MarkUnhealthy(defaultCtx, createdTarget.Upstream.ID, createdTarget)) assert.Nil(client.Upstreams.Delete(defaultCtx, createdUpstream.ID)) } go-kong-0.15.0/kong/types.go000066400000000000000000000451461400261364200155770ustar00rootroot00000000000000package kong import ( "encoding/json" "strings" ) // Service represents a Service in Kong. // Read https://getkong.org/docs/0.13.x/admin-api/#Service-object // +k8s:deepcopy-gen=true type Service struct { ClientCertificate *Certificate `json:"client_certificate,omitempty" yaml:"client_certificate,omitempty"` ConnectTimeout *int `json:"connect_timeout,omitempty" yaml:"connect_timeout,omitempty"` CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` Host *string `json:"host,omitempty" yaml:"host,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Path *string `json:"path,omitempty" yaml:"path,omitempty"` Port *int `json:"port,omitempty" yaml:"port,omitempty"` Protocol *string `json:"protocol,omitempty" yaml:"protocol,omitempty"` ReadTimeout *int `json:"read_timeout,omitempty" yaml:"read_timeout,omitempty"` Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"` UpdatedAt *int `json:"updated_at,omitempty" yaml:"updated_at,omitempty"` WriteTimeout *int `json:"write_timeout,omitempty" yaml:"write_timeout,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` TLSVerify *bool `json:"tls_verify,omitempty" yaml:"tls_verify,omitempty"` TLSVerifyDepth *int `json:"tls_verify_depth,omitempty" yaml:"tls_verify_depth,omitempty"` CACertificates []*string `json:"ca_certificates,omitempty" yaml:"ca_certificates,omitempty"` } // CIDRPort represents a set of CIDR and a port. // +k8s:deepcopy-gen=true type CIDRPort struct { IP *string `json:"ip,omitempty" yaml:"ip,omitempty"` Port *int `json:"port,omitempty" yaml:"port,omitempty"` } // Route represents a Route in Kong. // Read https://getkong.org/docs/0.13.x/admin-api/#Route-object // +k8s:deepcopy-gen=true type Route struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` Hosts []*string `json:"hosts,omitempty" yaml:"hosts,omitempty"` Headers map[string][]string `json:"headers,omitempty" yaml:"headers,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Methods []*string `json:"methods,omitempty" yaml:"methods,omitempty"` Paths []*string `json:"paths,omitempty" yaml:"paths,omitempty"` PathHandling *string `json:"path_handling,omitempty" yaml:"path_handling,omitempty"` PreserveHost *bool `json:"preserve_host,omitempty" yaml:"preserve_host,omitempty"` Protocols []*string `json:"protocols,omitempty" yaml:"protocols,omitempty"` RegexPriority *int `json:"regex_priority,omitempty" yaml:"regex_priority,omitempty"` Service *Service `json:"service,omitempty" yaml:"service,omitempty"` StripPath *bool `json:"strip_path,omitempty" yaml:"strip_path,omitempty"` UpdatedAt *int `json:"updated_at,omitempty" yaml:"updated_at,omitempty"` SNIs []*string `json:"snis,omitempty" yaml:"snis,omitempty"` Sources []*CIDRPort `json:"sources,omitempty" yaml:"sources,omitempty"` Destinations []*CIDRPort `json:"destinations,omitempty" yaml:"destinations,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` HTTPSRedirectStatusCode *int `json:"https_redirect_status_code,omitempty" yaml:"https_redirect_status_code,omitempty"` // Kong buffers requests and responses by default. Buffering is not always // desired, for instance if large payloads are being proxied using HTTP 1.1 // chunked encoding. // // The request and response route buffering options are enabled by default // and allow the user to disable buffering if desired for their use case. // // SEE ALSO: // - https://github.com/Kong/kong/pull/6057 // - https://docs.konghq.com/2.2.x/admin-api/#route-object // RequestBuffering *bool `json:"request_buffering,omitempty" yaml:"request_buffering,omitempty"` ResponseBuffering *bool `json:"response_buffering,omitempty" yaml:"response_buffering,omitempty"` } // Consumer represents a Consumer in Kong. // Read https://getkong.org/docs/0.13.x/admin-api/#consumer-object // +k8s:deepcopy-gen=true type Consumer struct { ID *string `json:"id,omitempty" yaml:"id,omitempty"` CustomID *string `json:"custom_id,omitempty" yaml:"custom_id,omitempty"` Username *string `json:"username,omitempty" yaml:"username,omitempty"` CreatedAt *int64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // Certificate represents a Certificate in Kong. // Read https://getkong.org/docs/0.14.x/admin-api/#certificate-object // +k8s:deepcopy-gen=true type Certificate struct { ID *string `json:"id,omitempty" yaml:"id,omitempty"` Cert *string `json:"cert,omitempty" yaml:"cert,omitempty"` Key *string `json:"key,omitempty" yaml:"key,omitempty"` CreatedAt *int64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` SNIs []*string `json:"snis,omitempty" yaml:"snis,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // SNI represents a SNI in Kong. // Read https://getkong.org/docs/0.14.x/admin-api/#sni-object // +k8s:deepcopy-gen=true type SNI struct { ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` CreatedAt *int64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` Certificate *Certificate `json:"certificate,omitempty" yaml:"certificate,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // Healthy configures thresholds and HTTP status codes // to mark targets healthy for an upstream. // +k8s:deepcopy-gen=true type Healthy struct { HTTPStatuses []int `json:"http_statuses,omitempty" yaml:"http_statuses,omitempty"` Interval *int `json:"interval,omitempty" yaml:"interval,omitempty"` Successes *int `json:"successes,omitempty" yaml:"successes,omitempty"` } // Unhealthy configures thresholds and HTTP status codes // to mark targets unhealthy. // +k8s:deepcopy-gen=true type Unhealthy struct { HTTPFailures *int `json:"http_failures,omitempty" yaml:"http_failures,omitempty"` HTTPStatuses []int `json:"http_statuses,omitempty" yaml:"http_statuses,omitempty"` TCPFailures *int `json:"tcp_failures,omitempty" yaml:"tcp_failures,omitempty"` Timeouts *int `json:"timeouts,omitempty" yaml:"timeouts,omitempty"` Interval *int `json:"interval,omitempty" yaml:"interval,omitempty"` } // ActiveHealthcheck configures active health check probing. // +k8s:deepcopy-gen=true type ActiveHealthcheck struct { Concurrency *int `json:"concurrency,omitempty" yaml:"concurrency,omitempty"` Healthy *Healthy `json:"healthy,omitempty" yaml:"healthy,omitempty"` HTTPPath *string `json:"http_path,omitempty" yaml:"http_path,omitempty"` HTTPSSni *string `json:"https_sni,omitempty" yaml:"https_sni,omitempty"` HTTPSVerifyCertificate *bool `json:"https_verify_certificate,omitempty" yaml:"https_verify_certificate,omitempty"` Type *string `json:"type,omitempty" yaml:"type,omitempty"` Timeout *int `json:"timeout,omitempty" yaml:"timeout,omitempty"` Unhealthy *Unhealthy `json:"unhealthy,omitempty" yaml:"unhealthy,omitempty"` } // PassiveHealthcheck configures passive checks around // passive health checks. // +k8s:deepcopy-gen=true type PassiveHealthcheck struct { Healthy *Healthy `json:"healthy,omitempty" yaml:"healthy,omitempty"` Type *string `json:"type,omitempty" yaml:"type,omitempty"` Unhealthy *Unhealthy `json:"unhealthy,omitempty" yaml:"unhealthy,omitempty"` } // Healthcheck represents a health-check config of an upstream // in Kong. // +k8s:deepcopy-gen=true type Healthcheck struct { Active *ActiveHealthcheck `json:"active,omitempty" yaml:"active,omitempty"` Passive *PassiveHealthcheck `json:"passive,omitempty" yaml:"passive,omitempty"` Threshold *float64 `json:"threshold,omitempty" yaml:"threshold,omitempty"` } // Upstream represents an Upstream in Kong. // +k8s:deepcopy-gen=true type Upstream struct { ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` HostHeader *string `json:"host_header,omitempty" yaml:"host_header,omitempty"` ClientCertificate *Certificate `json:"client_certificate,omitempty" yaml:"client_certificate,omitempty"` Algorithm *string `json:"algorithm,omitempty" yaml:"algorithm,omitempty"` Slots *int `json:"slots,omitempty" yaml:"slots,omitempty"` Healthchecks *Healthcheck `json:"healthchecks,omitempty" yaml:"healthchecks,omitempty"` CreatedAt *int64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` HashOn *string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"` HashFallback *string `json:"hash_fallback,omitempty" yaml:"hash_fallback,omitempty"` HashOnHeader *string `json:"hash_on_header,omitempty" yaml:"hash_on_header,omitempty"` HashFallbackHeader *string `json:"hash_fallback_header,omitempty" yaml:"hash_fallback_header,omitempty"` HashOnCookie *string `json:"hash_on_cookie,omitempty" yaml:"hash_on_cookie,omitempty"` HashOnCookiePath *string `json:"hash_on_cookie_path,omitempty" yaml:"hash_on_cookie_path,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // Target represents a Target in Kong. // +k8s:deepcopy-gen=true type Target struct { CreatedAt *float64 `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Target *string `json:"target,omitempty" yaml:"target,omitempty"` Upstream *Upstream `json:"upstream,omitempty" yaml:"upstream,omitempty"` Weight *int `json:"weight,omitempty" yaml:"weight,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // Configuration represents a config of a plugin in Kong. type Configuration map[string]interface{} // DeepCopyInto copies the receiver, writing into out. in must be non-nil. func (in Configuration) DeepCopyInto(out *Configuration) { // Resorting to JSON since interface{} cannot be DeepCopied easily. // This could be replaced using reflection-fu. // XXX Ignoring errors b, _ := json.Marshal(&in) _ = json.Unmarshal(b, out) } // DeepCopy copies the receiver, creating a new Configuration. func (in Configuration) DeepCopy() Configuration { if in == nil { return nil } out := new(Configuration) in.DeepCopyInto(out) return *out } // Plugin represents a Plugin in Kong. // Read https://getkong.org/docs/0.13.x/admin-api/#Plugin-object // +k8s:deepcopy-gen=true type Plugin struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Route *Route `json:"route,omitempty" yaml:"route,omitempty"` Service *Service `json:"service,omitempty" yaml:"service,omitempty"` Consumer *Consumer `json:"consumer,omitempty" yaml:"consumer,omitempty"` Config Configuration `json:"config,omitempty" yaml:"config,omitempty"` Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"` RunOn *string `json:"run_on,omitempty" yaml:"run_on,omitempty"` Protocols []*string `json:"protocols,omitempty" yaml:"protocols,omitempty"` Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"` } // Enterprise Entities // Workspace represents a Workspace in Kong. type Workspace struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` Config map[string]interface{} `json:"config,omitempty" yaml:"config,omitempty"` Meta map[string]interface{} `json:"meta,omitempty" yaml:"meta,omitempty"` } // Admin represents an Admin in Kong. // +k8s:deepcopy-gen=true type Admin struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Email *string `json:"email,omitempty" yaml:"email,omitempty"` Username *string `json:"username,omitempty" yaml:"username,omitempty"` Password *string `json:"password,omitempty" yaml:"password,omitempty"` CustomID *string `json:"custom_id,omitempty" yaml:"custom_id,omitempty"` RBACTokenEnabled *bool `json:"rbac_token_enabled,omitempty" yaml:"rbac_token_enabled,omitempty"` Status *int `json:"status,omitempty" yaml:"status,omitempty"` Token *string `json:"token,omitempty" yaml:"token,omitempty"` } // RBACUser represents an RBAC user in Kong Enterprise // +k8s:deepcopy-gen=true type RBACUser struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"` UserToken *string `json:"user_token,omitempty" yaml:"user_token,omitempty"` UserTokenIdent *string `json:"user_token_ident,omitempty" yaml:"user_token_ident,omitempty"` } // Workspace Entity represents a WorkspaceEntity in Kong // +k8s:deepcopy-gen=true type WorkspaceEntity struct { EntityID *string `json:"entity_id,omitempty" yaml:"entity_id,omitempty"` EntityType *string `json:"entity_type,omitempty" yaml:"entity_type,omitempty"` UniqueFieldName *string `json:"unique_field_name,omitempty" yaml:"unique_field_name,omitempty"` UniqueFieldValue *string `json:"unique_field_value,omitempty" yaml:"unique_field_value,omitempty"` WorkspaceID *string `json:"workspace_id,omitempty" yaml:"workspace_id,omitempty"` WorkspaceName *string `json:"workspace_name,omitempty" yaml:"workspace_name,omitempty"` } // RBACRole represents an RBAC Role in Kong. // +k8s:deepcopy-gen=true type RBACRole struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` ID *string `json:"id,omitempty" yaml:"id,omitempty"` Name *string `json:"name,omitempty" yaml:"name,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` IsDefault *bool `json:"is_default,omitempty" yaml:"is_default,omitempty"` } // RBACEndpointPermission represents an RBAC Endpoint Permission in Kong Enterprise // +k8s:deepcopy-gen=true type RBACEndpointPermission struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` Workspace *string `json:"workspace,omitempty" yaml:"workspace,omitempty"` Endpoint *string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` Actions []*string `json:"actions,omitempty" yaml:"actions,omitempty"` Negative *bool `json:"negative,omitempty" yaml:"negative,omitempty"` Role *RBACRole `json:"role,omitempty" yaml:"role,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` } // MarshalJSON marshals an endpoint permission into a suitable form for the Kong admin API func (e *RBACEndpointPermission) MarshalJSON() ([]byte, error) { type ep struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` Workspace *string `json:"workspace,omitempty" yaml:"workspace,omitempty"` Endpoint *string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` Actions *string `json:"actions,omitempty" yaml:"actions,omitempty"` Negative *bool `json:"negative,omitempty" yaml:"negative,omitempty"` Role *RBACRole `json:"role,omitempty" yaml:"role,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` } var actions []string for _, action := range e.Actions { actions = append(actions, *action) } return json.Marshal(&ep{ CreatedAt: e.CreatedAt, Workspace: e.Workspace, Endpoint: e.Endpoint, Actions: String(strings.Join(actions, ",")), Comment: e.Comment, }) } // RBACEntityPermission represents an RBAC Entity Permission in Kong Enterprise // +k8s:deepcopy-gen=true type RBACEntityPermission struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` EntityID *string `json:"entity_id,omitempty" yaml:"entity_id,omitempty"` EntityType *string `json:"entity_type,omitempty" yaml:"entity_type,omitempty"` Actions []*string `json:"actions,omitempty" yaml:"actions,omitempty"` Negative *bool `json:"negative,omitempty" yaml:"negative,omitempty"` Role *RBACRole `json:"role,omitempty" yaml:"role,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` } // MarshalJSON marshals an endpoint permission into a suitable form for the Kong admin API func (e *RBACEntityPermission) MarshalJSON() ([]byte, error) { type ep struct { CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"` EntityID *string `json:"entity_id,omitempty" yaml:"entity_id,omitempty"` EntityType *string `json:"entity_type,omitempty" yaml:"entity_type,omitempty"` Actions *string `json:"actions,omitempty" yaml:"actions,omitempty"` Negative *bool `json:"negative,omitempty" yaml:"negative,omitempty"` Role *RBACRole `json:"role,omitempty" yaml:"role,omitempty"` Comment *string `json:"comment,omitempty" yaml:"comment,omitempty"` } var actions []string for _, action := range e.Actions { actions = append(actions, *action) } return json.Marshal(&ep{ CreatedAt: e.CreatedAt, EntityID: e.EntityID, EntityType: e.EntityType, Actions: String(strings.Join(actions, ",")), Comment: e.Comment, }) } // PermissionsList is a list of permissions, both endpoint and entity, associated with a Role. type RBACPermissionsList struct { Endpoints map[string]interface{} `json:"endpoints,omitempty" yaml:"endpoints,omitempty"` Entities map[string]interface{} `json:"entities,omitempty" yaml:"entities,omitempty"` } go-kong-0.15.0/kong/types_test.go000066400000000000000000000011631400261364200166250ustar00rootroot00000000000000package kong import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" ) func TestConfigurationDeepCopyInto(T *testing.T) { assert := assert.New(T) var c Configuration byt := []byte(`{"int":42,"float":4.2,"strings":["foo","bar"]}`) if err := json.Unmarshal(byt, &c); err != nil { panic(err) } c2 := c.DeepCopy() assert.Equal(c, c2) // Both are independent now c["int"] = 24 assert.Equal(24, c["int"]) assert.Equal(float64(42), c2["int"]) c["strings"] = []string{"fubar"} assert.Equal([]string{"fubar"}, c["strings"].([]string)) assert.Equal([]interface{}{"foo", "bar"}, c2["strings"]) } go-kong-0.15.0/kong/upstream_service.go000066400000000000000000000065021400261364200200040ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // UpstreamService handles Upstreams in Kong. type UpstreamService service // Create creates a Upstream in Kong. // If an ID is specified, it will be used to // create a upstream in Kong, otherwise an ID // is auto-generated. func (s *UpstreamService) Create(ctx context.Context, upstream *Upstream) (*Upstream, error) { queryPath := "/upstreams" method := "POST" if upstream.ID != nil { queryPath = queryPath + "/" + *upstream.ID method = "PUT" } req, err := s.client.NewRequest(method, queryPath, nil, upstream) if err != nil { return nil, err } var createdUpstream Upstream _, err = s.client.Do(ctx, req, &createdUpstream) if err != nil { return nil, err } return &createdUpstream, nil } // Get fetches a Upstream in Kong. func (s *UpstreamService) Get(ctx context.Context, upstreamNameOrID *string) (*Upstream, error) { if isEmptyString(upstreamNameOrID) { return nil, errors.New("upstreamNameOrID cannot" + " be nil for Get operation") } endpoint := fmt.Sprintf("/upstreams/%v", *upstreamNameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var upstream Upstream _, err = s.client.Do(ctx, req, &upstream) if err != nil { return nil, err } return &upstream, nil } // Update updates a Upstream in Kong func (s *UpstreamService) Update(ctx context.Context, upstream *Upstream) (*Upstream, error) { if isEmptyString(upstream.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/upstreams/%v", *upstream.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, upstream) if err != nil { return nil, err } var updatedUpstream Upstream _, err = s.client.Do(ctx, req, &updatedUpstream) if err != nil { return nil, err } return &updatedUpstream, nil } // Delete deletes a Upstream in Kong func (s *UpstreamService) Delete(ctx context.Context, upstreamNameOrID *string) error { if isEmptyString(upstreamNameOrID) { return errors.New("upstreamNameOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/upstreams/%v", *upstreamNameOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of Upstreams in Kong. // opt can be used to control pagination. func (s *UpstreamService) List(ctx context.Context, opt *ListOpt) ([]*Upstream, *ListOpt, error) { data, next, err := s.client.list(ctx, "/upstreams", opt) if err != nil { return nil, nil, err } var upstreams []*Upstream for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var upstream Upstream err = json.Unmarshal(b, &upstream) if err != nil { return nil, nil, err } upstreams = append(upstreams, &upstream) } return upstreams, next, nil } // ListAll fetches all Upstreams in Kong. // This method can take a while if there // a lot of Upstreams present. func (s *UpstreamService) ListAll(ctx context.Context) ([]*Upstream, error) { var upstreams, data []*Upstream var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } upstreams = append(upstreams, data...) } return upstreams, nil } go-kong-0.15.0/kong/upstream_service_test.go000066400000000000000000000152271400261364200210470ustar00rootroot00000000000000package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestUpstreamsService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("virtual-host1"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) upstream, err = client.Upstreams.Get(defaultCtx, createdUpstream.ID) assert.Nil(err) assert.NotNil(upstream) upstream.Name = String("virtual-host2") upstream, err = client.Upstreams.Update(defaultCtx, upstream) assert.Nil(err) assert.NotNil(upstream) assert.Equal("virtual-host2", *upstream.Name) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() upstream = &Upstream{ Name: String("key-auth"), ID: String(id), } createdUpstream, err = client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) assert.Equal(id, *createdUpstream.ID) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } func TestUpstreamWithTags(T *testing.T) { runWhenKong(T, ">=1.1.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("key-auth"), Tags: StringSlice("tag1", "tag2"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) assert.Equal(StringSlice("tag1", "tag2"), createdUpstream.Tags) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } // regression test for #6 func TestUpstreamWithActiveUnHealthyInterval(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("upstream-foo"), Healthchecks: &Healthcheck{ Active: &ActiveHealthcheck{ Unhealthy: &Unhealthy{ Interval: Int(5), }, }, }, } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } // regression test for #6 func TestUpstreamWithPassiveUnHealthyInterval(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("upstream-foo"), Healthchecks: &Healthcheck{ Passive: &PassiveHealthcheck{ Unhealthy: &Unhealthy{ Interval: Int(5), }, }, }, } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.NotNil(err) assert.Nil(createdUpstream) } func TestUpstreamWithPassiveHealthy(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("upstream-foo"), Healthchecks: &Healthcheck{ Passive: &PassiveHealthcheck{ Type: String("http"), Healthy: &Healthy{ HTTPStatuses: []int{200, 201}, Successes: Int(3), }, }, }, } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) assert.Equal("http", *createdUpstream.Healthchecks.Passive.Type) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } func TestUpstreamWithAlgorithm(T *testing.T) { runWhenKong(T, ">=1.3.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("upstream1"), Algorithm: String("least-connections"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) assert.Equal("least-connections", *createdUpstream.Algorithm) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } func TestUpstreamListEndpoint(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) // fixtures upstreams := []*Upstream{ { Name: String("vhost1.com"), }, { Name: String("vhost2.com"), }, { Name: String("vhost3.com"), }, } // create fixturs for i := 0; i < len(upstreams); i++ { upstream, err := client.Upstreams.Create(defaultCtx, upstreams[i]) assert.Nil(err) assert.NotNil(upstream) upstreams[i] = upstream } upstreamsFromKong, next, err := client.Upstreams.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(upstreamsFromKong) assert.Equal(3, len(upstreamsFromKong)) // check if we see all upstreams assert.True(compareUpstreams(upstreams, upstreamsFromKong)) // Test pagination upstreamsFromKong = []*Upstream{} // first page page1, next, err := client.Upstreams.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) upstreamsFromKong = append(upstreamsFromKong, page1...) // second page page2, next, err := client.Upstreams.List(defaultCtx, next) assert.Nil(err) assert.NotNil(next) assert.NotNil(page2) assert.Equal(1, len(page2)) upstreamsFromKong = append(upstreamsFromKong, page2...) // last page page3, next, err := client.Upstreams.List(defaultCtx, next) assert.Nil(err) assert.Nil(next) assert.NotNil(page3) assert.Equal(1, len(page3)) upstreamsFromKong = append(upstreamsFromKong, page3...) assert.True(compareUpstreams(upstreams, upstreamsFromKong)) upstreams, err = client.Upstreams.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(upstreams) assert.Equal(3, len(upstreams)) for i := 0; i < len(upstreams); i++ { assert.Nil(client.Upstreams.Delete(defaultCtx, upstreams[i].ID)) } } func compareUpstreams(expected, actual []*Upstream) bool { var expectedNames, actualNames []string for _, upstream := range expected { expectedNames = append(expectedNames, *upstream.Name) } for _, upstream := range actual { actualNames = append(actualNames, *upstream.Name) } return (compareSlices(expectedNames, actualNames)) } func TestUpstreamsWithHostHeader(T *testing.T) { runWhenKong(T, ">=1.4.0") assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) upstream := &Upstream{ Name: String("upstream-with-host-header"), HostHeader: String("example.com"), } createdUpstream, err := client.Upstreams.Create(defaultCtx, upstream) assert.Nil(err) assert.NotNil(createdUpstream) assert.Equal("example.com", *createdUpstream.HostHeader) err = client.Upstreams.Delete(defaultCtx, createdUpstream.ID) assert.Nil(err) } go-kong-0.15.0/kong/utils.go000066400000000000000000000035751400261364200155730ustar00rootroot00000000000000package kong import ( "bytes" "net/http" "strings" ) // String returns pointer to s. func String(s string) *string { return &s } // Bool returns a pointer to b. func Bool(b bool) *bool { return &b } // Int returns a pointer to i. func Int(i int) *int { return &i } func isEmptyString(s *string) bool { return s == nil || strings.TrimSpace(*s) == "" } // StringSlice converts a slice of string to a // slice of *string func StringSlice(elements ...string) []*string { var res []*string for _, element := range elements { e := element res = append(res, &e) } return res } func stringArrayToString(arr []*string) string { if arr == nil { return "nil" } var buf bytes.Buffer buf.WriteString("[ ") l := len(arr) for i, el := range arr { buf.WriteString(*el) if i != l-1 { buf.WriteString(", ") } } buf.WriteString(" ]") return buf.String() } // headerRoundTripper injects Headers into requests // made via RT. type headerRoundTripper struct { headers http.Header rt http.RoundTripper } // RoundTrip satisfies the RoundTripper interface. func (t headerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { newRequest := new(http.Request) *newRequest = *req newRequest.Header = make(http.Header, len(req.Header)) for k, s := range req.Header { newRequest.Header[k] = append([]string(nil), s...) } for k, v := range t.headers { newRequest.Header[k] = v } return t.rt.RoundTrip(newRequest) } // RoundTripperWithHTTPHeaders returns a client which injects headers // before sending any request. func HTTPClientWithHeaders(client *http.Client, headers http.Header) http.Client { var res http.Client if client == nil { defaultTransport := http.DefaultTransport.(*http.Transport) res.Transport = defaultTransport } else { res = *client } res.Transport = headerRoundTripper{ headers: headers, rt: client.Transport, } return res } go-kong-0.15.0/kong/utils_test.go000066400000000000000000000016221400261364200166210ustar00rootroot00000000000000package kong import ( "testing" "github.com/stretchr/testify/assert" ) func TestStringArrayToString(t *testing.T) { assert := assert.New(t) arr := StringSlice("foo", "bar") s := stringArrayToString(arr) assert.Equal("[ foo, bar ]", s) arr = StringSlice("foo") s = stringArrayToString(arr) assert.Equal("[ foo ]", s) assert.Equal(stringArrayToString(nil), "nil") } func TestString(t *testing.T) { assert := assert.New(t) s := String("foo") assert.Equal("foo", *s) } func TestBool(t *testing.T) { assert := assert.New(t) b := Bool(true) assert.Equal(true, *b) } func TestInt(t *testing.T) { assert := assert.New(t) i := Int(42) assert.Equal(42, *i) } func TestStringSlice(t *testing.T) { assert := assert.New(t) arrp := StringSlice() assert.Empty(arrp) arrp = StringSlice("foo", "bar") assert.Equal(2, len(arrp)) assert.Equal("foo", *arrp[0]) assert.Equal("bar", *arrp[1]) } go-kong-0.15.0/kong/workspace_service.go000066400000000000000000000131151400261364200201400ustar00rootroot00000000000000package kong import ( "context" "encoding/json" "errors" "fmt" ) // WorkspaceService handles Workspaces in Kong. type WorkspaceService service // Create creates a Workspace in Kong. func (s *WorkspaceService) Create(ctx context.Context, workspace *Workspace) (*Workspace, error) { if workspace == nil { return nil, errors.New("cannot create a nil workspace") } endpoint := "/workspaces" method := "POST" if workspace.ID != nil { endpoint = endpoint + "/" + *workspace.ID method = "PUT" } req, err := s.client.NewRequest(method, endpoint, nil, workspace) if err != nil { return nil, err } var createdWorkspace Workspace _, err = s.client.Do(ctx, req, &createdWorkspace) if err != nil { return nil, err } return &createdWorkspace, nil } // Get fetches a Workspace in Kong. func (s *WorkspaceService) Get(ctx context.Context, nameOrID *string) (*Workspace, error) { if isEmptyString(nameOrID) { return nil, errors.New("nameOrID cannot be nil for Get operation") } endpoint := fmt.Sprintf("/workspaces/%v", *nameOrID) req, err := s.client.NewRequest("GET", endpoint, nil, nil) if err != nil { return nil, err } var Workspace Workspace _, err = s.client.Do(ctx, req, &Workspace) if err != nil { return nil, err } return &Workspace, nil } // Update updates a Workspace in Kong. Only updates to the // `comment` field are supported. To rename a workspace use Create. func (s *WorkspaceService) Update(ctx context.Context, workspace *Workspace) (*Workspace, error) { if workspace == nil { return nil, errors.New("cannot update a nil Workspace") } if isEmptyString(workspace.ID) { return nil, errors.New("ID cannot be nil for Update operation") } endpoint := fmt.Sprintf("/workspaces/%v", *workspace.ID) req, err := s.client.NewRequest("PATCH", endpoint, nil, workspace) if err != nil { return nil, err } var updatedWorkspace Workspace _, err = s.client.Do(ctx, req, &updatedWorkspace) if err != nil { return nil, err } return &updatedWorkspace, nil } // Delete deletes a Workspace in Kong func (s *WorkspaceService) Delete(ctx context.Context, WorkspaceOrID *string) error { if isEmptyString(WorkspaceOrID) { return errors.New("WorkspaceOrID cannot be nil for Delete operation") } endpoint := fmt.Sprintf("/workspaces/%v", *WorkspaceOrID) req, err := s.client.NewRequest("DELETE", endpoint, nil, nil) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) return err } // List fetches a list of all Workspaces in Kong. func (s *WorkspaceService) List(ctx context.Context, opt *ListOpt) ([]*Workspace, *ListOpt, error) { data, next, err := s.client.list(ctx, "/workspaces/", opt) if err != nil { return nil, nil, err } var workspaces []*Workspace for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, nil, err } var workspace Workspace err = json.Unmarshal(b, &workspace) if err != nil { return nil, nil, err } workspaces = append(workspaces, &workspace) } return workspaces, next, nil } // ListAll fetches all workspaces in Kong. func (s *WorkspaceService) ListAll(ctx context.Context) ([]*Workspace, error) { var workspaces, data []*Workspace var err error opt := &ListOpt{Size: pageSize} for opt != nil { data, opt, err = s.List(ctx, opt) if err != nil { return nil, err } workspaces = append(workspaces, data...) } return workspaces, nil } // AddEntities adds entity ids given as a a comma delimited string // to a given workspace in Kong. The response is a representation // of the entity that was added to the workspace. func (s *WorkspaceService) AddEntities(ctx context.Context, workspaceNameOrID *string, entityIds *string) (*[]map[string]interface{}, error) { if entityIds == nil { return nil, errors.New("entityIds cannot be nil") } endpoint := fmt.Sprintf("/workspaces/%v/entities", *workspaceNameOrID) var entities struct { Entities *string `json:"entities,omitempty"` } entities.Entities = entityIds req, err := s.client.NewRequest("POST", endpoint, nil, entities) if err != nil { return nil, err } var createdWorkspaceEntities []map[string]interface{} _, err = s.client.Do(ctx, req, &createdWorkspaceEntities) if err != nil { return nil, err } return &createdWorkspaceEntities, nil } // DeleteEntities deletes entity ids given as a a comma delimited string // to a given workspace in Kong. func (s *WorkspaceService) DeleteEntities(ctx context.Context, workspaceNameOrID *string, entityIds *string) error { if entityIds == nil { return errors.New("entityIds cannot be nil") } endpoint := fmt.Sprintf("/workspaces/%v/entities", *workspaceNameOrID) var entities struct { Entities *string `json:"entities,omitempty"` } entities.Entities = entityIds req, err := s.client.NewRequest("DELETE", endpoint, nil, entities) if err != nil { return err } _, err = s.client.Do(ctx, req, nil) if err != nil { return err } return nil } // ListEntities fetches a list of all workspace entities in Kong. func (s *WorkspaceService) ListEntities(ctx context.Context, workspaceNameOrID *string) ([]*WorkspaceEntity, error) { endpoint := fmt.Sprintf("/workspaces/%v/entities", *workspaceNameOrID) data, _, err := s.client.list(ctx, endpoint, nil) if err != nil { return nil, err } var workspaceEntities []*WorkspaceEntity for _, object := range data { b, err := object.MarshalJSON() if err != nil { return nil, err } var workspaceEntity WorkspaceEntity err = json.Unmarshal(b, &workspaceEntity) if err != nil { return nil, err } workspaceEntities = append(workspaceEntities, &workspaceEntity) } return workspaceEntities, nil } go-kong-0.15.0/kong/workspace_service_test.go000066400000000000000000000113541400261364200212020ustar00rootroot00000000000000// +build enterprise package kong import ( "testing" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestWorkspaceService(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspace := &Workspace{ Name: String("teamA"), Meta: map[string]interface{}{ "color": "#814CA6", "thumbnail": nil, }, } createdWorkspace, err := client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) workspace, err = client.Workspaces.Get(defaultCtx, createdWorkspace.ID) assert.Nil(err) assert.NotNil(workspace) workspace.Comment = String("new comment") workspace, err = client.Workspaces.Update(defaultCtx, workspace) assert.Nil(err) assert.NotNil(workspace) assert.NotNil(workspace.Config) assert.Equal("teamA", *workspace.Name) assert.Equal("new comment", *workspace.Comment) assert.Equal("#814CA6", workspace.Meta["color"]) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) // ID can be specified id := uuid.NewV4().String() workspace = &Workspace{ Name: String("teamB"), ID: String(id), } createdWorkspace, err = client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) assert.Equal(id, *createdWorkspace.ID) err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) } func TestWorkspaceServiceList(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspaceA := &Workspace{ Name: String("teamA"), } workspaceB := &Workspace{ Name: String("teamB"), } createdWorkspaceA, err := client.Workspaces.Create(defaultCtx, workspaceA) assert.Nil(err) createdWorkspaceB, err := client.Workspaces.Create(defaultCtx, workspaceB) assert.Nil(err) // paged List page1, next, err := client.Workspaces.List(defaultCtx, &ListOpt{Size: 1}) assert.Nil(err) assert.NotNil(next) assert.NotNil(page1) assert.Equal(1, len(page1)) // nil ListOpt List workspaces, next, err := client.Workspaces.List(defaultCtx, nil) assert.Nil(err) assert.Nil(next) assert.NotNil(workspaces) // Counts default workspace assert.Equal(3, len(workspaces)) err = client.Workspaces.Delete(defaultCtx, createdWorkspaceA.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspaceB.ID) assert.Nil(err) } func TestWorkspaceServiceListAll(T *testing.T) { assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspaceA := &Workspace{ Name: String("teamA"), } workspaceB := &Workspace{ Name: String("teamB"), } createdWorkspaceA, err := client.Workspaces.Create(defaultCtx, workspaceA) assert.Nil(err) createdWorkspaceB, err := client.Workspaces.Create(defaultCtx, workspaceB) assert.Nil(err) workspaces, err := client.Workspaces.ListAll(defaultCtx) assert.Nil(err) assert.NotNil(workspaces) // Counts default workspace assert.Equal(3, len(workspaces)) err = client.Workspaces.Delete(defaultCtx, createdWorkspaceA.ID) assert.Nil(err) err = client.Workspaces.Delete(defaultCtx, createdWorkspaceB.ID) assert.Nil(err) } // Workspace entities func TestWorkspaceService_Entities(T *testing.T) { runWhenEnterprise(T, ">=0.33.0", false) assert := assert.New(T) client, err := NewTestClient(nil, nil) assert.Nil(err) assert.NotNil(client) workspace := &Workspace{ Name: String("teamA"), Meta: map[string]interface{}{ "color": "#814CA6", "thumbnail": nil, }, } // Create a workspace createdWorkspace, err := client.Workspaces.Create(defaultCtx, workspace) assert.Nil(err) assert.NotNil(createdWorkspace) service := &Service{ Name: String("foo"), Host: String("upstream"), Port: Int(42), Path: String("/path"), } // Create a service createdService, err := client.Services.Create(defaultCtx, service) assert.Nil(err) assert.NotNil(createdService) // Add the service to the workspace entities, err := client.Workspaces.AddEntities( defaultCtx, createdWorkspace.ID, createdService.ID) assert.Nil(err) assert.NotNil(entities) // List Entities attached to the workspace entitiesAdded, err := client.Workspaces.ListEntities(defaultCtx, createdWorkspace.ID) assert.Nil(err) assert.NotNil(entitiesAdded) // The two entities are records capturing the service name and id assert.Equal(2, len(entitiesAdded)) // Delete the service from the workspace err = client.Workspaces.DeleteEntities(defaultCtx, createdWorkspace.ID, createdService.ID) assert.Nil(err) // Delete the service err = client.Services.Delete(defaultCtx, createdService.ID) assert.Nil(err) // Delete the workspace err = client.Workspaces.Delete(defaultCtx, createdWorkspace.ID) assert.Nil(err) } go-kong-0.15.0/kong/zz_generated.deepcopy.go000066400000000000000000001116401400261364200207140ustar00rootroot00000000000000// +build !ignore_autogenerated /* Copyright 2018-2020 Harry Bagdi 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. */ // Code generated by deepcopy-gen. DO NOT EDIT. package kong // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACLGroup) DeepCopyInto(out *ACLGroup) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Group != nil { in, out := &in.Group, &out.Group *out = new(string) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACLGroup. func (in *ACLGroup) DeepCopy() *ACLGroup { if in == nil { return nil } out := new(ACLGroup) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ActiveHealthcheck) DeepCopyInto(out *ActiveHealthcheck) { *out = *in if in.Concurrency != nil { in, out := &in.Concurrency, &out.Concurrency *out = new(int) **out = **in } if in.Healthy != nil { in, out := &in.Healthy, &out.Healthy *out = new(Healthy) (*in).DeepCopyInto(*out) } if in.HTTPPath != nil { in, out := &in.HTTPPath, &out.HTTPPath *out = new(string) **out = **in } if in.HTTPSSni != nil { in, out := &in.HTTPSSni, &out.HTTPSSni *out = new(string) **out = **in } if in.HTTPSVerifyCertificate != nil { in, out := &in.HTTPSVerifyCertificate, &out.HTTPSVerifyCertificate *out = new(bool) **out = **in } if in.Type != nil { in, out := &in.Type, &out.Type *out = new(string) **out = **in } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout *out = new(int) **out = **in } if in.Unhealthy != nil { in, out := &in.Unhealthy, &out.Unhealthy *out = new(Unhealthy) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveHealthcheck. func (in *ActiveHealthcheck) DeepCopy() *ActiveHealthcheck { if in == nil { return nil } out := new(ActiveHealthcheck) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Admin) DeepCopyInto(out *Admin) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Email != nil { in, out := &in.Email, &out.Email *out = new(string) **out = **in } if in.Username != nil { in, out := &in.Username, &out.Username *out = new(string) **out = **in } if in.Password != nil { in, out := &in.Password, &out.Password *out = new(string) **out = **in } if in.CustomID != nil { in, out := &in.CustomID, &out.CustomID *out = new(string) **out = **in } if in.RBACTokenEnabled != nil { in, out := &in.RBACTokenEnabled, &out.RBACTokenEnabled *out = new(bool) **out = **in } if in.Status != nil { in, out := &in.Status, &out.Status *out = new(int) **out = **in } if in.Token != nil { in, out := &in.Token, &out.Token *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Admin. func (in *Admin) DeepCopy() *Admin { if in == nil { return nil } out := new(Admin) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BasicAuth) DeepCopyInto(out *BasicAuth) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Username != nil { in, out := &in.Username, &out.Username *out = new(string) **out = **in } if in.Password != nil { in, out := &in.Password, &out.Password *out = new(string) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicAuth. func (in *BasicAuth) DeepCopy() *BasicAuth { if in == nil { return nil } out := new(BasicAuth) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CACertificate) DeepCopyInto(out *CACertificate) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Cert != nil { in, out := &in.Cert, &out.Cert *out = new(string) **out = **in } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int64) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CACertificate. func (in *CACertificate) DeepCopy() *CACertificate { if in == nil { return nil } out := new(CACertificate) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CIDRPort) DeepCopyInto(out *CIDRPort) { *out = *in if in.IP != nil { in, out := &in.IP, &out.IP *out = new(string) **out = **in } if in.Port != nil { in, out := &in.Port, &out.Port *out = new(int) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CIDRPort. func (in *CIDRPort) DeepCopy() *CIDRPort { if in == nil { return nil } out := new(CIDRPort) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Certificate) DeepCopyInto(out *Certificate) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Cert != nil { in, out := &in.Cert, &out.Cert *out = new(string) **out = **in } if in.Key != nil { in, out := &in.Key, &out.Key *out = new(string) **out = **in } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int64) **out = **in } if in.SNIs != nil { in, out := &in.SNIs, &out.SNIs *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Certificate. func (in *Certificate) DeepCopy() *Certificate { if in == nil { return nil } out := new(Certificate) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Consumer) DeepCopyInto(out *Consumer) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.CustomID != nil { in, out := &in.CustomID, &out.CustomID *out = new(string) **out = **in } if in.Username != nil { in, out := &in.Username, &out.Username *out = new(string) **out = **in } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int64) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Consumer. func (in *Consumer) DeepCopy() *Consumer { if in == nil { return nil } out := new(Consumer) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HMACAuth) DeepCopyInto(out *HMACAuth) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Username != nil { in, out := &in.Username, &out.Username *out = new(string) **out = **in } if in.Secret != nil { in, out := &in.Secret, &out.Secret *out = new(string) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HMACAuth. func (in *HMACAuth) DeepCopy() *HMACAuth { if in == nil { return nil } out := new(HMACAuth) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Healthcheck) DeepCopyInto(out *Healthcheck) { *out = *in if in.Active != nil { in, out := &in.Active, &out.Active *out = new(ActiveHealthcheck) (*in).DeepCopyInto(*out) } if in.Passive != nil { in, out := &in.Passive, &out.Passive *out = new(PassiveHealthcheck) (*in).DeepCopyInto(*out) } if in.Threshold != nil { in, out := &in.Threshold, &out.Threshold *out = new(float64) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Healthcheck. func (in *Healthcheck) DeepCopy() *Healthcheck { if in == nil { return nil } out := new(Healthcheck) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Healthy) DeepCopyInto(out *Healthy) { *out = *in if in.HTTPStatuses != nil { in, out := &in.HTTPStatuses, &out.HTTPStatuses *out = make([]int, len(*in)) copy(*out, *in) } if in.Interval != nil { in, out := &in.Interval, &out.Interval *out = new(int) **out = **in } if in.Successes != nil { in, out := &in.Successes, &out.Successes *out = new(int) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Healthy. func (in *Healthy) DeepCopy() *Healthy { if in == nil { return nil } out := new(Healthy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *JWTAuth) DeepCopyInto(out *JWTAuth) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Algorithm != nil { in, out := &in.Algorithm, &out.Algorithm *out = new(string) **out = **in } if in.Key != nil { in, out := &in.Key, &out.Key *out = new(string) **out = **in } if in.RSAPublicKey != nil { in, out := &in.RSAPublicKey, &out.RSAPublicKey *out = new(string) **out = **in } if in.Secret != nil { in, out := &in.Secret, &out.Secret *out = new(string) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuth. func (in *JWTAuth) DeepCopy() *JWTAuth { if in == nil { return nil } out := new(JWTAuth) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeyAuth) DeepCopyInto(out *KeyAuth) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Key != nil { in, out := &in.Key, &out.Key *out = new(string) **out = **in } if in.TTL != nil { in, out := &in.TTL, &out.TTL *out = new(int) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyAuth. func (in *KeyAuth) DeepCopy() *KeyAuth { if in == nil { return nil } out := new(KeyAuth) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MTLSAuth) DeepCopyInto(out *MTLSAuth) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.SubjectName != nil { in, out := &in.SubjectName, &out.SubjectName *out = new(string) **out = **in } if in.CACertificate != nil { in, out := &in.CACertificate, &out.CACertificate *out = new(CACertificate) (*in).DeepCopyInto(*out) } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MTLSAuth. func (in *MTLSAuth) DeepCopy() *MTLSAuth { if in == nil { return nil } out := new(MTLSAuth) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Oauth2Credential) DeepCopyInto(out *Oauth2Credential) { *out = *in if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.ClientID != nil { in, out := &in.ClientID, &out.ClientID *out = new(string) **out = **in } if in.ClientSecret != nil { in, out := &in.ClientSecret, &out.ClientSecret *out = new(string) **out = **in } if in.RedirectURIs != nil { in, out := &in.RedirectURIs, &out.RedirectURIs *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Oauth2Credential. func (in *Oauth2Credential) DeepCopy() *Oauth2Credential { if in == nil { return nil } out := new(Oauth2Credential) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PassiveHealthcheck) DeepCopyInto(out *PassiveHealthcheck) { *out = *in if in.Healthy != nil { in, out := &in.Healthy, &out.Healthy *out = new(Healthy) (*in).DeepCopyInto(*out) } if in.Type != nil { in, out := &in.Type, &out.Type *out = new(string) **out = **in } if in.Unhealthy != nil { in, out := &in.Unhealthy, &out.Unhealthy *out = new(Unhealthy) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthcheck. func (in *PassiveHealthcheck) DeepCopy() *PassiveHealthcheck { if in == nil { return nil } out := new(PassiveHealthcheck) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Plugin) DeepCopyInto(out *Plugin) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.Route != nil { in, out := &in.Route, &out.Route *out = new(Route) (*in).DeepCopyInto(*out) } if in.Service != nil { in, out := &in.Service, &out.Service *out = new(Service) (*in).DeepCopyInto(*out) } if in.Consumer != nil { in, out := &in.Consumer, &out.Consumer *out = new(Consumer) (*in).DeepCopyInto(*out) } out.Config = in.Config.DeepCopy() if in.Enabled != nil { in, out := &in.Enabled, &out.Enabled *out = new(bool) **out = **in } if in.RunOn != nil { in, out := &in.RunOn, &out.RunOn *out = new(string) **out = **in } if in.Protocols != nil { in, out := &in.Protocols, &out.Protocols *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. func (in *Plugin) DeepCopy() *Plugin { if in == nil { return nil } out := new(Plugin) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RBACEndpointPermission) DeepCopyInto(out *RBACEndpointPermission) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.Workspace != nil { in, out := &in.Workspace, &out.Workspace *out = new(string) **out = **in } if in.Endpoint != nil { in, out := &in.Endpoint, &out.Endpoint *out = new(string) **out = **in } if in.Actions != nil { in, out := &in.Actions, &out.Actions *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Negative != nil { in, out := &in.Negative, &out.Negative *out = new(bool) **out = **in } if in.Role != nil { in, out := &in.Role, &out.Role *out = new(RBACRole) (*in).DeepCopyInto(*out) } if in.Comment != nil { in, out := &in.Comment, &out.Comment *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBACEndpointPermission. func (in *RBACEndpointPermission) DeepCopy() *RBACEndpointPermission { if in == nil { return nil } out := new(RBACEndpointPermission) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RBACEntityPermission) DeepCopyInto(out *RBACEntityPermission) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.EntityID != nil { in, out := &in.EntityID, &out.EntityID *out = new(string) **out = **in } if in.EntityType != nil { in, out := &in.EntityType, &out.EntityType *out = new(string) **out = **in } if in.Actions != nil { in, out := &in.Actions, &out.Actions *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Negative != nil { in, out := &in.Negative, &out.Negative *out = new(bool) **out = **in } if in.Role != nil { in, out := &in.Role, &out.Role *out = new(RBACRole) (*in).DeepCopyInto(*out) } if in.Comment != nil { in, out := &in.Comment, &out.Comment *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBACEntityPermission. func (in *RBACEntityPermission) DeepCopy() *RBACEntityPermission { if in == nil { return nil } out := new(RBACEntityPermission) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RBACRole) DeepCopyInto(out *RBACRole) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.Comment != nil { in, out := &in.Comment, &out.Comment *out = new(string) **out = **in } if in.IsDefault != nil { in, out := &in.IsDefault, &out.IsDefault *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBACRole. func (in *RBACRole) DeepCopy() *RBACRole { if in == nil { return nil } out := new(RBACRole) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RBACUser) DeepCopyInto(out *RBACUser) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.Comment != nil { in, out := &in.Comment, &out.Comment *out = new(string) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.Enabled != nil { in, out := &in.Enabled, &out.Enabled *out = new(bool) **out = **in } if in.UserToken != nil { in, out := &in.UserToken, &out.UserToken *out = new(string) **out = **in } if in.UserTokenIdent != nil { in, out := &in.UserTokenIdent, &out.UserTokenIdent *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBACUser. func (in *RBACUser) DeepCopy() *RBACUser { if in == nil { return nil } out := new(RBACUser) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Route) DeepCopyInto(out *Route) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.Hosts != nil { in, out := &in.Hosts, &out.Hosts *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Headers != nil { in, out := &in.Headers, &out.Headers *out = make(map[string][]string, len(*in)) for key, val := range *in { var outVal []string if val == nil { (*out)[key] = nil } else { in, out := &val, &outVal *out = make([]string, len(*in)) copy(*out, *in) } (*out)[key] = outVal } } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.Methods != nil { in, out := &in.Methods, &out.Methods *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Paths != nil { in, out := &in.Paths, &out.Paths *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.PathHandling != nil { in, out := &in.PathHandling, &out.PathHandling *out = new(string) **out = **in } if in.PreserveHost != nil { in, out := &in.PreserveHost, &out.PreserveHost *out = new(bool) **out = **in } if in.Protocols != nil { in, out := &in.Protocols, &out.Protocols *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.RegexPriority != nil { in, out := &in.RegexPriority, &out.RegexPriority *out = new(int) **out = **in } if in.Service != nil { in, out := &in.Service, &out.Service *out = new(Service) (*in).DeepCopyInto(*out) } if in.StripPath != nil { in, out := &in.StripPath, &out.StripPath *out = new(bool) **out = **in } if in.UpdatedAt != nil { in, out := &in.UpdatedAt, &out.UpdatedAt *out = new(int) **out = **in } if in.SNIs != nil { in, out := &in.SNIs, &out.SNIs *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.Sources != nil { in, out := &in.Sources, &out.Sources *out = make([]*CIDRPort, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(CIDRPort) (*in).DeepCopyInto(*out) } } } if in.Destinations != nil { in, out := &in.Destinations, &out.Destinations *out = make([]*CIDRPort, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(CIDRPort) (*in).DeepCopyInto(*out) } } } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.HTTPSRedirectStatusCode != nil { in, out := &in.HTTPSRedirectStatusCode, &out.HTTPSRedirectStatusCode *out = new(int) **out = **in } if in.RequestBuffering != nil { in, out := &in.RequestBuffering, &out.RequestBuffering *out = new(bool) **out = **in } if in.ResponseBuffering != nil { in, out := &in.ResponseBuffering, &out.ResponseBuffering *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. func (in *Route) DeepCopy() *Route { if in == nil { return nil } out := new(Route) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SNI) DeepCopyInto(out *SNI) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int64) **out = **in } if in.Certificate != nil { in, out := &in.Certificate, &out.Certificate *out = new(Certificate) (*in).DeepCopyInto(*out) } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SNI. func (in *SNI) DeepCopy() *SNI { if in == nil { return nil } out := new(SNI) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Service) DeepCopyInto(out *Service) { *out = *in if in.ClientCertificate != nil { in, out := &in.ClientCertificate, &out.ClientCertificate *out = new(Certificate) (*in).DeepCopyInto(*out) } if in.ConnectTimeout != nil { in, out := &in.ConnectTimeout, &out.ConnectTimeout *out = new(int) **out = **in } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int) **out = **in } if in.Host != nil { in, out := &in.Host, &out.Host *out = new(string) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.Path != nil { in, out := &in.Path, &out.Path *out = new(string) **out = **in } if in.Port != nil { in, out := &in.Port, &out.Port *out = new(int) **out = **in } if in.Protocol != nil { in, out := &in.Protocol, &out.Protocol *out = new(string) **out = **in } if in.ReadTimeout != nil { in, out := &in.ReadTimeout, &out.ReadTimeout *out = new(int) **out = **in } if in.Retries != nil { in, out := &in.Retries, &out.Retries *out = new(int) **out = **in } if in.UpdatedAt != nil { in, out := &in.UpdatedAt, &out.UpdatedAt *out = new(int) **out = **in } if in.WriteTimeout != nil { in, out := &in.WriteTimeout, &out.WriteTimeout *out = new(int) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } if in.TLSVerify != nil { in, out := &in.TLSVerify, &out.TLSVerify *out = new(bool) **out = **in } if in.TLSVerifyDepth != nil { in, out := &in.TLSVerifyDepth, &out.TLSVerifyDepth *out = new(int) **out = **in } if in.CACertificates != nil { in, out := &in.CACertificates, &out.CACertificates *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. func (in *Service) DeepCopy() *Service { if in == nil { return nil } out := new(Service) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Target) DeepCopyInto(out *Target) { *out = *in if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(float64) **out = **in } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Target != nil { in, out := &in.Target, &out.Target *out = new(string) **out = **in } if in.Upstream != nil { in, out := &in.Upstream, &out.Upstream *out = new(Upstream) (*in).DeepCopyInto(*out) } if in.Weight != nil { in, out := &in.Weight, &out.Weight *out = new(int) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. func (in *Target) DeepCopy() *Target { if in == nil { return nil } out := new(Target) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Unhealthy) DeepCopyInto(out *Unhealthy) { *out = *in if in.HTTPFailures != nil { in, out := &in.HTTPFailures, &out.HTTPFailures *out = new(int) **out = **in } if in.HTTPStatuses != nil { in, out := &in.HTTPStatuses, &out.HTTPStatuses *out = make([]int, len(*in)) copy(*out, *in) } if in.TCPFailures != nil { in, out := &in.TCPFailures, &out.TCPFailures *out = new(int) **out = **in } if in.Timeouts != nil { in, out := &in.Timeouts, &out.Timeouts *out = new(int) **out = **in } if in.Interval != nil { in, out := &in.Interval, &out.Interval *out = new(int) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Unhealthy. func (in *Unhealthy) DeepCopy() *Unhealthy { if in == nil { return nil } out := new(Unhealthy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Upstream) DeepCopyInto(out *Upstream) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) **out = **in } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } if in.HostHeader != nil { in, out := &in.HostHeader, &out.HostHeader *out = new(string) **out = **in } if in.ClientCertificate != nil { in, out := &in.ClientCertificate, &out.ClientCertificate *out = new(Certificate) (*in).DeepCopyInto(*out) } if in.Algorithm != nil { in, out := &in.Algorithm, &out.Algorithm *out = new(string) **out = **in } if in.Slots != nil { in, out := &in.Slots, &out.Slots *out = new(int) **out = **in } if in.Healthchecks != nil { in, out := &in.Healthchecks, &out.Healthchecks *out = new(Healthcheck) (*in).DeepCopyInto(*out) } if in.CreatedAt != nil { in, out := &in.CreatedAt, &out.CreatedAt *out = new(int64) **out = **in } if in.HashOn != nil { in, out := &in.HashOn, &out.HashOn *out = new(string) **out = **in } if in.HashFallback != nil { in, out := &in.HashFallback, &out.HashFallback *out = new(string) **out = **in } if in.HashOnHeader != nil { in, out := &in.HashOnHeader, &out.HashOnHeader *out = new(string) **out = **in } if in.HashFallbackHeader != nil { in, out := &in.HashFallbackHeader, &out.HashFallbackHeader *out = new(string) **out = **in } if in.HashOnCookie != nil { in, out := &in.HashOnCookie, &out.HashOnCookie *out = new(string) **out = **in } if in.HashOnCookiePath != nil { in, out := &in.HashOnCookiePath, &out.HashOnCookiePath *out = new(string) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*string, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] *out = new(string) **out = **in } } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upstream. func (in *Upstream) DeepCopy() *Upstream { if in == nil { return nil } out := new(Upstream) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceEntity) DeepCopyInto(out *WorkspaceEntity) { *out = *in if in.EntityID != nil { in, out := &in.EntityID, &out.EntityID *out = new(string) **out = **in } if in.EntityType != nil { in, out := &in.EntityType, &out.EntityType *out = new(string) **out = **in } if in.UniqueFieldName != nil { in, out := &in.UniqueFieldName, &out.UniqueFieldName *out = new(string) **out = **in } if in.UniqueFieldValue != nil { in, out := &in.UniqueFieldValue, &out.UniqueFieldValue *out = new(string) **out = **in } if in.WorkspaceID != nil { in, out := &in.WorkspaceID, &out.WorkspaceID *out = new(string) **out = **in } if in.WorkspaceName != nil { in, out := &in.WorkspaceName, &out.WorkspaceName *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceEntity. func (in *WorkspaceEntity) DeepCopy() *WorkspaceEntity { if in == nil { return nil } out := new(WorkspaceEntity) in.DeepCopyInto(out) return out }