├── .github ├── ISSUE_TEMPLATE.md └── workflows │ ├── golangci-lint.yml │ ├── release-dispatch.yml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── CHANGELOG.md ├── GNUmakefile ├── LICENSE ├── LICENSES └── MPL-2.0.txt ├── README.md ├── REUSE.toml ├── docs ├── data-sources │ ├── arc_agent_ids_v1.md │ ├── arc_agent_v1.md │ ├── arc_job_ids_v1.md │ ├── arc_job_v1.md │ ├── automation_v1.md │ ├── billing_domain_masterdata.md │ ├── billing_project_masterdata.md │ ├── endpoint_service_v1.md │ ├── gslb_services_v1.md │ └── networking_router_v2.md ├── index.md └── resources │ ├── arc_agent_bootstrap_v1.md │ ├── arc_agent_v1.md │ ├── arc_job_v1.md │ ├── automation_run_v1.md │ ├── automation_v1.md │ ├── bgpvpn_interconnection_v2.md │ ├── billing_domain_masterdata.md │ ├── billing_project_masterdata.md │ ├── endpoint_accept_v1.md │ ├── endpoint_quota_v1.md │ ├── endpoint_rbac_policy_v1.md │ ├── endpoint_service_v1.md │ ├── endpoint_v1.md │ ├── gslb_datacenter_v1.md │ ├── gslb_domain_v1.md │ ├── gslb_geomap_v1.md │ ├── gslb_member_v1.md │ ├── gslb_monitor_v1.md │ ├── gslb_pool_v1.md │ ├── gslb_quota_v1.md │ └── kubernetes_v1.md ├── go.mod ├── go.sum ├── main.go ├── renovate.json ├── sci ├── andromeda.go ├── archer.go ├── config.go ├── data_source_sci_arc_agent_ids_v1.go ├── data_source_sci_arc_agent_v1.go ├── data_source_sci_arc_job_ids_v1.go ├── data_source_sci_arc_job_v1.go ├── data_source_sci_automation_v1.go ├── data_source_sci_billing_domain_masterdata.go ├── data_source_sci_billing_project_masterdata.go ├── data_source_sci_endpoint_service_v1.go ├── data_source_sci_gslb_services_v1.go ├── data_source_sci_networking_router_v2.go ├── kubernikus.go ├── logger.go ├── migrate_resource_sci_gslb_quota_v1.go ├── provider.go ├── resource_sci_arc_agent_bootstrap_v1.go ├── resource_sci_arc_agent_v1.go ├── resource_sci_arc_job_v1.go ├── resource_sci_automation_run_v1.go ├── resource_sci_automation_v1.go ├── resource_sci_bgpvpn_interconnection_v2.go ├── resource_sci_billing_domain_masterdata.go ├── resource_sci_billing_project_masterdata.go ├── resource_sci_endpoint_accept_v1.go ├── resource_sci_endpoint_quota_v1.go ├── resource_sci_endpoint_rbac_policy_v1.go ├── resource_sci_endpoint_service_v1.go ├── resource_sci_endpoint_v1.go ├── resource_sci_gslb_datacenter_v1.go ├── resource_sci_gslb_domain_v1.go ├── resource_sci_gslb_geomap_v1.go ├── resource_sci_gslb_member_v1.go ├── resource_sci_gslb_monitor_v1.go ├── resource_sci_gslb_pool_v1.go ├── resource_sci_gslb_quota_v1.go ├── resource_sci_kubernetes_v1.go ├── sci_arc_agent_v1.go ├── sci_arc_job_v1.go ├── sci_auth_scope.go ├── sci_billing_domain_masterdata.go ├── sci_billing_project_masterdata.go ├── sci_kubernetes_v1.go └── util.go ├── scripts ├── changelog-links.sh ├── errcheck.sh ├── gofmtcheck.sh └── gogetcookie.sh └── terraform-registry-manifest.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hi there, 2 | 3 | Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see https://www.terraform.io/community.html. 4 | 5 | ### Terraform Version 6 | Run `terraform -v` to show the version. If you are not running the latest version of Terraform, please upgrade because your issue may have already been fixed. 7 | 8 | ### Affected Resource(s) 9 | Please list the resources as a list, for example: 10 | - opc_instance 11 | - opc_storage_volume 12 | 13 | If this issue appears to affect multiple resources, it may be an issue with Terraform's core, so please mention this. 14 | 15 | ### Terraform Configuration Files 16 | ```hcl 17 | # Copy-paste your Terraform configurations here - for large Terraform configs, 18 | # please use a service like Dropbox and share a link to the ZIP file. For 19 | # security, you can also encrypt the files using our GPG public key. 20 | ``` 21 | 22 | ### Debug Output 23 | Please provide a link to a GitHub Gist containing the complete debug output: https://www.terraform.io/docs/internals/debugging.html. 24 | 25 | In addition, running Terraform with the `OS_DEBUG=1` environment variable set will print additional information specific to the OpenStack provider which will be helpful for troubleshooting. 26 | 27 | Please do NOT paste the debug output in the issue; just paste a link to the Gist. 28 | 29 | ### Panic Output 30 | If Terraform produced a panic, please provide a link to a GitHub Gist containing the output of the `crash.log`. 31 | 32 | ### Expected Behavior 33 | What should have happened? 34 | 35 | ### Actual Behavior 36 | What actually happened? 37 | 38 | ### Steps to Reproduce 39 | Please list the steps required to reproduce the issue, for example: 40 | 1. `terraform apply` 41 | 42 | ### Important Factoids 43 | Is there anything atypical about your accounts that we should know? For example: Running in EC2 Classic? A custom version of OpenStack? Tight ACLs? 44 | 45 | ### References 46 | Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example: 47 | - GH-1234 48 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: Golangci-lint 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | golangci-lint: 13 | name: Lint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup Go 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version-file: 'go.mod' 23 | cache: true 24 | 25 | - name: Golangci-lint 26 | uses: golangci/golangci-lint-action@v8 27 | with: 28 | version: 'v2.1' 29 | -------------------------------------------------------------------------------- /.github/workflows/release-dispatch.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action will publish assets for release when a tag is created 2 | # that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # Based on the configuration provided at: 5 | # https://github.com/hashicorp/terraform-provider-scaffolding 6 | name: Release dispatch 7 | 8 | on: 9 | workflow_dispatch: 10 | inputs: 11 | tag: 12 | required: true 13 | previous_tag: 14 | required: true 15 | project_name: 16 | default: 'terraform-provider-sci' 17 | goreleaser_version: 18 | default: 'v2' 19 | use_old_key: 20 | type: boolean 21 | default: false 22 | 23 | # to allow the action to create a release 24 | permissions: 25 | contents: write 26 | 27 | jobs: 28 | goreleaser: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | with: 34 | ref: refs/tags/${{ github.event.inputs.tag }} 35 | 36 | - name: Unshallow 37 | run: git fetch --prune --unshallow 38 | 39 | - name: Set up Go 40 | uses: actions/setup-go@v5 41 | with: 42 | go-version-file: 'go.mod' 43 | cache: true 44 | 45 | - name: Import GPG key 46 | id: import_gpg 47 | if: ${{ github.event.inputs.use_old_key == 'false' }} 48 | uses: crazy-max/ghaction-import-gpg@v6.3.0 49 | with: 50 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 51 | passphrase: ${{ secrets.PASSPHRASE }} 52 | 53 | - name: Import old GPG key 54 | id: import_gpg_old 55 | if: ${{ github.event.inputs.use_old_key == 'true' }} 56 | uses: crazy-max/ghaction-import-gpg@v6.3.0 57 | with: 58 | gpg_private_key: ${{ secrets.OLD_GPG_PRIVATE_KEY }} 59 | passphrase: ${{ secrets.OLD_GPG_PASSPHRASE }} 60 | 61 | - name: Copy goreleaser config to temp location 62 | run: cp .goreleaser.yml /tmp/.goreleaser.yml 63 | 64 | - name: Override project_name in copied config 65 | run: yq -i '.project_name = "${{ github.event.inputs.project_name }}"' /tmp/.goreleaser.yml 66 | 67 | - name: Run GoReleaser 68 | uses: goreleaser/goreleaser-action@v6 69 | with: 70 | version: ${{ github.event.inputs.goreleaser_version }} 71 | args: release --clean --config /tmp/.goreleaser.yml 72 | env: 73 | GPG_FINGERPRINT: ${{ github.event.inputs.use_old_key == 'true' && steps.import_gpg_old.outputs.fingerprint || steps.import_gpg.outputs.fingerprint }} 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | GORELEASER_CURRENT_TAG: ${{ github.event.inputs.tag }} 76 | GORELEASER_PREVIOUS_TAG: ${{ github.event.inputs.previous_tag }} 77 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action will publish assets for release when a tag is created 2 | # that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # Based on the configuration provided at: 5 | # https://github.com/hashicorp/terraform-provider-scaffolding 6 | name: Release 7 | 8 | on: 9 | push: 10 | tags: 11 | - 'v*' 12 | 13 | # to allow the action to create a release 14 | permissions: 15 | contents: write 16 | 17 | jobs: 18 | goreleaser: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Unshallow 25 | run: git fetch --prune --unshallow 26 | 27 | - name: Set up Go 28 | uses: actions/setup-go@v5 29 | with: 30 | go-version-file: 'go.mod' 31 | cache: true 32 | 33 | - name: Import GPG key 34 | id: import_gpg 35 | uses: crazy-max/ghaction-import-gpg@v6.3.0 36 | with: 37 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 38 | passphrase: ${{ secrets.PASSPHRASE }} 39 | 40 | - name: Run GoReleaser 41 | uses: goreleaser/goreleaser-action@v6 42 | with: 43 | version: v2 44 | args: release --clean 45 | env: 46 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dll 2 | *.exe 3 | .DS_Store 4 | example.tf 5 | terraform.tfplan 6 | terraform.tfstate 7 | .terraform.lock.hcl 8 | bin/ 9 | modules-dev/ 10 | /pkg/ 11 | /terraform-provider-ccloud 12 | website/.vagrant 13 | website/.bundle 14 | website/build 15 | website/node_modules 16 | .vagrant/ 17 | *.backup 18 | ./*.tfstate 19 | .terraform/ 20 | *.log 21 | *.bak 22 | *~ 23 | .*.swp 24 | .idea 25 | *.iml 26 | *.test 27 | *.iml 28 | 29 | vendor 30 | website/vendor 31 | 32 | # Test exclusions 33 | !command/test-fixtures/**/*.tfstate 34 | !command/test-fixtures/**/.terraform/ 35 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | run: 4 | timeout: 5m 5 | 6 | linters: 7 | default: none 8 | enable: 9 | - asciicheck 10 | - bodyclose 11 | - copyloopvar 12 | - dogsled 13 | - errcheck 14 | - exhaustive 15 | - godot 16 | - goheader 17 | - gomodguard 18 | - goprintffuncname 19 | - govet 20 | - ineffassign 21 | - misspell 22 | - nakedret 23 | - nolintlint 24 | - prealloc 25 | - staticcheck 26 | - unconvert 27 | - unused 28 | - whitespace 29 | exclusions: 30 | generated: lax 31 | presets: 32 | - comments 33 | - common-false-positives 34 | - legacy 35 | - std-error-handling 36 | rules: 37 | - linters: 38 | - staticcheck 39 | text: "SA1019: (x509.EncryptPEMBlock|strings.Title)" 40 | paths: 41 | - third_party$ 42 | - builtin$ 43 | - examples$ 44 | formatters: 45 | enable: 46 | - gofmt 47 | - goimports 48 | - gci 49 | exclusions: 50 | generated: lax 51 | paths: 52 | - third_party$ 53 | - builtin$ 54 | - examples$ 55 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | version: 2 4 | before: 5 | hooks: 6 | # this is just an example and not a requirement for provider building/publishing 7 | - go mod tidy 8 | builds: 9 | - env: 10 | # goreleaser does not work with CGO, it could also complicate 11 | # usage by users in CI/CD systems like Terraform Cloud where 12 | # they are unable to install libraries. 13 | - CGO_ENABLED=0 14 | mod_timestamp: '{{ .CommitTimestamp }}' 15 | flags: 16 | - -trimpath 17 | ldflags: 18 | - '-s -w -X github.com/SAP-cloud-infrastructure/terraform-provider-sci/sci.version={{.Version}}' 19 | goos: 20 | - freebsd 21 | - windows 22 | - linux 23 | - darwin 24 | goarch: 25 | - amd64 26 | - '386' 27 | - arm 28 | - arm64 29 | ignore: 30 | - goos: darwin 31 | goarch: '386' 32 | binary: '{{ .ProjectName }}_v{{ .Version }}' 33 | archives: 34 | - formats: 35 | - zip 36 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 37 | checksum: 38 | extra_files: 39 | - glob: 'terraform-registry-manifest.json' 40 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 41 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 42 | algorithm: sha256 43 | signs: 44 | - artifacts: checksum 45 | args: 46 | # if you are using this is a GitHub action or some other automated pipeline, you 47 | # need to pass the batch flag to indicate its not interactive. 48 | - "--batch" 49 | - "--local-user" 50 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 51 | - "--output" 52 | - "${signature}" 53 | - "--detach-sign" 54 | - "${artifact}" 55 | release: 56 | extra_files: 57 | - glob: 'terraform-registry-manifest.json' 58 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 59 | # Visit your project's GitHub Releases page to publish this release. 60 | draft: true 61 | changelog: 62 | disable: true 63 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.1 (Unreleased) 2 | ## 1.0.0 (September 26, 2017) 3 | 4 | * No changes from 0.1.1; just adjusting to [the new version numbering scheme](https://www.hashicorp.com/blog/hashicorp-terraform-provider-versioning/). 5 | 6 | ## 0.1.1 (June 21, 2017) 7 | 8 | NOTES: 9 | 10 | Bumping the provider version to get around provider caching issues - still same functionality 11 | 12 | ## 0.1.0 (June 21, 2017) 13 | 14 | NOTES: 15 | 16 | * Same functionality as that of Terraform 0.9.8. Repacked as part of [Provider Splitout](https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10/) 17 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./...) 2 | GOFMT_FILES?=$$(find . -name '*.go') 3 | WEBSITE_REPO=github.com/hashicorp/terraform-website 4 | PKG_NAME=sci 5 | 6 | default: build 7 | 8 | build: fmtcheck 9 | go install 10 | 11 | test: fmtcheck 12 | go test -i $(TEST) || exit 1 13 | echo $(TEST) | \ 14 | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 15 | 16 | testacc: fmtcheck 17 | TF_ACC=1 TF_ACC_TERRAFORM_VERSION=1.2.9 go test $(TEST) -v $(TESTARGS) -timeout 120m 18 | 19 | vet: 20 | @echo "go vet ." 21 | @go vet $$(go list ./...) ; if [ $$? -eq 1 ]; then \ 22 | echo ""; \ 23 | echo "Vet found suspicious constructs. Please check the reported constructs"; \ 24 | echo "and fix them if necessary before submitting the code for review."; \ 25 | exit 1; \ 26 | fi 27 | 28 | fmt: 29 | gofmt -w $(GOFMT_FILES) 30 | 31 | fmtcheck: 32 | @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" 33 | 34 | errcheck: 35 | @sh -c "'$(CURDIR)/scripts/errcheck.sh'" 36 | 37 | test-compile: 38 | @if [ "$(TEST)" = "./..." ]; then \ 39 | echo "ERROR: Set TEST to a specific package. For example,"; \ 40 | echo " make test-compile TEST=./$(PKG_NAME)"; \ 41 | exit 1; \ 42 | fi 43 | go test -c $(TEST) $(TESTARGS) 44 | 45 | website: 46 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 47 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 48 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 49 | endif 50 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 51 | 52 | website-test: 53 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 54 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 55 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 56 | endif 57 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider-test PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 58 | 59 | .PHONY: build test testacc vet fmt fmtcheck errcheck test-compile website website-test 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SAP Cloud Infrastructure - Terraform Provider 2 | ======================================================= 3 | 4 | Documentation: [registry.terraform.io](https://registry.terraform.io/providers/SAP-cloud-infrastructure/sci/latest/docs) 5 | 6 | Maintainers 7 | ----------- 8 | 9 | This provider plugin is maintained by: 10 | 11 | * [@kayrus](https://github.com/kayrus) 12 | * [@bugroger](https://github.com/BugRoger) 13 | 14 | Requirements 15 | ------------ 16 | 17 | - [Terraform](https://www.terraform.io/downloads.html) 1.0.x 18 | - [Go](https://golang.org/doc/install) 1.24 (to build the provider plugin) 19 | 20 | Usage 21 | --------------------- 22 | 23 | The SAP Cloud Infrastructure provider is an extension to the [OpenStack Terraform 24 | Provider](https://github.com/terraform-provider-openstack/terraform-provider-openstack). 25 | It provides resources that allow to use Terraform for SAP Cloud Infrastructure's 26 | additional services: 27 | 28 | * Kubernikus (Kubernetes as a Service) 29 | * Arc for Arc resources management 30 | * Lyra for Automation management 31 | * Billing for Billing management 32 | * Andromeda for GSLB / GTM (Global Server Load Balancing / Global Traffic Management) 33 | * Archer for Endpoint Services 34 | 35 | The provider needs to be configured with the proper OpenStack credentials 36 | before it can be used. For details see the OpenStack provider. 37 | 38 | Building The Provider 39 | --------------------- 40 | 41 | Clone the repository 42 | 43 | ```sh 44 | $ git clone git@github.com:SAP-cloud-infrastructure/terraform-provider-sci 45 | ``` 46 | 47 | Enter the provider directory and build the provider 48 | 49 | ```sh 50 | $ cd terraform-provider-sci 51 | $ make build 52 | ``` 53 | 54 | Installing the provider 55 | ----------------------- 56 | 57 | To install this provider, copy and paste this code into your Terraform configuration. Then, run `terraform init`. 58 | 59 | ```hcl 60 | terraform { 61 | required_providers { 62 | sci = { 63 | source = "SAP-cloud-infrastructure/sci" 64 | } 65 | } 66 | } 67 | 68 | provider "sci" { 69 | # Configuration options 70 | } 71 | ``` 72 | 73 | Using the provider 74 | ---------------------- 75 | Please see the documentation at [registry.terraform.io](https://registry.terraform.io/providers/SAP-cloud-infrastructure/sci/latest/docs). 76 | 77 | Or you can browse the documentation within this repo [here](https://github.com/SAP-cloud-infrastructure/terraform-provider-sci/tree/master/website/docs). 78 | 79 | Developing the Provider 80 | --------------------------- 81 | 82 | If you wish to work on the provider, you'll first need [Go](https://golang.org) installed on your machine (version 1.20+ is *required*). 83 | 84 | To compile the provider, run `make build`. This will build the provider and put the provider binary in the current directory. 85 | 86 | ```sh 87 | $ make build 88 | ``` 89 | 90 | In order to test the provider, you can simply run `make test`. 91 | 92 | ```sh 93 | $ make test 94 | ``` 95 | 96 | Releasing the Provider 97 | ---------------------- 98 | 99 | This repository contains a GitHub Action configured to automatically build and 100 | publish assets for release when a tag is pushed that matches the pattern `v*` 101 | (ie. `v0.1.0`). 102 | 103 | A [Gorelaser](https://goreleaser.com/) configuration is provided that produce 104 | build artifacts matching the [layout required](https://www.terraform.io/docs/registry/providers/publishing.html#manually-preparing-a-release) 105 | to publish the provider in the Terraform Registry. 106 | 107 | Releases will as drafts. Once marked as published on the GitHub Releases page, 108 | they will become available via the Terraform Registry. 109 | 110 | Support, Feedback, Contributing 111 | ------------------------------- 112 | 113 | This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/creating-an-issue). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](https://github.com/SAP-cloud-infrastructure/.github/blob/main/CONTRIBUTING.md). 114 | 115 | Security / Disclosure 116 | --------------------- 117 | 118 | If you find any bug that may be a security problem, please follow our instructions [in our security policy](https://github.com/SAP-cloud-infrastructure/.github/blob/main/SECURITY.md) on how to report it. Please do not create GitHub issues for security-related doubts or problems. 119 | 120 | Code of Conduct 121 | --------------- 122 | 123 | We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its [Code of Conduct](https://github.com/SAP-cloud-infrastructure/.github/blob/main/CODE_OF_CONDUCT.md) at all times. 124 | 125 | Licensing 126 | --------- 127 | 128 | Copyright 2018-2025 SAP SE or an SAP affiliate company and terraform-provider-sci contributors. This repository contains code from [terraform-provider-openstack](https://github.com/terraform-provider-openstack/terraform-provider-openstack), copyright 2017-2025 terraform-provider-openstack contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP-cloud-infrastructure/terraform-provider-sci). 129 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | SPDX-PackageName = "terraform-provider-sci" 3 | SPDX-PackageSupplier = "ospo@sap.com" 4 | SPDX-PackageDownloadLocation = "https://github.com/SAP-cloud-infrastructure/terraform-provider-sci" 5 | SPDX-PackageComment = "The code in this project may include calls to APIs (\"API Calls\") of\n SAP or third-party products or services developed outside of this project\n (\"External Products\").\n \"APIs\" means application programming interfaces, as well as their respective\n specifications and implementing code that allows software to communicate with\n other software.\n API Calls to External Products are not licensed under the open source license\n that governs this project. The use of such API Calls and related External\n Products are subject to applicable additional agreements with the relevant\n provider of the External Products. In no event shall the open source license\n that governs this project grant any rights in or to any External Products,or\n alter, expand or supersede any terms of the applicable additional agreements.\n If you have a valid license agreement with SAP for the use of a particular SAP\n External Product, then you may make use of any API Calls included in this\n project's code for that SAP External Product, subject to the terms of such\n license agreement. If you do not have a valid license agreement for the use of\n a particular SAP External Product, then you may only make use of any API Calls\n in this project for that SAP External Product for your internal, non-productive\n and non-commercial test and evaluation of such API Calls. Nothing herein grants\n you any rights to use or access any SAP External Product, or provide any third\n parties the right to use of access any SAP External Product, through API Calls." 6 | 7 | [[annotations]] 8 | path = "**" 9 | precedence = "aggregate" 10 | SPDX-FileCopyrightText = "2018-2025 SAP SE or an SAP affiliate company and terraform-provider-sci contributors. 2017-2025 terraform-provider-openstack contributors" 11 | SPDX-License-Identifier = "MPL-2.0" 12 | -------------------------------------------------------------------------------- /docs/data-sources/arc_agent_ids_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_arc_agent_ids_v1" 4 | sidebar_current: "docs-sci-datasource-arc-agent-ids-v1" 5 | description: |- 6 | Get a list of Arc Agent IDs. 7 | --- 8 | 9 | # sci\_arc\_agent\_ids\_v1 10 | 11 | Use this data source to get a list of Arc Agent IDs. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "sci_arc_agent_ids_v1" "agent_ids_1" { 17 | filter = "@os = 'linux' AND @platform = 'ubuntu'" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | * `region` - (Optional) The region in which to obtain the Arc client. If 24 | omitted, the `region` argument of the provider is used. 25 | 26 | * `filter` - (Optional) The filter, used to filter the desired Arc agents. 27 | 28 | ## Attributes Reference 29 | 30 | `id` is set to hash of the returned agents ID list. In addition, the following 31 | attributes are exported: 32 | 33 | * `region` - See Argument Reference above. 34 | * `filter` - See Argument Reference above. 35 | * `ids` - The list of Arc Agent IDs. 36 | -------------------------------------------------------------------------------- /docs/data-sources/arc_agent_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_arc_agent_v1" 4 | sidebar_current: "docs-sci-datasource-arc-agent-v1" 5 | description: |- 6 | Get information on an Arc Agent. 7 | --- 8 | 9 | # sci\_arc\_agent\_v1 10 | 11 | Use this data source to get the ID and other attributes of an available Arc 12 | Agent. 13 | 14 | The resource can wait for an Arc Agent to be available (the Arc Agent bootstrap 15 | takes time due to compute instance boot time and cloud-init execution delay) 16 | within the `timeouts` 17 | [nested](https://www.terraform.io/docs/configuration/resources.html#operation-timeouts) 18 | block argument. The default read timeout is 0, what means don't wait. 19 | 20 | ## Example Usage 21 | 22 | ### Get an Arc Agent by an agent ID 23 | 24 | ```hcl 25 | data "sci_arc_agent_v1" "agent_1" { 26 | agent_id = "72f50dc1-03c2-4177-9ffa-d75929734c0d" 27 | } 28 | ``` 29 | 30 | ### Find an Arc Agent with a filter 31 | 32 | The example below will be completed once it finds the exact one agent 33 | satisfying the specified filter. 34 | 35 | ```hcl 36 | data "sci_arc_agent_v1" "agent_1" { 37 | filter = "@metadata_name = 'hostname'" 38 | 39 | timeouts { 40 | read = "10m" 41 | } 42 | } 43 | ``` 44 | 45 | ## Argument Reference 46 | 47 | * `region` - (Optional) The region in which to obtain the Arc client. If 48 | omitted, the `region` argument of the provider is used. 49 | 50 | * `agent_id` - (Optional) The ID of the known Arc agent. Conflicts with 51 | `filter`. 52 | 53 | * `filter` - (Optional) The filter, used to filter the desired Arc agent. 54 | Conflicts with `agent_id`. 55 | 56 | ## Attributes Reference 57 | 58 | `id` is set to the ID of the found agent. In addition, the following attributes 59 | are exported: 60 | 61 | * `region` - See Argument Reference above. 62 | * `agent_id` - See Argument Reference above. 63 | * `filter` - See Argument Reference above. 64 | * `timeout` - See Argument Reference above. 65 | * `display_name` - The Arc agent display name. 66 | * `project` - The Arc agent parent OpenStack project ID. 67 | * `organization` - The Arc agent parent OpenStack domain ID. 68 | * `created_at` - The date the Arc agent was created. 69 | * `updated_at` - The date the Arc agent was last updated. 70 | * `updated_with` - The registration ID, used to submit the latest update. 71 | * `updated_by` - The type of the application, submitted the latest update. 72 | * `all_tags` - The map of tags, assigned on the Arc agent. 73 | * `facts` - The map of facts, submitted by the Arc agent. 74 | * `facts_agents` - The map of agent types enabled on the Arc agent. 75 | -------------------------------------------------------------------------------- /docs/data-sources/arc_job_ids_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_arc_job_ids_v1" 4 | sidebar_current: "docs-sci-datasource-arc-job-ids-v1" 5 | description: |- 6 | Get a list of Arc Job IDs. 7 | --- 8 | 9 | # sci\_arc\_job\_ids\_v1 10 | 11 | Use this data source to get a list of Arc Job IDs. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "sci_arc_agent_v1" "agent_1" { 17 | filter = "@metadata_name = 'hostname'" 18 | } 19 | 20 | data "sci_arc_job_ids_v1" "job_ids_1" { 21 | agent_id = data.sci_arc_agent_v1.agent_1.id 22 | agent = "chef" 23 | action = "zero" 24 | } 25 | ``` 26 | 27 | ## Argument Reference 28 | 29 | * `region` - (Optional) The region in which to obtain the Arc client. If 30 | omitted, the `region` argument of the provider is used. 31 | 32 | * `agent_id` - (Optional) The ID of the Arc agent. 33 | 34 | * `timeout` - (Optional) The Arc job timeout in seconds. If specified, 35 | must be between 1 and 86400 seconds. 36 | 37 | * `agent` - (Optional) The agent type, which executed the Arc job. Can either 38 | be `chef` or `execute`. 39 | 40 | * `action` - (Optional) The Arc job action type. Can either be `script`, `zero`, 41 | `tarball` or `enable`. 42 | 43 | * `status` - (Optional) The Arc job status. Can either be `queued`, 44 | `executing`, `failed`, `complete`. 45 | 46 | ## Attributes Reference 47 | 48 | `id` is set to hash of the returned jobs ID list. In addition, the following 49 | attributes are exported: 50 | 51 | * `region` - See Argument Reference above. 52 | * `agent_id` - See Argument Reference above. 53 | * `timeout` - See Argument Reference above. 54 | * `agent` - See Argument Reference above. 55 | * `action` - See Argument Reference above. 56 | * `status` - See Argument Reference above. 57 | * `ids` - The list of Arc Job IDs. 58 | -------------------------------------------------------------------------------- /docs/data-sources/arc_job_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_arc_job_v1" 4 | sidebar_current: "docs-sci-datasource-arc-job-v1" 5 | description: |- 6 | Get information on an Arc Job. 7 | --- 8 | 9 | # sci\_arc\_job\_v1 10 | 11 | Use this data source to get the ID and other attributes of an Arc Job. 12 | 13 | ## Example Usage 14 | 15 | ### Get Arc Job using a Job ID 16 | 17 | ```hcl 18 | resource "sci_automation_run_v1" "run_1" { 19 | automation_id = "123" 20 | selector = "@metadata_name = 'hostname'" 21 | } 22 | 23 | data "sci_arc_job_v1" "job_1" { 24 | job_id = sci_automation_run_v1.run_1.jobs[0] 25 | } 26 | ``` 27 | 28 | ### Get Arc Job using a filter 29 | 30 | ```hcl 31 | data "sci_arc_agent_v1" "agent_1" { 32 | filter = "@metadata_name = 'hostname'" 33 | } 34 | 35 | data "sci_arc_job_v1" "job_1" { 36 | agent_id = data.sci_arc_agent_v1.agent_1.id 37 | timeout = 3600 38 | agent = "chef" 39 | action = "zero" 40 | status = "complete" 41 | } 42 | ``` 43 | 44 | ## Argument Reference 45 | 46 | * `region` - (Optional) The region in which to obtain the Arc client. If 47 | omitted, the `region` argument of the provider is used. 48 | 49 | * `job_id` - (Optional) The ID of the known Arc job. Conflicts with `agent_id`, 50 | `timeout`, `agent`, `action` and `status`. 51 | 52 | * `agent_id` - (Optional) The ID of the known Arc agent. Conflicts with 53 | `job_id`. 54 | 55 | * `timeout` - (Optional) The Arc job timeout in seconds. If specified, 56 | must be between 1 and 86400 seconds. Conflicts with `job_id`. 57 | 58 | * `agent` - (Optional) The agent type, which executed the Arc job. Can either 59 | be `chef` or `execute`. Conflicts with `job_id`. 60 | 61 | * `action` - (Optional) The Arc job action type. Can either be `script`, `zero`, 62 | `tarball` or `enable`. Conflicts with `job_id`. 63 | 64 | * `status` - (Optional) The Arc job status. Can either be `queued`, 65 | `executing`, `failed`, `complete`. Conflicts with `job_id`. 66 | 67 | ## Attributes Reference 68 | 69 | `id` is set to the ID of the found job. In addition, the following attributes 70 | are exported: 71 | 72 | * `region` - See Argument Reference above. 73 | * `job_id` - See Argument Reference above. 74 | * `agent_id` - See Argument Reference above. 75 | * `timeout` - See Argument Reference above. 76 | * `execute` - See Argument Reference in the `sci_arc_job_v1` resource 77 | documentation. 78 | * `chef` - See Argument Reference in the `sci_arc_job_v1` resource 79 | documentation. 80 | * `agent` - See Argument Reference above. 81 | * `action` - See Argument Reference above. 82 | * `status` - See Argument Reference above. 83 | * `to` - A read-only alias to the `agent_id`. 84 | * `payload` - The Arc job payload. 85 | * `version` - The Arc job version. 86 | * `sender` - The Arc job sender. 87 | * `created_at` - The date the Arc job was created. 88 | * `updated_at` - The date the Arc job was last updated. 89 | * `project` - The parent Openstack project ID. 90 | * `log` - The Arc job log. 91 | * `user` - The user, who submitted the Arc job. The structure is described 92 | below. 93 | 94 | The `user` attribute has fields below: 95 | 96 | * `id` - The OpenStack user ID. 97 | 98 | * `name` - The OpenStack user name. 99 | 100 | * `domain_id` - The OpenStack domain ID. 101 | 102 | * `domain_name` - The OpenStack domain name. 103 | 104 | * `roles` - The list of the OpenStack user roles. 105 | -------------------------------------------------------------------------------- /docs/data-sources/automation_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_automation_v1" 4 | sidebar_current: "docs-sci-datasource-automation-v1" 5 | description: |- 6 | Get information on a Lyra Automation. 7 | --- 8 | 9 | # sci\_automation\_v1 10 | 11 | Use this data source to get the ID and other attributes of a Lyra Automation. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "sci_automation_v1" "automation_1" { 17 | name = "chef-automation" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | * `region` - (Optional) The region in which to obtain the Automation client. If 24 | omitted, the `region` argument of the provider is used. 25 | 26 | * `name` - (Optional) The name filter. 27 | 28 | * `repository` - (Optional) The repository filter. 29 | 30 | * `repository_revision` - (Optional) The repository revision filter. 31 | 32 | * `timeout` - (Optional) The automation timeout filter in seconds. 33 | 34 | * `type` - (Optional) The automation type filter. Can either be `Script` or 35 | `Chef`. 36 | 37 | * `debug` - (Optional) The Chef debug flag filter. 38 | 39 | * `chef_version` - (Optional) The Chef version filter. 40 | 41 | * `path` - (Optional) The Script path filter. 42 | 43 | ## Attributes Reference 44 | 45 | `id` is set to the ID of the found automation. In addition, the following 46 | attributes are exported: 47 | 48 | * `region` - See Argument Reference above. 49 | * `name` - See Argument Reference above. 50 | * `repository` - See Argument Reference above. 51 | * `repository_revision` - See Argument Reference above. 52 | * `repository_authentication_enabled` - Set to true when a 53 | `repository_credentials` is set. 54 | * `timeout` - See Argument Reference above. 55 | * `type` - See Argument Reference above. 56 | * `run_list` - The Chef run list. 57 | * `chef_attributes` - The Chef attributes. 58 | * `debug` - See Argument Reference above. 59 | * `chef_version` - See Argument Reference above. 60 | * `path` - See Argument Reference above. 61 | * `arguments` - The Script arguments list. 62 | * `environment` - The Script environment map. 63 | * `created_at` - The date the Lyra automation was created. 64 | * `updated_at` - The date the Lyra automation was last updated. 65 | * `project_id` - The parent Openstack project ID. 66 | -------------------------------------------------------------------------------- /docs/data-sources/billing_domain_masterdata.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_billing_domain_masterdata" 4 | sidebar_current: "docs-sci-datasource-billing-domain-masterdata" 5 | description: |- 6 | Get information on the Billing Domain Masterdata 7 | --- 8 | 9 | # sci\_billing\_domain\_masterdata 10 | 11 | Use this data source to get the Billing Domain Masterdata. 12 | 13 | ~> **Note:** You _must_ have admin privileges in your OpenStack cloud to use 14 | this resource. 15 | 16 | ## Example Usage 17 | 18 | ```hcl 19 | data "sci_billing_domain_masterdata" "masterdata" { 20 | domain_id = "01482666f9004d4ea6b3458205642c30" 21 | } 22 | 23 | output "cost_object" { 24 | value = data.sci_billing_domain_masterdata.masterdata.cost_object 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to obtain the Billing client. If 33 | omitted, the `region` argument of the provider is used. Changing this forces 34 | a new resource to be created. 35 | 36 | * `domain_id` - (Optional) A domain ID. Defaults to the current domain scope. 37 | 38 | ## Attributes Reference 39 | 40 | In addition to arguments above, extra attributes are exported. Please refer 41 | to the `sci_billing_domain_masterdata` resource arguments and attributes 42 | [documentation](../resources/billing_domain_masterdata.html) for more information. 43 | -------------------------------------------------------------------------------- /docs/data-sources/billing_project_masterdata.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_billing_project_masterdata" 4 | sidebar_current: "docs-sci-datasource-billing-project-masterdata" 5 | description: |- 6 | Get information on the Billing Project Masterdata 7 | --- 8 | 9 | # sci\_billing\_project\_masterdata 10 | 11 | Use this data source to get the Billing Project Masterdata. 12 | 13 | ~> **Note:** You _must_ have admin privileges in your OpenStack cloud to use 14 | this resource for other tenant projects. 15 | 16 | ## Example Usage 17 | 18 | ```hcl 19 | data "sci_billing_project_masterdata" "masterdata" { 20 | project_id = "30dd31bcac8748daaa75720dab7e019a" 21 | } 22 | 23 | output "cost_object" { 24 | value = data.sci_billing_project_masterdata.masterdata.cost_object 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to obtain the Billing client. If 33 | omitted, the `region` argument of the provider is used. Changing this forces 34 | a new resource to be created. 35 | 36 | * `project_id` - (Optional) A project ID. Available only for users with an 37 | admin access. Defaults to the current project scope. 38 | 39 | ## Attributes Reference 40 | 41 | In addition to arguments above, extra attributes are exported. Please refer 42 | to the `sci_billing_project_masterdata` resource arguments and attributes 43 | [documentation](../resources/billing_project_masterdata.html) for more information. 44 | -------------------------------------------------------------------------------- /docs/data-sources/endpoint_service_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_service_v1" 4 | sidebar_current: "docs-sci-data-source-endpoint-service-v1" 5 | description: |- 6 | Retrieve information about an Archer endpoint service. 7 | --- 8 | 9 | # sci\_endpoint\_service\_v1 10 | 11 | Use this data source to get information about an Archer endpoint service within 12 | the SAP Cloud Infrastructure environment. This can be used to fetch details of a 13 | specific service by various selectors like name, project ID, or tags. 14 | 15 | ## Example Usage 16 | 17 | ```hcl 18 | data "sci_endpoint_service_v1" "service_1" { 19 | name = "my-service" 20 | project_id = "fa84c217f361441986a220edf9b1e337" 21 | } 22 | 23 | output "service_ip_addresses" { 24 | value = data.sci_endpoint_service_v1.service_1.ip_addresses 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to query for the endpoint service. 33 | If omitted, the `region` argument of the provider is used. 34 | 35 | * `enabled` - (Optional) Filter services by their enabled status. 36 | 37 | * `availability_zone` - (Optional) Filter services by their availability zone. 38 | 39 | * `name` - (Optional) The name of the endpoint service. 40 | 41 | * `description` - (Optional) A description of the endpoint service. 42 | 43 | * `ip_addresses` - (Optional) A list of IP addresses associated with the service. 44 | 45 | * `port` - (Optional) The port on which the service is exposed. 46 | 47 | * `network_id` - (Optional) The network ID associated with the service. 48 | 49 | * `project_id` - (Optional) The project ID associated with the service. 50 | 51 | * `service_provider` - (Optional) Filter services by their provider (`tenant` or `cp`). 52 | 53 | * `proxy_protocol` - (Optional) Filter services by their use of the proxy protocol. 54 | 55 | * `require_approval` - (Optional) Filter services by whether they require approval. 56 | 57 | * `visibility` - (Optional) Filter services by their visibility (`private` or `public`). 58 | 59 | * `tags` - (Optional) A list of tags assigned to the service. 60 | 61 | ## Attributes Reference 62 | 63 | In addition to all arguments above, the following attributes are exported: 64 | 65 | * `id` - The ID of the found endpoint service. 66 | * `all_ip_addresses` - A list of all IP addresses associated with the service. 67 | * `all_tags` - A list of all tags assigned to the service. 68 | * `host` - The host of the service owner. 69 | * `status` - The current status of the service. 70 | * `created_at` - The timestamp when the service was created. 71 | * `updated_at` - The timestamp when the service was last updated. 72 | -------------------------------------------------------------------------------- /docs/data-sources/gslb_services_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_services_v1" 4 | sidebar_current: "docs-sci-datasource-gslb-services-v1" 5 | description: |- 6 | Get information about available GSLB services. 7 | --- 8 | 9 | # sci\_gslb\_services\_v1 10 | 11 | Use this data source to get information about available GSLB services. This 12 | data source is available only for OpenStack cloud admins. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | data "sci_gslb_services_v1" "services_1" { 18 | // No arguments 19 | } 20 | ``` 21 | 22 | ## Attributes Reference 23 | 24 | The following attributes are exported: 25 | 26 | * `id` - The unique ID for the GSLB services generated from data hash. 27 | * `region` - The region in which the GSLB services are available. 28 | * `services` - A list of maps representing the available GSLB services. 29 | 30 | The `services` attribute is a list of maps, where each map represents a service 31 | and contains the following keys: 32 | 33 | * `heartbeat` - The heartbeat of the service. 34 | * `host` - The host of the service. 35 | * `id` - The unique identifier of the service. 36 | * `metadata` - The metadata map associated with the service. 37 | * `provider` - The provider of the service. 38 | * `rpc_address` - The RPC address of the service. 39 | * `type` - The type of the service. 40 | * `version` - The version of the service. 41 | -------------------------------------------------------------------------------- /docs/data-sources/networking_router_v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_networking_router_v2" 4 | sidebar_current: "docs-sci-datasource-networking-router-v2" 5 | description: |- 6 | Get information about a SAP Cloud Infrastructure router. 7 | --- 8 | 9 | # sci\_networking\_router\_v2 10 | 11 | This is based on the [openstack_netwroking_router_v2 data 12 | source](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/data-sources/networking_router_v2) 13 | to add additional SAP Cloud Infrastructure specific fields. Use this data 14 | source to get the ID of an available SAP Cloud Infrastructure router and more. 15 | 16 | ## Example Usage 17 | 18 | ```hcl 19 | data "sci_networking_router_v2" "router" { 20 | name = "router_1" 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | * `region` - (Optional) The region in which to obtain the V2 Neutron client. 27 | A Neutron client is needed to retrieve router ids. If omitted, the 28 | `region` argument of the provider is used. 29 | 30 | * `router_id` - (Optional) The UUID of the router resource. 31 | 32 | * `name` - (Optional) The name of the router. 33 | 34 | * `description` - (Optional) Human-readable description of the router. 35 | 36 | * `admin_state_up` - (Optional) Administrative up/down status for the router (must be "true" or "false" if provided). 37 | 38 | * `distributed` - (Optional) Indicates whether or not to get a distributed router. 39 | 40 | * `status` - (Optional) The status of the router (ACTIVE/DOWN). 41 | 42 | * `tags` - (Optional) The list of router tags to filter. 43 | 44 | * `tenant_id` - (Optional) The owner of the router. 45 | 46 | ## Attributes Reference 47 | 48 | `id` is set to the ID of the found router. In addition, the following attributes 49 | are exported: 50 | 51 | * `enable_snat` - The value that points out if the Source NAT is enabled on the router. 52 | 53 | * `external_network_id` - The network UUID of an external gateway for the router. 54 | 55 | * `external_port_id` - The UUID of the external gateway port of the router. 56 | 57 | * `availability_zone_hints` - The availability zone that is used to make router resources highly available. 58 | 59 | * `external_fixed_ip` - The external fixed IPs of the router. 60 | 61 | The `external_fixed_ip` block supports: 62 | 63 | * `subnet_id`- Subnet in which the fixed IP belongs to. 64 | 65 | * `ip_address` - The IP address to set on the router. 66 | 67 | * `all_tags` - The set of string tags applied on the router. 68 | -------------------------------------------------------------------------------- /docs/resources/arc_agent_bootstrap_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_arc_agent_bootstrap_v1" 4 | sidebar_current: "docs-sci-resource-arc-agent-bootstrap-v1" 5 | description: |- 6 | Get the bootstrap information for a new Arc Agent. 7 | --- 8 | 9 | # sci\_arc\_agent\_bootstrap\_v1 10 | 11 | Use this resource to get the initialize data for a new Arc Agent. This data 12 | could be used as an OpenStack user data, executed by cloud-init system on 13 | compute instance boot. 14 | 15 | The `terraform destroy` command destroys the `sci_arc_agent_bootstrap_v1` 16 | state, but not the remote object, since the bootstrap data is a PKI token, not a 17 | real resource. 18 | 19 | The `terraform refresh` command doesn't refresh the bootstrap data, but reads it 20 | from the Terraform state. 21 | 22 | ## Example Usage 23 | 24 | ### Get an Arc Agent bootstrap script for Linux cloud-init 25 | 26 | ```hcl 27 | resource "sci_arc_agent_bootstrap_v1" "agent_1" {} 28 | 29 | resource "openstack_compute_instance_v2" "node" { 30 | name = "linux-vm" 31 | image_name = "ubuntu-16.04-amd64" 32 | flavor_name = "m1.small" 33 | user_data = sci_arc_agent_bootstrap_v1.agent_1.user_data 34 | 35 | network { 36 | name = "private_network" 37 | } 38 | } 39 | ``` 40 | 41 | ### Get an Arc Agent bootstrap script for Windows cloud-init 42 | 43 | ```hcl 44 | resource "sci_arc_agent_bootstrap_v1" "agent_1" { 45 | type = "windows" 46 | } 47 | 48 | resource "openstack_compute_instance_v2" "node" { 49 | name = "win-vm" 50 | image_name = "windows-2016-amd64" 51 | flavor_name = "m1.large" 52 | user_data = sci_arc_agent_bootstrap_v1.agent_1.user_data 53 | 54 | network { 55 | name = "private_network" 56 | } 57 | } 58 | ``` 59 | 60 | ### Get an extended Arc Agent bootstrap script for Windows cloud-init 61 | 62 | ```hcl 63 | resource "sci_arc_agent_bootstrap_v1" "agent_1" { 64 | type = "json" 65 | } 66 | 67 | data "template_file" "user_data" { 68 | template = < **Note:** All arguments and attributes, including repository credentials will 14 | be stored in the raw state as plaintext. 15 | [Read more about sensitive data in state](https://www.terraform.io/docs/state/sensitive-data.html). 16 | 17 | ## Example Usage 18 | 19 | ### Chef automation 20 | 21 | ```hcl 22 | resource "sci_automation_v1" "chef_automation_1" { 23 | name = "automation" 24 | repository = "https://example.com/org/repo.git" 25 | type = "Chef" 26 | run_list = ["recipe[repo::default]"] 27 | chef_attributes = < **Note:** The `terraform destroy` command destroys the 14 | `sci_billing_domain_masterdata` state, but not the actual billing domain 15 | masterdata. 16 | 17 | ~> **Note:** You _must_ have admin privileges in your OpenStack cloud to use 18 | this resource. 19 | 20 | ## Example Usage 21 | 22 | ```hcl 23 | resource "sci_billing_domain_masterdata" "masterdata" { 24 | responsible_primary_contact_id = "D123456" 25 | responsible_primary_contact_email = "mail@example.com" 26 | 27 | cost_object { 28 | projects_can_inherit = false 29 | } 30 | } 31 | ``` 32 | 33 | ## Argument Reference 34 | 35 | The following arguments are supported: 36 | 37 | * `region` - (Optional) The region in which to obtain the Billing client. If 38 | omitted, the `region` argument of the provider is used. Changing this forces 39 | a new resource to be created. 40 | 41 | * `domain_id` - (Optional) A domain ID. Defaults to the current domain scope. 42 | 43 | * `domain_name` - (Optional) A human-readable name for the domain. 44 | 45 | * `description` - (Optional) A domain description. 46 | 47 | * `additional_information` - (Optional) Freetext field for additional 48 | information for domain. 49 | 50 | * `responsible_primary_contact_id` - (Optional) SAP-User-Id of primary contact 51 | for the domain. 52 | 53 | * `responsible_primary_contact_email` - (Optional) Email-address of primary 54 | contact for the domain. 55 | 56 | * `cost_object` - (Optional) The cost object. The `cost_object` object structure 57 | is documented below. 58 | 59 | * `collector` - (Optional) The Collector of the domain and subprojects. 60 | 61 | The `cost_object` block supports: 62 | 63 | * `projects_can_inherit` - (Optional) Set to true, if the costobject should be 64 | inheritable for subprojects. 65 | 66 | * `name` - Name or ID of the costobject. 67 | 68 | * `type` - Type of the costobject. Can either be `IO` (internal order), `CC` 69 | (cost center), `WBS` (Work Breakdown Structure element) or `SO` (sales order). 70 | 71 | ## Attributes Reference 72 | 73 | In addition to all arguments above, the following attributes are exported: 74 | 75 | * `id` - The domain ID. 76 | * `created_at` - The date the Lyra automation was created. 77 | * `changed_at` - The date the Lyra automation was last updated. 78 | * `changed_by` - The OpenStack user ID of the user performed the last update. 79 | * `is_complete` - True, if the given masterdata is complete. Otherwise false. 80 | * `missing_attributes` - A human readable text, showing, what information is missing. 81 | 82 | ## Import 83 | 84 | Billing Domain Masterdata can be imported with a `domain_id` argument, e.g. 85 | 86 | ``` 87 | $ terraform import sci_billing_domain_masterdata.demo 30dd31bcac8748daaa75720dab7e019a 88 | ``` 89 | -------------------------------------------------------------------------------- /docs/resources/billing_project_masterdata.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_billing_project_masterdata" 4 | sidebar_current: "docs-sci-resource-billing-project-masterdata" 5 | description: |- 6 | Manages Billing Project Masterdata 7 | --- 8 | 9 | # sci\_billing\_project\_masterdata 10 | 11 | Manages Billing Project masterdata. 12 | 13 | ~> **Note:** The `terraform destroy` command destroys the 14 | `sci_billing_project_masterdata` state, but not the actual billing project 15 | masterdata. 16 | 17 | ~> **Note:** You _must_ have admin privileges in your OpenStack cloud to use 18 | this resource for other tenant projects. 19 | 20 | ## Example Usage 21 | 22 | ```hcl 23 | resource "sci_billing_project_masterdata" "masterdata" { 24 | responsible_primary_contact_id = "D123456" 25 | responsible_primary_contact_email = "mail@example.com" 26 | 27 | number_of_endusers = 100 28 | 29 | cost_object { 30 | inherited = true 31 | } 32 | } 33 | ``` 34 | 35 | ## Argument Reference 36 | 37 | The following arguments are supported: 38 | 39 | * `region` - (Optional) The region in which to obtain the Billing client. If 40 | omitted, the `region` argument of the provider is used. Changing this forces 41 | a new resource to be created. 42 | 43 | * `project_id` - (Optional) A project ID. Available only for users with an 44 | admin access. Defaults to the current project scope. 45 | 46 | * `project_name` - (Optional) A human-readable name for the project. Available 47 | only for users with an admin access. 48 | 49 | * `domain_id` - (Optional) A domain ID in which the project is contained. 50 | Available only for users with an admin access. 51 | 52 | * `domain_name` - (Optional) A domain name in which the project is contained. 53 | Available only for users with an admin access. 54 | 55 | * `parent_id` - (Optional) A project parent ID. Available only for users with 56 | an admin access. 57 | 58 | * `project_type` - (Optional) A project type. Available only for users with an 59 | admin access. 60 | 61 | * `description` - (Optional) A project description. 62 | 63 | * `revenue_relevance` - (Optional) Indicating if the project is directly or 64 | indirectly creating revenue. Can either be `generating`", `enabling` or 65 | `other`. 66 | 67 | * `business_criticality` - (Optional) Indicates how important the project for 68 | the business is. Can either be `dev`, `test` or `prod`. 69 | 70 | * `number_of_endusers` - (Optional) An amount of end users. `-1` indicates that 71 | it is infinite. 72 | 73 | * `additional_information` - (Optional) Freetext field for additional 74 | information for project. 75 | 76 | * `responsible_primary_contact_id` - (Optional) SAP-User-Id of primary contact 77 | for the project. 78 | 79 | * `responsible_primary_contact_email` - (Optional) Email-address of primary 80 | contact for the project. 81 | 82 | * `responsible_operator_id` - (Optional) SAP-User-Id of the person who is 83 | responsible for operating the project. 84 | 85 | * `responsible_operator_email` - (Optional) Email-address or DL of the 86 | person/group who is operating the project. 87 | 88 | * `responsible_inventory_role_id` - (Optional) SAP-User-Id of the Person/entity 89 | responsible to correctly maintain assets in SAP's Global DC HW asset inventory 90 | SISM/CCIR. 91 | 92 | * `responsible_inventory_role_email` - (Optional) Email-address or DL of the 93 | Person/entity responsible to correctly maintain assets in SAP's Global DC HW 94 | asset inventory SISM/CCIR. 95 | 96 | * `responsible_infrastructure_coordinator_id` - (Optional) SAP-User-Id of the 97 | infrastructure coordinator. 98 | 99 | * `responsible_infrastructure_coordinator_email` - (Optional) Email-address or 100 | DL of the infrastructure coordinator. 101 | 102 | * `cost_object` - (Optional) The cost object. The `cost_object` object structure 103 | is documented below. 104 | 105 | * `environment` - (Optional) Build environment of the project. Can either be 106 | `Prod`, `QA`, `Admin`, `DEV`, `Demo`, `Train`, `Sandbox`, `Lab` or `Test`. 107 | 108 | * `soft_license_mode` - (Optional) Software License Mode. Can either be 109 | `Revenue Generating`, `Training & Demo`, `Development`, `Test & QS`, 110 | `Administration`, `Make`, `Virtualization-Host` or `Productive`. 111 | 112 | * `type_of_data` - (Optional) Input parameter for KRITIS flag in CCIR. Can 113 | either be `SAP Business Process`, `Customer Cloud Service`, `Customer Business 114 | Process` or `Training & Demo Cloud`. 115 | 116 | * `gpu_enabled` - (Optional) Indicates whether the project uses GPUs. 117 | 118 | * `contains_pii_dpp_hr` - (Optional) Indicates whether the project contains 119 | sensitive personal data. 120 | 121 | * `contains_external_customer_data` - (Optional) Indicates whether the project 122 | contains data from external customer. 123 | 124 | * `ext_certification` - (Optional) Contains information about whether there is 125 | any external certification present in this project. The `ext_certification` 126 | object structure is documented below. 127 | 128 | The `cost_object` block supports: 129 | 130 | * `inherited` - (Optional) Shows, if the cost object is inherited. Required, if 131 | name/type not set. 132 | 133 | * `name` - Name or ID of the costobject. Required, if `inherited` not true. 134 | 135 | * `type` - Type of the costobject. Can either be `IO` (internal order), `CC` 136 | (cost center), `WBS` (Work Breakdown Structure element) or `SO` (sales order). 137 | Required, if `inherited` not true. 138 | 139 | The `ext_certification` block supports boolean values indicating whether the 140 | project has a corresponding certification: 141 | 142 | * `c5` - C5 is a government-backed verification framework implemented by the 143 | German Federal Office for Information Security (BSI). 144 | 145 | * `iso` - An ISO certification describes the process that confirms that ISO 146 | standards are being followed. 147 | 148 | * `pci` - PCI certification ensures the security of card data at your business 149 | through a set of requirements established by the PCI SSC. 150 | 151 | * `soc1` - SOC is a type of audit report that attests to the trustworthiness of 152 | services provided by a service organization. 153 | 154 | * `soc2` - SOC is a type of audit report that attests to the trustworthiness of 155 | services provided by a service organization. 156 | 157 | * `sox` - The law mandates strict reforms to improve financial disclosures from 158 | corporations and prevent accounting fraud. 159 | 160 | ## Attributes Reference 161 | 162 | In addition to all arguments above, the following attributes are exported: 163 | 164 | * `id` - The project ID. 165 | * `created_at` - The date the Lyra automation was created. 166 | * `changed_at` - The date the Lyra automation was last updated. 167 | * `changed_by` - The OpenStack user ID of the user performed the last update. 168 | * `is_complete` - True, if the given masterdata is complete. Otherwise false. 169 | * `missing_attributes` - A human readable text, showing, what information is missing. 170 | * `collector` - The Collector of the project. 171 | 172 | ## Import 173 | 174 | Billing Project Masterdata can be imported with a `project_id` argument, e.g. 175 | 176 | ``` 177 | $ terraform import sci_billing_project_masterdata.demo 30dd31bcac8748daaa75720dab7e019a 178 | ``` 179 | -------------------------------------------------------------------------------- /docs/resources/endpoint_accept_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_accept_v1" 4 | sidebar_current: "docs-sci-resource-endpoint-accept-v1" 5 | description: |- 6 | Accept an Archer endpoint request. 7 | --- 8 | 9 | # sci\_endpoint\_accept\_v1 10 | 11 | Use this resource to accept an Archer endpoint connection request within the 12 | SAP Cloud Infrastructure environment. This is typically used in scenarios where services 13 | are shared across projects and require explicit acceptance to establish 14 | connectivity. 15 | 16 | ~> **Note:** The `terraform destroy` command will reject the endpoint 17 | connection. 18 | 19 | ## Example Usage 20 | 21 | ```hcl 22 | provider "sci" { 23 | alias = "remote" 24 | 25 | tenant_name = "remote-project" 26 | } 27 | 28 | resource "sci_endpoint_v1" "endpoint_1" { 29 | provider = sci.remote 30 | 31 | name = "ep1" 32 | service_id = sci_endpoint_service_v1.service_1.id 33 | target { 34 | network = "8cd158e4-7b10-43ad-9b92-4251b10b5ee8" 35 | } 36 | 37 | tags = ["tag1","tag2"] 38 | } 39 | 40 | resource "sci_endpoint_service_v1" "service_1" { 41 | name = "svc1" 42 | visibility = "public" 43 | require_approval = true 44 | ip_addresses = ["192.168.1.2"] 45 | network_id = "a7ec6c35-4e17-4e97-aa2b-0d93e56bb6c7" 46 | port = 80 47 | } 48 | 49 | resource "sci_endpoint_accept_v1" "accept_1" { 50 | service_id = sci_endpoint_service_v1.service_1.id 51 | endpoint_id = sci_endpoint_v1.endpoint_1.id 52 | } 53 | ``` 54 | 55 | ## Argument Reference 56 | 57 | The following arguments are supported: 58 | 59 | * `region` - (Optional) The region in which to accept the endpoint. If omitted, 60 | the `region` argument of the provider is used. Changing this forces a new 61 | resource to be created. 62 | 63 | * `service_id` - (Required) The ID of the service to which the endpoint is 64 | connected. 65 | 66 | * `endpoint_id` - (Required) The ID of the endpoint to accept. 67 | 68 | ## Attributes Reference 69 | 70 | In addition to all arguments above, the following attributes are exported: 71 | 72 | * `id` - A combined ID of the Archer service and endpoint separated by a slash. 73 | * `status` - The current status of the Archer service endpoint acceptance. 74 | 75 | ## Import 76 | 77 | An Archer endpoint consumer can be imported using the endpoint `id` and 78 | `service_id` separated by a slash, e.g.: 79 | 80 | ```shell 81 | $ terraform import sci_endpoint_accept_v1.accept_1 301317d8-9067-439f-b90f-9916beaf087c/74931fd2-90ff-41c0-93f2-f536eb3c2412 82 | ``` 83 | -------------------------------------------------------------------------------- /docs/resources/endpoint_quota_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_quota_v1" 4 | sidebar_current: "docs-sci-resource-endpoint-quota-v1" 5 | description: |- 6 | Manage quotas for Archer endpoints and services. 7 | --- 8 | 9 | # sci\_endpoint\_quota\_v1 10 | 11 | Use this resource to create, manage, and delete quotas for endpoints and services within the SAP Cloud Infrastructure environment. 12 | 13 | ~> **Note:** This resource can be used only by OpenStack cloud administrators. 14 | 15 | ~> **Note:** The `terraform destroy` command will reset all the quotas back to 16 | zero. 17 | 18 | ## Example Usage 19 | 20 | ```hcl 21 | resource "sci_endpoint_quota_v1" "quota_1" { 22 | project_id = "08c49418f7274a57864cd468ebbfb062" 23 | endpoint = 10 24 | service = 5 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to manage the quota. If omitted, 33 | the `region` argument of the provider is used. Changing this forces a new 34 | resource to be created. 35 | 36 | * `endpoint` - (Optional) The quota for the number of endpoints. This is the 37 | maximum number of Archer endpoints that can be created. 38 | 39 | * `service` - (Optional) The quota for the number of services. This is the 40 | maximum number of Archer services that can be created. 41 | 42 | * `project_id` - (Required) The ID of the project for which to manage quotas. 43 | 44 | ## Attributes Reference 45 | 46 | In addition to all arguments above, the following attributes are exported: 47 | 48 | * `id` - The ID of the project. 49 | * `in_use_endpoint` - The number of endpoints currently in use. 50 | * `in_use_service` - The number of services currently in use. 51 | 52 | ## Import 53 | 54 | A quota can be imported using the project `id`, e.g. 55 | 56 | ```shell 57 | $ terraform import sci_endpoint_quota_v1.quota_1 08c49418f7274a57864cd468ebbfb062 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/resources/endpoint_rbac_policy_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_rbac_policy_v1" 4 | sidebar_current: "docs-sci-resource-endpoint-rbac-policy-v1" 5 | description: |- 6 | Manage RBAC policies for endpoints within the SAP Cloud Infrastructure environment. 7 | --- 8 | 9 | # sci\_endpoint\_rbac\_policy\_v1 10 | 11 | Use this resource to create, manage, and delete RBAC policies for endpoints within the SAP Cloud Infrastructure environment. This resource allows you to define access control policies for services and projects, specifying who can access what within your cloud environment. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_endpoint_service_v1" "service_1" { 17 | name = "svc1" 18 | port = 80 19 | ip_addresses = ["192.168.1.2"] 20 | network_id = "a7ec6c35-4e17-4e97-aa2b-0d93e56bb6c7" 21 | } 22 | 23 | resource "sci_endpoint_rbac_policy_v1" "rbac_1" { 24 | service_id = cc_endpoint_service_v1.service_1.id 25 | target = "ea8e0fa95bc145cba3d58170d76f7643" 26 | } 27 | ``` 28 | 29 | ## Argument Reference 30 | 31 | The following arguments are supported: 32 | 33 | * `region` - (Optional) The region in which to create the RBAC policy. If 34 | omitted, the `region` argument of the provider is used. Changing this forces 35 | a new resource to be created. 36 | 37 | * `service_id` - (Required) The ID of the service to which the policy applies. 38 | 39 | * `project_id` - (Optional) The ID of the project within which the policy is 40 | created. If omitted, the project ID of the provider is used. 41 | 42 | * `target` - (Required) The ID of the target project to which the policy 43 | applies. 44 | 45 | * `target_type` - (Optional) Specifies the type of the target. Valid values are 46 | `project`. 47 | 48 | ## Attributes Reference 49 | 50 | In addition to all arguments above, the following attributes are exported: 51 | 52 | * `id` - The ID of the RBAC policy. 53 | * `created_at` - The timestamp when the RBAC policy was created. 54 | * `updated_at` - The timestamp when the RBAC policy was last updated. 55 | 56 | ## Import 57 | 58 | Archer RBAC policies can be imported using the `id`, e.g. 59 | 60 | ```shell 61 | $ terraform import sci_endpoint_rbac_policy_v1.rbac_1 b6e99485-bfcc-415f-acef-6ea2b3984c03 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/resources/endpoint_service_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_service_v1" 4 | sidebar_current: "docs-sci-resource-endpoint-service-v1" 5 | description: |- 6 | Manage an Archer endpoint service. 7 | --- 8 | 9 | # sci\_endpoint\_service\_v1 10 | 11 | Use this resource to create, manage, and delete an endpoint service within the 12 | SAP Cloud Infrastructure environment. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | resource "sci_endpoint_service_v1" "service_1" { 18 | availability_zone = "region1a" 19 | name = "service1" 20 | ip_addresses = ["192.168.1.1"] 21 | port = 8080 22 | network_id = "982d8699-b1a0-4933-8b65-7f1cd8a0f78b" 23 | visibility = "private" 24 | tags = ["tag1", "tag2"] 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to create the endpoint service. If 33 | omitted, the `region` argument of the provider is used. Changing this forces 34 | a new resource to be created. 35 | 36 | * `enabled` - (Optional) Specifies if the service is enabled. Defaults to 37 | `true`. 38 | 39 | * `availability_zone` - (Optional) The availability zone in which to create the 40 | service. Changing this forces a new resource to be created 41 | 42 | * `name` - (Optional) The name of the endpoint service. 43 | 44 | * `description` - (Optional) A description of the endpoint service. 45 | 46 | * `ip_addresses` - (Required) A list of IP addresses associated with the 47 | service. 48 | 49 | * `port` - (Required) The port on which the service is exposed. 50 | 51 | * `network_id` - (Required) The network ID associated with the service. 52 | Changing this forces a new resource to be created. 53 | 54 | * `project_id` - (Optional) The project ID associated with the service. 55 | Changing this forces a new resource to be created. 56 | 57 | * `service_provider` - (Optional) The provider of the service (`tenant` or 58 | `cp`). Changing this forces a new resource to be created. Defaults to 59 | `tenant`. 60 | 61 | * `proxy_protocol` - (Optional) Specifies if the proxy protocol is used. 62 | Defaults to `true`. 63 | 64 | * `require_approval` - (Optional) Specifies if the service requires approval. 65 | Defaults to `true`. 66 | 67 | * `visibility` - (Optional) The visibility of the service (`private` or 68 | `public`). Defaults to `private`. 69 | 70 | * `tags` - (Optional) A list of tags assigned to the service. 71 | 72 | ## Attributes Reference 73 | 74 | In addition to all arguments above, the following attributes are exported: 75 | 76 | * `id` - The ID of the endpoint service. 77 | * `host` - The host name of the service. 78 | * `status` - The current status of the service. 79 | * `created_at` - The timestamp when the service was created. 80 | * `updated_at` - The timestamp when the service was last updated. 81 | 82 | ## Import 83 | 84 | An Archer endpoint service can be imported using the `id`, e.g. 85 | 86 | ```shell 87 | $ terraform import sci_endpoint_service_v1.service_1 069d36b0-125c-4c34-994d-849693805980 88 | ``` 89 | -------------------------------------------------------------------------------- /docs/resources/endpoint_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_endpoint_v1" 4 | sidebar_current: "docs-sci-resource-endpoint-v1" 5 | description: |- 6 | Manage an Archer endpoint. 7 | --- 8 | 9 | # sci\_endpoint\_v1 10 | 11 | Use this resource to create, manage, and delete an Archer endpoint within the 12 | SAP Cloud Infrastructure environment. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | data "sci_endpoint_service_v1" "service_1" { 18 | name = "service_1" 19 | status = "AVAILABLE" 20 | enabled = true 21 | 22 | availability_zone = "zone1" 23 | } 24 | 25 | resource "sci_endpoint_v1" "endpoint_1" { 26 | name = "endpoint_1" 27 | service_id = data.sci_endpoint_service_v1.service_1.id 28 | tags = ["tag1", "tag2"] 29 | 30 | target { 31 | network = "49b6480b-24d3-4376-a4c9-aecbb89e16d9" 32 | } 33 | } 34 | ``` 35 | 36 | ## Argument Reference 37 | 38 | * `region` - (Optional) The region in which to create the endpoint. If omitted, 39 | the `region` argument of the provider is used. Changing this forces a new 40 | resource to be created. 41 | 42 | * `name` - (Optional) The name of the endpoint. 43 | 44 | * `description` - (Optional) A description of the endpoint. 45 | 46 | * `project_id` - (Optional) The ID of the project in which to create the 47 | endpoint. Changing this forces a new resource to be created. 48 | 49 | * `service_id` - (Required) The ID of the service to which the endpoint is 50 | connected. Changing this forces a new resource to be created. 51 | 52 | * `tags` - (Optional) A list of tags assigned to the endpoint. 53 | 54 | * `target` - (Required) A block that defines the target of the endpoint. 55 | Changing this forces a new resource to be created. The block must contain one 56 | of the following arguments: 57 | 58 | * `network` - (Optional) The ID of the network to which the endpoint is 59 | connected. Conflicts with `subnet` and `port`. 60 | 61 | * `subnet` - (Optional) The ID of the subnet to which the endpoint is 62 | connected. Conflicts with `network` and `port`. 63 | 64 | * `port` - (Optional) The ID of the port to which the endpoint is connected. 65 | Conflicts with `network` and `subnet`. 66 | 67 | ## Attributes Reference 68 | 69 | In addition to all arguments above, the following attributes are exported: 70 | 71 | * `id` - The ID of the endpoint. 72 | * `ip_address` - The IP address assigned to the endpoint. 73 | * `status` - The current status of the endpoint. 74 | * `created_at` - The timestamp when the endpoint was created. 75 | * `updated_at` - The timestamp when the endpoint was last updated. 76 | 77 | ## Import 78 | 79 | An Archer endpoint can be imported using the `id`, e.g. 80 | 81 | ```shell 82 | $ terraform import sci_endpoint_v1.endpoint_1 5f955108-5d6a-422d-b460-b7de087953b3 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/resources/gslb_datacenter_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_datacenter_v1" 4 | sidebar_current: "docs-sci-resource-gslb-datacenter-v1" 5 | description: |- 6 | Manage GSLB datacenters 7 | --- 8 | 9 | # sci\_gslb\_datacenter\_v1 10 | 11 | This resource allows you to manage GSLB datacenters. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_gslb_datacenter_v1" "datacenter_1" { 17 | admin_state_up = true 18 | city = "City Name" 19 | continent = "Continent Name" 20 | country = "Country Name" 21 | latitude = 12.34 22 | longitude = 56.78 23 | name = "Datacenter Name" 24 | project_id = "Project ID" 25 | service_provider = "akamai" 26 | scope = "private" 27 | state_or_province = "State or Province Name" 28 | } 29 | ``` 30 | 31 | ## Argument Reference 32 | 33 | The following arguments are supported: 34 | 35 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 36 | omitted, the `region` argument of the provider is used. Changing this creates 37 | a new datacenter. 38 | 39 | * `admin_state_up` - (Optional) Whether the datacenter is administratively up. 40 | Default is `true`. 41 | 42 | * `city` - (Optional) The city where the datacenter is located. 43 | 44 | * `continent` - (Optional) The continent where the datacenter is located. 45 | 46 | * `country` - (Optional) The country where the datacenter is located. 47 | 48 | * `latitude` - (Optional) The latitude of the datacenter. 49 | 50 | * `longitude` - (Optional) The longitude of the datacenter. 51 | 52 | * `name` - (Optional) The name of the datacenter. 53 | 54 | * `project_id` - (Optional) The ID of the project that the datacenter belongs 55 | to. Changes to this field will trigger a new resource. 56 | 57 | * `service_provider` - (Optional) The service provider of the datacenter. Can 58 | be either `akamai` or `f5`. Default is `akamai`. 59 | 60 | * `scope` - (Optional) The scope of the datacenter. Can be either `private` or 61 | `shared`. Default is `private`. 62 | 63 | * `state_or_province` - (Optional) The state or province where the datacenter 64 | is located. 65 | 66 | ## Attributes Reference 67 | 68 | In addition to the arguments listed above, the following computed attributes are exported: 69 | 70 | * `id` - The ID of the datacenter. 71 | * `provisioning_status` - The provisioning status of the datacenter. 72 | * `meta` - Metadata associated with the datacenter. 73 | * `created_at` - The time when the datacenter was created. 74 | * `updated_at` - The time when the datacenter was last updated. 75 | 76 | ## Import 77 | 78 | Datacenters can be imported using the `id`, e.g. 79 | 80 | ```hcl 81 | $ terraform import sci_gslb_datacenter_v1.datacenter_1 041053d5-e1ce-4724-bf96-aeeda1df2465 82 | ``` 83 | -------------------------------------------------------------------------------- /docs/resources/gslb_domain_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_domain_v1" 4 | sidebar_current: "docs-sci-resource-gslb-domain-v1" 5 | description: |- 6 | Manage GSLB domains 7 | --- 8 | 9 | # sci\_gslb\_domain\_v1 10 | 11 | This resource allows you to manage GSLB domains. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_gslb_domain_v1" "domain_1" { 17 | admin_state_up = true 18 | fqdn = "example.com" 19 | mode = "ROUND_ROBIN" 20 | name = "example-domain" 21 | project_id = "your-project-id" 22 | service_provider = "akamai" 23 | record_type = "A" 24 | aliases = ["www.example.com", "api.example.com"] 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 33 | omitted, the `region` argument of the provider is used. Changing this creates 34 | a new domain. 35 | 36 | * `admin_state_up` - (Optional) Specifies whether the domain is administratively 37 | up or down. Defaults to `true`. 38 | 39 | * `fqdn` - (Required) The fully qualified domain name managed by this GSLB 40 | domain. 41 | 42 | * `mode` - (Optional) The load balancing mode for the domain. Supported values 43 | are `ROUND_ROBIN`, `WEIGHTED`, `GEOGRAPHIC`, and `AVAILABILITY`. Defaults to 44 | `ROUND_ROBIN`. 45 | 46 | * `name` - (Optional) The name of the GSLB domain. 47 | 48 | * `project_id` - (Optional) The ID of the project this domain belongs to. This 49 | field is computed if not set. Changes to this field will trigger a new 50 | resource. 51 | 52 | * `service_provider` - (Optional) The service provider for the GSLB domain. 53 | Supported values are `akamai` and `f5`. Defaults to `akamai`. 54 | 55 | * `record_type` - (Optional) The type of DNS record for the domain. Supported 56 | values are `A`, `AAAA`, `CNAME`, and `MX`. Defaults to `A`. 57 | 58 | * `aliases` - (Optional) A list of aliases (additional domain names) that are 59 | managed by this GSLB domain. 60 | 61 | ## Attributes Reference 62 | 63 | In addition to the arguments listed above, the following computed attributes are exported: 64 | 65 | * `id` - The ID of the domain. 66 | * `cname_target` - The CNAME target for the GSLB domain. 67 | * `provisioning_status` - The provisioning status of the domain. 68 | * `status` - The operational status of the domain. 69 | * `created_at` - The timestamp when the domain was created. 70 | * `updated_at` - The timestamp when the domain was last updated. 71 | 72 | ## Import 73 | 74 | Domains can be imported using the `id`, e.g. 75 | 76 | ```hcl 77 | $ terraform import sci_gslb_domain_v1.domain_1 f0f599a9-3a0d-4b4c-88d2-40c4fb071bba 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/resources/gslb_geomap_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_geomap_v1" 4 | sidebar_current: "docs-sci-resource-gslb-geomap-v1" 5 | description: |- 6 | Manage GSLB geographical maps 7 | --- 8 | 9 | # sci\_gslb\_geomap\_v1 10 | 11 | ~> **Note:** This kind of resources is experimental in Andromeda. 12 | 13 | This resource allows to manage GSLB geographical maps. 14 | 15 | ## Example Usage 16 | 17 | ```hcl 18 | resource "sci_gslb_geomap_v1" "geomap_1" { 19 | default_datacenter = "5c978d3c-a6c8-4322-9788-81a24212e958" 20 | name = "geomap1" 21 | service_provider = "akamai" 22 | scope = "private" 23 | assignments { 24 | country = "DE" 25 | datacenter = "5bfafa80-dbb9-4f7b-82a8-b60729373f5e" 26 | } 27 | assignments { 28 | country = "US" 29 | datacenter = "e242ff7e-9f8f-4571-b8c7-82014ab6918c" 30 | } 31 | } 32 | ``` 33 | 34 | ## Argument Reference 35 | 36 | The following arguments are supported: 37 | 38 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 39 | omitted, the `region` argument of the provider is used. Changing this creates 40 | a new geographical map. 41 | 42 | * `default_datacenter` - (Required) The UUID of the default data center to use 43 | when no country match is found in the assignments. 44 | 45 | * `name` - (Optional) The name of the geographical map. 46 | 47 | * `project_id` - (Optional) The ID of the project this geographical map belongs 48 | to. This field is computed if not set. Changes to this field will trigger a 49 | new resource. 50 | 51 | * `service_provider` - (Optional) The service provider for the GSLB geographical 52 | map. Supported values are `akamai` and `f5`. Defaults to `akamai`. 53 | 54 | * `scope` - (Optional) The scope of the geographical map. Supported values are 55 | `private` and `shared`. Defaults to `private`. 56 | 57 | * `assignments` - (Optional) A list of country to data center mappings. Each 58 | assignment specifies a `country` and a `datacenter` UUID. 59 | 60 | ## Attributes Reference 61 | 62 | In addition to the arguments listed above, the following computed attributes are exported: 63 | 64 | * `id` - The ID of the geographical map. 65 | * `provisioning_status` - The provisioning status of the geographical map. 66 | * `created_at` - The timestamp when the geographical map was created. 67 | * `updated_at` - The timestamp when the geographical map was last updated. 68 | 69 | ## Import 70 | 71 | Geographical map can be imported using the `id`, e.g. 72 | 73 | ```hcl 74 | $ terraform import sci_gslb_geomap_v1.geomap_1 24404021-e95a-4362-af9c-0e0cf8c6b856 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/resources/gslb_member_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_member_v1" 4 | sidebar_current: "docs-sci-resource-gslb-member-v1" 5 | description: |- 6 | Manage GSLB Members 7 | --- 8 | 9 | # sci\_gslb\_member\_v1 10 | 11 | This resource allows you to manage GSLB Members. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_gslb_member_v1" "member_1" { 17 | address = "192.168.0.1" 18 | admin_state_up = true 19 | datacenter_id = "datacenter-uuid" 20 | name = "example-member" 21 | pool_id = "pool-uuid" 22 | port = 80 23 | project_id = "your-project-id" 24 | } 25 | ``` 26 | 27 | ## Argument Reference 28 | 29 | The following arguments are supported: 30 | 31 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 32 | omitted, the `region` argument of the provider is used. Changing this creates 33 | a new member. 34 | 35 | * `address` - (Required) The IP address of the member. 36 | 37 | * `admin_state_up` - (Optional) Specifies whether the member is 38 | administratively up or down. Defaults to `true`. 39 | 40 | * `datacenter_id` - (Optional) The UUID of the data center where the member is 41 | located. 42 | 43 | * `name` - (Optional) The name of the GSLB member. 44 | 45 | * `pool_id` - (Optional) The UUID of the GSLB pool to which the member belongs. 46 | 47 | * `port` - (Required) The port on which the member is accepting traffic. 48 | 49 | * `project_id` (Optional): The ID of the project this member belongs to. This 50 | field is computed if not set. Changes to this field will trigger a new 51 | resource. 52 | 53 | ## Attributes Reference 54 | 55 | In addition to the arguments listed above, the following computed attributes are exported: 56 | 57 | * `id` - The ID of the member. 58 | * `provisioning_status` - The provisioning status of the member. 59 | * `status` - The operational status of the member. 60 | * `created_at` - The timestamp when the member was created. 61 | * `updated_at` - The timestamp when the member was last updated. 62 | 63 | ## Import 64 | 65 | Members can be imported using the `id`, e.g. 66 | 67 | ```hcl 68 | $ terraform import sci_gslb_member_v1.member_1 63c4c7fa-a90f-4fa1-8f21-ed8dbba6bc4b 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/resources/gslb_monitor_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_monitor_v1" 4 | sidebar_current: "docs-sci-resource-gslb-monitor-v1" 5 | description: |- 6 | Manage GSLB Monitors 7 | --- 8 | 9 | # sci\_gslb\_monitor\_v1 10 | 11 | This resource allows you to manage GSLB Monitors. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_gslb_monitor_v1" "monitor_1" { 17 | admin_state_up = true 18 | interval = 10 19 | name = "example-monitor" 20 | pool_id = "your-pool-id" 21 | project_id = "your-project-id" 22 | receive = "HTTP 200 OK" 23 | send = "/health" 24 | timeout = 5 25 | type = "HTTP" 26 | } 27 | ``` 28 | 29 | ## Argument Reference 30 | 31 | The following arguments are supported: 32 | 33 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 34 | omitted, the `region` argument of the provider is used. Changing this creates 35 | a new monitor. 36 | 37 | * `admin_state_up` - (Optional) Specifies whether the monitor is 38 | administratively up or down. Defaults to `true`. 39 | 40 | * `interval` - (Optional) The time, in seconds, between sending probes to 41 | members. 42 | 43 | * `name` - (Optional) The name of the monitor. 44 | 45 | * `domain_name` - (Optional) The domain name to use in the HTTP host header. 46 | Only used with `HTTP` and `HTTPS` monitor types. 47 | 48 | * `pool_id` - (Optional) The ID of the pool that this monitor is associated 49 | with. 50 | 51 | * `project_id` - (Optional) The ID of the project this monitor belongs to. This 52 | field is computed if not set. Changes to this field will trigger a new 53 | resource. 54 | 55 | * `receive` - (Optional) The expected response text from the monitored resource. 56 | Valid only for `TCP` monitor types. 57 | 58 | * `send` - (Optional) The HTTP request method and path that the monitor sends to 59 | the monitored resource. 60 | 61 | * `timeout` - (Optional) Maximum time, in seconds, the monitor waits to receive 62 | a response from the monitored resource. This field is computed if not set. 63 | 64 | * `type` - (Optional) The type of monitor, which determines the method used to 65 | check the health of the monitored resource. Supported types are `ICMP`, 66 | `HTTP`, `HTTPS`, `TCP`, and `UDP`. Defaults to `ICMP`. 67 | 68 | * `http_method` - (Optional) The HTTP method to use for the monitor. Supported 69 | methods are `GET`, `POST`, `PUT`, `HEAD`, `DELETE` and `OPTIONS`. Only used 70 | with `HTTP` and `HTTPS` monitor types. Defaults to `GET`. 71 | 72 | ## Attributes Reference 73 | 74 | In addition to the arguments listed above, the following computed attributes are exported: 75 | 76 | * `id` - The ID of the monitor. 77 | * `provisioning_status` - The provisioning status of the monitor. 78 | * `created_at` - The time when the monitor was created. 79 | * `updated_at` - The time when the monitor was last updated. 80 | 81 | ## Import 82 | 83 | Monitors can be imported using the `id`, e.g. 84 | 85 | ```hcl 86 | $ terraform import sci_gslb_monitor_v1.monitor_1 de731802-f092-496d-9508-9e02eb6ba0b1 87 | ``` 88 | -------------------------------------------------------------------------------- /docs/resources/gslb_pool_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_pool_v1" 4 | sidebar_current: "docs-sci-resource-gslb-pool-v1" 5 | description: |- 6 | Manage GSLB Pools 7 | --- 8 | 9 | # sci\_gslb\_pool\_v1 10 | 11 | This resource allows you to manage GSLB Pools. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "sci_gslb_pool_v1" "pool_1" { 17 | admin_state_up = true 18 | domains = ["4da21196-4f20-48e6-aa56-42a567f40598"] 19 | name = "pool1" 20 | } 21 | ``` 22 | 23 | ## Argument Reference 24 | 25 | The following arguments are supported: 26 | 27 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 28 | omitted, the `region` argument of the provider is used. Changing this creates 29 | a new pool. 30 | 31 | * `admin_state_up` - (Optional) Specifies whether the pool is administratively 32 | up or down. Defaults to `true`. 33 | 34 | * `domains` - (Optional) A list of UUIDs referencing the domain names 35 | associated with the pool. 36 | 37 | * `name` - (Optional) The name of the pool. 38 | 39 | * `project_id` - (Optional) The ID of the project this pool belongs to. This 40 | field is computed if not set. Changes to this field will trigger a new 41 | resource. 42 | 43 | ## Attributes Reference 44 | 45 | In addition to the arguments listed above, the following computed attributes are exported: 46 | 47 | * `members` - The list of members (servers) associated with this pool. 48 | * `monitors` - The list of health monitors associated with this pool. 49 | * `provisioning_status` - The provisioning status of the pool. 50 | * `status` - The operational status of the pool. 51 | * `created_at` - The timestamp when the pool was created. 52 | * `updated_at` - The timestamp when the pool was last updated. 53 | 54 | ## Import 55 | 56 | Pools can be imported using the `id`, e.g. 57 | 58 | ```hcl 59 | $ terraform import sci_gslb_pool_v1.pool_1 a4182fdb-a763-451e-8fd8-05f79d57128b 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/resources/gslb_quota_v1.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "sci" 3 | page_title: "SAP Cloud Infrastructure: sci_gslb_quota_v1" 4 | sidebar_current: "docs-sci-resource-gslb-quota-v1" 5 | description: |- 6 | Manage GSLB Quotas 7 | --- 8 | 9 | # sci\_gslb\_quota\_v1 10 | 11 | This resource allows you to manage GSLB Quotas. 12 | 13 | ~> **Note:** This resource can be used only by OpenStack cloud administrators. 14 | 15 | ~> **Note:** The `terraform destroy` command will reset all the quotas back to 16 | zero. 17 | 18 | ## Example Usage 19 | 20 | ```hcl 21 | resource "sci_gslb_quota_v1" "quota_1" { 22 | datacenter = 10 23 | domain_akamai = 20 24 | domain_f5 = 20 25 | member = 30 26 | monitor = 40 27 | pool = 50 28 | project_id = "ea3b508ba36142d9888dc087b014ef78" 29 | } 30 | ``` 31 | 32 | ## Argument Reference 33 | 34 | The following arguments are supported: 35 | 36 | * `region` - (Optional) The region in which to obtain the Andromeda client. If 37 | omitted, the `region` argument of the provider is used. Changing this creates 38 | a new quota. 39 | 40 | * `project_id` - (Required) The ID of the project that the quota belongs to. 41 | Changes to this field will trigger a new resource. 42 | 43 | * `datacenter` - (Optional) The number of datacenters for the quota. 44 | 45 | * `domain` - (Deprecated) Use `domain_akamai` and `domain_f5` instead. The number of 46 | domains for the quota. This field is deprecated and will be removed in a future 47 | version. 48 | 49 | * `domain_akamai` - (Optional) The number of Akamai domains for the quota. 50 | 51 | * `domain_f5` - (Optional) The number of F5 domains for the quota. 52 | 53 | * `member` - (Optional) The number of members for the quota. 54 | 55 | * `monitor` - (Optional) The number of monitors for the quota. 56 | 57 | * `pool` - (Optional) The number of pools for the quota. 58 | 59 | ## Attributes Reference 60 | 61 | In addition to the arguments listed above, the following computed attributes 62 | are exported: 63 | 64 | * `id` - The ID of the project. 65 | * `in_use_datacenter` - The number of datacenters currently in use. 66 | * `in_use_domain` - The number of domains currently in use. This is a deprecated 67 | field and will be removed in a future version. Use `in_use_domain_akamai` and 68 | `in_use_domain_f5` instead. 69 | * `in_use_domain_akamai` - The number of Akamai domains currently in use. 70 | * `in_use_domain_f5` - The number of F5 domains currently in use. 71 | * `in_use_member` - The number of members currently in use. 72 | * `in_use_monitor` - The number of monitors currently in use. 73 | * `in_use_pool` - The number of pools currently in use. 74 | 75 | ## Import 76 | 77 | Quotas can be imported using the project `id`, e.g. 78 | 79 | ```hcl 80 | $ terraform import sci_gslb_quota_v1.quota_1 ea3b508ba36142d9888dc087b014ef78 81 | ``` 82 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/SAP-cloud-infrastructure/terraform-provider-sci 2 | 3 | go 1.24.0 4 | 5 | toolchain go1.24.4 6 | 7 | require ( 8 | github.com/go-openapi/runtime v0.28.0 9 | github.com/go-openapi/strfmt v0.23.0 10 | github.com/go-openapi/validate v0.24.0 11 | github.com/gophercloud/gophercloud/v2 v2.7.1-0.20250416153453-3eff99bf6fe8 12 | github.com/gophercloud/utils/v2 v2.0.0-20250617123236-b0c67de63928 13 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 14 | github.com/sapcc/andromeda v1.1.1 15 | github.com/sapcc/archer v1.3.1 16 | github.com/sapcc/gophercloud-sapcc/v2 v2.0.3 17 | github.com/sapcc/kubernikus v1.0.1-0.20250603090049-415897d6bcf8 18 | k8s.io/client-go v0.33.2 19 | sigs.k8s.io/yaml v1.4.0 20 | ) 21 | 22 | require ( 23 | cel.dev/expr v0.20.0 // indirect 24 | github.com/agext/levenshtein v1.2.2 // indirect 25 | github.com/antlr4-go/antlr/v4 v4.13.0 // indirect 26 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 27 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 28 | github.com/beorn7/perks v1.0.1 // indirect 29 | github.com/blang/semver/v4 v4.0.0 // indirect 30 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 31 | github.com/fatih/color v1.16.0 // indirect 32 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 33 | github.com/go-logr/logr v1.4.2 // indirect 34 | github.com/go-logr/stdr v1.2.2 // indirect 35 | github.com/go-openapi/analysis v0.23.0 // indirect 36 | github.com/go-openapi/errors v0.22.1 // indirect 37 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 38 | github.com/go-openapi/jsonreference v0.21.0 // indirect 39 | github.com/go-openapi/loads v0.22.0 // indirect 40 | github.com/go-openapi/spec v0.21.0 // indirect 41 | github.com/go-openapi/swag v0.23.1 // indirect 42 | github.com/gofrs/uuid/v5 v5.3.2 // indirect 43 | github.com/gogo/protobuf v1.3.2 // indirect 44 | github.com/golang/protobuf v1.5.4 // indirect 45 | github.com/google/cel-go v0.22.0 // indirect 46 | github.com/google/go-cmp v0.7.0 // indirect 47 | github.com/google/uuid v1.6.0 // indirect 48 | github.com/hashicorp/go-cty v1.5.0 // indirect 49 | github.com/hashicorp/go-hclog v1.6.3 // indirect 50 | github.com/hashicorp/go-plugin v1.6.3 // indirect 51 | github.com/hashicorp/go-uuid v1.0.3 // indirect 52 | github.com/hashicorp/go-version v1.7.0 // indirect 53 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 54 | github.com/hashicorp/logutils v1.0.0 // indirect 55 | github.com/hashicorp/terraform-plugin-go v0.27.0 // indirect 56 | github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect 57 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect 58 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect 59 | github.com/hashicorp/yamux v0.1.1 // indirect 60 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 61 | github.com/josharian/intern v1.0.0 // indirect 62 | github.com/json-iterator/go v1.1.12 // indirect 63 | github.com/mailru/easyjson v0.9.0 // indirect 64 | github.com/mattn/go-colorable v0.1.13 // indirect 65 | github.com/mattn/go-isatty v0.0.20 // indirect 66 | github.com/mitchellh/copystructure v1.2.0 // indirect 67 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 68 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 69 | github.com/mitchellh/mapstructure v1.5.0 // indirect 70 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 71 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 72 | github.com/modern-go/reflect2 v1.0.2 // indirect 73 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 74 | github.com/oklog/run v1.1.0 // indirect 75 | github.com/oklog/ulid v1.3.1 // indirect 76 | github.com/opentracing/opentracing-go v1.2.0 // indirect 77 | github.com/pkg/errors v0.9.1 // indirect 78 | github.com/prometheus/client_golang v1.22.0 // indirect 79 | github.com/prometheus/client_model v0.6.2 // indirect 80 | github.com/prometheus/common v0.64.0 // indirect 81 | github.com/prometheus/procfs v0.15.1 // indirect 82 | github.com/spf13/cobra v1.8.1 // indirect 83 | github.com/spf13/pflag v1.0.6 // indirect 84 | github.com/stoewer/go-strcase v1.3.0 // indirect 85 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 86 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 87 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 88 | github.com/x448/float16 v0.8.4 // indirect 89 | github.com/zclconf/go-cty v1.16.2 // indirect 90 | go.mongodb.org/mongo-driver v1.14.0 // indirect 91 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 92 | go.opentelemetry.io/otel v1.34.0 // indirect 93 | go.opentelemetry.io/otel/metric v1.34.0 // indirect 94 | go.opentelemetry.io/otel/trace v1.34.0 // indirect 95 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 96 | golang.org/x/mod v0.25.0 // indirect 97 | golang.org/x/net v0.40.0 // indirect 98 | golang.org/x/sync v0.15.0 // indirect 99 | golang.org/x/sys v0.33.0 // indirect 100 | golang.org/x/text v0.26.0 // indirect 101 | golang.org/x/tools v0.33.0 // indirect 102 | google.golang.org/appengine v1.6.8 // indirect 103 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect 104 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 105 | google.golang.org/grpc v1.72.1 // indirect 106 | google.golang.org/protobuf v1.36.6 // indirect 107 | gopkg.in/inf.v0 v0.9.1 // indirect 108 | gopkg.in/yaml.v3 v3.0.1 // indirect 109 | k8s.io/api v0.33.2 // indirect 110 | k8s.io/apimachinery v0.33.2 // indirect 111 | k8s.io/apiserver v0.32.2 // indirect 112 | k8s.io/component-base v0.32.2 // indirect 113 | k8s.io/klog/v2 v2.130.1 // indirect 114 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect 115 | k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect 116 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 117 | sigs.k8s.io/randfill v1.0.0 // indirect 118 | sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect 119 | ) 120 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/SAP-cloud-infrastructure/terraform-provider-sci/sci" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 8 | ) 9 | 10 | const providerAddr = "registry.terraform.io/SAP-cloud-infrastructure/sci" 11 | 12 | func main() { 13 | // added debugMode to enable debugging for provider per https://www.terraform.io/plugin/sdkv2/debugging 14 | var debugMode bool 15 | flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") 16 | flag.Parse() 17 | 18 | plugin.Serve(&plugin.ServeOpts{ 19 | Debug: debugMode, 20 | ProviderAddr: providerAddr, 21 | ProviderFunc: sci.Provider, 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /sci/andromeda.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "reflect" 8 | 9 | "github.com/go-openapi/runtime" 10 | httptransport "github.com/go-openapi/runtime/client" 11 | "github.com/go-openapi/strfmt" 12 | "github.com/gophercloud/gophercloud/v2" 13 | osClient "github.com/gophercloud/utils/v2/client" 14 | "github.com/sapcc/andromeda/client" 15 | ) 16 | 17 | func newAndromedaV1(c *Config, eo gophercloud.EndpointOpts) (*client.Andromeda, error) { 18 | var err error 19 | var endpoint string 20 | var aurl *url.URL 21 | 22 | if v, ok := c.EndpointOverrides["gtm"]; ok { 23 | if e, ok := v.(string); ok && e != "" { 24 | endpoint = e 25 | } 26 | } 27 | 28 | if endpoint == "" && !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) { 29 | eo.ApplyDefaults("gtm") 30 | endpoint, err = c.OsClient.EndpointLocator(eo) 31 | if err != nil { 32 | return nil, err 33 | } 34 | } 35 | 36 | if aurl, err = url.Parse(endpoint); err != nil { 37 | return nil, fmt.Errorf("parsing the Andromeda URL failed: %s", err) 38 | } 39 | 40 | transport := httptransport.New(aurl.Host, aurl.EscapedPath(), []string{aurl.Scheme}) 41 | 42 | if v, ok := c.OsClient.HTTPClient.Transport.(*osClient.RoundTripper); ok && v.Logger != nil { 43 | // enable JSON debug for Andromeda 44 | transport.SetLogger(logger{"Andromeda"}) 45 | transport.Debug = true 46 | } 47 | 48 | transport.DefaultAuthentication = runtime.ClientAuthInfoWriterFunc( 49 | func(req runtime.ClientRequest, reg strfmt.Registry) error { 50 | err := req.SetHeaderParam("X-Auth-Token", c.OsClient.Token()) 51 | if err != nil { 52 | log.Printf("[DEBUG] Andromeda auth func cannot set X-Auth-Token header value: %v", err) 53 | } 54 | err = req.SetHeaderParam("User-Agent", c.OsClient.UserAgent.Join()) 55 | if err != nil { 56 | log.Printf("[DEBUG] Andromeda auth func cannot set User-Agent header value: %v", err) 57 | } 58 | return nil 59 | }) 60 | 61 | operations := client.New(transport, strfmt.Default) 62 | 63 | return operations, nil 64 | } 65 | -------------------------------------------------------------------------------- /sci/archer.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "reflect" 8 | 9 | "github.com/go-openapi/runtime" 10 | httptransport "github.com/go-openapi/runtime/client" 11 | "github.com/go-openapi/strfmt" 12 | "github.com/gophercloud/gophercloud/v2" 13 | osClient "github.com/gophercloud/utils/v2/client" 14 | "github.com/sapcc/archer/client" 15 | ) 16 | 17 | type archer struct { 18 | client.Archer 19 | provider *gophercloud.ProviderClient 20 | } 21 | 22 | func newArcherV1(c *Config, eo gophercloud.EndpointOpts) (*archer, error) { 23 | var err error 24 | var endpoint string 25 | var aurl *url.URL 26 | 27 | if v, ok := c.EndpointOverrides["endpoint-services"]; ok { 28 | if e, ok := v.(string); ok && e != "" { 29 | endpoint = e 30 | } 31 | } 32 | 33 | if endpoint == "" && !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) { 34 | eo.ApplyDefaults("endpoint-services") 35 | endpoint, err = c.OsClient.EndpointLocator(eo) 36 | if err != nil { 37 | return nil, err 38 | } 39 | } 40 | 41 | if aurl, err = url.Parse(endpoint); err != nil { 42 | return nil, fmt.Errorf("parsing the Archer URL failed: %s", err) 43 | } 44 | 45 | transport := httptransport.New(aurl.Host, aurl.EscapedPath(), []string{aurl.Scheme}) 46 | 47 | if v, ok := c.OsClient.HTTPClient.Transport.(*osClient.RoundTripper); ok && v.Logger != nil { 48 | // enable JSON debug for Archer 49 | transport.SetLogger(logger{"Archer"}) 50 | transport.Debug = true 51 | } 52 | 53 | operations := client.New(transport, strfmt.Default) 54 | 55 | return &archer{*operations, c.OsClient}, nil 56 | } 57 | 58 | func (a *archer) authFunc() runtime.ClientAuthInfoWriterFunc { 59 | return runtime.ClientAuthInfoWriterFunc( 60 | func(req runtime.ClientRequest, reg strfmt.Registry) error { 61 | err := req.SetHeaderParam("X-Auth-Token", a.provider.Token()) 62 | if err != nil { 63 | log.Printf("[DEBUG] Kubernikus auth func cannot set X-Auth-Token header value: %v", err) 64 | } 65 | err = req.SetHeaderParam("User-Agent", a.provider.UserAgent.Join()) 66 | if err != nil { 67 | log.Printf("[DEBUG] Kubernikus auth func cannot set User-Agent header value: %v", err) 68 | } 69 | return nil 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /sci/config.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gophercloud/gophercloud/v2" 7 | "github.com/gophercloud/utils/v2/openstack/clientconfig" 8 | "github.com/sapcc/andromeda/client" 9 | "github.com/sapcc/gophercloud-sapcc/v2/clients" 10 | ) 11 | 12 | func (c *Config) kubernikusV1Client(ctx context.Context, region string, isAdmin bool) (*kubernikus, error) { 13 | if err := c.Authenticate(ctx); err != nil { 14 | return nil, err 15 | } 16 | 17 | serviceType := "kubernikus" 18 | if isAdmin { 19 | serviceType = "kubernikus-kubernikus" 20 | } 21 | 22 | return newKubernikusV1(c, gophercloud.EndpointOpts{ 23 | Type: serviceType, 24 | Region: c.DetermineRegion(region), 25 | Availability: clientconfig.GetEndpointType(c.EndpointType), 26 | }) 27 | } 28 | 29 | func (c *Config) andromedaV1Client(ctx context.Context, region string) (*client.Andromeda, error) { 30 | if err := c.Authenticate(ctx); err != nil { 31 | return nil, err 32 | } 33 | 34 | return newAndromedaV1(c, gophercloud.EndpointOpts{ 35 | Type: "gtm", 36 | Region: c.DetermineRegion(region), 37 | Availability: clientconfig.GetEndpointType(c.EndpointType), 38 | }) 39 | } 40 | 41 | func (c *Config) archerV1Client(ctx context.Context, region string) (*archer, error) { 42 | if err := c.Authenticate(ctx); err != nil { 43 | return nil, err 44 | } 45 | 46 | return newArcherV1(c, gophercloud.EndpointOpts{ 47 | Type: "endpoint-services", 48 | Region: c.DetermineRegion(region), 49 | Availability: clientconfig.GetEndpointType(c.EndpointType), 50 | }) 51 | } 52 | 53 | func (c *Config) arcV1Client(ctx context.Context, region string) (*gophercloud.ServiceClient, error) { 54 | return c.CommonServiceClientInit(ctx, clients.NewArcV1, region, "arc") 55 | } 56 | 57 | func (c *Config) automationV1Client(ctx context.Context, region string) (*gophercloud.ServiceClient, error) { 58 | return c.CommonServiceClientInit(ctx, clients.NewAutomationV1, region, "automation") 59 | } 60 | 61 | func (c *Config) billingClient(ctx context.Context, region string) (*gophercloud.ServiceClient, error) { 62 | return c.CommonServiceClientInit(ctx, clients.NewBilling, region, "sapcc-billing") 63 | } 64 | -------------------------------------------------------------------------------- /sci/data_source_sci_arc_agent_ids_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "strings" 8 | 9 | "github.com/gophercloud/utils/v2/terraform/hashcode" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | "github.com/sapcc/gophercloud-sapcc/v2/arc/v1/agents" 13 | ) 14 | 15 | func dataSourceSCIArcAgentIDsV1() *schema.Resource { 16 | return &schema.Resource{ 17 | ReadContext: dataSourceSCIArcAgentIDsV1Read, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "region": { 21 | Type: schema.TypeString, 22 | Optional: true, 23 | Computed: true, 24 | ForceNew: true, 25 | }, 26 | 27 | "filter": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | }, 31 | 32 | // computed attributes 33 | "ids": { 34 | Type: schema.TypeList, 35 | Computed: true, 36 | Elem: &schema.Schema{Type: schema.TypeString}, 37 | }, 38 | }, 39 | } 40 | } 41 | 42 | func dataSourceSCIArcAgentIDsV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 43 | config := meta.(*Config) 44 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 45 | if err != nil { 46 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 47 | } 48 | 49 | filter := d.Get("filter").(string) 50 | 51 | listOpts := agents.ListOpts{Filter: filter} 52 | 53 | log.Printf("[DEBUG] sci_arc_agent_ids_v1 list options: %#v", listOpts) 54 | 55 | allPages, err := agents.List(arcClient, listOpts).AllPages(ctx) 56 | if err != nil { 57 | return diag.Errorf("Unable to list sci_arc_agent_ids_v1: %s", err) 58 | } 59 | 60 | allAgents, err := agents.ExtractAgents(allPages) 61 | if err != nil { 62 | return diag.Errorf("Unable to retrieve sci_arc_agent_ids_v1: %s", err) 63 | } 64 | 65 | agentIDs := make([]string, 0, len(allAgents)) 66 | for _, a := range allAgents { 67 | agentIDs = append(agentIDs, a.AgentID) 68 | } 69 | 70 | log.Printf("[DEBUG] Retrieved %d agents in sci_arc_agent_ids_v1: %+v", len(allAgents), allAgents) 71 | 72 | d.SetId(fmt.Sprintf("%d", hashcode.String(strings.Join(agentIDs, "")))) 73 | _ = d.Set("ids", agentIDs) 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /sci/data_source_sci_arc_agent_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 9 | ) 10 | 11 | func dataSourceSCIArcAgentV1() *schema.Resource { 12 | return &schema.Resource{ 13 | ReadContext: dataSourceSCIArcAgentV1Read, 14 | 15 | // Terraform timeouts don't work in data sources. 16 | // However "Timeouts" has to be specified, otherwise "timeouts" argument below won't work. 17 | Timeouts: &schema.ResourceTimeout{ 18 | Read: schema.DefaultTimeout(0), 19 | }, 20 | 21 | Schema: map[string]*schema.Schema{ 22 | "region": { 23 | Type: schema.TypeString, 24 | Optional: true, 25 | Computed: true, 26 | ForceNew: true, 27 | }, 28 | 29 | "agent_id": { 30 | Type: schema.TypeString, 31 | Optional: true, 32 | Computed: true, 33 | ForceNew: true, 34 | ConflictsWith: []string{"filter"}, 35 | ValidateFunc: validation.NoZeroValues, 36 | }, 37 | 38 | "filter": { 39 | Type: schema.TypeString, 40 | Optional: true, 41 | ForceNew: true, 42 | ConflictsWith: []string{"agent_id"}, 43 | ValidateFunc: validation.NoZeroValues, 44 | }, 45 | 46 | // Terraform timeouts don't work in data sources. 47 | // This is a workaround. 48 | "timeouts": { 49 | Type: schema.TypeList, 50 | Optional: true, 51 | MaxItems: 1, 52 | Elem: &schema.Resource{ 53 | Schema: map[string]*schema.Schema{ 54 | "read": { 55 | Type: schema.TypeString, 56 | Optional: true, 57 | ValidateFunc: validateTimeout, 58 | }, 59 | }, 60 | }, 61 | }, 62 | 63 | // computed attributes 64 | "display_name": { 65 | Type: schema.TypeString, 66 | Computed: true, 67 | }, 68 | 69 | "project": { 70 | Type: schema.TypeString, 71 | Computed: true, 72 | }, 73 | 74 | "organization": { 75 | Type: schema.TypeString, 76 | Computed: true, 77 | }, 78 | 79 | "created_at": { 80 | Type: schema.TypeString, 81 | Computed: true, 82 | }, 83 | 84 | "updated_at": { 85 | Type: schema.TypeString, 86 | Computed: true, 87 | }, 88 | 89 | "updated_with": { 90 | Type: schema.TypeString, 91 | Computed: true, 92 | }, 93 | 94 | "updated_by": { 95 | Type: schema.TypeString, 96 | Computed: true, 97 | }, 98 | 99 | "all_tags": { 100 | Type: schema.TypeMap, 101 | Computed: true, 102 | }, 103 | 104 | "facts": { 105 | Type: schema.TypeMap, 106 | Computed: true, 107 | }, 108 | 109 | "facts_agents": { 110 | Type: schema.TypeMap, 111 | Computed: true, 112 | }, 113 | }, 114 | } 115 | } 116 | 117 | func dataSourceSCIArcAgentV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 118 | config := meta.(*Config) 119 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 120 | if err != nil { 121 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 122 | } 123 | 124 | agentID := d.Get("agent_id").(string) 125 | filter := d.Get("filter").(string) 126 | 127 | timeout, err := arcAgentV1ParseTimeout(d.Get("timeouts")) 128 | if err != nil { 129 | return diag.Errorf("Error parsing the read timeout for sci_arc_job_v1: %s", err) 130 | } 131 | 132 | agent, err := arcSCIArcAgentV1WaitForAgent(ctx, arcClient, agentID, filter, timeout) 133 | if err != nil { 134 | return diag.FromErr(err) 135 | } 136 | 137 | d.SetId(agent.AgentID) 138 | 139 | arcSCIArcAgentV1ReadAgent(ctx, d, arcClient, agent, GetRegion(d, config)) 140 | 141 | return nil 142 | } 143 | -------------------------------------------------------------------------------- /sci/data_source_sci_arc_job_ids_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "strings" 8 | 9 | "github.com/gophercloud/utils/v2/terraform/hashcode" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 13 | ) 14 | 15 | func dataSourceSCIArcJobIDsV1() *schema.Resource { 16 | return &schema.Resource{ 17 | ReadContext: dataSourceSCIArcJobIDsV1Read, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "region": { 21 | Type: schema.TypeString, 22 | Optional: true, 23 | Computed: true, 24 | ForceNew: true, 25 | }, 26 | 27 | "agent_id": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | }, 31 | 32 | "timeout": { 33 | Type: schema.TypeInt, 34 | Optional: true, 35 | ValidateFunc: validation.IntBetween(1, 86400), 36 | }, 37 | 38 | "agent": { 39 | Type: schema.TypeString, 40 | Optional: true, 41 | ValidateFunc: validation.StringInSlice([]string{ 42 | "chef", "execute", 43 | }, false), 44 | }, 45 | 46 | "action": { 47 | Type: schema.TypeString, 48 | Optional: true, 49 | ValidateFunc: validation.StringInSlice([]string{ 50 | "script", "zero", "tarball", 51 | }, false), 52 | }, 53 | 54 | "status": { 55 | Type: schema.TypeString, 56 | Optional: true, 57 | ValidateFunc: validation.StringInSlice([]string{ 58 | "queued", "executing", "failed", "complete", 59 | }, false), 60 | }, 61 | 62 | "ids": { 63 | Type: schema.TypeList, 64 | Computed: true, 65 | Elem: &schema.Schema{Type: schema.TypeString}, 66 | }, 67 | }, 68 | } 69 | } 70 | 71 | func dataSourceSCIArcJobIDsV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 72 | config := meta.(*Config) 73 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 74 | if err != nil { 75 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 76 | } 77 | 78 | jobs, err := arcSCIArcJobV1Filter(ctx, d, arcClient, "sci_arc_job_ids_v1") 79 | if err != nil { 80 | return diag.FromErr(err) 81 | } 82 | 83 | jobIDs := make([]string, 0, len(jobs)) 84 | for _, j := range jobs { 85 | jobIDs = append(jobIDs, j.RequestID) 86 | } 87 | 88 | log.Printf("[DEBUG] Retrieved %d jobs in sci_arc_job_ids_v1: %+v", len(jobs), jobs) 89 | 90 | d.SetId(fmt.Sprintf("%d", hashcode.String(strings.Join(jobIDs, "")))) 91 | _ = d.Set("ids", jobIDs) 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /sci/data_source_sci_automation_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "log" 7 | "time" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 12 | "github.com/sapcc/gophercloud-sapcc/v2/automation/v1/automations" 13 | ) 14 | 15 | func dataSourceSCIAutomationV1() *schema.Resource { 16 | return &schema.Resource{ 17 | ReadContext: dataSourceSCIAutomationV1Read, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "region": { 21 | Type: schema.TypeString, 22 | Optional: true, 23 | Computed: true, 24 | ForceNew: true, 25 | }, 26 | 27 | "name": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | Computed: true, 31 | }, 32 | 33 | "repository": { 34 | Type: schema.TypeString, 35 | Optional: true, 36 | Computed: true, 37 | }, 38 | 39 | "repository_revision": { 40 | Type: schema.TypeString, 41 | Optional: true, 42 | Computed: true, 43 | }, 44 | 45 | "timeout": { 46 | Type: schema.TypeInt, 47 | Optional: true, 48 | Computed: true, 49 | }, 50 | 51 | "type": { 52 | Type: schema.TypeString, 53 | Optional: true, 54 | Computed: true, 55 | ValidateFunc: validation.StringInSlice([]string{ 56 | "Script", "Chef", 57 | }, false), 58 | }, 59 | 60 | "tags": { 61 | Type: schema.TypeMap, 62 | Computed: true, 63 | Deprecated: "This field is not supported by the Lyra API", 64 | }, 65 | 66 | // Chef 67 | "run_list": { 68 | Type: schema.TypeList, 69 | Computed: true, 70 | Elem: &schema.Schema{Type: schema.TypeString}, 71 | }, 72 | 73 | "chef_attributes": { 74 | Type: schema.TypeString, 75 | Computed: true, 76 | }, 77 | 78 | "log_level": { 79 | Type: schema.TypeString, 80 | Computed: true, 81 | }, 82 | 83 | "debug": { 84 | Type: schema.TypeBool, 85 | Optional: true, 86 | Computed: true, 87 | }, 88 | 89 | "chef_version": { 90 | Type: schema.TypeString, 91 | Optional: true, 92 | Computed: true, 93 | }, 94 | 95 | // Script 96 | "path": { 97 | Type: schema.TypeString, 98 | Optional: true, 99 | Computed: true, 100 | }, 101 | 102 | "arguments": { 103 | Type: schema.TypeList, 104 | Computed: true, 105 | Elem: &schema.Schema{Type: schema.TypeString}, 106 | }, 107 | 108 | "environment": { 109 | Type: schema.TypeMap, 110 | Computed: true, 111 | }, 112 | 113 | "created_at": { 114 | Type: schema.TypeString, 115 | Computed: true, 116 | }, 117 | 118 | "updated_at": { 119 | Type: schema.TypeString, 120 | Computed: true, 121 | }, 122 | 123 | "project_id": { 124 | Type: schema.TypeString, 125 | Computed: true, 126 | }, 127 | 128 | "repository_authentication_enabled": { 129 | Type: schema.TypeBool, 130 | Computed: true, 131 | }, 132 | }, 133 | } 134 | } 135 | 136 | func dataSourceSCIAutomationV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 137 | config := meta.(*Config) 138 | automationClient, err := config.automationV1Client(ctx, GetRegion(d, config)) 139 | if err != nil { 140 | return diag.Errorf("Error creating OpenStack Automation client: %s", err) 141 | } 142 | 143 | allPages, err := automations.List(automationClient, automations.ListOpts{}).AllPages(ctx) 144 | if err != nil { 145 | return diag.Errorf("Unable to list sci_automation_v1: %s", err) 146 | } 147 | 148 | allAutomations, err := automations.ExtractAutomations(allPages) 149 | if err != nil { 150 | return diag.Errorf("Unable to retrieve sci_automation_v1: %s", err) 151 | } 152 | 153 | if len(allAutomations) == 0 { 154 | return diag.Errorf("No sci_automation_v1 found") 155 | } 156 | 157 | var automations []automations.Automation 158 | var v interface{} 159 | var debugExists, debug bool 160 | 161 | if v, debugExists = getOkExists(d, "debug"); debugExists { 162 | debug = v.(bool) 163 | } 164 | name := d.Get("name").(string) 165 | repository := d.Get("repository").(string) 166 | repositoryRevision := d.Get("repository_revision").(string) 167 | timeout := d.Get("timeout").(int) 168 | automationType := d.Get("type").(string) 169 | chefVersion := d.Get("chef_version").(string) 170 | path := d.Get("path").(string) 171 | 172 | for _, automation := range allAutomations { 173 | found := true 174 | if found && len(name) > 0 && automation.Name != name { 175 | found = false 176 | } 177 | if found && len(repository) > 0 && automation.Repository != repository { 178 | found = false 179 | } 180 | if found && len(repositoryRevision) > 0 && automation.RepositoryRevision != repositoryRevision { 181 | found = false 182 | } 183 | if found && timeout > 0 && automation.Timeout != timeout { 184 | found = false 185 | } 186 | if found && len(automationType) > 0 && automation.Type != automationType { 187 | found = false 188 | } 189 | if found && debugExists && automation.Debug != debug { 190 | found = false 191 | } 192 | if found && len(chefVersion) > 0 && automation.ChefVersion != chefVersion { 193 | found = false 194 | } 195 | if found && len(path) > 0 && automation.Path != path { 196 | found = false 197 | } 198 | 199 | if found { 200 | automations = append(automations, automation) 201 | } 202 | } 203 | 204 | if len(automations) == 0 { 205 | return diag.Errorf("No sci_automation_v1 found") 206 | } 207 | 208 | if len(automations) > 1 { 209 | return diag.Errorf("More than one sci_automation_v1 found (%d)", len(automations)) 210 | } 211 | 212 | automation := automations[0] 213 | 214 | log.Printf("[DEBUG] Retrieved %s sci_automation_v1: %+v", automation.ID, automation) 215 | d.SetId(automation.ID) 216 | _ = d.Set("name", automation.Name) 217 | _ = d.Set("repository", automation.Repository) 218 | _ = d.Set("repository_revision", automation.RepositoryRevision) 219 | _ = d.Set("repository_authentication_enabled", automation.RepositoryAuthenticationEnabled) 220 | _ = d.Set("project_id", automation.ProjectID) 221 | _ = d.Set("timeout", automation.Timeout) 222 | _ = d.Set("tags", automation.Tags) 223 | _ = d.Set("created_at", automation.CreatedAt.Format(time.RFC3339)) 224 | _ = d.Set("updated_at", automation.UpdatedAt.Format(time.RFC3339)) 225 | _ = d.Set("type", automation.Type) 226 | _ = d.Set("run_list", automation.RunList) 227 | 228 | chefAttributes, err := json.Marshal(automation.ChefAttributes) 229 | if err != nil { 230 | log.Printf("[DEBUG] dataSourceSCIAutomationV1Read: Cannot marshal automation.ChefAttributes: %s", err) 231 | } 232 | _ = d.Set("chef_attributes", string(chefAttributes)) 233 | 234 | _ = d.Set("log_level", automation.LogLevel) 235 | _ = d.Set("debug", automation.Debug) 236 | _ = d.Set("chef_version", automation.ChefVersion) 237 | _ = d.Set("path", automation.Path) 238 | _ = d.Set("arguments", automation.Arguments) 239 | _ = d.Set("environment", automation.Environment) 240 | 241 | _ = d.Set("region", GetRegion(d, config)) 242 | 243 | return nil 244 | } 245 | -------------------------------------------------------------------------------- /sci/data_source_sci_billing_domain_masterdata.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/sapcc/gophercloud-sapcc/v2/billing/masterdata/domains" 11 | ) 12 | 13 | func dataSourceSCIBillingDomainMasterdata() *schema.Resource { 14 | return &schema.Resource{ 15 | ReadContext: dataSourceSCIBillingDomainMasterdataRead, 16 | 17 | Schema: map[string]*schema.Schema{ 18 | "region": { 19 | Type: schema.TypeString, 20 | Optional: true, 21 | Computed: true, 22 | }, 23 | 24 | "domain_id": { 25 | Type: schema.TypeString, 26 | Optional: true, 27 | }, 28 | 29 | "domain_name": { 30 | Type: schema.TypeString, 31 | Computed: true, 32 | }, 33 | 34 | "description": { 35 | Type: schema.TypeString, 36 | Computed: true, 37 | }, 38 | 39 | "additional_information": { 40 | Type: schema.TypeString, 41 | Computed: true, 42 | }, 43 | 44 | "responsible_primary_contact_id": { 45 | Type: schema.TypeString, 46 | Computed: true, 47 | }, 48 | 49 | "responsible_primary_contact_email": { 50 | Type: schema.TypeString, 51 | Computed: true, 52 | }, 53 | 54 | "cost_object": { 55 | Type: schema.TypeList, 56 | Computed: true, 57 | Elem: &schema.Resource{ 58 | Schema: map[string]*schema.Schema{ 59 | "projects_can_inherit": { 60 | Type: schema.TypeBool, 61 | Computed: true, 62 | }, 63 | "name": { 64 | Type: schema.TypeString, 65 | Computed: true, 66 | }, 67 | "type": { 68 | Type: schema.TypeString, 69 | Computed: true, 70 | }, 71 | }, 72 | }, 73 | }, 74 | 75 | "created_at": { 76 | Type: schema.TypeString, 77 | Computed: true, 78 | }, 79 | 80 | "changed_at": { 81 | Type: schema.TypeString, 82 | Computed: true, 83 | }, 84 | 85 | "changed_by": { 86 | Type: schema.TypeString, 87 | Computed: true, 88 | }, 89 | 90 | "is_complete": { 91 | Type: schema.TypeBool, 92 | Computed: true, 93 | }, 94 | 95 | "missing_attributes": { 96 | Type: schema.TypeString, 97 | Computed: true, 98 | }, 99 | 100 | "collector": { 101 | Type: schema.TypeString, 102 | Computed: true, 103 | }, 104 | }, 105 | } 106 | } 107 | 108 | func dataSourceSCIBillingDomainMasterdataRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 109 | config := meta.(*Config) 110 | billing, err := config.billingClient(ctx, GetRegion(d, config)) 111 | if err != nil { 112 | return diag.Errorf("Error creating OpenStack billing client: %s", err) 113 | } 114 | 115 | domainID := d.Get("domain_id").(string) 116 | if domainID == "" { 117 | // first call, expecting to get current scope domain 118 | identityClient, err := config.IdentityV3Client(ctx, GetRegion(d, config)) 119 | if err != nil { 120 | return diag.Errorf("Error creating OpenStack identity client: %s", err) 121 | } 122 | 123 | tokenDetails, err := getTokenDetails(ctx, identityClient) 124 | if err != nil { 125 | return diag.FromErr(err) 126 | } 127 | 128 | if tokenDetails.domain == nil { 129 | return diag.Errorf("Error getting billing domain scope: %s", err) 130 | } 131 | 132 | domainID = tokenDetails.domain.ID 133 | } 134 | 135 | domain, err := domains.Get(ctx, billing, domainID).Extract() 136 | if err != nil { 137 | return diag.Errorf("Error getting billing domain masterdata: %s", err) 138 | } 139 | 140 | log.Printf("[DEBUG] Retrieved domain masterdata: %+v", domain) 141 | 142 | d.SetId(domain.DomainID) 143 | 144 | _ = d.Set("domain_id", domain.DomainID) 145 | _ = d.Set("domain_name", domain.DomainName) 146 | _ = d.Set("description", domain.Description) 147 | _ = d.Set("responsible_primary_contact_id", domain.ResponsiblePrimaryContactID) 148 | _ = d.Set("responsible_primary_contact_email", domain.ResponsiblePrimaryContactEmail) 149 | _ = d.Set("additional_information", domain.AdditionalInformation) 150 | _ = d.Set("cost_object", billingDomainFlattenCostObject(domain.CostObject)) 151 | _ = d.Set("created_at", domain.CreatedAt.Format(time.RFC3339)) 152 | _ = d.Set("changed_at", domain.ChangedAt.Format(time.RFC3339)) 153 | _ = d.Set("changed_by", domain.ChangedBy) 154 | _ = d.Set("is_complete", domain.IsComplete) 155 | _ = d.Set("missing_attributes", domain.MissingAttributes) 156 | _ = d.Set("collector", domain.Collector) 157 | 158 | _ = d.Set("region", GetRegion(d, config)) 159 | 160 | return nil 161 | } 162 | -------------------------------------------------------------------------------- /sci/data_source_sci_gslb_services_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "crypto/sha256" 6 | "fmt" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/sapcc/andromeda/client/administrative" 11 | "github.com/sapcc/andromeda/models" 12 | ) 13 | 14 | func dataSourceSCIGSLBServicesV1() *schema.Resource { 15 | return &schema.Resource{ 16 | ReadContext: dataSourceSCIGSLBServicesV1Read, 17 | 18 | Schema: map[string]*schema.Schema{ 19 | "region": { 20 | Type: schema.TypeString, 21 | Optional: true, 22 | Computed: true, 23 | ForceNew: true, 24 | }, 25 | "services": { 26 | Type: schema.TypeList, 27 | Computed: true, 28 | Elem: &schema.Resource{ 29 | Schema: map[string]*schema.Schema{ 30 | "heartbeat": { 31 | Type: schema.TypeString, 32 | Computed: true, 33 | }, 34 | "host": { 35 | Type: schema.TypeString, 36 | Computed: true, 37 | }, 38 | "id": { 39 | Type: schema.TypeString, 40 | Computed: true, 41 | }, 42 | "metadata": { 43 | Type: schema.TypeMap, 44 | Computed: true, 45 | Elem: &schema.Schema{Type: schema.TypeString}, 46 | }, 47 | "provider": { 48 | Type: schema.TypeString, 49 | Computed: true, 50 | }, 51 | "rpc_address": { 52 | Type: schema.TypeString, 53 | Computed: true, 54 | }, 55 | "type": { 56 | Type: schema.TypeString, 57 | Computed: true, 58 | }, 59 | "version": { 60 | Type: schema.TypeString, 61 | Computed: true, 62 | }, 63 | }, 64 | }, 65 | }, 66 | }, 67 | } 68 | } 69 | 70 | func dataSourceSCIGSLBServicesV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 71 | config := meta.(*Config) 72 | c, err := config.andromedaV1Client(ctx, GetRegion(d, config)) 73 | if err != nil { 74 | return diag.Errorf("error creating Andromeda client: %s", err) 75 | } 76 | client := c.Administrative 77 | 78 | opts := &administrative.GetServicesParams{ 79 | Context: ctx, 80 | } 81 | res, err := client.GetServices(opts) 82 | if err != nil { 83 | return diag.Errorf("error fetching Andromeda services: %s", err) 84 | } 85 | if res == nil || res.Payload == nil || res.Payload.Services == nil { 86 | return diag.Errorf("error fetching Andromeda services: empty response") 87 | } 88 | 89 | id := andromedaServicesHash(res.Payload.Services) 90 | d.SetId(id) 91 | _ = d.Set("services", andromedaFlattenServices(res.Payload.Services)) 92 | _ = d.Set("region", GetRegion(d, config)) 93 | 94 | return diag.FromErr(err) 95 | } 96 | 97 | func andromedaFlattenServices(services []*models.Service) []map[string]interface{} { 98 | res := make([]map[string]interface{}, len(services)) 99 | for i, service := range services { 100 | res[i] = map[string]interface{}{ 101 | "heartbeat": service.Heartbeat.String(), 102 | "host": service.Host, 103 | "id": service.ID, 104 | "metadata": service.Metadata, 105 | "provider": service.Provider, 106 | "rpc_address": service.RPCAddress, 107 | "type": service.Type, 108 | "version": service.Version, 109 | } 110 | } 111 | return res 112 | } 113 | 114 | func andromedaServicesHash(services []*models.Service) string { 115 | h := sha256.New() 116 | for _, service := range services { 117 | b, _ := service.MarshalBinary() 118 | h.Write(b) 119 | } 120 | return fmt.Sprintf("%x", h.Sum(nil)) 121 | } 122 | -------------------------------------------------------------------------------- /sci/data_source_sci_networking_router_v2.go: -------------------------------------------------------------------------------- 1 | // This augments the following upstream sources to include the SAP Cloud Infrastructure specific external_port_id 2 | // https://github.com/terraform-provider-openstack/terraform-provider-openstack/blob/74d82f6ce503df74a5e63ac2491e837dc296a82b/openstack/data_source_openstack_networking_router_v2.go 3 | // https://github.com/gophercloud/gophercloud/blob/39fc33cbe7c0176655a409e5fd6cbccae23bfb18/openstack/networking/v2/extensions/layer3/routers/results.go 4 | 5 | package sci 6 | 7 | import ( 8 | "context" 9 | "log" 10 | "strings" 11 | 12 | "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 14 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 15 | ) 16 | 17 | type GatewayInfo struct { 18 | NetworkID string `json:"network_id,omitempty"` 19 | EnableSNAT *bool `json:"enable_snat,omitempty"` 20 | ExternalFixedIPs []routers.ExternalFixedIP `json:"external_fixed_ips,omitempty"` 21 | QoSPolicyID string `json:"qos_policy_id,omitempty"` 22 | ExternalPortID string `json:"external_port_id,omitempty"` 23 | } 24 | 25 | type ccRouter struct { 26 | CCGatewayInfo GatewayInfo `json:"external_gateway_info"` 27 | routers.Router 28 | } 29 | 30 | func dataSourceSCINetworkingRouterV2() *schema.Resource { 31 | return &schema.Resource{ 32 | ReadContext: dataSourceSCINetworkingRouterV2Read, 33 | 34 | Schema: map[string]*schema.Schema{ 35 | "region": { 36 | Type: schema.TypeString, 37 | Optional: true, 38 | }, 39 | "router_id": { 40 | Type: schema.TypeString, 41 | Optional: true, 42 | }, 43 | "name": { 44 | Type: schema.TypeString, 45 | Optional: true, 46 | }, 47 | "description": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | }, 51 | "admin_state_up": { 52 | Type: schema.TypeBool, 53 | Optional: true, 54 | }, 55 | "distributed": { 56 | Type: schema.TypeBool, 57 | Optional: true, 58 | }, 59 | "status": { 60 | Type: schema.TypeString, 61 | Optional: true, 62 | }, 63 | "tenant_id": { 64 | Type: schema.TypeString, 65 | Optional: true, 66 | }, 67 | "external_network_id": { 68 | Type: schema.TypeString, 69 | Computed: true, 70 | }, 71 | "external_port_id": { 72 | Type: schema.TypeString, 73 | Computed: true, 74 | }, 75 | "enable_snat": { 76 | Type: schema.TypeBool, 77 | Computed: true, 78 | Optional: true, 79 | }, 80 | "availability_zone_hints": { 81 | Type: schema.TypeList, 82 | Computed: true, 83 | Elem: &schema.Schema{Type: schema.TypeString}, 84 | }, 85 | "external_fixed_ip": { 86 | Type: schema.TypeList, 87 | Computed: true, 88 | Elem: &schema.Resource{ 89 | Schema: map[string]*schema.Schema{ 90 | "subnet_id": { 91 | Type: schema.TypeString, 92 | Optional: true, 93 | }, 94 | "ip_address": { 95 | Type: schema.TypeString, 96 | Optional: true, 97 | }, 98 | }, 99 | }, 100 | }, 101 | "tags": { 102 | Type: schema.TypeSet, 103 | Optional: true, 104 | Elem: &schema.Schema{Type: schema.TypeString}, 105 | }, 106 | "all_tags": { 107 | Type: schema.TypeSet, 108 | Computed: true, 109 | Elem: &schema.Schema{Type: schema.TypeString}, 110 | }, 111 | }, 112 | } 113 | } 114 | 115 | func dataSourceSCINetworkingRouterV2Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 116 | config := meta.(*Config) 117 | networkingClient, err := config.NetworkingV2Client(ctx, GetRegion(d, config)) 118 | if err != nil { 119 | return diag.Errorf("Error creating OpenStack networking client: %s", err) 120 | } 121 | 122 | listOpts := routers.ListOpts{} 123 | 124 | if v, ok := d.GetOk("router_id"); ok { 125 | listOpts.ID = v.(string) 126 | } 127 | 128 | if v, ok := d.GetOk("name"); ok { 129 | listOpts.Name = v.(string) 130 | } 131 | 132 | if v, ok := d.GetOk("description"); ok { 133 | listOpts.Description = v.(string) 134 | } 135 | 136 | if v, ok := getOkExists(d, "admin_state_up"); ok { 137 | asu := v.(bool) 138 | listOpts.AdminStateUp = &asu 139 | } 140 | 141 | if v, ok := getOkExists(d, "distributed"); ok { 142 | dist := v.(bool) 143 | listOpts.Distributed = &dist 144 | } 145 | 146 | if v, ok := d.GetOk("status"); ok { 147 | listOpts.Status = v.(string) 148 | } 149 | 150 | if v, ok := d.GetOk("tenant_id"); ok { 151 | listOpts.TenantID = v.(string) 152 | } 153 | 154 | tags := expandObjectTags(d) 155 | if len(tags) > 0 { 156 | listOpts.Tags = strings.Join(tags, ",") 157 | } 158 | 159 | pages, err := routers.List(networkingClient, listOpts).AllPages(ctx) 160 | if err != nil { 161 | return diag.Errorf("Unable to list Routers: %s", err) 162 | } 163 | 164 | var allRouters []ccRouter 165 | err = routers.ExtractRoutersInto(pages, &allRouters) 166 | if err != nil { 167 | return diag.Errorf("Unable to retrieve Routers: %s", err) 168 | } 169 | 170 | if len(allRouters) < 1 { 171 | return diag.Errorf("No Router found") 172 | } 173 | 174 | if len(allRouters) > 1 { 175 | return diag.Errorf("More than one Router found") 176 | } 177 | 178 | router := allRouters[0] 179 | 180 | log.Printf("[DEBUG] Retrieved Router %s: %+v", router.ID, router) 181 | d.SetId(router.ID) 182 | 183 | _ = d.Set("name", router.Name) 184 | _ = d.Set("description", router.Description) 185 | _ = d.Set("admin_state_up", router.AdminStateUp) 186 | _ = d.Set("distributed", router.Distributed) 187 | _ = d.Set("status", router.Status) 188 | _ = d.Set("tenant_id", router.TenantID) 189 | _ = d.Set("external_network_id", router.CCGatewayInfo.NetworkID) 190 | _ = d.Set("external_port_id", router.CCGatewayInfo.ExternalPortID) 191 | _ = d.Set("enable_snat", router.CCGatewayInfo.EnableSNAT) 192 | _ = d.Set("all_tags", router.Tags) 193 | _ = d.Set("region", GetRegion(d, config)) 194 | 195 | if err := d.Set("availability_zone_hints", router.AvailabilityZoneHints); err != nil { 196 | log.Printf("[DEBUG] Unable to set availability_zone_hints: %s", err) 197 | } 198 | 199 | externalFixedIPs := make([]map[string]string, 0, len(router.GatewayInfo.ExternalFixedIPs)) 200 | for _, v := range router.GatewayInfo.ExternalFixedIPs { 201 | externalFixedIPs = append(externalFixedIPs, map[string]string{ 202 | "subnet_id": v.SubnetID, 203 | "ip_address": v.IPAddress, 204 | }) 205 | } 206 | if err = d.Set("external_fixed_ip", externalFixedIPs); err != nil { 207 | log.Printf("[DEBUG] Unable to set external_fixed_ip: %s", err) 208 | } 209 | return nil 210 | } 211 | -------------------------------------------------------------------------------- /sci/kubernikus.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "reflect" 8 | 9 | "github.com/go-openapi/runtime" 10 | httptransport "github.com/go-openapi/runtime/client" 11 | "github.com/go-openapi/strfmt" 12 | "github.com/gophercloud/gophercloud/v2" 13 | osClient "github.com/gophercloud/utils/v2/client" 14 | "github.com/sapcc/kubernikus/pkg/api/client/operations" 15 | ) 16 | 17 | type kubernikus struct { 18 | operations.ClientService 19 | provider *gophercloud.ProviderClient 20 | } 21 | 22 | func newKubernikusV1(c *Config, eo gophercloud.EndpointOpts) (*kubernikus, error) { 23 | var err error 24 | var endpoint string 25 | var kurl *url.URL 26 | 27 | if v, ok := c.EndpointOverrides["kubernikus"]; ok { 28 | if e, ok := v.(string); ok && e != "" { 29 | endpoint = e 30 | } 31 | } 32 | 33 | if endpoint == "" && !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) { 34 | eo.ApplyDefaults("kubernikus") 35 | endpoint, err = c.OsClient.EndpointLocator(eo) 36 | if err != nil { 37 | return nil, err 38 | } 39 | } 40 | 41 | if kurl, err = url.Parse(endpoint); err != nil { 42 | return nil, fmt.Errorf("parsing the Kubernikus URL failed: %s", err) 43 | } 44 | 45 | transport := httptransport.New(kurl.Host, kurl.EscapedPath(), []string{kurl.Scheme}) 46 | 47 | if v, ok := c.OsClient.HTTPClient.Transport.(*osClient.RoundTripper); ok && v.Logger != nil { 48 | // enable JSON debug for Kubernikus 49 | transport.SetLogger(logger{"Kubernikus"}) 50 | transport.Debug = true 51 | } 52 | 53 | operations := operations.New(transport, strfmt.Default) 54 | 55 | return &kubernikus{operations, c.OsClient}, nil 56 | } 57 | 58 | func (k *kubernikus) authFunc() runtime.ClientAuthInfoWriterFunc { 59 | return runtime.ClientAuthInfoWriterFunc( 60 | func(req runtime.ClientRequest, reg strfmt.Registry) error { 61 | err := req.SetHeaderParam("X-Auth-Token", k.provider.Token()) 62 | if err != nil { 63 | log.Printf("[DEBUG] Kubernikus auth func cannot set X-Auth-Token header value: %v", err) 64 | } 65 | err = req.SetHeaderParam("User-Agent", k.provider.UserAgent.Join()) 66 | if err != nil { 67 | log.Printf("[DEBUG] Kubernikus auth func cannot set User-Agent header value: %v", err) 68 | } 69 | return nil 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /sci/logger.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | httpMethods = []string{ 13 | "GET", 14 | "POST", 15 | "PATCH", 16 | "DELETE", 17 | "PUT", 18 | "HEAD", 19 | "OPTIONS", 20 | "CONNECT", 21 | "TRACE", 22 | } 23 | maskHeader = strings.ToLower("X-Auth-Token:") 24 | ) 25 | 26 | type logger struct { 27 | svc string 28 | } 29 | 30 | func (l logger) Printf(format string, args ...interface{}) { 31 | if len(format) == 0 || format[len(format)-1] != '\n' { 32 | format += "\n" 33 | } 34 | fmt.Fprintf(os.Stderr, format, args...) 35 | } 36 | 37 | func (l logger) Debugf(format string, args ...interface{}) { 38 | for _, arg := range args { 39 | v, ok := arg.(string) 40 | if !ok { 41 | continue 42 | } 43 | str := deleteEmpty(strings.Split(v, "\n")) 44 | cycle := "Response" 45 | if len(str) > 0 { 46 | for _, method := range httpMethods { 47 | if strings.HasPrefix(str[0], method) { 48 | cycle = "Request" 49 | break 50 | } 51 | } 52 | } 53 | printed := false 54 | 55 | for i, s := range str { 56 | if i == 0 && cycle == "Request" { 57 | v := strings.SplitN(s, " ", 3) 58 | if len(v) > 1 { 59 | log.Printf("[DEBUG] %s %s URL: %s %s", l.svc, cycle, v[0], v[1]) 60 | } 61 | } else if i == 0 && cycle == "Response" { 62 | v := strings.SplitN(s, " ", 2) 63 | if len(v) > 1 { 64 | log.Printf("[DEBUG] %s %s Code: %s", l.svc, cycle, v[1]) 65 | } 66 | } else if i == len(str)-1 { 67 | debugInfo, err := formatJSON([]byte(s)) 68 | if err != nil { 69 | printHeaders(l.svc, cycle, &printed) 70 | log.Print(s) 71 | } else { 72 | log.Printf("[DEBUG] %s %s Body: %s", l.svc, cycle, debugInfo) 73 | } 74 | } else if strings.HasPrefix(strings.ToLower(s), maskHeader) { 75 | printHeaders(l.svc, cycle, &printed) 76 | v := strings.SplitN(s, ":", 2) 77 | log.Printf("%s: ***", v[0]) 78 | } else { 79 | printHeaders(l.svc, cycle, &printed) 80 | log.Print(s) 81 | } 82 | } 83 | } 84 | } 85 | 86 | func deleteEmpty(s []string) []string { 87 | var r []string 88 | for _, str := range s { 89 | if strings.TrimSpace(str) != "" { 90 | r = append(r, str) 91 | } 92 | } 93 | return r 94 | } 95 | 96 | func printHeaders(name, cycle string, printed *bool) { 97 | if !*printed { 98 | log.Printf("[DEBUG] %s %s Headers:", name, cycle) 99 | *printed = true 100 | } 101 | } 102 | 103 | // formatJSON is a function to pretty-format a JSON body. 104 | // It will also mask known fields which contain sensitive information. 105 | func formatJSON(raw []byte) (string, error) { 106 | var rawData interface{} 107 | 108 | err := json.Unmarshal(raw, &rawData) 109 | if err != nil { 110 | return string(raw), fmt.Errorf("unable to parse OpenStack JSON: %s", err) 111 | } 112 | 113 | data, ok := rawData.(map[string]interface{}) 114 | if !ok { 115 | pretty, err := json.MarshalIndent(rawData, "", " ") 116 | if err != nil { 117 | return string(raw), fmt.Errorf("unable to re-marshal OpenStack JSON: %s", err) 118 | } 119 | 120 | return string(pretty), nil 121 | } 122 | 123 | // Strip kubeconfig 124 | if _, ok := data["kubeconfig"].(string); ok { 125 | data["kubeconfig"] = "***" 126 | } 127 | 128 | pretty, err := json.MarshalIndent(data, "", " ") 129 | if err != nil { 130 | return string(raw), fmt.Errorf("unable to re-marshal OpenStack JSON: %s", err) 131 | } 132 | 133 | return string(pretty), nil 134 | } 135 | -------------------------------------------------------------------------------- /sci/migrate_resource_sci_gslb_quota_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | ) 8 | 9 | func resourceSCIGSLBQuotaV1V0() *schema.Resource { 10 | return &schema.Resource{ 11 | Schema: map[string]*schema.Schema{ 12 | "region": { 13 | Type: schema.TypeString, 14 | Optional: true, 15 | Computed: true, 16 | ForceNew: true, 17 | }, 18 | "datacenter": { 19 | Type: schema.TypeInt, 20 | Optional: true, 21 | Computed: true, 22 | }, 23 | "domain": { 24 | Type: schema.TypeInt, 25 | Optional: true, 26 | Computed: true, 27 | }, 28 | "member": { 29 | Type: schema.TypeInt, 30 | Optional: true, 31 | Computed: true, 32 | }, 33 | "monitor": { 34 | Type: schema.TypeInt, 35 | Optional: true, 36 | Computed: true, 37 | }, 38 | "pool": { 39 | Type: schema.TypeInt, 40 | Optional: true, 41 | Computed: true, 42 | }, 43 | "project_id": { 44 | Type: schema.TypeString, 45 | Required: true, 46 | }, 47 | 48 | // computed 49 | "in_use_datacenter": { 50 | Type: schema.TypeInt, 51 | Optional: true, 52 | Computed: true, 53 | }, 54 | "in_use_domain": { 55 | Type: schema.TypeInt, 56 | Optional: true, 57 | Computed: true, 58 | }, 59 | "in_use_member": { 60 | Type: schema.TypeInt, 61 | Optional: true, 62 | Computed: true, 63 | }, 64 | "in_use_monitor": { 65 | Type: schema.TypeInt, 66 | Optional: true, 67 | Computed: true, 68 | }, 69 | "in_use_pool": { 70 | Type: schema.TypeInt, 71 | Optional: true, 72 | Computed: true, 73 | }, 74 | }, 75 | } 76 | } 77 | 78 | func resourceSCIGSLBQuotaV1StateUpgradeV0(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { 79 | rawState["domain_akamai"] = rawState["domain"] 80 | rawState["in_use_domain_akamai"] = rawState["in_use_domain"] 81 | 82 | return rawState, nil 83 | } 84 | -------------------------------------------------------------------------------- /sci/resource_sci_arc_agent_bootstrap_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | 9 | "github.com/gophercloud/utils/v2/terraform/hashcode" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 13 | "github.com/sapcc/gophercloud-sapcc/v2/arc/v1/agents" 14 | ) 15 | 16 | func resourceSCIArcAgentBootstrapV1() *schema.Resource { 17 | return &schema.Resource{ 18 | CreateContext: resourceSCIArcAgentBootstrapV1Create, 19 | ReadContext: func(context.Context, *schema.ResourceData, interface{}) diag.Diagnostics { return nil }, 20 | DeleteContext: func(context.Context, *schema.ResourceData, interface{}) diag.Diagnostics { return nil }, 21 | 22 | Schema: map[string]*schema.Schema{ 23 | "region": { 24 | Type: schema.TypeString, 25 | Optional: true, 26 | Computed: true, 27 | ForceNew: true, 28 | }, 29 | 30 | "type": { 31 | Type: schema.TypeString, 32 | Optional: true, 33 | ForceNew: true, 34 | Default: "cloud-config", 35 | ValidateFunc: validation.StringInSlice([]string{ 36 | "linux", "windows", "cloud-config", "json", 37 | }, false), 38 | }, 39 | 40 | "triggers": { 41 | Type: schema.TypeMap, 42 | Optional: true, 43 | ForceNew: true, 44 | }, 45 | 46 | // computed attributes 47 | "user_data": { 48 | Type: schema.TypeString, 49 | Computed: true, 50 | }, 51 | 52 | "raw_map": { 53 | Type: schema.TypeMap, 54 | Computed: true, 55 | }, 56 | }, 57 | } 58 | } 59 | 60 | func resourceSCIArcAgentBootstrapV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 61 | config := meta.(*Config) 62 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 63 | if err != nil { 64 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 65 | } 66 | 67 | var bootstrapType string 68 | switch d.Get("type") { 69 | case "linux": 70 | bootstrapType = "text/x-shellscript" 71 | case "windows": 72 | bootstrapType = "text/x-powershellscript" 73 | case "cloud-config": 74 | bootstrapType = "text/cloud-config" 75 | case "json": 76 | bootstrapType = "application/json" 77 | } 78 | 79 | createOpts := agents.InitOpts{Accept: bootstrapType} 80 | 81 | log.Printf("[DEBUG] sci_arc_agent_bootstrap_v1 create options: %#v", createOpts) 82 | 83 | res := agents.Init(ctx, arcClient, createOpts) 84 | if res.Err != nil { 85 | return diag.Errorf("Error creating sci_arc_agent_bootstrap_v1: %s", res.Err) 86 | } 87 | 88 | headers, err := res.ExtractHeaders() 89 | if err != nil { 90 | return diag.Errorf("Error extracting headers while creating sci_arc_agent_bootstrap_v1: %s", err) 91 | } 92 | 93 | if bootstrapType != headers.ContentType { 94 | return diag.Errorf("Error verifying headers while creating sci_arc_agent_bootstrap_v1: wants '%s', got '%s'", bootstrapType, headers.ContentType) 95 | } 96 | 97 | data, err := res.ExtractContent() 98 | if err != nil { 99 | return diag.Errorf("Error extracting content while creating sci_arc_agent_bootstrap_v1: %s", err) 100 | } 101 | 102 | userData := string(data) 103 | 104 | d.SetId(fmt.Sprintf("%d", hashcode.String(userData))) 105 | 106 | if bootstrapType == "application/json" { 107 | var initMap map[string]string 108 | err = json.Unmarshal(data, &initMap) 109 | if err != nil { 110 | return diag.Errorf("Error unmarshalling JSON content while creating sci_arc_agent_bootstrap_v1: %s", err) 111 | } 112 | _ = d.Set("raw_map", initMap) 113 | } else { 114 | _ = d.Set("raw_map", map[string]string{}) 115 | } 116 | 117 | _ = d.Set("user_data", userData) 118 | _ = d.Set("region", GetRegion(d, config)) 119 | 120 | return nil 121 | } 122 | -------------------------------------------------------------------------------- /sci/resource_sci_arc_agent_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 12 | "github.com/sapcc/gophercloud-sapcc/v2/arc/v1/agents" 13 | ) 14 | 15 | func resourceSCIArcAgentV1() *schema.Resource { 16 | return &schema.Resource{ 17 | ReadContext: resourceSCIArcAgentV1Read, 18 | CreateContext: resourceSCIArcAgentV1Create, 19 | UpdateContext: resourceSCIArcAgentV1Update, 20 | DeleteContext: resourceSCIArcAgentV1Delete, 21 | Importer: &schema.ResourceImporter{ 22 | StateContext: schema.ImportStatePassthroughContext, 23 | }, 24 | 25 | Timeouts: &schema.ResourceTimeout{ 26 | Create: schema.DefaultTimeout(30 * time.Minute), 27 | Delete: schema.DefaultTimeout(30 * time.Minute), 28 | }, 29 | 30 | Schema: map[string]*schema.Schema{ 31 | "region": { 32 | Type: schema.TypeString, 33 | Optional: true, 34 | Computed: true, 35 | ForceNew: true, 36 | }, 37 | 38 | "agent_id": { 39 | Type: schema.TypeString, 40 | Optional: true, 41 | Computed: true, 42 | ForceNew: true, 43 | ConflictsWith: []string{"filter"}, 44 | ValidateFunc: validation.NoZeroValues, 45 | }, 46 | 47 | "filter": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | ForceNew: true, 51 | ConflictsWith: []string{"agent_id"}, 52 | ValidateFunc: validation.NoZeroValues, 53 | }, 54 | 55 | "tags": { 56 | Type: schema.TypeMap, 57 | Optional: true, 58 | }, 59 | 60 | "force_delete": { 61 | Type: schema.TypeBool, 62 | Optional: true, 63 | Default: true, 64 | }, 65 | 66 | // Computed attributes 67 | "display_name": { 68 | Type: schema.TypeString, 69 | Computed: true, 70 | }, 71 | 72 | "project": { 73 | Type: schema.TypeString, 74 | Computed: true, 75 | }, 76 | 77 | "organization": { 78 | Type: schema.TypeString, 79 | Computed: true, 80 | }, 81 | 82 | "created_at": { 83 | Type: schema.TypeString, 84 | Computed: true, 85 | }, 86 | 87 | "updated_at": { 88 | Type: schema.TypeString, 89 | Computed: true, 90 | }, 91 | 92 | "updated_with": { 93 | Type: schema.TypeString, 94 | Computed: true, 95 | }, 96 | 97 | "updated_by": { 98 | Type: schema.TypeString, 99 | Computed: true, 100 | }, 101 | 102 | "all_tags": { 103 | Type: schema.TypeMap, 104 | Computed: true, 105 | }, 106 | 107 | "facts": { 108 | Type: schema.TypeMap, 109 | Computed: true, 110 | }, 111 | 112 | "facts_agents": { 113 | Type: schema.TypeMap, 114 | Computed: true, 115 | }, 116 | }, 117 | } 118 | } 119 | 120 | func resourceSCIArcAgentV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 121 | config := meta.(*Config) 122 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 123 | if err != nil { 124 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 125 | } 126 | 127 | agentID := d.Get("agent_id").(string) 128 | filter := d.Get("filter").(string) 129 | timeout := d.Timeout(schema.TimeoutCreate) 130 | 131 | agent, err := arcSCIArcAgentV1WaitForAgent(ctx, arcClient, agentID, filter, timeout) 132 | if err != nil { 133 | return diag.FromErr(err) 134 | } 135 | 136 | d.SetId(agent.AgentID) 137 | 138 | err = updateArcAgentTagsV1(ctx, arcClient, d.Id(), nil, d.Get("tags")) 139 | if err != nil { 140 | return diag.FromErr(err) 141 | } 142 | 143 | return resourceSCIArcAgentV1Read(ctx, d, meta) 144 | } 145 | 146 | func resourceSCIArcAgentV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 147 | config := meta.(*Config) 148 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 149 | if err != nil { 150 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 151 | } 152 | 153 | agent, err := agents.Get(ctx, arcClient, d.Id()).Extract() 154 | if err != nil { 155 | return diag.FromErr(CheckDeleted(d, err, "Unable to retrieve sci_arc_agent_v1")) 156 | } 157 | 158 | arcSCIArcAgentV1ReadAgent(ctx, d, arcClient, agent, GetRegion(d, config)) 159 | 160 | return nil 161 | } 162 | 163 | func resourceSCIArcAgentV1Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 164 | config := meta.(*Config) 165 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 166 | if err != nil { 167 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 168 | } 169 | 170 | oldTags, newTags := d.GetChange("tags") 171 | err = updateArcAgentTagsV1(ctx, arcClient, d.Id(), oldTags, newTags) 172 | if err != nil { 173 | return diag.FromErr(err) 174 | } 175 | 176 | return resourceSCIArcAgentV1Read(ctx, d, meta) 177 | } 178 | 179 | func resourceSCIArcAgentV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 180 | config := meta.(*Config) 181 | arcClient, err := config.arcV1Client(ctx, GetRegion(d, config)) 182 | if err != nil { 183 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 184 | } 185 | 186 | if !d.Get("force_delete").(bool) { 187 | // Wait for the instance to delete before moving on. 188 | log.Printf("[DEBUG] Waiting for compute instance (%s) to delete", d.Id()) 189 | 190 | computeClient, err := config.ComputeV2Client(ctx, GetRegion(d, config)) 191 | if err != nil { 192 | return diag.Errorf("Error creating OpenStack compute client: %s", err) 193 | } 194 | 195 | stateConf := &retry.StateChangeConf{ 196 | Pending: []string{"ACTIVE", "SHUTOFF"}, 197 | Target: []string{"DELETED", "SOFT_DELETED"}, 198 | Refresh: serverV2StateRefreshFunc(ctx, computeClient, d.Id()), 199 | Timeout: d.Timeout(schema.TimeoutDelete), 200 | Delay: 10 * time.Second, 201 | MinTimeout: 3 * time.Second, 202 | } 203 | 204 | _, err = stateConf.WaitForStateContext(ctx) 205 | if err != nil { 206 | return diag.Errorf("Error waiting for compute instance (%s) to delete: %v", d.Id(), err) 207 | } 208 | } 209 | 210 | log.Printf("[DEBUG] Deleting sci_arc_agent_v1: %s", d.Id()) 211 | err = agents.Delete(ctx, arcClient, d.Id()).ExtractErr() 212 | if err != nil { 213 | return diag.FromErr(CheckDeleted(d, err, "Error deleting sci_arc_agent_v1")) 214 | } 215 | 216 | return nil 217 | } 218 | -------------------------------------------------------------------------------- /sci/resource_sci_automation_run_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | "time" 9 | 10 | "github.com/gophercloud/gophercloud/v2" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 14 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 15 | "github.com/sapcc/gophercloud-sapcc/v2/automation/v1/runs" 16 | ) 17 | 18 | func resourceSCIAutomationRunV1() *schema.Resource { 19 | return &schema.Resource{ 20 | CreateContext: resourceSCIAutomationRunV1Create, 21 | ReadContext: resourceSCIAutomationRunV1Read, 22 | DeleteContext: func(context.Context, *schema.ResourceData, interface{}) diag.Diagnostics { return nil }, 23 | 24 | Timeouts: &schema.ResourceTimeout{ 25 | Create: schema.DefaultTimeout(10 * time.Minute), 26 | }, 27 | 28 | Schema: map[string]*schema.Schema{ 29 | "region": { 30 | Type: schema.TypeString, 31 | Optional: true, 32 | Computed: true, 33 | ForceNew: true, 34 | }, 35 | 36 | "triggers": { 37 | Type: schema.TypeMap, 38 | Optional: true, 39 | ForceNew: true, 40 | }, 41 | 42 | "automation_id": { 43 | Type: schema.TypeString, 44 | Required: true, 45 | ForceNew: true, 46 | }, 47 | 48 | "selector": { 49 | Type: schema.TypeString, 50 | Required: true, 51 | ForceNew: true, 52 | ValidateFunc: validation.NoZeroValues, 53 | }, 54 | 55 | // Computed 56 | "automation_name": { 57 | Type: schema.TypeString, 58 | Computed: true, 59 | }, 60 | 61 | "repository": { 62 | Type: schema.TypeString, 63 | Computed: true, 64 | Deprecated: "This field is not returned by the Lyra API", 65 | }, 66 | 67 | "repository_revision": { 68 | Type: schema.TypeString, 69 | Computed: true, 70 | }, 71 | 72 | "automation_attributes": { 73 | Type: schema.TypeString, 74 | Computed: true, 75 | }, 76 | 77 | "state": { 78 | Type: schema.TypeString, 79 | Computed: true, 80 | }, 81 | 82 | "log": { 83 | Type: schema.TypeString, 84 | Computed: true, 85 | // Don't print the huge log during the terraform plan/apply 86 | Sensitive: true, 87 | }, 88 | 89 | "jobs": { 90 | Type: schema.TypeList, 91 | Computed: true, 92 | Elem: &schema.Schema{Type: schema.TypeString}, 93 | }, 94 | 95 | "project_id": { 96 | Type: schema.TypeString, 97 | Computed: true, 98 | }, 99 | 100 | "created_at": { 101 | Type: schema.TypeString, 102 | Computed: true, 103 | }, 104 | 105 | "updated_at": { 106 | Type: schema.TypeString, 107 | Computed: true, 108 | }, 109 | 110 | "owner": { 111 | Type: schema.TypeList, 112 | Computed: true, 113 | Elem: &schema.Resource{ 114 | Schema: map[string]*schema.Schema{ 115 | "id": { 116 | Type: schema.TypeString, 117 | Computed: true, 118 | }, 119 | "name": { 120 | Type: schema.TypeString, 121 | Computed: true, 122 | }, 123 | "domain_id": { 124 | Type: schema.TypeString, 125 | Computed: true, 126 | }, 127 | "domain_name": { 128 | Type: schema.TypeString, 129 | Computed: true, 130 | }, 131 | }, 132 | }, 133 | }, 134 | }, 135 | } 136 | } 137 | 138 | func resourceSCIAutomationRunV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 139 | config := meta.(*Config) 140 | automationClient, err := config.automationV1Client(ctx, GetRegion(d, config)) 141 | if err != nil { 142 | return diag.Errorf("Error creating OpenStack Arc client: %s", err) 143 | } 144 | 145 | createOpts := runs.CreateOpts{ 146 | AutomationID: d.Get("automation_id").(string), 147 | Selector: d.Get("selector").(string), 148 | } 149 | 150 | log.Printf("[DEBUG] sci_automation_run_v1 create options: %#v", createOpts) 151 | 152 | run, err := runs.Create(ctx, automationClient, createOpts).Extract() 153 | if err != nil { 154 | return diag.Errorf("Error creating sci_automation_run_v1: %s", err) 155 | } 156 | 157 | d.SetId(run.ID) 158 | 159 | timeout := d.Timeout(schema.TimeoutCreate) 160 | target := []string{ 161 | "completed", 162 | "failed", 163 | } 164 | pending := []string{ 165 | "preparing", 166 | "executing", 167 | } 168 | err = waitForAutomationRunV1(ctx, automationClient, run.ID, target, pending, timeout) 169 | if err != nil { 170 | return diag.FromErr(err) 171 | } 172 | 173 | return resourceSCIAutomationRunV1Read(ctx, d, meta) 174 | } 175 | 176 | func resourceSCIAutomationRunV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 177 | config := meta.(*Config) 178 | automationClient, err := config.automationV1Client(ctx, GetRegion(d, config)) 179 | if err != nil { 180 | return diag.Errorf("Error creating OpenStack Automation client: %s", err) 181 | } 182 | 183 | run, err := runs.Get(ctx, automationClient, d.Id()).Extract() 184 | if err != nil { 185 | return diag.FromErr(CheckDeleted(d, err, "Unable to retrieve sci_automation_run_v1")) 186 | } 187 | 188 | _ = d.Set("automation_id", run.AutomationID) 189 | _ = d.Set("automation_name", run.AutomationName) 190 | _ = d.Set("selector", run.Selector) 191 | _ = d.Set("repository_revision", run.RepositoryRevision) 192 | 193 | automationAttributes, err := json.Marshal(run.AutomationAttributes) 194 | if err != nil { 195 | log.Printf("[DEBUG] resourceSCIAutomationRunV1Read: Cannot marshal run.AutomationAttributes: %s", err) 196 | } 197 | _ = d.Set("automation_attributes", string(automationAttributes)) 198 | 199 | _ = d.Set("state", run.State) 200 | _ = d.Set("created_at", run.CreatedAt.Format(time.RFC3339)) 201 | _ = d.Set("updated_at", run.UpdatedAt.Format(time.RFC3339)) 202 | _ = d.Set("log", run.Log) 203 | _ = d.Set("jobs", run.Jobs) 204 | _ = d.Set("owner", flattenAutomationiOwnerV1(run.Owner)) 205 | _ = d.Set("project_id", run.ProjectID) 206 | 207 | _ = d.Set("region", GetRegion(d, config)) 208 | 209 | return nil 210 | } 211 | 212 | func flattenAutomationiOwnerV1(owner runs.Owner) []interface{} { 213 | return []interface{}{map[string]interface{}{ 214 | "id": owner.ID, 215 | "name": owner.Name, 216 | "domain_id": owner.DomainID, 217 | "domain_name": owner.DomainName, 218 | }} 219 | } 220 | 221 | func waitForAutomationRunV1(ctx context.Context, automationClient *gophercloud.ServiceClient, id string, target []string, pending []string, timeout time.Duration) error { 222 | log.Printf("[DEBUG] Waiting for %s run to become %v.", id, target) 223 | 224 | stateConf := &retry.StateChangeConf{ 225 | Target: target, 226 | Pending: pending, 227 | Refresh: automationRunV1GetState(ctx, automationClient, id), 228 | Timeout: timeout, 229 | Delay: 1 * time.Second, 230 | MinTimeout: 1 * time.Second, 231 | } 232 | 233 | _, err := stateConf.WaitForStateContext(ctx) 234 | 235 | return err 236 | } 237 | 238 | func automationRunV1GetState(ctx context.Context, automationClient *gophercloud.ServiceClient, id string) retry.StateRefreshFunc { 239 | return func() (interface{}, string, error) { 240 | run, err := runs.Get(ctx, automationClient, id).Extract() 241 | if err != nil { 242 | return nil, "", fmt.Errorf("enable to retrieve %s sci_automation_run_v1: %v", id, err) 243 | } 244 | 245 | return run, run.State, nil 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /sci/resource_sci_bgpvpn_interconnection_v2.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 11 | "github.com/sapcc/gophercloud-sapcc/v2/networking/v2/bgpvpn/interconnections" 12 | ) 13 | 14 | func resourceSCIBGPVPNInterconnectionV2() *schema.Resource { 15 | return &schema.Resource{ 16 | CreateContext: resourceSCIBGPVPNInterconnectionV2Create, 17 | ReadContext: resourceSCIBGPVPNInterconnectionV2Read, 18 | UpdateContext: resourceSCIBGPVPNInterconnectionV2Update, 19 | DeleteContext: resourceSCIBGPVPNInterconnectionV2Delete, 20 | Importer: &schema.ResourceImporter{ 21 | StateContext: schema.ImportStatePassthroughContext, 22 | }, 23 | 24 | Timeouts: &schema.ResourceTimeout{ 25 | Create: schema.DefaultTimeout(10 * time.Minute), 26 | Update: schema.DefaultTimeout(10 * time.Minute), 27 | Delete: schema.DefaultTimeout(10 * time.Minute), 28 | }, 29 | 30 | Schema: map[string]*schema.Schema{ 31 | "region": { 32 | Type: schema.TypeString, 33 | Optional: true, 34 | Computed: true, 35 | ForceNew: true, 36 | }, 37 | "name": { 38 | Type: schema.TypeString, 39 | Optional: true, 40 | }, 41 | "type": { 42 | Type: schema.TypeString, 43 | Optional: true, 44 | Computed: true, 45 | ForceNew: true, 46 | ValidateFunc: validation.StringInSlice([]string{ 47 | "bgpvpn", 48 | }, false), 49 | }, 50 | "project_id": { 51 | Type: schema.TypeString, 52 | Optional: true, 53 | ForceNew: true, 54 | Computed: true, 55 | }, 56 | "local_resource_id": { 57 | Type: schema.TypeString, 58 | Required: true, 59 | ForceNew: true, 60 | }, 61 | "remote_resource_id": { 62 | Type: schema.TypeString, 63 | Required: true, 64 | ForceNew: true, 65 | }, 66 | "remote_region": { 67 | Type: schema.TypeString, 68 | Required: true, 69 | ForceNew: true, 70 | }, 71 | "remote_interconnection_id": { 72 | Type: schema.TypeString, 73 | Optional: true, 74 | Computed: true, 75 | }, 76 | "state": { 77 | Type: schema.TypeString, 78 | Optional: true, 79 | Computed: true, 80 | }, 81 | "local_parameters": { 82 | Type: schema.TypeList, 83 | Computed: true, 84 | Elem: &schema.Resource{ 85 | Schema: map[string]*schema.Schema{ 86 | "project_id": { 87 | Type: schema.TypeList, 88 | Computed: true, 89 | Elem: &schema.Schema{Type: schema.TypeString}, 90 | }, 91 | }, 92 | }, 93 | }, 94 | "remote_parameters": { 95 | Type: schema.TypeList, 96 | Computed: true, 97 | Elem: &schema.Resource{ 98 | Schema: map[string]*schema.Schema{ 99 | "project_id": { 100 | Type: schema.TypeList, 101 | Computed: true, 102 | Elem: &schema.Schema{Type: schema.TypeString}, 103 | }, 104 | }, 105 | }, 106 | }, 107 | }, 108 | } 109 | } 110 | 111 | func resourceSCIBGPVPNInterconnectionV2Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 112 | config := meta.(*Config) 113 | networkingClient, err := config.NetworkingV2Client(ctx, GetRegion(d, config)) 114 | if err != nil { 115 | return diag.Errorf("Error creating OpenStack networking client: %s", err) 116 | } 117 | 118 | createOpts := interconnections.CreateOpts{ 119 | Name: d.Get("name").(string), 120 | ProjectID: d.Get("project_id").(string), 121 | Type: d.Get("type").(string), 122 | LocalResourceID: d.Get("local_resource_id").(string), 123 | RemoteResourceID: d.Get("remote_resource_id").(string), 124 | RemoteRegion: d.Get("remote_region").(string), 125 | RemoteInterconnectionID: d.Get("remote_interconnection_id").(string), 126 | } 127 | 128 | log.Printf("[DEBUG] Create BGP VPN interconnection: %#v", createOpts) 129 | 130 | interConn, err := interconnections.Create(ctx, networkingClient, createOpts).Extract() 131 | if err != nil { 132 | return diag.FromErr(err) 133 | } 134 | 135 | log.Printf("[DEBUG] BGP VPN interconnection created: %#v", interConn) 136 | 137 | d.SetId(interConn.ID) 138 | 139 | return resourceSCIBGPVPNInterconnectionV2Read(ctx, d, meta) 140 | } 141 | 142 | func resourceSCIBGPVPNInterconnectionV2Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 143 | config := meta.(*Config) 144 | networkingClient, err := config.NetworkingV2Client(ctx, GetRegion(d, config)) 145 | if err != nil { 146 | return diag.Errorf("Error creating OpenStack networking client: %s", err) 147 | } 148 | 149 | interConn, err := interconnections.Get(ctx, networkingClient, d.Id()).Extract() 150 | if err != nil { 151 | return diag.FromErr(CheckDeleted(d, err, "interconnection")) 152 | } 153 | 154 | log.Printf("[DEBUG] Read OpenStack BPG VPN interconnection %s: %#v", d.Id(), interConn) 155 | 156 | _ = d.Set("name", interConn.Name) 157 | _ = d.Set("type", interConn.Type) 158 | _ = d.Set("project_id", interConn.ProjectID) 159 | _ = d.Set("local_resource_id", interConn.LocalResourceID) 160 | _ = d.Set("remote_resource_id", interConn.RemoteResourceID) 161 | _ = d.Set("remote_region", interConn.RemoteRegion) 162 | _ = d.Set("remote_interconnection_id", interConn.RemoteInterconnectionID) 163 | _ = d.Set("state", interConn.State) 164 | _ = d.Set("local_parameters", []map[string][]string{{"project_id": interConn.LocalParameters.ProjectID}}) 165 | _ = d.Set("remote_parameters", []map[string][]string{{"project_id": interConn.RemoteParameters.ProjectID}}) 166 | _ = d.Set("region", GetRegion(d, config)) 167 | 168 | return nil 169 | } 170 | 171 | func resourceSCIBGPVPNInterconnectionV2Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 172 | config := meta.(*Config) 173 | networkingClient, err := config.NetworkingV2Client(ctx, GetRegion(d, config)) 174 | if err != nil { 175 | return diag.Errorf("Error creating OpenStack networking client: %s", err) 176 | } 177 | 178 | opts := interconnections.UpdateOpts{} 179 | 180 | var hasChange bool 181 | 182 | if d.HasChange("name") { 183 | name := d.Get("name").(string) 184 | opts.Name = &name 185 | hasChange = true 186 | } 187 | 188 | if d.HasChange("state") { 189 | state := d.Get("state").(string) 190 | opts.State = &state 191 | hasChange = true 192 | } 193 | 194 | if d.HasChange("remote_interconnection_id") { 195 | id := d.Get("remote_interconnection_id").(string) 196 | opts.RemoteInterconnectionID = &id 197 | hasChange = true 198 | } 199 | 200 | log.Printf("[DEBUG] Updating BGP VPN interconnection with id %s: %#v", d.Id(), opts) 201 | 202 | if hasChange { 203 | _, err = interconnections.Update(ctx, networkingClient, d.Id(), opts).Extract() 204 | if err != nil { 205 | return diag.FromErr(err) 206 | } 207 | 208 | log.Printf("[DEBUG] Updated BGP VPN interconnection with id %s", d.Id()) 209 | } 210 | 211 | return resourceSCIBGPVPNInterconnectionV2Read(ctx, d, meta) 212 | } 213 | 214 | func resourceSCIBGPVPNInterconnectionV2Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 215 | log.Printf("[DEBUG] Destroy interconnection: %s", d.Id()) 216 | 217 | config := meta.(*Config) 218 | networkingClient, err := config.NetworkingV2Client(ctx, GetRegion(d, config)) 219 | if err != nil { 220 | return diag.Errorf("Error creating OpenStack networking client: %s", err) 221 | } 222 | 223 | err = interconnections.Delete(ctx, networkingClient, d.Id()).Err 224 | if err != nil { 225 | return diag.FromErr(err) 226 | } 227 | 228 | return nil 229 | } 230 | -------------------------------------------------------------------------------- /sci/resource_sci_billing_domain_masterdata.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/gophercloud/gophercloud/v2" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 13 | "github.com/sapcc/gophercloud-sapcc/v2/billing/masterdata/domains" 14 | ) 15 | 16 | func resourceSCIBillingDomainMasterdata() *schema.Resource { 17 | return &schema.Resource{ 18 | ReadContext: resourceSCIBillingDomainMasterdataRead, 19 | UpdateContext: resourceSCIBillingDomainMasterdataCreateOrUpdate, 20 | CreateContext: resourceSCIBillingDomainMasterdataCreateOrUpdate, 21 | Delete: schema.RemoveFromState, 22 | Importer: &schema.ResourceImporter{ 23 | StateContext: schema.ImportStatePassthroughContext, 24 | }, 25 | 26 | Schema: map[string]*schema.Schema{ 27 | "region": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | Computed: true, 31 | ForceNew: true, 32 | }, 33 | 34 | "domain_id": { 35 | Type: schema.TypeString, 36 | Optional: true, 37 | Computed: true, 38 | ForceNew: true, 39 | }, 40 | 41 | "domain_name": { 42 | Type: schema.TypeString, 43 | Optional: true, 44 | Computed: true, 45 | }, 46 | 47 | "description": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | }, 51 | 52 | "additional_information": { 53 | Type: schema.TypeString, 54 | Optional: true, 55 | }, 56 | 57 | "responsible_primary_contact_id": { 58 | Type: schema.TypeString, 59 | Optional: true, 60 | }, 61 | 62 | "responsible_primary_contact_email": { 63 | Type: schema.TypeString, 64 | Optional: true, 65 | }, 66 | 67 | "cost_object": { 68 | Type: schema.TypeList, 69 | Optional: true, 70 | MaxItems: 1, 71 | Elem: &schema.Resource{ 72 | Schema: map[string]*schema.Schema{ 73 | "projects_can_inherit": { 74 | Type: schema.TypeBool, 75 | Optional: true, 76 | }, 77 | "name": { 78 | Type: schema.TypeString, 79 | Optional: true, 80 | }, 81 | "type": { 82 | Type: schema.TypeString, 83 | Optional: true, 84 | ValidateFunc: validation.StringInSlice([]string{ 85 | "IO", "CC", "WBS", "SO", 86 | }, false), 87 | }, 88 | }, 89 | }, 90 | }, 91 | 92 | "collector": { 93 | Type: schema.TypeString, 94 | Optional: true, 95 | Computed: true, 96 | }, 97 | 98 | // computed parameters 99 | "created_at": { 100 | Type: schema.TypeString, 101 | Computed: true, 102 | }, 103 | 104 | "changed_at": { 105 | Type: schema.TypeString, 106 | Computed: true, 107 | }, 108 | 109 | "changed_by": { 110 | Type: schema.TypeString, 111 | Computed: true, 112 | }, 113 | 114 | "is_complete": { 115 | Type: schema.TypeBool, 116 | Computed: true, 117 | }, 118 | 119 | "missing_attributes": { 120 | Type: schema.TypeString, 121 | Computed: true, 122 | }, 123 | }, 124 | } 125 | } 126 | 127 | func resourceSCIBillingDomainMasterdataCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 128 | config := meta.(*Config) 129 | billing, err := config.billingClient(ctx, GetRegion(d, config)) 130 | if err != nil { 131 | return diag.Errorf("Error creating OpenStack billing client: %s", err) 132 | } 133 | 134 | domainID := d.Get("domain_id").(string) 135 | if d.Id() == "" && domainID == "" { 136 | // first call, expecting to get current scope domain 137 | identityClient, err := config.IdentityV3Client(ctx, GetRegion(d, config)) 138 | if err != nil { 139 | return diag.Errorf("Error creating OpenStack identity client: %s", err) 140 | } 141 | 142 | tokenDetails, err := getTokenDetails(ctx, identityClient) 143 | if err != nil { 144 | return diag.FromErr(err) 145 | } 146 | 147 | if tokenDetails.domain == nil { 148 | return diag.Errorf("Error getting billing domain scope: %s", err) 149 | } 150 | 151 | domainID = tokenDetails.domain.ID 152 | } 153 | 154 | domain, err := domains.Get(ctx, billing, domainID).Extract() 155 | if err != nil { 156 | if d.Id() != "" || !gophercloud.ResponseCodeIs(err, http.StatusNotFound) { 157 | return diag.Errorf("Error getting billing domain masterdata: %s", err) 158 | } 159 | log.Printf("[DEBUG] Error getting billing domain masterdata, probably this domain was not created yet: %s", err) 160 | domain = &domains.Domain{DomainID: domainID} 161 | } 162 | 163 | log.Printf("[DEBUG] Retrieved domain masterdata before the created/update: %+v", domain) 164 | 165 | // API doesn't support partial update, thus prefilling the update options with the existing data 166 | opts := domains.DomainToUpdateOpts(domain) 167 | opts.DomainID = replaceEmptyString(d, "domain_id", opts.DomainID) 168 | opts.DomainName = replaceEmptyString(d, "domain_name", opts.DomainName) 169 | opts.ResponsiblePrimaryContactID = replaceEmptyString(d, "responsible_primary_contact_id", opts.ResponsiblePrimaryContactID) 170 | opts.ResponsiblePrimaryContactEmail = replaceEmptyString(d, "responsible_primary_contact_email", opts.ResponsiblePrimaryContactEmail) 171 | opts.AdditionalInformation = replaceEmptyString(d, "additional_information", opts.AdditionalInformation) 172 | opts.Collector = replaceEmptyString(d, "collector", opts.Collector) 173 | 174 | if v := billingDomainExpandCostObject(d.Get("cost_object")); v != (domains.CostObject{}) { 175 | opts.CostObject = v 176 | } 177 | 178 | log.Printf("[DEBUG] Updating %s domain masterdata: %+v", opts.DomainID, opts) 179 | 180 | _, err = domains.Update(ctx, billing, opts.DomainID, opts).Extract() 181 | if err != nil { 182 | return diag.Errorf("Error updating billing domain masterdata: %s", err) 183 | } 184 | 185 | if d.Id() == "" { 186 | d.SetId(opts.DomainID) 187 | } 188 | 189 | return resourceSCIBillingDomainMasterdataRead(ctx, d, meta) 190 | } 191 | 192 | func resourceSCIBillingDomainMasterdataRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 193 | config := meta.(*Config) 194 | billing, err := config.billingClient(ctx, GetRegion(d, config)) 195 | if err != nil { 196 | return diag.Errorf("Error creating OpenStack billing client: %s", err) 197 | } 198 | 199 | domain, err := domains.Get(ctx, billing, d.Id()).Extract() 200 | if err != nil { 201 | return diag.FromErr(CheckDeleted(d, err, "Error getting billing domain masterdata")) 202 | } 203 | 204 | log.Printf("[DEBUG] Retrieved domain masterdata: %+v", domain) 205 | 206 | _ = d.Set("domain_id", domain.DomainID) 207 | _ = d.Set("domain_name", domain.DomainName) 208 | _ = d.Set("description", domain.Description) 209 | _ = d.Set("responsible_primary_contact_id", domain.ResponsiblePrimaryContactID) 210 | _ = d.Set("responsible_primary_contact_email", domain.ResponsiblePrimaryContactEmail) 211 | _ = d.Set("additional_information", domain.AdditionalInformation) 212 | _ = d.Set("cost_object", billingDomainFlattenCostObject(domain.CostObject)) 213 | _ = d.Set("created_at", domain.CreatedAt.Format(time.RFC3339)) 214 | _ = d.Set("changed_at", domain.ChangedAt.Format(time.RFC3339)) 215 | _ = d.Set("changed_by", domain.ChangedBy) 216 | _ = d.Set("is_complete", domain.IsComplete) 217 | _ = d.Set("missing_attributes", domain.MissingAttributes) 218 | _ = d.Set("collector", domain.Collector) 219 | 220 | _ = d.Set("region", GetRegion(d, config)) 221 | 222 | return nil 223 | } 224 | -------------------------------------------------------------------------------- /sci/resource_sci_endpoint_quota_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/sapcc/archer/client/quota" 10 | "github.com/sapcc/archer/models" 11 | ) 12 | 13 | func resourceSCIEndpointQuotaV1() *schema.Resource { 14 | return &schema.Resource{ 15 | CreateContext: resourceSCIEndpointQuotaV1Create, 16 | ReadContext: resourceSCIEndpointQuotaV1Read, 17 | UpdateContext: resourceSCIEndpointQuotaV1Update, 18 | DeleteContext: resourceSCIEndpointQuotaV1Delete, 19 | Importer: &schema.ResourceImporter{ 20 | StateContext: schema.ImportStatePassthroughContext, 21 | }, 22 | 23 | Schema: map[string]*schema.Schema{ 24 | "region": { 25 | Type: schema.TypeString, 26 | Optional: true, 27 | Computed: true, 28 | ForceNew: true, 29 | }, 30 | "endpoint": { 31 | Type: schema.TypeInt, 32 | Optional: true, 33 | Computed: true, 34 | }, 35 | "service": { 36 | Type: schema.TypeInt, 37 | Optional: true, 38 | Computed: true, 39 | }, 40 | "project_id": { 41 | Type: schema.TypeString, 42 | Required: true, 43 | }, 44 | 45 | // computed 46 | "in_use_endpoint": { 47 | Type: schema.TypeInt, 48 | Optional: true, 49 | Computed: true, 50 | }, 51 | "in_use_service": { 52 | Type: schema.TypeInt, 53 | Optional: true, 54 | Computed: true, 55 | }, 56 | }, 57 | } 58 | } 59 | 60 | func resourceSCIEndpointQuotaV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 61 | config := meta.(*Config) 62 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 63 | if err != nil { 64 | return diag.Errorf("error creating Archer client: %s", err) 65 | } 66 | client := c.Quota 67 | 68 | projectID := d.Get("project_id").(string) 69 | req := &models.Quota{} 70 | if v, ok := d.GetOk("endpoint"); ok && v != 0 { 71 | req.Endpoint = int64(v.(int)) 72 | } 73 | if v, ok := d.GetOk("service"); ok && v != 0 { 74 | req.Service = int64(v.(int)) 75 | } 76 | 77 | opts := "a.PutQuotasProjectIDParams{ 78 | Body: req, 79 | ProjectID: projectID, 80 | Context: ctx, 81 | } 82 | res, err := client.PutQuotasProjectID(opts, c.authFunc()) 83 | if err != nil { 84 | return diag.Errorf("error creating Archer quota: %s", err) 85 | } 86 | if res == nil || res.Payload == nil { 87 | return diag.Errorf("error creating Archer quota: empty response") 88 | } 89 | 90 | log.Printf("[DEBUG] Created Archer quota: %v", res) 91 | 92 | d.SetId(projectID) 93 | 94 | return resourceSCIEndpointQuotaV1Read(ctx, d, meta) 95 | } 96 | 97 | func resourceSCIEndpointQuotaV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 98 | config := meta.(*Config) 99 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 100 | if err != nil { 101 | return diag.Errorf("error creating Archer client: %s", err) 102 | } 103 | client := c.Quota 104 | 105 | id := d.Id() 106 | opts := "a.GetQuotasProjectIDParams{ 107 | ProjectID: id, 108 | Context: ctx, 109 | } 110 | res, err := client.GetQuotasProjectID(opts, c.authFunc()) 111 | if err != nil { 112 | return diag.Errorf("error reading Archer quota: %s, %T", err, err) 113 | } 114 | if res == nil || res.Payload == nil { 115 | return diag.Errorf("error reading Archer quota: empty response") 116 | } 117 | if err != nil { 118 | if _, ok := err.(*quota.GetQuotasNotFound); ok { 119 | d.SetId("") 120 | return nil 121 | } 122 | return diag.FromErr(err) 123 | } 124 | 125 | archerSetQuotaResource(d, config, res.Payload) 126 | 127 | return nil 128 | } 129 | 130 | func resourceSCIEndpointQuotaV1Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 131 | config := meta.(*Config) 132 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 133 | if err != nil { 134 | return diag.Errorf("error creating Archer client: %s", err) 135 | } 136 | client := c.Quota 137 | 138 | id := d.Id() 139 | req := &models.Quota{ 140 | Endpoint: int64(d.Get("endpoint").(int)), 141 | Service: int64(d.Get("service").(int)), 142 | } 143 | 144 | opts := "a.PutQuotasProjectIDParams{ 145 | Body: req, 146 | ProjectID: id, 147 | Context: ctx, 148 | } 149 | res, err := client.PutQuotasProjectID(opts, c.authFunc()) 150 | if err != nil { 151 | return diag.Errorf("error updating Archer quota: %s", err) 152 | } 153 | if res == nil || res.Payload == nil { 154 | return diag.Errorf("error updating Archer quota: empty response") 155 | } 156 | 157 | return resourceSCIEndpointQuotaV1Read(ctx, d, meta) 158 | } 159 | 160 | func resourceSCIEndpointQuotaV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 161 | config := meta.(*Config) 162 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 163 | if err != nil { 164 | return diag.Errorf("error creating Archer client: %s", err) 165 | } 166 | client := c.Quota 167 | 168 | id := d.Id() 169 | opts := "a.DeleteQuotasProjectIDParams{ 170 | ProjectID: id, 171 | Context: ctx, 172 | } 173 | _, err = client.DeleteQuotasProjectID(opts, c.authFunc()) 174 | if err != nil { 175 | if _, ok := err.(*quota.DeleteQuotasProjectIDNotFound); ok { 176 | return nil 177 | } 178 | return diag.Errorf("error deleting Archer quota: %s", err) 179 | } 180 | 181 | return nil 182 | } 183 | 184 | func archerSetQuotaResource(d *schema.ResourceData, config *Config, q *quota.GetQuotasProjectIDOKBody) { 185 | _ = d.Set("endpoint", q.Endpoint) 186 | _ = d.Set("service", q.Service) 187 | 188 | // computed 189 | _ = d.Set("in_use_endpoint", q.InUseEndpoint) 190 | _ = d.Set("in_use_service", q.InUseService) 191 | 192 | _ = d.Set("region", GetRegion(d, config)) 193 | } 194 | -------------------------------------------------------------------------------- /sci/resource_sci_endpoint_rbac_policy_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/go-openapi/strfmt" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 11 | "github.com/sapcc/archer/client/rbac" 12 | "github.com/sapcc/archer/models" 13 | ) 14 | 15 | func resourceSCIEndpointRBACV1() *schema.Resource { 16 | return &schema.Resource{ 17 | CreateContext: resourceSCIEndpointRBACV1Create, 18 | ReadContext: resourceSCIEndpointRBACV1Read, 19 | UpdateContext: resourceSCIEndpointRBACV1Update, 20 | DeleteContext: resourceSCIEndpointRBACV1Delete, 21 | Importer: &schema.ResourceImporter{ 22 | StateContext: schema.ImportStatePassthroughContext, 23 | }, 24 | 25 | Schema: map[string]*schema.Schema{ 26 | "region": { 27 | Type: schema.TypeString, 28 | Optional: true, 29 | Computed: true, 30 | ForceNew: true, 31 | }, 32 | "service_id": { 33 | Type: schema.TypeString, 34 | Required: true, 35 | ForceNew: true, 36 | }, 37 | "project_id": { 38 | Type: schema.TypeString, 39 | Optional: true, 40 | Computed: true, 41 | ForceNew: true, 42 | }, 43 | "target": { 44 | Type: schema.TypeString, 45 | Required: true, 46 | }, 47 | "target_type": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | Computed: true, 51 | ValidateFunc: validation.StringInSlice([]string{ 52 | "project", 53 | }, false), 54 | }, 55 | 56 | // computed 57 | "created_at": { 58 | Type: schema.TypeString, 59 | Computed: true, 60 | }, 61 | 62 | "updated_at": { 63 | Type: schema.TypeString, 64 | Computed: true, 65 | }, 66 | }, 67 | } 68 | } 69 | 70 | func resourceSCIEndpointRBACV1Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 71 | config := meta.(*Config) 72 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 73 | if err != nil { 74 | return diag.Errorf("error creating Archer client: %s", err) 75 | } 76 | client := c.Rbac 77 | 78 | // Create the rbac 79 | req := &models.Rbacpolicy{ 80 | ProjectID: models.Project(d.Get("project_id").(string)), 81 | ServiceID: ptr(strfmt.UUID(d.Get("service_id").(string))), 82 | Target: d.Get("target").(string), 83 | } 84 | if v, ok := d.GetOk("target_type"); ok { 85 | req.TargetType = ptr(v.(string)) 86 | } 87 | 88 | opts := &rbac.PostRbacPoliciesParams{ 89 | Body: req, 90 | Context: ctx, 91 | } 92 | res, err := client.PostRbacPolicies(opts, c.authFunc()) 93 | if err != nil { 94 | return diag.Errorf("error creating Archer RBAC policy: %s", err) 95 | } 96 | if res == nil || res.Payload == nil { 97 | return diag.Errorf("error creating Archer RBAC policy: empty response") 98 | } 99 | 100 | log.Printf("[DEBUG] Created Archer RBAC policy: %v", res) 101 | 102 | id := string(res.Payload.ID) 103 | d.SetId(id) 104 | 105 | archerSetRBACPolicyResource(d, config, res.Payload) 106 | 107 | return nil 108 | } 109 | 110 | func resourceSCIEndpointRBACV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 111 | config := meta.(*Config) 112 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 113 | if err != nil { 114 | return diag.Errorf("error creating Archer client: %s", err) 115 | } 116 | client := c.Rbac 117 | 118 | opts := &rbac.GetRbacPoliciesRbacPolicyIDParams{ 119 | RbacPolicyID: strfmt.UUID(d.Id()), 120 | Context: ctx, 121 | } 122 | res, err := client.GetRbacPoliciesRbacPolicyID(opts, c.authFunc()) 123 | if err != nil { 124 | if _, ok := err.(*rbac.GetRbacPoliciesRbacPolicyIDNotFound); ok { 125 | d.SetId("") 126 | return nil 127 | } 128 | return diag.Errorf("error reading Archer RBAC policy: %s", err) 129 | } 130 | if res == nil || res.Payload == nil { 131 | return diag.Errorf("error reading Archer RBAC policy: empty response") 132 | } 133 | 134 | log.Printf("[DEBUG] Read Archer RBAC policy: %v", res) 135 | 136 | archerSetRBACPolicyResource(d, config, res.Payload) 137 | 138 | return nil 139 | } 140 | 141 | func resourceSCIEndpointRBACV1Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 142 | config := meta.(*Config) 143 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 144 | if err != nil { 145 | return diag.Errorf("error creating Archer client: %s", err) 146 | } 147 | client := c.Rbac 148 | 149 | id := d.Id() 150 | rbacPolicy := &models.Rbacpolicycommon{ 151 | ProjectID: models.Project(d.Get("project_id").(string)), 152 | Target: ptr(d.Get("target").(string)), 153 | } 154 | 155 | if d.HasChange("target_type") { 156 | v := d.Get("target_type").(string) 157 | rbacPolicy.TargetType = &v 158 | } 159 | 160 | opts := &rbac.PutRbacPoliciesRbacPolicyIDParams{ 161 | Body: rbacPolicy, 162 | RbacPolicyID: strfmt.UUID(id), 163 | Context: ctx, 164 | } 165 | res, err := client.PutRbacPoliciesRbacPolicyID(opts, c.authFunc()) 166 | if err != nil { 167 | return diag.Errorf("error updating Archer RBAC policy: %s", err) 168 | } 169 | if res == nil || res.Payload == nil { 170 | return diag.Errorf("error updating Archer RBAC policy: empty response") 171 | } 172 | 173 | archerSetRBACPolicyResource(d, config, res.Payload) 174 | 175 | return nil 176 | } 177 | 178 | func resourceSCIEndpointRBACV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 179 | config := meta.(*Config) 180 | c, err := config.archerV1Client(ctx, GetRegion(d, config)) 181 | if err != nil { 182 | return diag.Errorf("error creating Archer client: %s", err) 183 | } 184 | client := c.Rbac 185 | 186 | id := d.Id() 187 | opts := &rbac.DeleteRbacPoliciesRbacPolicyIDParams{ 188 | RbacPolicyID: strfmt.UUID(id), 189 | Context: ctx, 190 | } 191 | _, err = client.DeleteRbacPoliciesRbacPolicyID(opts, c.authFunc()) 192 | if err != nil { 193 | if _, ok := err.(*rbac.DeleteRbacPoliciesRbacPolicyIDNotFound); ok { 194 | return nil 195 | } 196 | return diag.Errorf("error deleting Archer endpoint: %s", err) 197 | } 198 | 199 | return nil 200 | } 201 | 202 | func archerSetRBACPolicyResource(d *schema.ResourceData, config *Config, rbacPolicy *models.Rbacpolicy) { 203 | _ = d.Set("service_id", ptrValue(rbacPolicy.ServiceID)) 204 | _ = d.Set("project_id", rbacPolicy.ProjectID) 205 | _ = d.Set("target", rbacPolicy.Target) 206 | _ = d.Set("target_type", ptrValue(rbacPolicy.TargetType)) 207 | 208 | // computed 209 | _ = d.Set("created_at", rbacPolicy.CreatedAt.String()) 210 | _ = d.Set("updated_at", rbacPolicy.UpdatedAt.String()) 211 | 212 | _ = d.Set("region", GetRegion(d, config)) 213 | } 214 | -------------------------------------------------------------------------------- /sci/sci_arc_agent_v1.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "time" 9 | 10 | "github.com/gophercloud/gophercloud/v2" 11 | "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 14 | "github.com/sapcc/gophercloud-sapcc/v2/arc/v1/agents" 15 | ) 16 | 17 | func arcSCIArcAgentV1ReadAgent(ctx context.Context, d *schema.ResourceData, arcClient *gophercloud.ServiceClient, agent *agents.Agent, region string) { 18 | if len(agent.Facts) == 0 { 19 | facts, err := agents.GetFacts(ctx, arcClient, agent.AgentID).Extract() 20 | if err != nil { 21 | log.Printf("Unable to retrieve facts for sci_arc_agent_v1: %s", err) 22 | } 23 | agent.Facts = facts 24 | log.Printf("[DEBUG] Retrieved sci_arc_agent_v1 facts %s: %+v", agent.AgentID, agent.Facts) 25 | } 26 | 27 | _ = d.Set("display_name", agent.DisplayName) 28 | _ = d.Set("agent_id", agent.AgentID) 29 | _ = d.Set("project", agent.Project) 30 | _ = d.Set("organization", agent.Organization) 31 | _ = d.Set("all_tags", agent.Tags) 32 | _ = d.Set("created_at", agent.CreatedAt.Format(time.RFC3339)) 33 | _ = d.Set("updated_at", agent.UpdatedAt.Format(time.RFC3339)) 34 | _ = d.Set("updated_with", agent.UpdatedWith) 35 | _ = d.Set("updated_by", agent.UpdatedBy) 36 | 37 | _ = d.Set("facts", expandToMapStringString(agent.Facts)) 38 | factsAgents := agent.Facts["agents"] 39 | if v, ok := factsAgents.(map[string]interface{}); ok { 40 | _ = d.Set("facts_agents", expandToMapStringString(v)) 41 | } else { 42 | _ = d.Set("facts_agents", map[string]string{}) 43 | } 44 | 45 | _ = d.Set("region", region) 46 | } 47 | 48 | func arcSCIArcAgentV1WaitForAgent(ctx context.Context, arcClient *gophercloud.ServiceClient, agentID, filter string, timeout time.Duration) (*agents.Agent, error) { 49 | var agent interface{} 50 | var msg string 51 | var err error 52 | 53 | // This condition is required, otherwise zero timeout will always raise: 54 | // "timeout while waiting for state to become 'active'" 55 | if timeout > 0 { 56 | // Retryable case, when timeout is set 57 | waitForAgent := &retry.StateChangeConf{ 58 | Target: []string{"active"}, 59 | Refresh: arcSCIArcAgentV1GetAgent(ctx, arcClient, agentID, filter, timeout), 60 | Timeout: timeout, 61 | Delay: 1 * time.Second, 62 | MinTimeout: 1 * time.Second, 63 | NotFoundChecks: 1000, // workaround for default 20 retries, when the resource is nil 64 | } 65 | agent, err = waitForAgent.WaitForStateContext(ctx) 66 | } else { 67 | // When timeout is not set, just get the agent 68 | agent, msg, err = arcSCIArcAgentV1GetAgent(ctx, arcClient, agentID, filter, timeout)() 69 | } 70 | 71 | if len(msg) > 0 && msg != "active" { 72 | return nil, fmt.Errorf("%s", msg) 73 | } 74 | 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | return agent.(*agents.Agent), nil 80 | } 81 | 82 | func arcSCIArcAgentV1GetAgent(ctx context.Context, arcClient *gophercloud.ServiceClient, agentID, filter string, timeout time.Duration) retry.StateRefreshFunc { 83 | return func() (interface{}, string, error) { 84 | var agent *agents.Agent 85 | var err error 86 | 87 | if len(agentID) == 0 && len(filter) == 0 { 88 | return nil, "", fmt.Errorf("at least one of agent_id or filter parameters is expected in sci_arc_agent_v1") 89 | } 90 | 91 | if len(agentID) > 0 { 92 | agent, err = agents.Get(ctx, arcClient, agentID).Extract() 93 | if err != nil { 94 | if gophercloud.ResponseCodeIs(err, http.StatusNotFound) && timeout > 0 { 95 | // Retryable case, when timeout is set 96 | return nil, fmt.Sprintf("unable to retrieve %s sci_arc_agent_v1: %v", agentID, err), nil 97 | } 98 | return nil, "", fmt.Errorf("unable to retrieve %s sci_arc_agent_v1: %v", agentID, err) 99 | } 100 | } else { 101 | listOpts := agents.ListOpts{Filter: filter} 102 | 103 | log.Printf("[DEBUG] sci_arc_agent_v1 list options: %#v", listOpts) 104 | 105 | allPages, err := agents.List(arcClient, listOpts).AllPages(ctx) 106 | if err != nil { 107 | return nil, "", fmt.Errorf("unable to list sci_arc_agent_v1: %s", err) 108 | } 109 | 110 | allAgents, err := agents.ExtractAgents(allPages) 111 | if err != nil { 112 | return nil, "", fmt.Errorf("unable to retrieve sci_arc_agent_v1: %s", err) 113 | } 114 | 115 | if len(allAgents) == 0 { 116 | // Retryable case, when timeout is set 117 | return nil, "No sci_arc_agent_v1 found", nil 118 | } 119 | 120 | if len(allAgents) > 1 { 121 | return nil, "", fmt.Errorf("more than one sci_arc_agent_v1 found (%d)", len(allAgents)) 122 | } 123 | 124 | agent = &allAgents[0] 125 | } 126 | 127 | log.Printf("[DEBUG] Retrieved sci_arc_agent_v1 %s: %+v", agent.AgentID, *agent) 128 | 129 | return agent, "active", nil 130 | } 131 | } 132 | 133 | func updateArcAgentTagsV1(ctx context.Context, arcClient *gophercloud.ServiceClient, agentID string, oldTagsRaw, newTagsRaw interface{}) error { 134 | var tagsToDelete []string 135 | oldTags, _ := oldTagsRaw.(map[string]interface{}) 136 | newTags, _ := newTagsRaw.(map[string]interface{}) 137 | 138 | // Determine if any tag keys were removed from the configuration. 139 | // Then request those keys to be deleted. 140 | for oldKey := range oldTags { 141 | var found bool 142 | for newKey := range newTags { 143 | if oldKey == newKey { 144 | found = true 145 | } 146 | } 147 | 148 | if !found { 149 | tagsToDelete = append(tagsToDelete, oldKey) 150 | } 151 | } 152 | 153 | for _, key := range tagsToDelete { 154 | err := agents.DeleteTag(ctx, arcClient, agentID, key).ExtractErr() 155 | if err != nil { 156 | return fmt.Errorf("error deleting %s tag from %s sci_arc_agent_v1: %v", key, agentID, err) 157 | } 158 | } 159 | 160 | // Update existing tags and add any new tags. 161 | tagsOpts := make(agents.Tags) 162 | for k, v := range newTags { 163 | tagsOpts[k] = v.(string) 164 | } 165 | 166 | err := agents.CreateTags(ctx, arcClient, agentID, tagsOpts).ExtractErr() 167 | if err != nil { 168 | return fmt.Errorf("error updating tags for %s sci_arc_agent_v1: %v", agentID, err) 169 | } 170 | 171 | return nil 172 | } 173 | 174 | func arcAgentV1ParseTimeout(raw interface{}) (time.Duration, error) { 175 | if list, ok := raw.([]interface{}); ok { 176 | for _, t := range list { 177 | if timeout, ok := t.(map[string]interface{}); ok { 178 | if v, ok := timeout["read"]; ok { 179 | return time.ParseDuration(v.(string)) 180 | } 181 | } 182 | } 183 | } 184 | 185 | return time.Duration(0), nil 186 | } 187 | 188 | func serverV2StateRefreshFunc(ctx context.Context, client *gophercloud.ServiceClient, instanceID string) retry.StateRefreshFunc { 189 | return func() (interface{}, string, error) { 190 | s, err := servers.Get(ctx, client, instanceID).Extract() 191 | if err != nil { 192 | if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { 193 | return s, "DELETED", nil 194 | } 195 | return nil, "", err 196 | } 197 | 198 | return s, s.Status, nil 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /sci/sci_auth_scope.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gophercloud/gophercloud/v2" 7 | "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" 8 | ) 9 | 10 | type authScopeTokenDetails struct { 11 | user *tokens.User 12 | domain *tokens.Domain 13 | project *tokens.Project 14 | catalog *tokens.ServiceCatalog 15 | roles []tokens.Role 16 | } 17 | 18 | func getTokenDetails(ctx context.Context, sc *gophercloud.ServiceClient) (authScopeTokenDetails, error) { 19 | var ( 20 | details authScopeTokenDetails 21 | err error 22 | ) 23 | 24 | r := sc.GetAuthResult() 25 | switch result := r.(type) { 26 | case tokens.CreateResult: 27 | details.user, err = result.ExtractUser() 28 | if err != nil { 29 | return details, err 30 | } 31 | details.domain, err = result.ExtractDomain() 32 | if err != nil { 33 | return details, err 34 | } 35 | details.project, err = result.ExtractProject() 36 | if err != nil { 37 | return details, err 38 | } 39 | details.roles, err = result.ExtractRoles() 40 | if err != nil { 41 | return details, err 42 | } 43 | details.catalog, err = result.ExtractServiceCatalog() 44 | if err != nil { 45 | return details, err 46 | } 47 | case tokens.GetResult: 48 | details.user, err = result.ExtractUser() 49 | if err != nil { 50 | return details, err 51 | } 52 | details.domain, err = result.ExtractDomain() 53 | if err != nil { 54 | return details, err 55 | } 56 | details.project, err = result.ExtractProject() 57 | if err != nil { 58 | return details, err 59 | } 60 | details.roles, err = result.ExtractRoles() 61 | if err != nil { 62 | return details, err 63 | } 64 | details.catalog, err = result.ExtractServiceCatalog() 65 | if err != nil { 66 | return details, err 67 | } 68 | default: 69 | res := tokens.Get(ctx, sc, sc.TokenID) 70 | if res.Err != nil { 71 | return details, res.Err 72 | } 73 | details.user, err = res.ExtractUser() 74 | if err != nil { 75 | return details, err 76 | } 77 | details.domain, err = res.ExtractDomain() 78 | if err != nil { 79 | return details, err 80 | } 81 | details.project, err = res.ExtractProject() 82 | if err != nil { 83 | return details, err 84 | } 85 | details.roles, err = res.ExtractRoles() 86 | if err != nil { 87 | return details, err 88 | } 89 | details.catalog, err = res.ExtractServiceCatalog() 90 | if err != nil { 91 | return details, err 92 | } 93 | } 94 | 95 | return details, nil 96 | } 97 | -------------------------------------------------------------------------------- /sci/sci_billing_domain_masterdata.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "github.com/sapcc/gophercloud-sapcc/v2/billing/masterdata/domains" 5 | ) 6 | 7 | func billingDomainFlattenCostObject(co domains.CostObject) []map[string]interface{} { 8 | return []map[string]interface{}{{ 9 | "projects_can_inherit": co.ProjectsCanInherit, 10 | "name": co.Name, 11 | "type": co.Type, 12 | }} 13 | } 14 | 15 | func billingDomainExpandCostObject(raw interface{}) domains.CostObject { 16 | var co domains.CostObject 17 | 18 | if raw != nil { 19 | if v, ok := raw.([]interface{}); ok { 20 | for _, v := range v { 21 | if v, ok := v.(map[string]interface{}); ok { 22 | if v, ok := v["projects_can_inherit"]; ok { 23 | co.ProjectsCanInherit = v.(bool) 24 | } 25 | if v, ok := v["name"]; ok { 26 | co.Name = v.(string) 27 | } 28 | if v, ok := v["type"]; ok { 29 | co.Type = v.(string) 30 | } 31 | 32 | return co 33 | } 34 | } 35 | } 36 | } 37 | 38 | return co 39 | } 40 | -------------------------------------------------------------------------------- /sci/sci_billing_project_masterdata.go: -------------------------------------------------------------------------------- 1 | package sci 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/sapcc/gophercloud-sapcc/v2/billing/masterdata/projects" 6 | ) 7 | 8 | func billingProjectFlattenCostObject(co projects.CostObject) []map[string]interface{} { 9 | return []map[string]interface{}{{ 10 | "inherited": co.Inherited, 11 | "name": co.Name, 12 | "type": co.Type, 13 | }} 14 | } 15 | 16 | func billingProjectExpandCostObject(raw interface{}) projects.CostObject { 17 | var co projects.CostObject 18 | 19 | if raw != nil { 20 | if v, ok := raw.([]interface{}); ok { 21 | for _, v := range v { 22 | if v, ok := v.(map[string]interface{}); ok { 23 | if v, ok := v["inherited"]; ok { 24 | co.Inherited = v.(bool) 25 | } 26 | if !co.Inherited { 27 | if v, ok := v["name"]; ok { 28 | co.Name = v.(string) 29 | } 30 | if v, ok := v["type"]; ok { 31 | co.Type = v.(string) 32 | } 33 | } 34 | 35 | return co 36 | } 37 | } 38 | } 39 | } 40 | 41 | return co 42 | } 43 | 44 | // replaceEmptyString is a helper function to replace empty string fields with 45 | // another field. 46 | func replaceEmptyString(d *schema.ResourceData, field string, b string) string { 47 | var v interface{} 48 | var ok bool 49 | if v, ok = getOkExists(d, field); !ok { 50 | return b 51 | } 52 | return v.(string) 53 | } 54 | 55 | // replaceEmptyBool is a helper function to replace empty string fields with 56 | // another field. 57 | func replaceEmptyBool(d *schema.ResourceData, field string, b bool) bool { 58 | var v interface{} 59 | var ok bool 60 | if v, ok = getOkExists(d, field); !ok { 61 | return b 62 | } 63 | return v.(bool) 64 | } 65 | 66 | func billingProjectExpandExtCertificationV1(raw interface{}) *projects.ExtCertification { 67 | v, ok := raw.([]interface{}) 68 | if !ok { 69 | return nil 70 | } 71 | 72 | for _, v := range v { 73 | v, ok := v.(map[string]interface{}) 74 | if !ok { 75 | return nil 76 | } 77 | extCertification := &projects.ExtCertification{} 78 | if v, ok := v["c5"].(bool); ok { 79 | extCertification.C5 = v 80 | } 81 | if v, ok := v["iso"].(bool); ok { 82 | extCertification.ISO = v 83 | } 84 | if v, ok := v["pci"].(bool); ok { 85 | extCertification.PCI = v 86 | } 87 | if v, ok := v["soc1"].(bool); ok { 88 | extCertification.SOC1 = v 89 | } 90 | if v, ok := v["soc2"].(bool); ok { 91 | extCertification.SOC2 = v 92 | } 93 | if v, ok := v["SOX"].(bool); ok { 94 | extCertification.SOX = v 95 | } 96 | //nolint:staticcheck // we need the first element 97 | return extCertification 98 | } 99 | 100 | return nil 101 | } 102 | 103 | func billingProjectFlattenExtCertificationV1(extCertification *projects.ExtCertification) []map[string]interface{} { 104 | if extCertification == nil { 105 | return nil 106 | } 107 | 108 | return []map[string]interface{}{{ 109 | "c5": extCertification.C5, 110 | "iso": extCertification.ISO, 111 | "pci": extCertification.PCI, 112 | "soc1": extCertification.SOC1, 113 | "soc2": extCertification.SOC2, 114 | "sox": extCertification.SOX, 115 | }} 116 | } 117 | -------------------------------------------------------------------------------- /scripts/changelog-links.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to 4 | # be Markdown links to the given github issues. 5 | # 6 | # This is run during releases so that the issue references in all of the 7 | # released items are presented as clickable links, but we can just use the 8 | # easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section 9 | # while merging things between releases. 10 | 11 | set -e 12 | 13 | if [[ ! -f CHANGELOG.md ]]; then 14 | echo "ERROR: CHANGELOG.md not found in pwd." 15 | echo "Please run this from the root of the terraform provider repository" 16 | exit 1 17 | fi 18 | 19 | if [[ `uname` == "Darwin" ]]; then 20 | echo "Using BSD sed" 21 | SED="sed -i.bak -E -e" 22 | else 23 | echo "Using GNU sed" 24 | SED="sed -i.bak -r -e" 25 | fi 26 | 27 | PROVIDER_URL="https:\/\/github.com\/SAP-cloud-infrastructure\/terraform-provider-sci\/issues" 28 | 29 | $SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md 30 | 31 | rm CHANGELOG.md.bak 32 | -------------------------------------------------------------------------------- /scripts/errcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check gofmt 4 | echo "==> Checking for unchecked errors..." 5 | 6 | if ! which errcheck > /dev/null; then 7 | echo "==> Installing errcheck..." 8 | go get -u github.com/kisielk/errcheck 9 | fi 10 | 11 | err_files=$(errcheck -ignoretests \ 12 | -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \ 13 | -ignore 'bytes:.*' \ 14 | -ignore 'io:Close|Write' \ 15 | $(go list ./...)) 16 | 17 | if [[ -n ${err_files} ]]; then 18 | echo 'Unchecked errors found in the following places:' 19 | echo "${err_files}" 20 | echo "Please handle returned errors. You can check directly with \`make errcheck\`" 21 | exit 1 22 | fi 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /scripts/gofmtcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check gofmt 4 | echo "==> Checking that code complies with gofmt requirements..." 5 | gofmt_files=$(gofmt -l `find . -name '*.go'`) 6 | if [[ -n ${gofmt_files} ]]; then 7 | echo 'gofmt needs running on the following files:' 8 | echo "${gofmt_files}" 9 | echo "You can use the command: \`make fmt\` to reformat code." 10 | exit 1 11 | fi 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /scripts/gogetcookie.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch ~/.gitcookies 4 | chmod 0600 ~/.gitcookies 5 | 6 | git config --global http.cookiefile ~/.gitcookies 7 | 8 | tr , \\t <<\__END__ >>~/.gitcookies 9 | .googlesource.com,TRUE,/,TRUE,2147483647,o,git-paul.hashicorp.com=1/z7s05EYPudQ9qoe6dMVfmAVwgZopEkZBb1a2mA5QtHE 10 | __END__ 11 | -------------------------------------------------------------------------------- /terraform-registry-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "metadata": { 4 | "protocol_versions": ["5.0"] 5 | } 6 | } 7 | --------------------------------------------------------------------------------