diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3fd5474 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @genesiscloud/oss-dev diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..87fdf72 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# See GitHub's documentation for more information on this file: +# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9084bbf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +# Terraform Provider release workflow. +name: Release + +# This GitHub action creates a release when a tag that matches the pattern +# "v*" (e.g. v0.1.0) is created. +on: + push: + tags: + - "v*" + +# Releases need permissions to read and write the repository contents. +# GitHub considers creating releases and uploading assets as writing contents. +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + with: + # Allow goreleaser to access older tag information. + fetch-depth: 0 + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version-file: "go.mod" + cache: true + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@72b6676b71ab476b77e676928516f6982eef7a41 # v5.3.0 + id: import_gpg + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.PASSPHRASE }} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0 + with: + args: release --clean + env: + # GitHub sets the GITHUB_TOKEN secret automatically. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..3c46bbf --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,81 @@ +# Terraform Provider testing workflow. +name: Tests + +# This GitHub action runs your tests for each pull request and push. +# Optionally, you can turn it on using a schedule for regular testing. +on: + pull_request: + paths-ignore: + - "README.md" + push: + paths-ignore: + - "README.md" + +# Testing only needs permissions to read the repository contents. +permissions: + contents: read + +jobs: + # Ensure project builds before running testing matrix + build: + name: Build + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version-file: "go.mod" + cache: true + - run: go mod download + - run: go build -v . + - name: Run linters + uses: golangci/golangci-lint-action@639cd343e1d3b897ff35927a75193d57cfcba299 # v3.6.0 + with: + version: latest + + generate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version-file: "go.mod" + cache: true + - run: go generate ./... + - name: git diff + run: | + git diff --compact-summary --exit-code || \ + (echo; echo "Unexpected difference in directories after code generation. Run 'go generate ./...' command and commit."; exit 1) + + # # Run acceptance tests in a matrix with Terraform CLI versions + # test: + # name: Terraform Provider Acceptance Tests + # needs: build + # runs-on: ubuntu-latest + # timeout-minutes: 15 + # strategy: + # fail-fast: false + # matrix: + # # list whatever Terraform versions here you would like to support + # terraform: + # - "1.0.*" + # - "1.1.*" + # - "1.2.*" + # - "1.3.*" + # - "1.4.*" + # steps: + # - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + # - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + # with: + # go-version-file: "go.mod" + # cache: true + # - uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3 + # with: + # terraform_version: ${{ matrix.terraform }} + # terraform_wrapper: false + # - run: go mod download + # - env: + # TF_ACC: "1" + # run: go test -v -cover ./internal/provider/ + # timeout-minutes: 10 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd3ad8e --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +*.dll +*.exe +.DS_Store +example.tf +terraform.tfplan +terraform.tfstate +bin/ +dist/ +modules-dev/ +/pkg/ +website/.vagrant +website/.bundle +website/build +website/node_modules +.vagrant/ +*.backup +./*.tfstate +.terraform/ +*.log +*.bak +*~ +.*.swp +.idea +*.iml +*.test +*.iml + +website/vendor + +# Test exclusions +!command/test-fixtures/**/*.tfstate +!command/test-fixtures/**/.terraform/ + +# Keep windows files with windows line endings +*.winfile eol=crlf diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..61e0660 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,60 @@ +# Visit https://goreleaser.com for documentation on how to customize this +# behavior. +before: + hooks: + # this is just an example and not a requirement for provider building/publishing + - go mod tidy +builds: + - env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like Terraform Cloud where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + ldflags: + - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}" + goos: + - freebsd + - windows + - linux + - darwin + goarch: + - amd64 + - "386" + - arm + - arm64 + ignore: + - goos: darwin + goarch: "386" + binary: "{{ .ProjectName }}_v{{ .Version }}" +archives: + - format: zip + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" +checksum: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS" + algorithm: sha256 +signs: + - artifacts: checksum + args: + # if you are using this in a GitHub action or some other automated pipeline, you + # need to pass the batch flag to indicate its not interactive. + - "--batch" + - "--local-user" + - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key + - "--output" + - "${signature}" + - "--detach-sign" + - "${artifact}" +release: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + # If you want to manually examine the release before its live, uncomment this line: + # draft: true +changelog: + use: github-native diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..7771cd6 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,6 @@ +default: testacc + +# Run acceptance tests +.PHONY: testacc +testacc: + TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..920fa09 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,155 @@ +Mozilla Public License Version 2.0 + +================================== + +1. Definitions + +-------------- + +1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. +1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. +1.3. "Contribution" means Covered Software of a particular Contributor. +1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. +1.5. "Incompatible With Secondary Licenses" means +(a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or +(b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. +1.6. "Executable Form" means any form of the work other than Source Code Form. +1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. +1.8. "License" means this document. +1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. +1.10. "Modifications" means any of the following: +(a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or +(b) any new file in Source Code Form that contains any Covered Software. +1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. +1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. +1.13. "Source Code Form" means the form of the work preferred for making modifications. +1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. +2. License Grants and Conditions + +-------------------------------- + +2.1. Grants +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and +(b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. +2.2. Effective Date +The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. + +2.3. Limitations on Grant Scope +The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: + +(a) for any code that a Contributor has removed from Covered Software; or +(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or +(c) under Patent Claims infringed by Covered Software in the absence of its Contributions. +This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). + +2.4. Subsequent Licenses +No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). + +2.5. Representation +Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use +This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. + +3. Responsibilities + +------------------- + +3.1. Distribution of Source Form +All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. + +3.2. Distribution of Executable Form +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and +(b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. +3.3. Distribution of a Larger Work +You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). + +3.4. Notices +You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms +You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Termination + +-------------- + +5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. +5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. +************************************************************************ + +6. Disclaimer of Warranty + +* ------------------------- * + +Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. + +************************************************************************ + +************************************************************************ + +7. Limitation of Liability + +* -------------------------- * + +Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. + +************************************************************************ + +8. Litigation + +------------- + +Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. + +9. Miscellaneous + +---------------- + +This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. + +10. Versions of the License + +--------------------------- + +10.1. New Versions +Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. + +10.2. Effect of New Versions +You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. + +10.3. Modified Versions +If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses +If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + +------------------------------------------- + +This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + +--------------------------------------------------------- + +This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf436ed --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# Terraform Provider for Genesis Cloud + +The Genesis Cloud provider is used to interact with resources supported by [Genesis Cloud](https://www.genesiscloud.com/). The provider needs to be configured with the proper credentials before it can be used. + +- [Documentation](https://www.terraform.io/docs/providers/genesiscloud/index.html) +- [Genesis Cloud API Documentation](https://developers.genesiscloud.com/) +- [How to generate an API key?](https://support.genesiscloud.com/support/solutions/articles/47001126146-how-to-generate-an-api-token-) +- [Terraform Website](https://www.terraform.io) + +This repository is licensed under Mozilla Public License 2.0 (no copyleft exception) (see [LICENSE.txt](./LICENSE.txt)) and includes third-party code subject to third-party notices (see [THIRD-PARTY-NOTICES.txt](./THIRD-PARTY-NOTICES.txt)). + +# Maintainers + +This provider plugin is maintained by Genesis Cloud. If you encounter any problems, feel free to create issues or pull requests. + +## Requirements + +- [Terraform](https://www.terraform.io/downloads.html) >= 1.0 +- [Go](https://golang.org/doc/install) >= 1.18 + +## Using the provider + +Consult the [provider documentation](docs/index.md). + +## Development + +### Building The Provider + +1. Clone the repository +1. Enter the repository directory +1. Build the provider using the Go `install` command: + +```shell +go install +``` + +### Adding Dependencies + +This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). +Please see the Go documentation for the most up to date information about using Go modules. + +To add a new dependency `github.com/author/dependency` to your Terraform provider: + +```shell +go get github.com/author/dependency +go mod tidy +``` + +Then commit the changes to `go.mod` and `go.sum`. + +### Developing the Provider + +If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above). + +To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +_Note:_ Acceptance tests create real resources, and often cost money to run. + +```shell +make testacc +``` diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt new file mode 100644 index 0000000..9ffbd2a --- /dev/null +++ b/THIRD-PARTY-NOTICES.txt @@ -0,0 +1,3439 @@ +Third-party notice file + +This software makes use of open-source software, licensed as set out below. + +======================================================================================================================== + +terraform-plugin-framework-validators + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + + +Copyright (c) 2022 HashiCorp, Inc. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +======================================================================================================================== + +terraform-plugin-go-0.14.3 + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Copyright (c) 2020 HashiCorp, Inc. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +------------------------------------------------------------------------------------------------------------------------ + +MIT + +MIT License + +Copyright (c) 2017-2018 Martin Atkins + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================================================================== + +terraform-plugin-log-0.8.0 + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Copyright (c) 2021 HashiCorp, Inc. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + + +======================================================================================================================== + +terraform-registry-address-0.1.0 + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Copyright (c) 2021 HashiCorp, Inc. + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +======================================================================================================================== + +terraform-svchost-f050f53b97348772833a8f7fc1b297ec71f9fc7c + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +======================================================================================================================== + +yamux-2f1d1f20f75d5404f53b9edf6b53ed5505508675 + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +======================================================================================================================== + +go-colorable-0.1.13 + +------------------------------------------------------------------------------------------------------------------------ + +MIT + +MIT License + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================================================================== + +go-isatty-0.0.16 + +------------------------------------------------------------------------------------------------------------------------ + +MIT + +MIT License + +Copyright (c) Yasuhiro MATSUMOTO + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================================================================== + +go-testing-interface-1.14.1 + +------------------------------------------------------------------------------------------------------------------------ + +MIT + +MIT License + +Copyright (c) 2016 Mitchell Hashimoto + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================================================================== + +run-1.0.0 + +------------------------------------------------------------------------------------------------------------------------ + +Apache-2.0 + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +======================================================================================================================== + +msgpack-4.3.12 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-2-Clause + +Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +======================================================================================================================== + +tagparser-0.1.2 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-2-Clause + +Copyright (c) 2019 The github.com/vmihailenco/tagparser Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +======================================================================================================================== + +go-genproto-8698661620497c6fd6244a2fb2ff2518e6a6e892 + +------------------------------------------------------------------------------------------------------------------------ + +Apache-2.0 + +Copyright 2020 Google LLC +Copyright 2019 Google LLC. +Copyright 2019 Google LLC +Copyright 2018 The Grafeas Authors. All rights reserved. +Copyright 2018 Google LLC +Copyright 2018 Google Inc. +Copyright 2017 Google Inc. +Copyright 2016 Google Inc. +Copyright (c) 2015, Google Inc. + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +======================================================================================================================== + +grpc-go-1.51.0 + +------------------------------------------------------------------------------------------------------------------------ + +Apache-2.0 + +Copyright 2022 gRPC authors. +Copyright 2021 gRPC authors. +Copyright 2020 gRPC authors. +Copyright 2020 The gRPC Authors +Copyright 2019 gRPC authors. +Copyright 2018 gRPC authors. +Copyright 2018 The gRPC Authors All rights reserved. +Copyright 2018 The gRPC Authors +Copyright 2017 gRPC authors. +Copyright 2016 gRPC authors. +Copyright 2015-2016 gRPC authors. +Copyright 2015 gRPC authors. +Copyright 2015 The gRPC Authors +Copyright 2014 gRPC authors. + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +======================================================================================================================== + +protobuf-go-1.28.1 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-3-Clause + +Copyright The Go Authors. All rights reserved. +Copyright Google Inc. All rights reserved. +Copyright 2021 The Go Authors. All rights reserved. +Copyright 2020 The Go Authors. All rights reserved. +Copyright 2019 The Go Authors. All rights reserved. +Copyright 2018 The Go Authors. All rights reserved. +Copyright 2008 Google Inc. All rights reserved. +Copyright (c) 2018 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. +Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + + +======================================================================================================================== + +net-0.3.0 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-3-Clause + +Copyright (c) 2009-2013, 2016 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +BSD-3-Clause + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of works must retain the original copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the original copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of the W3C nor the names of its contributors may be used to endorse or promote products derived from this work without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +------------------------------------------------------------------------------------------------------------------------ + +LicenseRef-fossology-W3C-IP + +This document, Test Suites and other documents that link to this statement are provided by the copyright holders under the following license: By using and/or copying this document, or the W3C document from which this statement is linked, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: + +Permission to copy, and distribute the contents of this document, or the W3C document from which this statement is linked, in any medium for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the document, or portions thereof, that you use: + +A link or URL to the original W3C document. +The pre-existing copyright notice of the original author, or if it doesn't exist, a notice (hypertext is preferred, but a textual representation is permitted) of the form: "Copyright © [$date-of-document] World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) and others. All Rights Reserved. http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html" +If it exists, the STATUS of the W3C document. +When space permits, inclusion of the full text of this NOTICE should be provided. We request that authorship attribution be provided in any software, documents, or other items or products that you create pursuant to the implementation of the contents of this document, or any portion thereof. + +No right to create modifications or derivatives of W3C documents is granted pursuant to this license. However, if additional requirements (documented in the Copyright FAQ) are satisfied, the right to create modifications or derivatives is sometimes granted by the W3C to individuals complying with those requirements. + +If a Test Suite distinguishes the test harness (or, framework for navigation) and the actual tests, permission is given to remove or alter the harness or navigation if the Test Suite in question allows to do so. The tests themselves shall NOT be changed in any way. + +The name and trademarks of W3C and other copyright holders may NOT be used in advertising or publicity pertaining to this document or other documents that link to this statement without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. Permission is given to use the trademarked string W3C within claims of performance concerning W3C Specifications or features described therein, and there only, if the test suite so authorizes. + +THIS WORK IS PROVIDED BY W3C, MIT, ERCIM, KEIO, BEIHANG, THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL W3C, MIT, ERCIM, KEIO, BEIHANG, THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +BSD-2-Clause + +Copyright (C) 2009 Apple Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +======================================================================================================================== + +sys-0.3.0 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-3-Clause + +Copyright 2022 The Go Authors. All rights reserved. +Copyright 2021 The Go Authors. All rights reserved. +Copyright 2020 The Go Authors. All rights reserved. +Copyright 2019 The Go Authors. All rights reserved. +Copyright 2018 The Go Authors. All rights reserved. +Copyright 2017 The Go Authors. All rights reserved. +Copyright 2017 The Go Authors. All right reserved. +Copyright 2016 The Go Authors. All rights reserved. +Copyright 2015 The Go Authors. All rights reserved. +Copyright 2014 The Go Authors. All rights reserved. +Copyright 2013 The Go Authors. All rights reserved. +Copyright 2012 The Go Authors. All rights reserved. +Copyright 2011 The Go Authors. All rights reserved. +Copyright 2010 The Go Authors. All rights reserved. +Copyright 2009,2010 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. All rights reserved. +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + + +======================================================================================================================== + +text-0.5.0 + +------------------------------------------------------------------------------------------------------------------------ + +BSD-3-Clause + +Copyright 2021 The Go Authors. All rights reserved. +Copyright 2019 The Go Authors. All rights reserved. +Copyright 2018 The Go Authors. All rights reserved. +Copyright 2017 The Go Authors. All rights reserved. +Copyright 2016 The Go Authors. All rights reserved. +Copyright 2015 The Go Authors. All rights reserved. +Copyright 2014 The Go Authors. All rights reserved. +Copyright 2013 The Go Authors. All rights reserved. +Copyright 2012 The Go Authors. All rights reserved. +Copyright 2011 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------------------------------------------------ + +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + + +======================================================================================================================== + +color-1.13.0 + +------------------------------------------------------------------------------------------------------------------------ + +MIT + +MIT License + +Copyright (c) 2013 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================================================================== + +go-retryablehttp-0.7.2 + +------------------------------------------------------------------------------------------------------------------------ + +MPL-2.0-no-copyleft-exception + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +======================================================================================================================== diff --git a/docs/data-sources/images.md b/docs/data-sources/images.md new file mode 100644 index 0000000..671d56a --- /dev/null +++ b/docs/data-sources/images.md @@ -0,0 +1,81 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_images Data Source - terraform-provider-genesiscloud" +subcategory: "" +description: |- + Images data source +--- + +# genesiscloud_images (Data Source) + +Images data source + +## Example Usage + +```terraform +data "genesiscloud_images" "all-images" {} + +data "genesiscloud_images" "base-os-images" { + filter = { + type = "base-os" + } +} + +data "genesiscloud_images" "snapshots" { + filter = { + type = "snapshot" + region = "ARC-IS-HAF-1" + } +} + +data "genesiscloud_images" "preconfigured-images" { + filter = { + type = "preconfigured" + } +} +``` + + +## Schema + +### Optional + +- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `id` (String) The ID of the data source itself. +- `images` (Attributes List) (see [below for nested schema](#nestedatt--images)) + + +### Nested Schema for `filter` + +Optional: + +- `region` (String) Filter by the region identifier. + - The value must be one of: [`ARC-IS-HAF-1` `NORD-NO-KRS-1`]. +- `type` (String) Filter by the kind of image. + - The value must be one of: [`base-os` `preconfigured` `snapshot`]. + + + +### Nested Schema for `timeouts` + +Optional: + +- `read` (String) + + + +### Nested Schema for `images` + +Read-Only: + +- `created_at` (String) The timestamp when this image was created in RFC 3339. +- `id` (String) A unique number that can be used to identify and reference a specific image. +- `name` (String) The display name that has been given to an image. +- `regions` (Set of String) The list of regions in which this image can be used in. +- `type` (String) Describes the kind of image. + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..41a536a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,135 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud Provider" +subcategory: "" +description: |- + The Genesis Cloud provider is used to interact with resources supported by Genesis Cloud https://www.genesiscloud.com/. The provider needs to be configured with the proper credentials before it can be used. +--- + +# genesiscloud Provider + +The Genesis Cloud provider is used to interact with resources supported by [Genesis Cloud](https://www.genesiscloud.com/). The provider needs to be configured with the proper credentials before it can be used. + +## Example Usage + +```terraform +terraform { + required_providers { + genesiscloud = { + source = "genesiscloud/genesiscloud" + # version = "..." + } + } +} + +provider "genesiscloud" { + # optional configuration... + + # set GENESISCLOUD_TOKEN env var or: + # token = "..." +} + +# Create an instance: + +locals { + region = "ARC-IS-HAF-1" +} + +data "genesiscloud_images" "base-os" { + filter = { + type = "base-os" + region = local.region + } +} + +locals { + image_id = data.genesiscloud_images.base-os.images[index(data.genesiscloud_images.base-os.images.*.name, "Ubuntu 20.04")].id +} + +resource "genesiscloud_ssh_key" "alice" { + name = "alice" + public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOpdKM8wSI07+PO4xLDL7zW/kNWGbdFXeHyBU1TRlBn alice@example.com" +} + +resource "genesiscloud_security_group" "allow-ssh" { + name = "allow-ssh" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + }, + ] +} + +resource "genesiscloud_security_group" "allow-http" { + name = "allow-http" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 80 + port_range_max = 80 + } + ] +} + +resource "genesiscloud_security_group" "allow-https" { + name = "allow-https" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 443 + port_range_max = 443 + } + ] +} + +resource "genesiscloud_instance" "instance" { + name = "terraform-instance" + region = local.region + + image_id = local.image_id + type = "vcpu-4_memory-12g_disk-80g_nvidia3080-1" + + ssh_key_ids = [ + genesiscloud_ssh_key.alice.id, + ] + + security_group_ids = [ + genesiscloud_security_group.allow-ssh.id, + genesiscloud_security_group.allow-http.id, + genesiscloud_security_group.allow-https.id, + ] + + metadata = { + startup_script = < +## Schema + +### Optional + +- `endpoint` (String) Genesis Cloud API endpoint. May also be provided via `GENESISCLOUD_ENDPOINT` environment variable. If neither is provided, defaults to `https://api.genesiscloud.com`. +- `polling_interval` (String) The polling interval. + - The string must be a positive [time duration](https://pkg.go.dev/time#ParseDuration) for example "10s". +- `token` (String, Sensitive) Genesis Cloud API token. May also be provided via `GENESISCLOUD_TOKEN` environment variable. diff --git a/docs/resources/instance.md b/docs/resources/instance.md new file mode 100644 index 0000000..926fe90 --- /dev/null +++ b/docs/resources/instance.md @@ -0,0 +1,101 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_instance Resource - terraform-provider-genesiscloud" +subcategory: "" +description: |- + Instance resource +--- + +# genesiscloud_instance (Resource) + +Instance resource + +## Example Usage + +```terraform +resource "genesiscloud_instance" "example" { + name = "example" + region = "ARC-IS-HAF-1" + + image_id = "my-image-id" + type = "vcpu-2_memory-4g_disk-80g" + + ssh_key_ids = [ + "my-ssh-key-id" + ] +} +``` + + +## Schema + +### Required + +- `image_id` (String) The image of the instance. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. +- `name` (String) The human-readable name for the instance. +- `region` (String) The region identifier. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The value must be one of: [`ARC-IS-HAF-1` `NORD-NO-KRS-1`]. +- `type` (String) The instance type identifier. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The value must be one of: [`vcpu-12_memory-24g_disk-80g` `vcpu-12_memory-36g_disk-80g_nvidia1080ti-3` `vcpu-12_memory-36g_disk-80g_nvidia3060ti-3` `vcpu-12_memory-36g_disk-80g_nvidia3080-3` `vcpu-12_memory-72g_disk-80g_nvidia3090-3` `vcpu-16_memory-32g_disk-80g` `vcpu-16_memory-48g_disk-80g_nvidia1080ti-4` `vcpu-16_memory-48g_disk-80g_nvidia3060ti-4` `vcpu-16_memory-48g_disk-80g_nvidia3080-4` `vcpu-16_memory-64g_disk-80g_nvidia3080-2` `vcpu-16_memory-96g_disk-80g_nvidia3090-2` `vcpu-16_memory-96g_disk-80g_nvidia3090-4` `vcpu-20_memory-120g_disk-80g_nvidia3090-5` `vcpu-20_memory-40g_disk-80g` `vcpu-20_memory-60g_disk-80g_nvidia1080ti-5` `vcpu-20_memory-60g_disk-80g_nvidia3060ti-5` `vcpu-20_memory-60g_disk-80g_nvidia3080-5` `vcpu-24_memory-144g_disk-80g_nvidia3090-3` `vcpu-24_memory-144g_disk-80g_nvidia3090-6` `vcpu-24_memory-48g_disk-80g` `vcpu-24_memory-72g_disk-80g_nvidia1080ti-6` `vcpu-24_memory-72g_disk-80g_nvidia3060ti-6` `vcpu-24_memory-72g_disk-80g_nvidia3080-6` `vcpu-24_memory-96g_disk-80g_nvidia3080-3` `vcpu-28_memory-168g_disk-80g_nvidia3090-7` `vcpu-28_memory-84g_disk-80g_nvidia1080ti-7` `vcpu-28_memory-84g_disk-80g_nvidia3060ti-7` `vcpu-28_memory-84g_disk-80g_nvidia3080-7` `vcpu-2_memory-4g_disk-80g` `vcpu-2_memory-8g_disk-80g_amdrx470-4` `vcpu-2_memory-8g_disk-80g_amdrx470-5` `vcpu-2_memory-8g_disk-80g_amdrx470-6` `vcpu-2_memory-8g_disk-80g_amdrx470-7` `vcpu-2_memory-8g_disk-80g_amdrx470-8` `vcpu-32_memory-128g_disk-80g_nvidia3080-4` `vcpu-32_memory-192g_disk-80g_nvidia3090-4` `vcpu-32_memory-192g_disk-80g_nvidia3090-8` `vcpu-32_memory-96g_disk-80g_nvidia1080ti-8` `vcpu-32_memory-96g_disk-80g_nvidia3060ti-8` `vcpu-32_memory-96g_disk-80g_nvidia3080-8` `vcpu-4_memory-12g_disk-80g_nvidia1080ti-1` `vcpu-4_memory-12g_disk-80g_nvidia3060ti-1` `vcpu-4_memory-12g_disk-80g_nvidia3080-1` `vcpu-4_memory-24g_disk-80g_nvidia3090-1` `vcpu-4_memory-8g_disk-80g` `vcpu-8_memory-16g_disk-80g` `vcpu-8_memory-24g_disk-80g_nvidia1080ti-2` `vcpu-8_memory-24g_disk-80g_nvidia3060ti-2` `vcpu-8_memory-24g_disk-80g_nvidia3080-2` `vcpu-8_memory-32g_disk-80g_nvidia3080-1` `vcpu-8_memory-48g_disk-80g_nvidia3090-1` `vcpu-8_memory-48g_disk-80g_nvidia3090-2`]. + +### Optional + +- `hostname` (String) The hostname of your instance. If not provided will be initially set to the `name` attribute. + - If the value of this attribute is configured and changes, Terraform will destroy and recreate the resource. +- `metadata` (Attributes) Option to provide metadata. Currently supported is `startup_script`. (see [below for nested schema](#nestedatt--metadata)) +- `password` (String, Sensitive) The password to access the instance. Your password must have upper and lower chars, digits and length between 8-72. **Please Note**: Only one of `ssh_keys` or `password` can be provided. Password is less secure - we recommend you use an SSH key-pair. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The string length must be at least 16. +- `placement_option` (String) The placement option identifier in which instances are physically located relative to each other within a zone. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - Sets the default value `AUTO` if the attribute is not set. + - The value must be one of: [`A` `AUTO` `B`]. +- `public_ip_type` (String) When set to `static`, the instance's public IP will not change between start and stop actions. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - Sets the default value `dynamic` if the attribute is not set. + - The value must be one of: [`dynamic` `static`]. +- `security_group_ids` (Set of String) The security groups of the instance. If not provided will be set to the default security group. +- `ssh_key_ids` (Set of String) The ssh keys of the instance. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The set must contain at least 1 elements. +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) +- `volume_ids` (Set of String) The volumes of the instance. + +### Read-Only + +- `created_at` (String) The timestamp when this image was created in RFC 3339. +- `id` (String) The unique ID of the instance. +- `private_ip` (String) The private IPv4 IP-Address (IPv4 address). +- `public_ip` (String) The public IPv4 IP-Address (IPv4 address). +- `status` (String) The instance status. +- `updated_at` (String) The timestamp when this image was last updated in RFC 3339. + + +### Nested Schema for `metadata` + +Optional: + +- `startup_script` (String) A plain text bash script or "cloud-config" file that will be executed after the first instance boot. It is limited to 64 KiB in size. You can use it to configure your instance, e.g. installing the NVIDIA GPU driver. Learn more about [startup scripts and installing the GPU driver](https://support.com/support/solutions/articles/47001122478). + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import genesiscloud_instance.example 18efeec8-94f0-4776-8ff2-5e9b49c74608 +``` diff --git a/docs/resources/security_group.md b/docs/resources/security_group.md new file mode 100644 index 0000000..7929d9b --- /dev/null +++ b/docs/resources/security_group.md @@ -0,0 +1,87 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_security_group Resource - terraform-provider-genesiscloud" +subcategory: "" +description: |- + Security group resource +--- + +# genesiscloud_security_group (Resource) + +Security group resource + +## Example Usage + +```terraform +resource "genesiscloud_security_group" "allow-https" { + name = "allow-https" + region = "ARC-IS-HAF-1" + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 443 + port_range_max = 443 + } + ] +} +``` + + +## Schema + +### Required + +- `name` (String) The human-readable name for the security group. +- `region` (String) The region identifier. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The value must be one of: [`ARC-IS-HAF-1` `NORD-NO-KRS-1`]. +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + +### Optional + +- `description` (String) The human-readable description for the security group. + - Sets the default value `` if the attribute is not set. +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `created_at` (String) The timestamp when this security group was created in RFC 3339. +- `id` (String) The unique ID of the security group. +- `status` (String) The security group status. + + +### Nested Schema for `rules` + +Required: + +- `direction` (String) The direction of the rule. + - The value must be one of: [`egress` `ingress`]. +- `protocol` (String) The protocol of the rule. + - The value must be one of: [`all` `icmp` `tcp` `udp`]. + +Optional: + +- `port_range_max` (Number) The maximum port number of the rule. + - The value must be between 1 and 65535. +- `port_range_min` (Number) The minimum port number of the rule. + - The value must be between 1 and 65535. + + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import genesiscloud_security_group.example 18efeec8-94f0-4776-8ff2-5e9b49c74608 +``` diff --git a/docs/resources/snapshot.md b/docs/resources/snapshot.md new file mode 100644 index 0000000..fe08c56 --- /dev/null +++ b/docs/resources/snapshot.md @@ -0,0 +1,67 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_snapshot Resource - terraform-provider-genesiscloud" +subcategory: "" +description: |- + Snapshot resource +--- + +# genesiscloud_snapshot (Resource) + +Snapshot resource + +## Example Usage + +```terraform +resource "genesiscloud_instance" "target" { + # ... +} + +resource "genesiscloud_snapshot" "example" { + name = "example" + instance_id = genesiscloud_instance.target.id + + retain_on_delete = true # optional +} +``` + + +## Schema + +### Required + +- `instance_id` (String) The id of the instance to snapshot. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. +- `name` (String) The human-readable name for the snapshot. + +### Optional + +- `retain_on_delete` (Boolean) Flag to retain the snapshot when the resource is deleted. + - Sets the default value "false" if the attribute is not set. +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `created_at` (String) The timestamp when this snapshot was created in RFC 3339. +- `id` (String) The unique ID of the snapshot. +- `region` (String) The region identifier. +- `size` (Number) The storage size of this snapshot given in bytes. +- `status` (String) The snapshot status. + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import genesiscloud_snapshot.example 18efeec8-94f0-4776-8ff2-5e9b49c74608 +``` diff --git a/docs/resources/ssh_key.md b/docs/resources/ssh_key.md new file mode 100644 index 0000000..93d7864 --- /dev/null +++ b/docs/resources/ssh_key.md @@ -0,0 +1,57 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_ssh_key Resource - terraform-provider-genesiscloud" +subcategory: "" +description: |- + SSH key resource +--- + +# genesiscloud_ssh_key (Resource) + +SSH key resource + +## Example Usage + +```terraform +resource "genesiscloud_ssh_key" "example" { + name = "example" + public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOpdKM8wSI07+PO4xLDL7zW/kNWGbdFXeHyBU1TRlBn alice@example.com" +} +``` + + +## Schema + +### Required + +- `name` (String) The human-readable name for the SSH key. +- `public_key` (String) SSH public key. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + +### Optional + +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `created_at` (String) The timestamp when this SSH key was created in RFC 3339. +- `fingerprint` (String) The fingerprint of the SSH key. +- `id` (String) The unique ID of the SSH key. + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import genesiscloud_ssh_key.example 18efeec8-94f0-4776-8ff2-5e9b49c74608 +``` diff --git a/docs/resources/volume.md b/docs/resources/volume.md new file mode 100644 index 0000000..ab1a79b --- /dev/null +++ b/docs/resources/volume.md @@ -0,0 +1,66 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "genesiscloud_volume Resource - terraform-provider-genesiscloud" +subcategory: "" +description: |- + Volume resource +--- + +# genesiscloud_volume (Resource) + +Volume resource + +## Example Usage + +```terraform +resource "genesiscloud_volume" "example" { + name = "example" + region = "ARC-IS-HAF-1" + size = 50 +} +``` + + +## Schema + +### Required + +- `name` (String) The human-readable name for the volume. +- `region` (String) The region identifier. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The value must be one of: [`ARC-IS-HAF-1` `NORD-NO-KRS-1`]. +- `size` (Number) The storage size of this volume given in GiB. + - If the value of this attribute changes, Terraform will destroy and recreate the resource. + - The value must be at least 1. + +### Optional + +- `description` (String) The human-readable description for the volume. + - Sets the default value `` if the attribute is not set. +- `retain_on_delete` (Boolean) Flag to retain the volume when the resource is deleted + - Sets the default value "false" if the attribute is not set. +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `created_at` (String) The timestamp when this volume was created in RFC 3339. +- `id` (String) The unique ID of the volume. +- `status` (String) The volume status. + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import genesiscloud_volume.example 18efeec8-94f0-4776-8ff2-5e9b49c74608 +``` diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..026c42c --- /dev/null +++ b/examples/README.md @@ -0,0 +1,9 @@ +# Examples + +This directory contains examples that are mostly used for documentation, but can also be run/tested manually via the Terraform CLI. + +The document generation tool looks for files in the following locations by default. All other *.tf files besides the ones mentioned below are ignored by the documentation tool. This is useful for creating examples that can run and/or ar testable even if some parts are not relevant for the documentation. + +* **provider/provider.tf** example file for the provider index page +* **data-sources/`full data source name`/data-source.tf** example file for the named data source page +* **resources/`full resource name`/resource.tf** example file for the named data source page diff --git a/examples/data-sources/genesiscloud_images/00-provider.tf b/examples/data-sources/genesiscloud_images/00-provider.tf new file mode 100644 index 0000000..8eac306 --- /dev/null +++ b/examples/data-sources/genesiscloud_images/00-provider.tf @@ -0,0 +1,11 @@ +terraform { + required_providers { + genesiscloud = { + source = "genesiscloud/genesiscloud" + } + } +} + +provider "genesiscloud" { + # optional configuration... +} diff --git a/examples/data-sources/genesiscloud_images/data-source.tf b/examples/data-sources/genesiscloud_images/data-source.tf new file mode 100644 index 0000000..483fe3c --- /dev/null +++ b/examples/data-sources/genesiscloud_images/data-source.tf @@ -0,0 +1,20 @@ +data "genesiscloud_images" "all-images" {} + +data "genesiscloud_images" "base-os-images" { + filter = { + type = "base-os" + } +} + +data "genesiscloud_images" "snapshots" { + filter = { + type = "snapshot" + region = "ARC-IS-HAF-1" + } +} + +data "genesiscloud_images" "preconfigured-images" { + filter = { + type = "preconfigured" + } +} diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf new file mode 100644 index 0000000..1fbee5b --- /dev/null +++ b/examples/provider/provider.tf @@ -0,0 +1,109 @@ +terraform { + required_providers { + genesiscloud = { + source = "genesiscloud/genesiscloud" + # version = "..." + } + } +} + +provider "genesiscloud" { + # optional configuration... + + # set GENESISCLOUD_TOKEN env var or: + # token = "..." +} + +# Create an instance: + +locals { + region = "ARC-IS-HAF-1" +} + +data "genesiscloud_images" "base-os" { + filter = { + type = "base-os" + region = local.region + } +} + +locals { + image_id = data.genesiscloud_images.base-os.images[index(data.genesiscloud_images.base-os.images.*.name, "Ubuntu 20.04")].id +} + +resource "genesiscloud_ssh_key" "alice" { + name = "alice" + public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOpdKM8wSI07+PO4xLDL7zW/kNWGbdFXeHyBU1TRlBn alice@example.com" +} + +resource "genesiscloud_security_group" "allow-ssh" { + name = "allow-ssh" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + }, + ] +} + +resource "genesiscloud_security_group" "allow-http" { + name = "allow-http" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 80 + port_range_max = 80 + } + ] +} + +resource "genesiscloud_security_group" "allow-https" { + name = "allow-https" + region = local.region + rules = [ + { + direction = "ingress" + protocol = "tcp" + port_range_min = 443 + port_range_max = 443 + } + ] +} + +resource "genesiscloud_instance" "instance" { + name = "terraform-instance" + region = local.region + + image_id = local.image_id + type = "vcpu-4_memory-12g_disk-80g_nvidia3080-1" + + ssh_key_ids = [ + genesiscloud_ssh_key.alice.id, + ] + + security_group_ids = [ + genesiscloud_security_group.allow-ssh.id, + genesiscloud_security_group.allow-http.id, + genesiscloud_security_group.allow-https.id, + ] + + metadata = { + startup_script = < github.com/genesiscloud/terraform-plugin-framework v0.0.0-20230209224658-8e5bdfcff8eb diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..184b053 --- /dev/null +++ b/go.sum @@ -0,0 +1,430 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.0/go.mod h1:tWhwTbUTndesPNeF0C900vKoq283u6zp4APT9vaF3SI= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= +github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= +github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= +github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/deepmap/oapi-codegen v1.13.0 h1:cnFHelhsRQbYvanCUAbRSn/ZpkUb1HPRlQcu8YqSORQ= +github.com/deepmap/oapi-codegen v1.13.0/go.mod h1:Amy7tbubKY9qkZOXqymI3Z6xSbndmu+atMJheLdyg44= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/genesiscloud/genesiscloud-go v1.0.0-rc.1 h1:BUuldvlr5idIZTtYSbgl/bfzcRXPv8zUChMrZ6UqpIc= +github.com/genesiscloud/genesiscloud-go v1.0.0-rc.1/go.mod h1:NI5cu/MH/vQc/sVUzrP2JVEqH3n3LACHJqsf/qZc+Fs= +github.com/genesiscloud/terraform-plugin-framework v0.0.0-20230209224658-8e5bdfcff8eb h1:GiM6GYVU6p8cjsMFcuGuvpBYkF/Ra0b8h7GVMnsFsaw= +github.com/genesiscloud/terraform-plugin-framework v0.0.0-20230209224658-8e5bdfcff8eb/go.mod h1:JMR+Y8KdD9kWMLILo1gn1MzF3C3j607Pvv4PtxQj/8w= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= +github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hc-install v0.4.0 h1:cZkRFr1WVa0Ty6x5fTvL1TuO1flul231rWkGH92oYYk= +github.com/hashicorp/hc-install v0.4.0/go.mod h1:5d155H8EC5ewegao9A4PUTMNPZaq+TbOzkJJZ4vrXeI= +github.com/hashicorp/hcl/v2 v2.15.0 h1:CPDXO6+uORPjKflkWCCwoWc9uRp+zSIPcCQ+BrxV7m8= +github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjlaclkx3eErU= +github.com/hashicorp/terraform-exec v0.17.3/go.mod h1:+NELG0EqQekJzhvikkeQsOAZpsw0cv/03rbeQJqscAI= +github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= +github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= +github.com/hashicorp/terraform-plugin-docs v0.13.0 h1:6e+VIWsVGb6jYJewfzq2ok2smPzZrt1Wlm9koLeKazY= +github.com/hashicorp/terraform-plugin-docs v0.13.0/go.mod h1:W0oCmHAjIlTHBbvtppWHe8fLfZ2BznQbuv8+UD8OucQ= +github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1 h1:5GhozvHUsrqxqku+yd0UIRTkmDLp2QPX5paL1Kq5uUA= +github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1/go.mod h1:ThtYDU8p6sJ9+SI+TYxXrw28vXxgBwYOpoPv1EojSJI= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 h1:4L0tmy/8esP6OcvocVymw52lY0HyQ5OxB7VNl7k4bS0= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0/go.mod h1:qdQJCdimB9JeX2YwOpItEu+IrfoJjWQ5PhLpAOMDQAE= +github.com/hashicorp/terraform-plugin-go v0.14.3 h1:nlnJ1GXKdMwsC8g1Nh05tK2wsC3+3BL/DBBxFEki+j0= +github.com/hashicorp/terraform-plugin-go v0.14.3/go.mod h1:7ees7DMZ263q8wQ6E4RdIdR6nHHJtrdt4ogX5lPkX1A= +github.com/hashicorp/terraform-plugin-log v0.8.0 h1:pX2VQ/TGKu+UU1rCay0OlzosNKe4Nz1pepLXj95oyy0= +github.com/hashicorp/terraform-plugin-log v0.8.0/go.mod h1:1myFrhVsBLeylQzYYEV17VVjtG8oYPRFdaZs7xdW2xs= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 h1:zHcMbxY0+rFO9gY99elV/XC/UnQVg7FhRCbj1i5b7vM= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1/go.mod h1:+tNlb0wkfdsDJ7JEiERLz4HzM19HyiuIoGzTsM7rPpw= +github.com/hashicorp/terraform-registry-address v0.1.0 h1:W6JkV9wbum+m516rCl5/NjKxCyTVaaUBbzYcMzBDO3U= +github.com/hashicorp/terraform-registry-address v0.1.0/go.mod h1:EnyO2jYO6j29DTHbJcm00E5nQTFeTtyZH3H5ycydQ5A= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/cli v1.1.4 h1:qj8czE26AU4PbiaPXK5uVmMSM+V5BYsFBiM9HhGRLUA= +github.com/mitchellh/cli v1.1.4/go.mod h1:vTLESy5mRhKOs9KDp0/RATawxP1UqBmdrpVRMnpcvKQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY= +github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= +golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxtiIncJxFXeCyq84ixuKWVCaCAi9Oc= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/datasourceenhancer/attribute.go b/internal/datasourceenhancer/attribute.go new file mode 100644 index 0000000..dc0163e --- /dev/null +++ b/internal/datasourceenhancer/attribute.go @@ -0,0 +1,52 @@ +package datasourceenhancer + +import ( + "context" + + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +func Attribute(ctx context.Context, attr schema.Attribute) schema.Attribute { + switch attr := attr.(type) { + case schema.BoolAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Float64Attribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Int64Attribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ListAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.MapAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.NumberAttribute: + + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ObjectAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.SetAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.StringAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + default: + return attr + } +} diff --git a/internal/defaultplanmodifier/bool.go b/internal/defaultplanmodifier/bool.go new file mode 100644 index 0000000..ab6efba --- /dev/null +++ b/internal/defaultplanmodifier/bool.go @@ -0,0 +1,46 @@ +package defaultplanmodifier + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ planmodifier.Bool = (*defaultBoolValueAttributePlanModifier)(nil) + +// defaultBoolValueAttributePlanModifier specifies a default value (types.Int64) for an attribute. +type defaultBoolValueAttributePlanModifier struct { + DefaultValue types.Bool +} + +// Bool is a helper to instantiate a defaultValueAttributePlanModifier. +func Bool(v bool) planmodifier.Bool { + return &defaultBoolValueAttributePlanModifier{ + DefaultValue: types.BoolValue(v), + } +} + +func (apm *defaultBoolValueAttributePlanModifier) Description(ctx context.Context) string { + return apm.MarkdownDescription(ctx) +} + +func (apm *defaultBoolValueAttributePlanModifier) MarkdownDescription(ctx context.Context) string { + return fmt.Sprintf("Sets the default value %q if the attribute is not set.", apm.DefaultValue) +} + +func (apm *defaultBoolValueAttributePlanModifier) PlanModifyBool(_ context.Context, req planmodifier.BoolRequest, res *planmodifier.BoolResponse) { + // If the attribute configuration is not null, we are done here + if !req.ConfigValue.IsNull() { + return + } + + // If the attribute plan is "known" and "not null", then a previous plan modifier in the sequence + // has already been applied, and we don't want to interfere. + if !req.PlanValue.IsUnknown() && !req.PlanValue.IsNull() { + return + } + + res.PlanValue = apm.DefaultValue +} diff --git a/internal/defaultplanmodifier/string.go b/internal/defaultplanmodifier/string.go new file mode 100644 index 0000000..577953f --- /dev/null +++ b/internal/defaultplanmodifier/string.go @@ -0,0 +1,46 @@ +package defaultplanmodifier + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ planmodifier.String = (*defaultStringValueAttributePlanModifier)(nil) + +// defaultStringValueAttributePlanModifier specifies a default value (types.Int64) for an attribute. +type defaultStringValueAttributePlanModifier struct { + DefaultValue types.String +} + +// String is a helper to instantiate a defaultValueAttributePlanModifier. +func String(v string) planmodifier.String { + return &defaultStringValueAttributePlanModifier{ + DefaultValue: types.StringValue(v), + } +} + +func (apm *defaultStringValueAttributePlanModifier) Description(ctx context.Context) string { + return apm.MarkdownDescription(ctx) +} + +func (apm *defaultStringValueAttributePlanModifier) MarkdownDescription(ctx context.Context) string { + return fmt.Sprintf("Sets the default value %q if the attribute is not set.", apm.DefaultValue) +} + +func (apm *defaultStringValueAttributePlanModifier) PlanModifyString(_ context.Context, req planmodifier.StringRequest, res *planmodifier.StringResponse) { + // If the attribute configuration is not null, we are done here + if !req.ConfigValue.IsNull() { + return + } + + // If the attribute plan is "known" and "not null", then a previous plan modifier in the sequence + // has already been applied, and we don't want to interfere. + if !req.PlanValue.IsUnknown() && !req.PlanValue.IsNull() { + return + } + + res.PlanValue = apm.DefaultValue +} diff --git a/internal/provider/client.go b/internal/provider/client.go new file mode 100644 index 0000000..32a5cd9 --- /dev/null +++ b/internal/provider/client.go @@ -0,0 +1,181 @@ +package provider + +import ( + "context" + "crypto/x509" + "fmt" + "net/http" + "net/url" + "regexp" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type ClientLogger struct { + retryablehttp.Logger + + ctx context.Context +} + +func (l ClientLogger) Printf(format string, a ...interface{}) { + tflog.Trace(l.ctx, fmt.Sprintf(format, a...)) +} + +type Client struct { + *genesiscloud.ClientWithResponses + + PollingInterval time.Duration +} + +func (c *Client) PollingWait(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(c.PollingInterval): + return nil + } +} + +type ClientConfig struct { + genesiscloud.ClientConfig + PollingInterval time.Duration +} + +func NewClient(ctx context.Context, config ClientConfig) (*Client, error) { + retryClient := retryablehttp.NewClient() + retryClient.RetryMax = 4 + retryClient.Logger = ClientLogger{ctx: ctx} + retryClient.CheckRetry = RetryPolicy + + opts := []genesiscloud.ClientOption{ + genesiscloud.WithHTTPClient(retryClient.StandardClient()), + } + + client, err := genesiscloud.NewGenesisCloudClient(config.ClientConfig, opts...) + if err != nil { + return nil, err + } + + return &Client{ + ClientWithResponses: client, + PollingInterval: config.PollingInterval, + }, nil +} + +type DataSourceWithClient struct { + client *Client +} + +func (d *DataSourceWithClient) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +type ResourceWithClient struct { + client *Client +} + +func (r *ResourceWithClient) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +// Adapted from https://github.com/hashicorp/go-retryablehttp/blob/7f638666931a119b8d7a1239e44da11db0d446a4/client.go +var ( + // A regular expression to match the error returned by net/http when the + // configured number of redirects is exhausted. This error isn't typed + // specifically so we resort to matching on the error string. + redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`) + + // A regular expression to match the error returned by net/http when the + // scheme specified in the URL is invalid. This error isn't typed + // specifically so we resort to matching on the error string. + schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`) + + // A regular expression to match the error returned by net/http when the + // TLS certificate is not trusted. This error isn't typed + // specifically so we resort to matching on the error string. + notTrustedErrorRe = regexp.MustCompile(`certificate is not trusted`) +) + +func RetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { + // do not retry on context.Canceled or context.DeadlineExceeded + if ctx.Err() != nil { + return false, ctx.Err() + } + + if err != nil { + if v, ok := err.(*url.Error); ok { + // Don't retry if the error was due to too many redirects. + if redirectsErrorRe.MatchString(v.Error()) { + return false, v + } + + // Don't retry if the error was due to an invalid protocol scheme. + if schemeErrorRe.MatchString(v.Error()) { + return false, v + } + + // Don't retry if the error was due to TLS cert verification failure. + if notTrustedErrorRe.MatchString(v.Error()) { + return false, v + } + if _, ok := v.Err.(x509.UnknownAuthorityError); ok { + return false, v + } + } + + // The error is likely recoverable so retry. + return true, nil + } + + // 429 Too Many Requests is recoverable. Sometimes the server puts + // a Retry-After response header to indicate when the server is + // available to start processing request from client. + if resp.StatusCode == http.StatusTooManyRequests { + return true, nil + } + + // Check the response code. This will also catch + // invalid response codes as well, like 0 and 999. + if resp.StatusCode == 0 || resp.StatusCode >= 600 { + return true, fmt.Errorf("unexpected HTTP status %s", resp.Status) + } + + return false, nil +} diff --git a/internal/provider/common.go b/internal/provider/common.go new file mode 100644 index 0000000..67afd06 --- /dev/null +++ b/internal/provider/common.go @@ -0,0 +1,46 @@ +package provider + +import ( + "errors" + "fmt" + "net/http" + + "github.com/genesiscloud/genesiscloud-go" +) + +type ErrorResponse struct { + Body []byte + HTTPResponse *http.Response + Error *genesiscloud.ComputeV1Error +} + +var ErrResourceInErrorState = errors.New("the resource is in error state") + +func generateErrorMessage(verb string, err error) string { + return fmt.Sprintf("Error during %s: %s", verb, err) +} + +func generateClientErrorMessage(verb string, resp ErrorResponse) string { + if resp.Error != nil { + return fmt.Sprintf("Error during %s: [%s] %s %s", verb, resp.HTTPResponse.Status, resp.Error.Code, resp.Error.Message) + } else { + body := resp.Body + if len(body) > 200 { + body = append(body[:200], []byte("... (truncated)")...) + } + return fmt.Sprintf("Error during %s: [%s] %s", verb, resp.HTTPResponse.Status, body) + } +} + +func sliceStringify[T ~string](arr []T) []string { + ret := make([]string, len(arr)) + for i, value := range arr { + ret[i] = string(value) + } + + return ret +} + +func pointer[T any](v T) *T { + return &v +} diff --git a/internal/provider/images_data_source.go b/internal/provider/images_data_source.go new file mode 100644 index 0000000..6dc65af --- /dev/null +++ b/internal/provider/images_data_source.go @@ -0,0 +1,200 @@ +package provider + +import ( + "context" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/datasourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ datasource.DataSource = &ImagesDataSource{} + _ datasource.DataSourceWithConfigure = &ImagesDataSource{} +) + +func NewImagesDataSource() datasource.DataSource { + return &ImagesDataSource{} +} + +// ImagesDataSource defines the data source implementation. +type ImagesDataSource struct { + DataSourceWithClient + DataSourceWithTimeout +} + +type ImagesFilterDataSourceModel struct { + // Region Filter by the region identifier. + Region types.String `tfsdk:"region"` + + // Type Filter by the kind of image. + Type types.String `tfsdk:"type"` +} + +// ImagesDataSourceModel describes the data source data model. +type ImagesDataSourceModel struct { + Filter *ImagesFilterDataSourceModel `tfsdk:"filter"` + Images []ImageModel `tfsdk:"images"` + Id types.String `tfsdk:"id"` // placeholder + + // Internal + + // Timeouts The data source timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (d *ImagesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_images" +} + +func (d *ImagesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Images data source", + + Attributes: map[string]schema.Attribute{ + "filter": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "type": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "Filter by the kind of image.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1ImageTypes)...), + }, + }), + "region": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "Filter by the region identifier.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1Regions)...), + }, + }), + }, + }, + "images": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "created_at": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this image was created in RFC 3339.", + Computed: true, + }), + "id": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "A unique number that can be used to identify and reference a specific image.", + Computed: true, + }), + "name": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The display name that has been given to an image.", + Computed: true, + }), + "regions": datasourceenhancer.Attribute(ctx, schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The list of regions in which this image can be used in.", + Computed: true, + }), + "type": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "Describes the kind of image.", + Computed: true, + }), + }, + }, + }, + "id": datasourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The ID of the data source itself.", + Computed: true, + }), + + // Internal + "timeouts": timeouts.Attributes(ctx), + }, + } +} + +func (d *ImagesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data ImagesDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := d.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + var filterType *genesiscloud.ComputeV1ImageType + + if data.Filter != nil && !data.Filter.Type.IsNull() && !data.Filter.Type.IsUnknown() { + filterType = pointer(genesiscloud.ComputeV1ImageType(data.Filter.Type.ValueString())) + } + + var filterRegion *genesiscloud.ComputeV1Region + + if data.Filter != nil && !data.Filter.Region.IsNull() && !data.Filter.Region.IsUnknown() { + filterRegion = pointer(genesiscloud.ComputeV1Region(data.Filter.Region.ValueString())) + } + + for page := 1; ; page++ { + response, err := d.client.ListImagesWithResponse(ctx, &genesiscloud.ListImagesParams{ + Page: pointer(page), + PerPage: pointer(100), + Type: filterType, + }) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read images", err)) + return + } + + imagesResponse := response.JSON200 + if imagesResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read images", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + for _, image := range imagesResponse.Images { + if filterRegion != nil { + var found bool + for _, region := range image.Regions { + if region == *filterRegion { + found = true + break + } + } + + if !found { + continue + } + } + + model := ImageModel{} + model.PopulateFromClientResponse(&image) + + data.Images = append(data.Images, model) + } + + if len(imagesResponse.Images) < 100 { + // pagination done + break + } + } + + data.Id = types.StringValue("none") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/images_data_source_test.go b/internal/provider/images_data_source_test.go new file mode 100644 index 0000000..a22c2af --- /dev/null +++ b/internal/provider/images_data_source_test.go @@ -0,0 +1,35 @@ +package provider + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testAccImagesDataSourceConfig = ` +data "genesiscloud_images" "test" { + type = "base-os" +} +` + +func TestAccImagesDataSource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Read testing + { + Config: providerConfig + testAccImagesDataSourceConfig, + Check: resource.ComposeAggregateTestCheckFunc( + // Verify number of images returned + resource.TestCheckResourceAttr("data.genesiscloud_images.test", "images.#", "3"), + // Verify the first coffee to ensure all attributes are set + resource.TestCheckResourceAttr("data.genesiscloud_images.test", "images.0.id", "todo-uuid"), + resource.TestCheckResourceAttr("data.genesiscloud_images.test", "images.0.name", "todo-name"), + // Verify placeholder id attribute + resource.TestCheckResourceAttr("data.genesiscloud_images.test", "id", "none"), + ), + }, + }, + }) +} diff --git a/internal/provider/images_types.go b/internal/provider/images_types.go new file mode 100644 index 0000000..bb80eb6 --- /dev/null +++ b/internal/provider/images_types.go @@ -0,0 +1,35 @@ +package provider + +import ( + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ImageModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Id A unique number that can be used to identify and reference a specific image. + Id types.String `tfsdk:"id"` + + // Name The display name that has been given to an image. + Name types.String `tfsdk:"name"` + + // Regions The set of regions in which this image can be used in. + Regions []types.String `tfsdk:"regions"` + + // Type Describes the kind of image. + Type types.String `tfsdk:"type"` +} + +func (data *ImageModel) PopulateFromClientResponse(image *genesiscloud.ComputeV1Image) { + data.CreatedAt = types.StringValue(image.CreatedAt.Format(time.RFC3339)) + data.Id = types.StringValue(image.Id) + data.Name = types.StringValue(image.Name) + data.Regions = nil + for _, region := range image.Regions { + data.Regions = append(data.Regions, types.StringValue(string(region))) + } + data.Type = types.StringValue(string(image.Type)) +} diff --git a/internal/provider/instance_resource.go b/internal/provider/instance_resource.go new file mode 100644 index 0000000..0e3b7fe --- /dev/null +++ b/internal/provider/instance_resource.go @@ -0,0 +1,544 @@ +package provider + +import ( + "context" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/defaultplanmodifier" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &InstanceResource{} + _ resource.ResourceWithConfigure = &InstanceResource{} + _ resource.ResourceWithImportState = &InstanceResource{} + _ resource.ResourceWithConfigValidators = &InstanceResource{} +) + +func NewInstanceResource() resource.Resource { + return &InstanceResource{} +} + +// InstanceResource defines the resource implementation. +type InstanceResource struct { + ResourceWithClient + ResourceWithTimeout +} + +type InstanceResourceModel struct { + InstanceModel + + // Internal + + // Timeouts The resource timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (r *InstanceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_instance" +} + +func (r *InstanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Instance resource", + + Attributes: map[string]schema.Attribute{ + "created_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this image was created in RFC 3339.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "hostname": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The hostname of your instance. If not provided will be initially set to the `name` attribute.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplaceIfConfigured(), + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The unique ID of the instance.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "image_id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The image of the instance.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }), + "metadata": schema.SingleNestedAttribute{ + MarkdownDescription: "Option to provide metadata. Currently supported is `startup_script`.", + Optional: true, + Attributes: map[string]schema.Attribute{ + "startup_script": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "A plain text bash script or \"cloud-config\" file that will be executed after the first instance boot. " + + "It is limited to 64 KiB in size. You can use it to configure your instance, e.g. installing the NVIDIA GPU driver. " + + "Learn more about [startup scripts and installing the GPU driver](https://support.com/support/solutions/articles/47001122478).", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }), + }, + }, + "name": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable name for the instance.", + Required: true, + }), + "password": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The password to access the instance. " + + "Your password must have upper and lower chars, digits and length between 8-72. " + + "**Please Note**: Only one of `ssh_keys` or `password` can be provided. " + + "Password is less secure - we recommend you use an SSH key-pair.", + Optional: true, + Sensitive: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(16), + }, + }), + "placement_option": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The placement option identifier in which instances are physically located relative to each other within a zone.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + defaultplanmodifier.String(string(genesiscloud.ComputeV1PlacementOptionAUTO)), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1PlacementOptions)...), + }, + }), + "private_ip": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The private IPv4 IP-Address (IPv4 address).", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + // TODO: Could be changed outside of terraform via stop+start? + }, + }), + "public_ip": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The public IPv4 IP-Address (IPv4 address).", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + // TODO: Could be changed outside of terraform via stop+start? + }, + }), + "public_ip_type": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "When set to `static`, the instance's public IP will not change between start and stop actions.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + defaultplanmodifier.String(string(genesiscloud.ComputeV1InstancePublicIPTypeDynamic)), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1InstancePublicIPTypes)...), + }, + }), + "region": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The region identifier.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1Regions)...), + }, + }), + "security_group_ids": resourceenhancer.Attribute(ctx, schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The security groups of the instance. If not provided will be set to the default security group.", + Optional: true, + Computed: true, // might be changed outside of Terraform + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), // if unset, expect no changes + }, + }), + "ssh_key_ids": resourceenhancer.Attribute(ctx, schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The ssh keys of the instance.", + Optional: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), // Note: This is a internal limitation that should be lifted in the future + }, + }), + "status": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The instance status.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "type": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The instance type identifier.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1InstanceTypes)...), + }, + }), + "updated_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this image was last updated in RFC 3339.", + Computed: true, + }), + "volume_ids": resourceenhancer.Attribute(ctx, schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The volumes of the instance.", + Optional: true, + Computed: true, // might be changed outside of Terraform + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), // if unset, expect no changes + }, + }), + + // Internal + "timeouts": timeouts.AttributesAll(ctx), + }, + } +} + +func (r *InstanceResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{ + resourcevalidator.ExactlyOneOf( + path.MatchRoot("password"), + path.MatchRoot("ssh_key_ids"), + ), + resourcevalidator.Conflicting( + path.MatchRoot("metadata").AtName("startup_script"), + // In the future add additional metadata options here + ), + } +} + +func (r *InstanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data InstanceResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Create) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.CreateInstanceJSONRequestBody{} + + body.Name = data.Name.ValueString() + body.Hostname = data.Hostname.ValueString() + + if body.Hostname == "" { + body.Hostname = data.Name.ValueString() + } + + body.Type = genesiscloud.ComputeV1InstanceType(data.Type.ValueString()) + body.Image = data.ImageId.ValueString() + + if data.Metadata != nil { + body.Metadata = &struct { + StartupScript *string `json:"startup_script,omitempty"` + }{ + StartupScript: pointer(data.Metadata.StartupScript.ValueString()), + } + } + + if !data.Password.IsNull() && !data.Password.IsUnknown() { + body.Password = pointer(data.Password.ValueString()) + } + + if !data.SecurityGroupIds.IsNull() && !data.SecurityGroupIds.IsUnknown() { + var securityGroups []string + data.SecurityGroupIds.ElementsAs(ctx, &securityGroups, false) + body.SecurityGroups = &securityGroups + } + + if !data.SshKeyIds.IsNull() && !data.SshKeyIds.IsUnknown() { + var sshKeyIds []string + data.SshKeyIds.ElementsAs(ctx, &sshKeyIds, false) + body.SshKeys = &sshKeyIds + } + + if !data.VolumeIds.IsNull() && !data.VolumeIds.IsUnknown() { + var volumeIds []string + data.VolumeIds.ElementsAs(ctx, &volumeIds, false) + body.Volumes = &volumeIds + } + + body.PublicIpType = pointer(genesiscloud.ComputeV1InstancePublicIPType(data.PublicIpType.ValueString())) + body.Region = pointer(genesiscloud.ComputeV1Region(data.Region.ValueString())) + body.PlacementOption = pointer(genesiscloud.ComputeV1PlacementOption(data.PlacementOption.ValueString())) + + response, err := r.client.CreateInstanceWithResponse(ctx, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("create instance", err)) + return + } + + instanceResponse := response.JSON201 + if instanceResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("create instance", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &instanceResponse.Instance)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "created a instance resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + instanceId := instanceResponse.Instance.Id + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling instance", err)) + return + } + + response, err := r.client.GetInstanceWithResponse(ctx, instanceId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling instance", err)) + return + } + + instanceResponse := response.JSON200 + if instanceResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("polling instance", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + status := instanceResponse.Instance.Status + if status == "active" || status == "error" { + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &instanceResponse.Instance)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if status == "error" { + resp.Diagnostics.AddError("Provisioning Error", generateErrorMessage("polling instance", ErrResourceInErrorState)) + } + return + } + } +} + +func (r *InstanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data InstanceResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + instanceId := data.Id.ValueString() + + response, err := r.client.GetInstanceWithResponse(ctx, instanceId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read instance", err)) + return + } + + instanceResponse := response.JSON200 + if instanceResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read instance", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &instanceResponse.Instance)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read a instance resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *InstanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data InstanceResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Update) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.UpdateInstanceJSONRequestBody{} + + body.Name = pointer(data.Name.ValueString()) + + if !data.SecurityGroupIds.IsNull() && !data.SecurityGroupIds.IsUnknown() { + var securityGroups []string + data.SecurityGroupIds.ElementsAs(ctx, &securityGroups, false) + body.SecurityGroups = &securityGroups + } + + if !data.VolumeIds.IsNull() && !data.VolumeIds.IsUnknown() { + var volumeIds []string + data.VolumeIds.ElementsAs(ctx, &volumeIds, false) + body.Volumes = &volumeIds + } + + instanceId := data.Id.ValueString() + + response, err := r.client.UpdateInstanceWithResponse(ctx, instanceId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("update instance", err)) + return + } + + instanceResponse := response.JSON200 + if instanceResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("update instance", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &instanceResponse.Instance)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "updated a instance resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *InstanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data InstanceResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Delete) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + instanceId := data.Id.ValueString() + + response, err := r.client.DeleteInstanceWithResponse(ctx, instanceId) + + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("delete instance", err)) + return + } + + if response.StatusCode() != 204 { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("delete instance", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling instance", err)) + return + } + + tflog.Trace(ctx, "polling a instance resource") + + response, err := r.client.GetInstanceWithResponse(ctx, instanceId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling instance", err)) + return + } + + if response.StatusCode() == 404 { + return + } + } +} + +func (r *InstanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/instance_resource_test.go b/internal/provider/instance_resource_test.go new file mode 100644 index 0000000..8756b78 --- /dev/null +++ b/internal/provider/instance_resource_test.go @@ -0,0 +1,47 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccInstanceResourceConfig(name string) string { + return fmt.Sprintf(` +resource "genesiscloud_instance" "test" { + name = %[1]q +} +`, name) +} + +func TestAccInstanceResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + testAccInstanceResourceConfig("one"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_instance.test", "id", "instance-id"), + resource.TestCheckResourceAttr("genesiscloud_instance.test", "name", "one"), + ), + }, + // ImportState testing + { + ResourceName: "genesiscloud_instance.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update and Read testing + { + Config: providerConfig + testAccInstanceResourceConfig("two"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_instance.test", "name", "two"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/internal/provider/instance_types.go b/internal/provider/instance_types.go new file mode 100644 index 0000000..934d715 --- /dev/null +++ b/internal/provider/instance_types.go @@ -0,0 +1,120 @@ +package provider + +import ( + "context" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type InstanceMetadataModel struct { + // StartupScript A plain text bash script or "cloud-config" file that will be executed after the first instance boot. + // It is limited to 64 KiB in size. You can use it to configure your instance, e.g. installing the **NVIDIA GPU driver**. + // Learn more about [startup scripts and installing the GPU driver](https://support.com/support/solutions/articles/47001122478). + StartupScript types.String `tfsdk:"startup_script"` +} + +type InstanceModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Hostname The hostname of your instance. + Hostname types.String `tfsdk:"hostname"` + + // Id The unique ID of the instance. + Id types.String `tfsdk:"id"` + + // ImageId The image of the instance. + ImageId types.String `tfsdk:"image_id"` + + // Metadata Option to provide metadata. Currently supported is `startup_script`. + Metadata *InstanceMetadataModel `tfsdk:"metadata"` + + // Name The human-readable name for the instance. + Name types.String `tfsdk:"name"` + + // Password The password to access the instance. + // Your password must have a minimum length of 16 characters. + // **Please Note**: Only one of `ssh_keys` or `password` can be provided. + // Password is less secure - we recommend you use an SSH key-pair. + Password types.String `tfsdk:"password"` + + // PlacementOption The placement option identifier in which instances are physically located relative to each other within a zone. + PlacementOption types.String `tfsdk:"placement_option"` + + // PrivateIp The private IPv4 IP-Address (IPv4 address). + PrivateIp types.String `tfsdk:"private_ip"` + + // PublicIp The public IPv4 IP-Address (IPv4 address). + PublicIp types.String `tfsdk:"public_ip"` + + // PublicIpType When set to `static`, the instance's public IP will not change between start and stop actions. + PublicIpType types.String `tfsdk:"public_ip_type"` + + // Region The region identifier. + Region types.String `tfsdk:"region"` + + // SecurityGroupIds The security groups of the instance. + SecurityGroupIds types.Set `tfsdk:"security_group_ids"` + + // SshKeyIds The ssh keys of the instance. + SshKeyIds types.Set `tfsdk:"ssh_key_ids"` + + // Status The instance status + Status types.String `tfsdk:"status"` + + // Type The instance type identifier. + Type types.String `tfsdk:"type"` + + UpdatedAt types.String `tfsdk:"updated_at"` + + // VolumeIds The volumes of the instance + VolumeIds types.Set `tfsdk:"volume_ids"` +} + +func (data *InstanceModel) PopulateFromClientResponse(ctx context.Context, instance *genesiscloud.ComputeV1Instance) (diag diag.Diagnostics) { + data.Id = types.StringValue(instance.Id) + data.Name = types.StringValue(instance.Name) + data.Hostname = types.StringValue(instance.Hostname) + data.Type = types.StringValue(string(instance.Type)) + data.ImageId = types.StringValue(*instance.Image.Id) + + volumeIds := make([]string, 0) // volumes do NOT support NULL + for _, volume := range instance.Volumes { + volumeIds = append(volumeIds, *volume.Id) + } + data.VolumeIds, diag = types.SetValueFrom(ctx, types.StringType, volumeIds) + if diag.HasError() { + return + } + + securityGroupIds := make([]string, 0) // security groups do NOT support NULL + for _, securityGroup := range instance.SecurityGroups { + securityGroupIds = append(securityGroupIds, *securityGroup.Id) + } + data.SecurityGroupIds, diag = types.SetValueFrom(ctx, types.StringType, securityGroupIds) + if diag.HasError() { + return + } + + var sshKeyIds []string // ssh-keys do support NULL + for _, sshKey := range instance.SshKeys { + sshKeyIds = append(sshKeyIds, *sshKey.Id) + } + data.SshKeyIds, diag = types.SetValueFrom(ctx, types.StringType, sshKeyIds) + if diag.HasError() { + return + } + + data.PlacementOption = types.StringValue(string(instance.PlacementOption)) + data.PrivateIp = types.StringValue(instance.PrivateIp) + data.PublicIp = types.StringValue(instance.PublicIp) + data.PublicIpType = types.StringValue(string(instance.PublicIpType)) + data.Region = types.StringValue(string(instance.Region)) + data.Status = types.StringValue(string(instance.Status)) + data.CreatedAt = types.StringValue(instance.CreatedAt.Format(time.RFC3339)) + data.UpdatedAt = types.StringValue(instance.UpdatedAt.Format(time.RFC3339)) + + return +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go new file mode 100644 index 0000000..d8336ea --- /dev/null +++ b/internal/provider/provider.go @@ -0,0 +1,197 @@ +package provider + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/providerenhancer" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/timedurationvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Ensure GenesisCloudProvider satisfies various provider interfaces. +var ( + _ provider.Provider = &GenesisCloudProvider{} +) + +// GenesisCloudProvider defines the provider implementation. +type GenesisCloudProvider struct { + // version is set to the provider version on release, "dev" when the + // provider is built and ran locally, and "test" when running acceptance + // testing. + version string +} + +// GenesisCloudProviderModel describes the provider data model. +type GenesisCloudProviderModel struct { + Endpoint types.String `tfsdk:"endpoint"` + Token types.String `tfsdk:"token"` + PollingInterval types.String `tfsdk:"polling_interval"` +} + +func (p *GenesisCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "genesiscloud" + resp.Version = p.version +} + +func (p *GenesisCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "The Genesis Cloud provider is used to interact with resources supported by [Genesis Cloud](https://www.genesiscloud.com/). The provider needs to be configured with the proper credentials before it can be used.", + Attributes: map[string]schema.Attribute{ + "endpoint": schema.StringAttribute{ + MarkdownDescription: fmt.Sprintf( + "Genesis Cloud API endpoint. May also be provided via `GENESISCLOUD_ENDPOINT` environment variable. If neither is provided, defaults to `%s`.", + genesiscloud.DefaultEndpoint), + Optional: true, + }, + "token": schema.StringAttribute{ + MarkdownDescription: "Genesis Cloud API token. May also be provided via `GENESISCLOUD_TOKEN` environment variable.", + Optional: true, + Sensitive: true, + }, + "polling_interval": providerenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The polling interval.", + Optional: true, + Validators: []validator.String{ + timedurationvalidator.Positive(), + }, + }), + }, + } +} + +func (p *GenesisCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + var data GenesisCloudProviderModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if data.Endpoint.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("endpoint"), + "Unknown Genesis Cloud API endpoint", + "The provider cannot create the Genesis Cloud API client as there is an unknown configuration value for the Genesis Cloud API endpoint. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the GENESISCLOUD_ENDPOINT environment variable.", + ) + } + + if data.Token.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("token"), + "Unknown Genesis Cloud API token", + "The provider cannot create the Genesis Cloud API client as there is an unknown configuration value for the Genesis Cloud API token. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the GENESISCLOUD_TOKEN environment variable.", + ) + } + + if data.PollingInterval.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("polling_interval"), + "Unknown Polling Interval", + "The provider cannot create the Genesis Cloud API client as there is an unknown configuration value for the Polling Interval. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or remove it to use the default.", + ) + } + + if resp.Diagnostics.HasError() { + return + } + + endpoint := os.Getenv("GENESISCLOUD_ENDPOINT") + token := os.Getenv("GENESISCLOUD_TOKEN") + pollingInterval := 2 * time.Second + + if !data.Endpoint.IsNull() { + endpoint = data.Endpoint.ValueString() + } + if !data.Token.IsNull() { + token = data.Token.ValueString() + } + if !data.PollingInterval.IsNull() { + duration, err := time.ParseDuration(data.PollingInterval.ValueString()) + if err != nil { + resp.Diagnostics.AddAttributeError( + path.Root("polling_interval"), + "Timeout Cannot Be Parsed", + err.Error(), + ) + return + } + + pollingInterval = duration + } + + if endpoint == "" { + endpoint = genesiscloud.DefaultEndpoint + } + + if token == "" { + resp.Diagnostics.AddAttributeError( + path.Root("token"), + "Missing Genesis Cloud API token", + "The provider cannot create the Genesis Cloud API client as there is a missing or empty value for the Genesis Cloud API token. "+ + "Set the token value in the configuration or use the GENESISCLOUD_TOKEN environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if resp.Diagnostics.HasError() { + return + } + + providerClient, err := NewClient(ctx, ClientConfig{ + ClientConfig: genesiscloud.ClientConfig{ + Endpoint: endpoint, + Token: token, + }, + PollingInterval: pollingInterval, + }) + if err != nil { + resp.Diagnostics.AddError( + "Unable to Create Genesis Cloud API Client", + "An unexpected error occurred when creating the Genesis Cloud API client. "+ + "If the error is not clear, please contact the provider developers.\n\n"+ + "Error: "+err.Error(), + ) + return + } + + resp.DataSourceData = providerClient + resp.ResourceData = providerClient +} + +func (p *GenesisCloudProvider) Resources(ctx context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewInstanceResource, + NewSSHKeyResource, + NewVolumeResource, + NewSecurityGroupResource, + NewSnapshotResource, + } +} + +func (p *GenesisCloudProvider) DataSources(ctx context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewImagesDataSource, + } +} + +func New(version string) func() provider.Provider { + return func() provider.Provider { + return &GenesisCloudProvider{ + version: version, + } + } +} diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go new file mode 100644 index 0000000..3841955 --- /dev/null +++ b/internal/provider/provider_test.go @@ -0,0 +1,36 @@ +package provider + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" +) + +const ( + // providerConfig is a shared configuration to combine with the actual + // test configuration so the Genesis Cloud client is properly configured. + providerConfig = ` +provider "genesiscloud" {} +` +) + +// testAccProtoV6ProviderFactories are used to instantiate a provider during +// acceptance testing. The factory function will be invoked for every Terraform +// CLI command executed to create a provider server to which the CLI can +// reattach. +var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ + "genesiscloud": providerserver.NewProtocol6WithError(New("test")()), +} + +func testAccPreCheck(t *testing.T) { + // You can add code here to run prior to any test case execution, for example assertions + // about the appropriate environment variables being set are common to see in a pre-check + // function + + if os.Getenv("GENESISCLOUD_TOKEN") == "" { + t.Fatal("GENESISCLOUD_TOKEN must be set for acceptance tests") + } + +} diff --git a/internal/provider/security_group_resource.go b/internal/provider/security_group_resource.go new file mode 100644 index 0000000..420c54c --- /dev/null +++ b/internal/provider/security_group_resource.go @@ -0,0 +1,488 @@ +package provider + +import ( + "context" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/defaultplanmodifier" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &SecurityGroupResource{} + _ resource.ResourceWithConfigure = &SecurityGroupResource{} + _ resource.ResourceWithImportState = &SecurityGroupResource{} + _ resource.ResourceWithConfigValidators = &SecurityGroupResource{} +) + +func NewSecurityGroupResource() resource.Resource { + return &SecurityGroupResource{} +} + +// SecurityGroupResource defines the resource implementation. +type SecurityGroupResource struct { + ResourceWithClient + ResourceWithTimeout +} + +type SecurityGroupResourceModel struct { + SecurityGroupModel + + // Internal + + // Timeouts The resource timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (r *SecurityGroupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_security_group" +} + +func (r *SecurityGroupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Security group resource", + + Attributes: map[string]schema.Attribute{ + "created_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this security group was created in RFC 3339.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "description": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable description for the security group.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + defaultplanmodifier.String(""), + }, + }), + "id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The unique ID of the security group.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "name": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable name for the security group.", + Required: true, + }), + "region": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The region identifier.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1Regions)...), + }, + }), + "rules": schema.ListNestedAttribute{ + Required: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "direction": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The direction of the rule.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1SecurityGroupRuleDirections)...), + }, + }), + "port_range_max": resourceenhancer.Attribute(ctx, schema.Int64Attribute{ + MarkdownDescription: "The maximum port number of the rule.", + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 65535), + }, + }), + "port_range_min": resourceenhancer.Attribute(ctx, schema.Int64Attribute{ + MarkdownDescription: "The minimum port number of the rule.", + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 65535), + }, + }), + "protocol": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The protocol of the rule.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1SecurityGroupRuleProtocols)...), + }, + }), + }, + }, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, + }, + "status": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The security group status.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + + // Internal + "timeouts": timeouts.AttributesAll(ctx), + }, + } +} + +func (r *SecurityGroupResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{ + // Improvement: Add additional rule validation + } +} + +func (r *SecurityGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SecurityGroupResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Create) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.CreateSecurityGroupJSONRequestBody{} + + body.Description = pointer(data.Description.ValueString()) + body.Name = data.Name.ValueString() + body.Region = pointer(genesiscloud.ComputeV1Region(data.Region.ValueString())) + + for _, rule := range data.Rules { + var portRangeMax, portRangeMin *int + + if !rule.PortRangeMax.IsNull() && !rule.PortRangeMax.IsUnknown() { + portRangeMax = pointer(int(rule.PortRangeMax.ValueInt64())) + } + + if !rule.PortRangeMin.IsNull() && !rule.PortRangeMin.IsUnknown() { + portRangeMin = pointer(int(rule.PortRangeMin.ValueInt64())) + } + + body.Rules = append(body.Rules, genesiscloud.ComputeV1SecurityGroupRule{ + Direction: genesiscloud.ComputeV1SecurityGroupRuleDirection(rule.Direction.ValueString()), + PortRangeMax: portRangeMax, + PortRangeMin: portRangeMin, + Protocol: genesiscloud.ComputeV1SecurityGroupRuleProtocol(rule.Protocol.ValueString()), + }) + } + + response, err := r.client.CreateSecurityGroupWithResponse(ctx, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("create security_group", err)) + return + } + + securityGroupResponse := response.JSON201 + if securityGroupResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("create security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &securityGroupResponse.SecurityGroup)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "created a security group resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + securityGroupId := securityGroupResponse.SecurityGroup.Id + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling security_group", err)) + return + } + + tflog.Trace(ctx, "polling a security group resource") + + response, err := r.client.GetSecurityGroupWithResponse(ctx, securityGroupId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling security_group", err)) + return + } + + securityGroupResponse := response.JSON200 + if securityGroupResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("polling security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + status := securityGroupResponse.SecurityGroup.Status + if status == "created" || status == "error" { + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &securityGroupResponse.SecurityGroup)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if status == "error" { + resp.Diagnostics.AddError("Provisioning Error", generateErrorMessage("polling security_group", ErrResourceInErrorState)) + } + return + } + } +} + +func (r *SecurityGroupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data SecurityGroupResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + securityGroupId := data.Id.ValueString() + + response, err := r.client.GetSecurityGroupWithResponse(ctx, securityGroupId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read security_group", err)) + return + } + + securityGroupResponse := response.JSON200 + if securityGroupResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &securityGroupResponse.SecurityGroup)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read a security group resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SecurityGroupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data SecurityGroupResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Update) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.UpdateSecurityGroupJSONRequestBody{} + + body.Description = pointer(data.Description.ValueString()) + body.Name = data.Name.ValueString() + for _, rule := range data.Rules { + var portRangeMax, portRangeMin *int + + if !rule.PortRangeMax.IsNull() && !rule.PortRangeMax.IsUnknown() { + portRangeMax = pointer(int(rule.PortRangeMax.ValueInt64())) + } + + if !rule.PortRangeMin.IsNull() && !rule.PortRangeMin.IsUnknown() { + portRangeMin = pointer(int(rule.PortRangeMin.ValueInt64())) + } + + body.Rules = append(body.Rules, genesiscloud.ComputeV1SecurityGroupRule{ + Direction: genesiscloud.ComputeV1SecurityGroupRuleDirection(rule.Direction.ValueString()), + PortRangeMax: portRangeMax, + PortRangeMin: portRangeMin, + Protocol: genesiscloud.ComputeV1SecurityGroupRuleProtocol(rule.Protocol.ValueString()), + }) + } + + securityGroupId := data.Id.ValueString() + + response, err := r.client.UpdateSecurityGroupWithResponse(ctx, securityGroupId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("update security_group", err)) + return + } + + securityGroupResponse := response.JSON200 + if securityGroupResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("update security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &securityGroupResponse.SecurityGroup)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "updated a security group resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling security_group", err)) + return + } + + tflog.Trace(ctx, "polling a security group resource") + + response, err := r.client.GetSecurityGroupWithResponse(ctx, securityGroupId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling security_group", err)) + return + } + + securityGroupResponse := response.JSON200 + if securityGroupResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("polling security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + status := securityGroupResponse.SecurityGroup.Status + if status == "created" || status == "error" { + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &securityGroupResponse.SecurityGroup)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if status == "error" { + resp.Diagnostics.AddError("Provisioning Error", generateErrorMessage("polling security_group", ErrResourceInErrorState)) + } + return + } + } +} + +func (r *SecurityGroupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data SecurityGroupResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Delete) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + securityGroupId := data.Id.ValueString() + + response, err := r.client.DeleteSecurityGroupWithResponse(ctx, securityGroupId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("delete security_group", err)) + return + } + + if response.StatusCode() != 204 { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("delete security_group", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling security_group", err)) + return + } + + tflog.Trace(ctx, "polling a security group resource") + + response, err := r.client.GetSecurityGroupWithResponse(ctx, securityGroupId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling security_group", err)) + return + } + + if response.StatusCode() == 404 { + return + } + } +} + +func (r *SecurityGroupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/security_group_resource_test.go b/internal/provider/security_group_resource_test.go new file mode 100644 index 0000000..1098be7 --- /dev/null +++ b/internal/provider/security_group_resource_test.go @@ -0,0 +1,49 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccSecurityGroupResourceConfig(name, todo string) string { + return fmt.Sprintf(` +resource "genesiscloud_security_group" "test" { + name = %[1]q + todo = %[2]q +} +`, name, todo) +} + +func TestAccSecurityGroupResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + testAccSecurityGroupResourceConfig("one", samplePublicKey), + Check: resource.ComposeAggregateTestCheckFunc( + // resource.TestCheckResourceAttr("genesiscloud_security_group.test", "id", "ssh-key-id"), + resource.TestCheckResourceAttr("genesiscloud_security_group.test", "name", "one"), + resource.TestCheckResourceAttr("genesiscloud_security_group.test", "todo", "todo"), + ), + }, + // ImportState testing + { + ResourceName: "genesiscloud_security_group.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update and Read testing + { + Config: providerConfig + testAccSecurityGroupResourceConfig("two", samplePublicKey), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_security_group.test", "name", "two"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/internal/provider/security_group_types.go b/internal/provider/security_group_types.go new file mode 100644 index 0000000..6e1a0ac --- /dev/null +++ b/internal/provider/security_group_types.go @@ -0,0 +1,79 @@ +package provider + +import ( + "context" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SecurityGroupRuleModel struct { + // Direction The direction of the rule. + Direction types.String `tfsdk:"direction"` + + // PortRangeMax The maximum port number of the rule. + PortRangeMax types.Int64 `tfsdk:"port_range_max"` + + // PortRangeMin The minimum port number of the rule. + PortRangeMin types.Int64 `tfsdk:"port_range_min"` + + // Protocol The protocol of the rule. + Protocol types.String `tfsdk:"protocol"` +} + +type SecurityGroupModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Description The human-readable description for the security group. + Description types.String `tfsdk:"description"` + + // Id The unique ID of the security group. + Id types.String `tfsdk:"id"` + + // Name The human-readable name for the security group. + Name types.String `tfsdk:"name"` + + // Region The region identifier. + Region types.String `tfsdk:"region"` + + // Rules The security group rules. + Rules []SecurityGroupRuleModel `tfsdk:"rules"` + + // Status The security group status. + Status types.String `tfsdk:"status"` +} + +func (data *SecurityGroupModel) PopulateFromClientResponse(ctx context.Context, securityGroup *genesiscloud.ComputeV1SecurityGroup) (diag diag.Diagnostics) { + data.CreatedAt = types.StringValue(securityGroup.CreatedAt.Format(time.RFC3339)) + data.Description = types.StringValue(securityGroup.Description) + data.Id = types.StringValue(securityGroup.Id) + data.Name = types.StringValue(securityGroup.Name) + data.Region = types.StringValue(string(securityGroup.Region)) + + data.Rules = nil + for _, rule := range securityGroup.Rules { + portRangeMax := types.Int64Null() + portRangeMin := types.Int64Null() + + if rule.PortRangeMax != nil { + portRangeMax = types.Int64Value(int64(*rule.PortRangeMax)) + } + + if rule.PortRangeMin != nil { + portRangeMin = types.Int64Value(int64(*rule.PortRangeMin)) + } + + data.Rules = append(data.Rules, SecurityGroupRuleModel{ + Direction: types.StringValue(string(rule.Direction)), + PortRangeMax: portRangeMax, + PortRangeMin: portRangeMin, + Protocol: types.StringValue(string(rule.Protocol)), + }) + } + + data.Status = types.StringValue(string(securityGroup.Status)) + + return +} diff --git a/internal/provider/snapshot_resource.go b/internal/provider/snapshot_resource.go new file mode 100644 index 0000000..3991435 --- /dev/null +++ b/internal/provider/snapshot_resource.go @@ -0,0 +1,379 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/defaultplanmodifier" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &SnapshotResource{} + _ resource.ResourceWithConfigure = &SnapshotResource{} + _ resource.ResourceWithImportState = &SnapshotResource{} +) + +func NewSnapshotResource() resource.Resource { + return &SnapshotResource{} +} + +// SnapshotResource defines the resource implementation. +type SnapshotResource struct { + ResourceWithClient + ResourceWithTimeout +} + +type SnapshotResourceModel struct { + SnapshotModel + + // Internal + + // RetainOnDelete Flag to retain the snapshot when the resource is deleted. It has to be deleted manually. + RetainOnDelete types.Bool `tfsdk:"retain_on_delete"` + + // Timeouts The resource timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (r *SnapshotResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_snapshot" +} + +func (r *SnapshotResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Snapshot resource", + + Attributes: map[string]schema.Attribute{ + "created_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this snapshot was created in RFC 3339.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The unique ID of the snapshot.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "name": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable name for the snapshot.", + Required: true, + }), + "region": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The region identifier.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "instance_id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The id of the instance to snapshot.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }), + "size": resourceenhancer.Attribute(ctx, schema.Int64Attribute{ + MarkdownDescription: "The storage size of this snapshot given in bytes.", + Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), // immutable + }, + }), + "status": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The snapshot status.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + + // Internal + "retain_on_delete": resourceenhancer.Attribute(ctx, schema.BoolAttribute{ + MarkdownDescription: "Flag to retain the snapshot when the resource is deleted.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + defaultplanmodifier.Bool(false), + }, + }), + + "timeouts": timeouts.AttributesAll(ctx), + }, + } +} + +func (r *SnapshotResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SnapshotResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Create) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.CreateSnapshotJSONRequestBody{} + body.Name = data.Name.ValueString() + + instanceId := data.InstanceId.ValueString() + + response, err := r.client.CreateSnapshotWithResponse(ctx, instanceId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("create snapshot", err)) + return + } + + snapshotResponse := response.JSON201 + if snapshotResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("create snapshot", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &snapshotResponse.Snapshot)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "created a snapshot resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + snapshotId := snapshotResponse.Snapshot.Id + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling snapshot", err)) + return + } + + tflog.Trace(ctx, "polling a snapshot resource") + + response, err := r.client.GetSnapshotWithResponse(ctx, snapshotId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling snapshot", err)) + return + } + + snapshotResponse := response.JSON200 + if snapshotResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("polling snapshot", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + status := snapshotResponse.Snapshot.Status + if status == "active" || status == "error" { + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &snapshotResponse.Snapshot)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if status == "error" { + resp.Diagnostics.AddError("Provisioning Error", generateErrorMessage("polling snapshot", ErrResourceInErrorState)) + } + return + } + } +} + +func (r *SnapshotResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data SnapshotResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + snapshotId := data.Id.ValueString() + + response, err := r.client.GetSnapshotWithResponse(ctx, snapshotId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read snapshot", err)) + return + } + + snapshotResponse := response.JSON200 + if snapshotResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read snapshot", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &snapshotResponse.Snapshot)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read a snapshot resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SnapshotResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data SnapshotResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Update) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.UpdateSnapshotJSONRequestBody{} + + body.Name = data.Name.ValueString() + + snapshotId := data.Id.ValueString() + + response, err := r.client.UpdateSnapshotWithResponse(ctx, snapshotId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("update snapshot", err)) + return + } + + snapshotResponse := response.JSON200 + if snapshotResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("update snapshot", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &snapshotResponse.Snapshot)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "updated a snapshot resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SnapshotResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data SnapshotResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Delete) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + snapshotId := data.Id.ValueString() + + if data.RetainOnDelete.ValueBool() { + resp.Diagnostics.AddWarning( + "Snapshot is retained", + fmt.Sprintf("The snapshot resource with id %q was deleted from the state but the snapshot is retained.", snapshotId), + ) + return + } + + response, err := r.client.DeleteSnapshotWithResponse(ctx, snapshotId) + + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("delete snapshot", err)) + return + } + + if response.StatusCode() != 204 { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("delete snapshot", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling snapshot", err)) + return + } + + tflog.Trace(ctx, "polling a snapshot resource") + + response, err := r.client.GetSnapshotWithResponse(ctx, snapshotId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling snapshot", err)) + return + } + + if response.StatusCode() == 404 { + return + } + } +} + +func (r *SnapshotResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/snapshot_resource_test.go b/internal/provider/snapshot_resource_test.go new file mode 100644 index 0000000..1bde3a3 --- /dev/null +++ b/internal/provider/snapshot_resource_test.go @@ -0,0 +1,49 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccSnapshotResourceConfig(name string, size int) string { + return fmt.Sprintf(` +resource "genesiscloud_snapshot" "test" { + name = %[1]q + size = %[2]q +} +`, name, size) +} + +func TestAccSnapshotResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + testAccSnapshotResourceConfig("one", 1), + Check: resource.ComposeAggregateTestCheckFunc( + // resource.TestCheckResourceAttr("genesiscloud_snapshot.test", "id", "ssh-key-id"), + resource.TestCheckResourceAttr("genesiscloud_snapshot.test", "name", "one"), + resource.TestCheckResourceAttr("genesiscloud_snapshot.test", "size", "1"), + ), + }, + // ImportState testing + { + ResourceName: "genesiscloud_snapshot.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update and Read testing + { + Config: providerConfig + testAccSnapshotResourceConfig("two", 1), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_snapshot.test", "name", "two"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/internal/provider/snapshot_types.go b/internal/provider/snapshot_types.go new file mode 100644 index 0000000..e6f9d07 --- /dev/null +++ b/internal/provider/snapshot_types.go @@ -0,0 +1,62 @@ +package provider + +import ( + "context" + "fmt" + "strconv" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SnapshotModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Id The unique ID of the snapshot. + Id types.String `tfsdk:"id"` + + // Name The human-readable name for the snapshot. + Name types.String `tfsdk:"name"` + + // Region The region identifier. + Region types.String `tfsdk:"region"` + + // InstanceId The id of the instance that was snapshotted. + InstanceId types.String `tfsdk:"instance_id"` + + // Size The storage size of this snapshot given in bytes. + Size types.Int64 `tfsdk:"size"` + + // Status The snapshot status. + Status types.String `tfsdk:"status"` +} + +func (data *SnapshotModel) PopulateFromClientResponse(ctx context.Context, snapshot *genesiscloud.ComputeV1Snapshot) (diag diag.Diagnostics) { + data.CreatedAt = types.StringValue(snapshot.CreatedAt.Format(time.RFC3339)) + data.Id = types.StringValue(snapshot.Id) + data.Name = types.StringValue(snapshot.Name) + data.Region = types.StringValue(string(snapshot.Region)) + data.InstanceId = types.StringValue(string(snapshot.ResourceId)) + + data.Size = types.Int64Null() + if snapshot.Size != nil { + i, err := strconv.ParseInt(*snapshot.Size, 10, 64) + if err != nil { + diag.AddAttributeError( + path.Root("size"), + "Unmarshalling failed", + fmt.Sprintf("Failed to unmarshal BigInt response: %q", *snapshot.Size), + ) + return + } + + data.Size = types.Int64Value(i) + } + + data.Status = types.StringValue(string(snapshot.Status)) + + return +} diff --git a/internal/provider/ssh_key_resource.go b/internal/provider/ssh_key_resource.go new file mode 100644 index 0000000..878b916 --- /dev/null +++ b/internal/provider/ssh_key_resource.go @@ -0,0 +1,271 @@ +package provider + +import ( + "context" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &SSHKeyResource{} + _ resource.ResourceWithConfigure = &SSHKeyResource{} + _ resource.ResourceWithImportState = &SSHKeyResource{} +) + +func NewSSHKeyResource() resource.Resource { + return &SSHKeyResource{} +} + +// SSHKeyResource defines the resource implementation. +type SSHKeyResource struct { + ResourceWithClient + ResourceWithTimeout +} + +type SSHKeyResourceModel struct { + SSHKeyModel + + // Internal + + // Timeouts The resource timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (r *SSHKeyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_ssh_key" +} + +func (r *SSHKeyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "SSH key resource", + + Attributes: map[string]schema.Attribute{ + "created_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this SSH key was created in RFC 3339.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "fingerprint": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The fingerprint of the SSH key.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The unique ID of the SSH key.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "name": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable name for the SSH key.", + Required: true, + }), + "public_key": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "SSH public key.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }), + + // Internal + "timeouts": timeouts.AttributesAll(ctx), + }, + } +} + +func (r *SSHKeyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data SSHKeyResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Create) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.CreateSSHKeyJSONRequestBody{} + + body.Name = data.Name.ValueString() + body.Value = data.PublicKey.ValueString() + + response, err := r.client.CreateSSHKeyWithResponse(ctx, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("create ssh_key", err)) + return + } + + sshkeyResponse := response.JSON201 + if sshkeyResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("create ssh_key", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, sshkeyResponse)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "created a ssh_key resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SSHKeyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data SSHKeyResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + sshKeyId := data.Id.ValueString() + + response, err := r.client.GetSSHKeyWithResponse(ctx, sshKeyId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read ssh_key", err)) + return + } + + sshkeyResponse := response.JSON200 + if sshkeyResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read ssh_key", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, sshkeyResponse)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read a ssh_key resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SSHKeyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data SSHKeyResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Update) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.UpdateSSHKeyJSONRequestBody{} + + body.Name = data.Name.ValueString() + + sshKeyId := data.Id.ValueString() + + response, err := r.client.UpdateSSHKeyWithResponse(ctx, sshKeyId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("update ssh_key", err)) + return + } + + sshkeyResponse := response.JSON200 + if sshkeyResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("update ssh_key", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, sshkeyResponse)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "updated a ssh_key resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *SSHKeyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data SSHKeyResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Delete) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + sshKeyId := data.Id.ValueString() + + response, err := r.client.DeleteSSHKeyWithResponse(ctx, sshKeyId) + + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("delete ssh_key", err)) + return + } + + if response.StatusCode() != 204 { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("delete ssh_key", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } +} + +func (r *SSHKeyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/ssh_key_resource_test.go b/internal/provider/ssh_key_resource_test.go new file mode 100644 index 0000000..cd8a8d2 --- /dev/null +++ b/internal/provider/ssh_key_resource_test.go @@ -0,0 +1,51 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccSSHKeyResourceConfig(name, publicKey string) string { + return fmt.Sprintf(` +resource "genesiscloud_ssh_key" "test" { + name = %[1]q + public_key = %[2]q +} +`, name, publicKey) +} + +const samplePublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOpdKM8wSI07+PO4xLDL7zW/kNWGbdFXeHyBU1TRlBn alice@example.com" + +func TestAccSSHKeyResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + testAccSSHKeyResourceConfig("one", samplePublicKey), + Check: resource.ComposeAggregateTestCheckFunc( + // resource.TestCheckResourceAttr("genesiscloud_ssh_key.test", "id", "ssh-key-id"), + resource.TestCheckResourceAttr("genesiscloud_ssh_key.test", "name", "one"), + resource.TestCheckResourceAttr("genesiscloud_ssh_key.test", "public_key", samplePublicKey), + ), + }, + // ImportState testing + { + ResourceName: "genesiscloud_ssh_key.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update and Read testing + { + Config: providerConfig + testAccSSHKeyResourceConfig("two", samplePublicKey), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_ssh_key.test", "name", "two"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/internal/provider/ssh_key_types.go b/internal/provider/ssh_key_types.go new file mode 100644 index 0000000..58a2fc1 --- /dev/null +++ b/internal/provider/ssh_key_types.go @@ -0,0 +1,36 @@ +package provider + +import ( + "context" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SSHKeyModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Fingerprint The fingerprint of the SSH key. + Fingerprint types.String `tfsdk:"fingerprint"` + + // Id The unique ID of the SSH key. + Id types.String `tfsdk:"id"` + + // Name The human-readable name for the SSH key. + Name types.String `tfsdk:"name"` + + // PublicKey SSH public key. + PublicKey types.String `tfsdk:"public_key"` +} + +func (data *SSHKeyModel) PopulateFromClientResponse(ctx context.Context, sshKey *genesiscloud.ComputeV1SSHKey) (diag diag.Diagnostics) { + data.CreatedAt = types.StringValue(sshKey.CreatedAt.Format(time.RFC3339)) + data.Fingerprint = types.StringValue(sshKey.Fingerprint) + data.Id = types.StringValue(sshKey.Id) + data.Name = types.StringValue(sshKey.Name) + data.PublicKey = types.StringValue(sshKey.Value) + + return +} diff --git a/internal/provider/timeout.go b/internal/provider/timeout.go new file mode 100644 index 0000000..e3e8966 --- /dev/null +++ b/internal/provider/timeout.go @@ -0,0 +1,37 @@ +package provider + +import ( + "context" + "time" + + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +const defaultTimeout = 20 * time.Minute + +type CreateFn = func(ctx context.Context, defaultTimeout time.Duration) (time.Duration, diag.Diagnostics) + +func contextWithTimeout(ctx context.Context, timeoutFn CreateFn) (context.Context, context.CancelFunc, diag.Diagnostics) { + timeout, diag := timeoutFn(ctx, defaultTimeout) + if diag != nil { + return ctx, nil, diag + } + + ctx, cancel := context.WithTimeout(ctx, timeout) + + return ctx, cancel, nil +} + +type DataSourceWithTimeout struct { +} + +type ResourceWithTimeout struct { +} + +func (d *DataSourceWithTimeout) ContextWithTimeout(ctx context.Context, timeoutFn CreateFn) (context.Context, context.CancelFunc, diag.Diagnostics) { + return contextWithTimeout(ctx, timeoutFn) +} + +func (r *ResourceWithTimeout) ContextWithTimeout(ctx context.Context, timeoutFn CreateFn) (context.Context, context.CancelFunc, diag.Diagnostics) { + return contextWithTimeout(ctx, timeoutFn) +} diff --git a/internal/provider/volume_resource.go b/internal/provider/volume_resource.go new file mode 100644 index 0000000..9740c30 --- /dev/null +++ b/internal/provider/volume_resource.go @@ -0,0 +1,392 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/defaultplanmodifier" + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &VolumeResource{} + _ resource.ResourceWithConfigure = &VolumeResource{} + _ resource.ResourceWithImportState = &VolumeResource{} +) + +func NewVolumeResource() resource.Resource { + return &VolumeResource{} +} + +// VolumeResource defines the resource implementation. +type VolumeResource struct { + ResourceWithClient + ResourceWithTimeout +} + +type VolumeResourceModel struct { + VolumeModel + + // Internal + + // RetainOnDelete Flag to retain the volume when the resource is deleted. It has to be deleted manually. + RetainOnDelete types.Bool `tfsdk:"retain_on_delete"` + + // Timeouts The resource timeouts + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (r *VolumeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_volume" +} + +func (r *VolumeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Volume resource", + + Attributes: map[string]schema.Attribute{ + "created_at": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The timestamp when this volume was created in RFC 3339.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "description": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable description for the volume.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + defaultplanmodifier.String(""), + }, + }), + "id": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The unique ID of the volume.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + "name": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The human-readable name for the volume.", + Required: true, + }), + "region": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The region identifier.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.OneOf(sliceStringify(genesiscloud.AllComputeV1Regions)...), + }, + }), + "size": resourceenhancer.Attribute(ctx, schema.Int64Attribute{ + MarkdownDescription: "The storage size of this volume given in GiB.", + Required: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, + Validators: []validator.Int64{ + int64validator.AtLeast(1), + }, + }), + "status": resourceenhancer.Attribute(ctx, schema.StringAttribute{ + MarkdownDescription: "The volume status.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), // immutable + }, + }), + + // Internal + "retain_on_delete": resourceenhancer.Attribute(ctx, schema.BoolAttribute{ + MarkdownDescription: "Flag to retain the volume when the resource is deleted", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + defaultplanmodifier.Bool(false), + }, + }), + + "timeouts": timeouts.AttributesAll(ctx), + }, + } +} + +func (r *VolumeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data VolumeResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Create) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.CreateVolumeJSONRequestBody{} + + body.Description = data.Description.ValueString() + body.Name = data.Name.ValueString() + body.Region = pointer(genesiscloud.ComputeV1Region(data.Region.ValueString())) + body.Size = int(data.Size.ValueInt64()) + + response, err := r.client.CreateVolumeWithResponse(ctx, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("create volume", err)) + return + } + + volumeResponse := response.JSON201 + if volumeResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("create volume", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &volumeResponse.Volume)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "created a volume resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + volumeId := volumeResponse.Volume.Id + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling volume", err)) + return + } + + tflog.Trace(ctx, "polling a volume resource") + + response, err := r.client.GetVolumeWithResponse(ctx, volumeId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling volume", err)) + return + } + + volumeResponse := response.JSON200 + if volumeResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("polling volume", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + status := volumeResponse.Volume.Status + if status == "available" || status == "error" { + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &volumeResponse.Volume)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if status == "error" { + resp.Diagnostics.AddError("Provisioning Error", generateErrorMessage("polling volume", ErrResourceInErrorState)) + } + return + } + } +} + +func (r *VolumeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data VolumeResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Read) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + volumeId := data.Id.ValueString() + + response, err := r.client.GetVolumeWithResponse(ctx, volumeId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("read volume", err)) + return + } + + volumeResponse := response.JSON200 + if volumeResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("read volume", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &volumeResponse.Volume)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read a volume resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *VolumeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data VolumeResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Update) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + body := genesiscloud.UpdateVolumeJSONRequestBody{} + + body.Name = data.Name.ValueString() + body.Description = data.Description.ValueString() + + volumeId := data.Id.ValueString() + + response, err := r.client.UpdateVolumeWithResponse(ctx, volumeId, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("update volume", err)) + return + } + + volumeResponse := response.JSON200 + if volumeResponse == nil { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("update volume", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + resp.Diagnostics.Append(data.PopulateFromClientResponse(ctx, &volumeResponse.Volume)...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "updated a volume resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *VolumeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data VolumeResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + ctx, cancel, diag := r.ContextWithTimeout(ctx, data.Timeouts.Delete) + if diag != nil { + resp.Diagnostics.Append(diag...) + return + } + defer cancel() + + volumeId := data.Id.ValueString() + + if data.RetainOnDelete.ValueBool() { + resp.Diagnostics.AddWarning( + "Volume is retained", + fmt.Sprintf("The volume resource with id %q was deleted from the state but the volume is retained.", volumeId), + ) + return + } + + response, err := r.client.DeleteVolumeWithResponse(ctx, volumeId) + + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("delete volume", err)) + return + } + + if response.StatusCode() != 204 { + resp.Diagnostics.AddError("Client Error", generateClientErrorMessage("delete volume", ErrorResponse{ + Body: response.Body, + HTTPResponse: response.HTTPResponse, + Error: response.JSONDefault, + })) + return + } + + for { + err := r.client.PollingWait(ctx) + if err != nil { + resp.Diagnostics.AddError("Polling Error", generateErrorMessage("polling volume", err)) + return + } + + tflog.Trace(ctx, "polling a volume resource") + + response, err := r.client.GetVolumeWithResponse(ctx, volumeId) + if err != nil { + resp.Diagnostics.AddError("Client Error", generateErrorMessage("polling volume", err)) + return + } + + if response.StatusCode() == 404 { + return + } + } +} + +func (r *VolumeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/volume_resource_test.go b/internal/provider/volume_resource_test.go new file mode 100644 index 0000000..3d2ac81 --- /dev/null +++ b/internal/provider/volume_resource_test.go @@ -0,0 +1,49 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testAccVolumeResourceConfig(name string, size int) string { + return fmt.Sprintf(` +resource "genesiscloud_volume" "test" { + name = %[1]q + size = %[2]q +} +`, name, size) +} + +func TestAccVolumeResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + testAccVolumeResourceConfig("one", 1), + Check: resource.ComposeAggregateTestCheckFunc( + // resource.TestCheckResourceAttr("genesiscloud_volume.test", "id", "ssh-key-id"), + resource.TestCheckResourceAttr("genesiscloud_volume.test", "name", "one"), + resource.TestCheckResourceAttr("genesiscloud_volume.test", "size", "1"), + ), + }, + // ImportState testing + { + ResourceName: "genesiscloud_volume.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update and Read testing + { + Config: providerConfig + testAccVolumeResourceConfig("two", 1), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("genesiscloud_volume.test", "name", "two"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/internal/provider/volume_types.go b/internal/provider/volume_types.go new file mode 100644 index 0000000..5091ac2 --- /dev/null +++ b/internal/provider/volume_types.go @@ -0,0 +1,44 @@ +package provider + +import ( + "context" + "time" + + "github.com/genesiscloud/genesiscloud-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type VolumeModel struct { + CreatedAt types.String `tfsdk:"created_at"` + + // Description The human-readable description for the volume. + Description types.String `tfsdk:"description"` + + // Id The unique ID of the volume. + Id types.String `tfsdk:"id"` + + // Name The human-readable name for the volume. + Name types.String `tfsdk:"name"` + + // Region The region identifier. + Region types.String `tfsdk:"region"` + + // Size The storage size of this volume given in GiB. + Size types.Int64 `tfsdk:"size"` + + // Status The volume status. + Status types.String `tfsdk:"status"` +} + +func (data *VolumeModel) PopulateFromClientResponse(ctx context.Context, volume *genesiscloud.ComputeV1Volume) (diag diag.Diagnostics) { + data.CreatedAt = types.StringValue(volume.CreatedAt.Format(time.RFC3339)) + data.Description = types.StringValue(volume.Description) + data.Id = types.StringValue(volume.Id) + data.Name = types.StringValue(volume.Name) + data.Region = types.StringValue(string(volume.Region)) + data.Size = types.Int64Value(int64(volume.Size)) + data.Status = types.StringValue(string(volume.Status)) + + return +} diff --git a/internal/providerenhancer/attribute.go b/internal/providerenhancer/attribute.go new file mode 100644 index 0000000..0a73496 --- /dev/null +++ b/internal/providerenhancer/attribute.go @@ -0,0 +1,52 @@ +package providerenhancer + +import ( + "context" + + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/resourceenhancer" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" +) + +func Attribute(ctx context.Context, attr schema.Attribute) schema.Attribute { + switch attr := attr.(type) { + case schema.BoolAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Float64Attribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Int64Attribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ListAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.MapAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.NumberAttribute: + + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ObjectAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.SetAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.StringAttribute: + attr.MarkdownDescription += resourceenhancer.ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + default: + return attr + } +} diff --git a/internal/resourceenhancer/attribute.go b/internal/resourceenhancer/attribute.go new file mode 100644 index 0000000..6098bc5 --- /dev/null +++ b/internal/resourceenhancer/attribute.go @@ -0,0 +1,59 @@ +package resourceenhancer + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +func Attribute(ctx context.Context, attr schema.Attribute) schema.Attribute { + switch attr := attr.(type) { + case schema.BoolAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Float64Attribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.Int64Attribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ListAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.MapAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.NumberAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.ObjectAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.SetAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + case schema.StringAttribute: + attr.MarkdownDescription += PlanModifiersMarkdownDescription(ctx, attr.PlanModifiers) + attr.MarkdownDescription += ValidatorsMarkdownDescription(ctx, attr.Validators) + return attr + + default: + return attr + } +} diff --git a/internal/resourceenhancer/markdown.go b/internal/resourceenhancer/markdown.go new file mode 100644 index 0000000..27377ba --- /dev/null +++ b/internal/resourceenhancer/markdown.go @@ -0,0 +1,42 @@ +package resourceenhancer + +import ( + "context" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +// TODO: Upstream better quotes and remove this +func patchMarkdown(s string) string { + s = strings.ReplaceAll(s, `"\"`, "`") + s = strings.ReplaceAll(s, `\""`, "`") + return s +} + +func PlanModifiersMarkdownDescription[T planmodifier.Describer](ctx context.Context, mods []T) string { + response := "" + + for _, mod := range mods { + desc := mod.MarkdownDescription(ctx) + if desc == "Once set, the value of this attribute in state will not change." { + continue + } + + response += "\n - " + patchMarkdown(desc) + } + + return response +} + +func ValidatorsMarkdownDescription[T validator.Describer](ctx context.Context, validators []T) string { + response := "" + + for _, validator := range validators { + // TODO: Check existing dot and "The" vs "It" etc. + response += "\n - The " + patchMarkdown(validator.MarkdownDescription(ctx)) + "." + } + + return response +} diff --git a/internal/timedurationvalidator/positive.go b/internal/timedurationvalidator/positive.go new file mode 100644 index 0000000..32abe08 --- /dev/null +++ b/internal/timedurationvalidator/positive.go @@ -0,0 +1,67 @@ +package timedurationvalidator + +// Adapted from https://github.com/hashicorp/terraform-plugin-framework-timeouts/blob/3b8726d5a4e0c7204ce6b0529f2b37db9f8551c4/internal/validators/timeduration.go + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ validator.String = timeDurationPositiveValidator{} + +// timeDurationPositiveValidator validates that a string Attribute's value is parseable as time.Duration. +type timeDurationPositiveValidator struct { +} + +// Description describes the validation in plain text formatting. +func (validator timeDurationPositiveValidator) Description(_ context.Context) string { + return `string must be a positive [time duration](https://pkg.go.dev/time#ParseDuration) for example "10s"` +} + +// MarkdownDescription describes the validation in Markdown formatting. +func (validator timeDurationPositiveValidator) MarkdownDescription(ctx context.Context) string { + return validator.Description(ctx) +} + +// ValidateString performs the validation. +func (validator timeDurationPositiveValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + s := req.ConfigValue + + if s.IsUnknown() || s.IsNull() { + return + } + + duration, err := time.ParseDuration(s.ValueString()) + if err != nil { + resp.Diagnostics.Append(diag.NewAttributeErrorDiagnostic( + req.Path, + "Invalid Attribute Value Time Duration", + fmt.Sprintf("%q %s", s.ValueString(), validator.Description(ctx))), + ) + return + } + + if duration < 0 { + resp.Diagnostics.Append(diag.NewAttributeErrorDiagnostic( + req.Path, + "Time Duration Must Be Positive", + fmt.Sprintf("%q %s", s.ValueString(), validator.Description(ctx))), + ) + return + } +} + +// Positive returns an AttributeValidator which ensures that any configured +// attribute value: +// +// - Is parseable as time duration. +// - Is positive. +// +// Null (unconfigured) and unknown (known after apply) values are skipped. +func Positive() validator.String { + return timeDurationPositiveValidator{} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..b78bf50 --- /dev/null +++ b/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "context" + "flag" + "log" + + "github.com/genesiscloud/terraform-provider-genesiscloud/internal/provider" + "github.com/hashicorp/terraform-plugin-framework/providerserver" +) + +// Run "go generate" to format example terraform files and generate the docs for the registry/website + +// If you do not have terraform installed, you can remove the formatting command, but its suggested to +// ensure the documentation is formatted properly. +//go:generate terraform fmt -recursive ./examples/ + +// Run the docs generation tool, check its repository for more information on how it works and how docs +// can be customized. +//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs + +var ( + // these will be set by the goreleaser configuration + // to appropriate values for the compiled binary + version string = "dev" + + // goreleaser can also pass the specific commit if you want + // commit string = "" +) + +func main() { + var debug bool + + flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") + flag.Parse() + + opts := providerserver.ServeOpts{ + Address: "registry.terraform.io/genesiscloud/genesiscloud", + Debug: debug, + } + + err := providerserver.Serve(context.Background(), provider.New(version), opts) + + if err != nil { + log.Fatal(err.Error()) + } +} diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json new file mode 100644 index 0000000..295001a --- /dev/null +++ b/terraform-registry-manifest.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "metadata": { + "protocol_versions": ["6.0"] + } +} diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..2c4f8fb --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,8 @@ +//go:build tools + +package tools + +import ( + // Documentation generation + _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" +)