├── .changelog ├── 0.1.0.toml ├── 0.10.0.toml ├── 0.2.0.toml ├── 0.3.0.toml ├── 0.4.0.toml ├── 0.5.0.toml ├── 0.6.0.toml ├── 0.7.0.toml ├── 0.8.0.toml └── 0.9.0.toml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── feature_request.yaml │ └── release_checklist.md ├── dependabot.yml └── workflows │ ├── acceptance.yml │ ├── build-test.yml │ └── release.yml ├── .gitignore ├── .goreleaser.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── docs ├── data-sources │ ├── oxide_anti_affinity_group.md │ ├── oxide_floating_ip.md │ ├── oxide_image.md │ ├── oxide_images.md │ ├── oxide_instance_external_ips.md │ ├── oxide_ip_pool.md │ ├── oxide_project.md │ ├── oxide_projects.md │ ├── oxide_silo.md │ ├── oxide_ssh_key.md │ ├── oxide_vpc.md │ ├── oxide_vpc_internet_gateway.md │ ├── oxide_vpc_router.md │ ├── oxide_vpc_router_route.md │ └── oxide_vpc_subnet.md ├── index.md └── resources │ ├── oxide_anti_affinity_group.md │ ├── oxide_disk.md │ ├── oxide_floating_ip.md │ ├── oxide_image.md │ ├── oxide_instance.md │ ├── oxide_ip_pool.md │ ├── oxide_ip_pool_silo_link.md │ ├── oxide_project.md │ ├── oxide_silo.md │ ├── oxide_snapshot.md │ ├── oxide_ssh_key.md │ ├── oxide_vpc.md │ ├── oxide_vpc_firewall_rules.md │ ├── oxide_vpc_internet_gateway.md │ ├── oxide_vpc_router.md │ ├── oxide_vpc_router_route.md │ └── oxide_vpc_subnet.md ├── examples ├── demo │ ├── README.md │ ├── demo.tf │ └── variables.tf ├── disk_resource │ ├── README.md │ └── disk.tf ├── instance_resource │ ├── README.md │ ├── init.sh │ └── instance.tf └── vpc_resource │ ├── README.md │ └── vpc.tf ├── go.mod ├── go.sum ├── golangci.yaml ├── internal └── provider │ ├── data_source_anti_affinity_group.go │ ├── data_source_anti_affinity_group_test.go │ ├── data_source_floating_ip.go │ ├── data_source_floating_ip_test.go │ ├── data_source_image.go │ ├── data_source_image_test.go │ ├── data_source_images.go │ ├── data_source_images_test.go │ ├── data_source_instance_external_ips.go │ ├── data_source_instance_external_ips_test.go │ ├── data_source_ip_pool.go │ ├── data_source_ip_pool_test.go │ ├── data_source_project.go │ ├── data_source_project_test.go │ ├── data_source_projects.go │ ├── data_source_projects_test.go │ ├── data_source_silo.go │ ├── data_source_silo_test.go │ ├── data_source_ssh_key.go │ ├── data_source_ssh_key_test.go │ ├── data_source_vpc.go │ ├── data_source_vpc_internet_gateway.go │ ├── data_source_vpc_internet_gateway_test.go │ ├── data_source_vpc_router.go │ ├── data_source_vpc_router_route.go │ ├── data_source_vpc_router_route_test.go │ ├── data_source_vpc_router_test.go │ ├── data_source_vpc_subnet.go │ ├── data_source_vpc_subnet_test.go │ ├── data_source_vpc_test.go │ ├── planmodifiers.go │ ├── provider.go │ ├── resource_anti_affinity_group.go │ ├── resource_anti_affinity_group_test.go │ ├── resource_disk.go │ ├── resource_disk_test.go │ ├── resource_floating_ip.go │ ├── resource_floating_ip_test.go │ ├── resource_image.go │ ├── resource_image_test.go │ ├── resource_instance.go │ ├── resource_instance_test.go │ ├── resource_ip_pool.go │ ├── resource_ip_pool_silo_link.go │ ├── resource_ip_pool_silo_link_test.go │ ├── resource_ip_pool_test.go │ ├── resource_project.go │ ├── resource_project_test.go │ ├── resource_silo.go │ ├── resource_silo_test.go │ ├── resource_snapshot.go │ ├── resource_snapshot_test.go │ ├── resource_ssh_key.go │ ├── resource_ssh_key_test.go │ ├── resource_vpc.go │ ├── resource_vpc_firewall_rules.go │ ├── resource_vpc_firewall_rules_test.go │ ├── resource_vpc_internet_gateway.go │ ├── resource_vpc_internet_gateway_test.go │ ├── resource_vpc_router.go │ ├── resource_vpc_router_route.go │ ├── resource_vpc_router_route_test.go │ ├── resource_vpc_router_test.go │ ├── resource_vpc_subnet.go │ ├── resource_vpc_subnet_test.go │ ├── resource_vpc_test.go │ ├── testutils.go │ ├── testutils_test.go │ ├── utils.go │ ├── utils_test.go │ └── version.go ├── main.go └── terraform-registry-manifest.json /.changelog/0.1.0.toml: -------------------------------------------------------------------------------- 1 | [[features]] 2 | title = "New resource" 3 | description = "`oxide_ssh_key` [#211](https://github.com/oxidecomputer/terraform-provider-oxide/pull/211)" 4 | 5 | [[features]] 6 | title = "New data source" 7 | description = "`oxide_ssh_key` [#211](https://github.com/oxidecomputer/terraform-provider-oxide/pull/211)" 8 | 9 | [[enhancements]] 10 | title = "Documentation" 11 | description = "Various documentation clarifications [#185](https://github.com/oxidecomputer/terraform-provider-oxide/pull/185), [#218](https://github.com/oxidecomputer/terraform-provider-oxide/pull/218)" 12 | 13 | [[features]] 14 | title = "New resource" 15 | description = "`oxide_vpc_firewall_rules` [#220](https://github.com/oxidecomputer/terraform-provider-oxide/pull/220)" 16 | 17 | [[breaking]] 18 | title = "Image resource" 19 | description = "Image creation via URL is no longer supported [#228](https://github.com/oxidecomputer/terraform-provider-oxide/pull/228)" 20 | 21 | [[enhancements]] 22 | title = "Image resource" 23 | description = "Deletes are now supported [#228](https://github.com/oxidecomputer/terraform-provider-oxide/pull/228)" 24 | 25 | [[enhancements]] 26 | title = "VPC and project resources" 27 | description = "System created default VPCs and subnets are now removed automatically when deleting a VPC or project [#229](https://github.com/oxidecomputer/terraform-provider-oxide/pull/229)" 28 | 29 | [[breaking]] 30 | title = "Instance resource" 31 | description = "Support floating IPs as external IP addresses provided to the instance. The `ip_pool_name` attribute within the `external_ips` block has been modified to `name`. [#230](https://github.com/oxidecomputer/terraform-provider-oxide/pull/230)" 32 | 33 | [[breaking]] 34 | title = "Image data sources" 35 | description = "All image data sources no longer retrieve an image source URL [#234](https://github.com/oxidecomputer/terraform-provider-oxide/pull/234)" -------------------------------------------------------------------------------- /.changelog/0.10.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "Minimum Terraform version required" 3 | description = "`oxide_silo` [#425](https://github.com/oxidecomputer/terraform-provider-oxide/pull/425). Breaking change due to `tls_certificates` attribute being a 4 | [write-only attribute](https://developer.hashicorp.com/terraform/plugin/framework/resources/write-only-arguments)." 5 | 6 | [[features]] 7 | title = "New resource" 8 | description = "`oxide_silo` [#425](https://github.com/oxidecomputer/terraform-provider-oxide/pull/425)." 9 | 10 | title = "New data resource" 11 | description = "`oxide_vpc_router_route` [#423](https://github.com/oxidecomputer/terraform-provider-oxide/pull/423)." 12 | 13 | [[enhancements]] 14 | title = "" 15 | description = "" 16 | 17 | [[bugs]] 18 | title = "" 19 | description = "" 20 | -------------------------------------------------------------------------------- /.changelog/0.2.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "`oxide_instance` resource" 3 | description = "The `name` field in `external_ips` for the `oxide_instance` resource has been replaced with `id`. This ensures correctness, and helps avoid unintenional drift if the IP pool's name were to change outside the scope of terraform. [#263](https://github.com/oxidecomputer/terraform-provider-oxide/pull/263)" 4 | 5 | [[features]] 6 | title = "New data source" 7 | description = "`oxide_ip_pool` [#263](https://github.com/oxidecomputer/terraform-provider-oxide/pull/263)" 8 | 9 | [[breaking]] 10 | title = "`oxide_instance` resource" 11 | description = "A new optional `ssh_public_keys` field has been added to the `oxide_instance` resource. It is an allowlist of IDs of the saved SSH public keys to be transferred to the instance via cloud-init during instance creation. Saved SSH keys will no longer be automatically added to the instances [#269](https://github.com/oxidecomputer/terraform-provider-oxide/pull/269)" -------------------------------------------------------------------------------- /.changelog/0.3.0.toml: -------------------------------------------------------------------------------- 1 | [[enhancements]] 2 | title = "Documentation" 3 | description = "Clarification about retrieving silo images [#288](https://github.com/oxidecomputer/terraform-provider-oxide/pull/288)" -------------------------------------------------------------------------------- /.changelog/0.4.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "`oxide_vpc_firewall_rules` resource" 3 | description = "Setting an empty array for `filters.hosts`, `filters.ports` and `filters.protocols` is no longer supported. To omit they must be unset. [#322](https://github.com/oxidecomputer/terraform-provider-oxide/pull/322)" 4 | 5 | [[features]] 6 | title = "New resource" 7 | description = "`oxide_ip_pool` [#337](https://github.com/oxidecomputer/terraform-provider-oxide/pull/337)" -------------------------------------------------------------------------------- /.changelog/0.5.0.toml: -------------------------------------------------------------------------------- 1 | [[features]] 2 | title = "New resource" 3 | description = "`oxide_ip_pool_silo_link` [#345](https://github.com/oxidecomputer/terraform-provider-oxide/pull/345)." 4 | 5 | [[features]] 6 | title = "New datasource" 7 | description = "`oxide_silo` [#347](https://github.com/oxidecomputer/terraform-provider-oxide/pull/347)." 8 | 9 | [[features]] 10 | title = "New instance attribute" 11 | description = "It is now possible to specify a boot disk by setting `boot_disk_id` [#352](https://github.com/oxidecomputer/terraform-provider-oxide/pull/352)." 12 | 13 | [[enhancements]] 14 | title = "Instance resource" 15 | description = "Disk attachments no longer require resource replacement [#352](https://github.com/oxidecomputer/terraform-provider-oxide/pull/352)." 16 | -------------------------------------------------------------------------------- /.changelog/0.6.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "" 3 | description = "" 4 | 5 | [[features]] 6 | title = "" 7 | description = "" 8 | 9 | [[enhancements]] 10 | title = "Instance resource" 11 | description = "Updates to `Memory` and `NCPUs` no longer require resource replace [#370](https://github.com/oxidecomputer/terraform-provider-oxide/pull/370)." 12 | 13 | [[bugs]] 14 | title = "" 15 | description = "" -------------------------------------------------------------------------------- /.changelog/0.7.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "" 3 | description = "" 4 | 5 | [[features]] 6 | title = "Profile attribute in provider block" 7 | description = "Allows authentication via an authenticated `profile` in `credentials.toml` [#383](https://github.com/oxidecomputer/terraform-provider-oxide/pull/383)." 8 | 9 | [[features]] 10 | title = "New resource" 11 | description = "`oxide_vpc_router` [#388](https://github.com/oxidecomputer/terraform-provider-oxide/pull/388)." 12 | 13 | [[features]] 14 | title = "New datasource" 15 | description = "`oxide_vpc_router` [#388](https://github.com/oxidecomputer/terraform-provider-oxide/pull/388)." 16 | 17 | [[features]] 18 | title = "New resource" 19 | description = "`oxide_vpc_internet_gateway` [#389](https://github.com/oxidecomputer/terraform-provider-oxide/pull/389)." 20 | 21 | [[features]] 22 | title = "New datasource" 23 | description = "`oxide_vpc_internet_gateway` [#389](https://github.com/oxidecomputer/terraform-provider-oxide/pull/389)." 24 | 25 | [[enhancements]] 26 | title = "" 27 | description = "" 28 | 29 | [[bugs]] 30 | title = "" 31 | description = "" 32 | -------------------------------------------------------------------------------- /.changelog/0.8.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "" 3 | description = "" 4 | 5 | [[features]] 6 | title = "New instance argument" 7 | description = "It is now possible to manage anti-affinity group assigments on instance resources. [#414](https://github.com/oxidecomputer/terraform-provider-oxide/pull/414)." 8 | 9 | [[features]] 10 | title = "New resource" 11 | description = "`oxide_anti_affinity_group` [#415](https://github.com/oxidecomputer/terraform-provider-oxide/pull/415)." 12 | 13 | [[features]] 14 | title = "New data source" 15 | description = "`oxide_anti_affinity_group` [#415](https://github.com/oxidecomputer/terraform-provider-oxide/pull/415)." 16 | 17 | [[enhancements]] 18 | title = "" 19 | description = "" 20 | 21 | [[bugs]] 22 | title = "" 23 | description = "" -------------------------------------------------------------------------------- /.changelog/0.9.0.toml: -------------------------------------------------------------------------------- 1 | [[breaking]] 2 | title = "" 3 | description = "" 4 | 5 | [[features]] 6 | title = "New resource" 7 | description = "`oxide_floating_ip` [#427](https://github.com/oxidecomputer/terraform-provider-oxide/pull/427)." 8 | 9 | [[features]] 10 | title = "New data resource" 11 | description = "`oxide_floating_ip` [#427](https://github.com/oxidecomputer/terraform-provider-oxide/pull/427)." 12 | 13 | [[enhancements]] 14 | title = "" 15 | description = "" 16 | 17 | [[bugs]] 18 | title = "" 19 | description = "" 20 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @karencfv @sudomateo 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Let us know about unexpected behaviour when using the Oxide Terraform Provider 3 | labels: ["bug"] 4 | body: 5 | - type: checkboxes 6 | id: preliminary 7 | attributes: 8 | label: Preliminary checks 9 | description: Please verify the following. 10 | options: 11 | - label: I am using the latest version, or the latest version that corresponds to my Oxide installation. 12 | - label: There is no open issue that reports the same problem. 13 | validations: 14 | required: true 15 | 16 | - type: textarea 17 | id: expected 18 | attributes: 19 | label: What was the expected behaviour 20 | validations: 21 | required: true 22 | 23 | - type: textarea 24 | id: problem 25 | attributes: 26 | label: What is the current behaviour and what actions did you take to get there 27 | description: Please provide as much background as you can. 28 | validations: 29 | required: true 30 | 31 | - type: input 32 | id: oxide-version 33 | attributes: 34 | label: Provider version 35 | description: The version of the Oxide Terraform Provider you are using. 36 | validations: 37 | required: true 38 | 39 | - type: input 40 | id: terraform-version 41 | attributes: 42 | label: Terraform version 43 | description: The version of Terraform you are using. 44 | validations: 45 | required: true 46 | 47 | - type: input 48 | id: os 49 | attributes: 50 | label: Operating system 51 | description: What operating system are you using. 52 | validations: 53 | required: true 54 | 55 | - type: textarea 56 | id: additional 57 | attributes: 58 | label: Anything else you would like to add? 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Let us know about something you'd like to see as part of the Oxide Terraform provider 3 | labels: ["feature"] 4 | body: 5 | - type: textarea 6 | id: overview 7 | attributes: 8 | label: Overview 9 | description: What is it that you would like to be able to do with this feature? 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | id: implementation 15 | attributes: 16 | label: Implementation details 17 | description: Optionally provide an idea of how you'd like this feature to be implemented. 18 | 19 | - type: textarea 20 | id: additional 21 | attributes: 22 | label: Anything else you would like to add? 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/release_checklist.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release checklist 3 | about: Steps to take when releasing a new version (only for Oxide release team). 4 | labels: release 5 | 6 | --- 7 | 8 | ## Release checklist 9 | 14 | - [ ] Make sure all examples and docs reference the new provider version. 15 | - [ ] Make sure the [VERSION](https://github.com/oxidecomputer/terraform-provider-oxide/blob/main/VERSION) and [internal/provider/version.go](https://github.com/oxidecomputer/terraform-provider-oxide/blob/main/oxide/version.go) files have the new version you want to release. 16 | - [ ] Make sure the `oxide` SDK dependency is up to date with the latest release. 17 | - [ ] Generate changelog by running `make changelog` and add date of the release to the title. 18 | - [ ] Release the new version draft by running `make tag`. 19 | - [ ] Verify the release is correct, it's being created from the correct tag on GitHub, and make the release live. Note: Terraform registry will silently fail to publish if the tag is incorrect, and GitHub has a habit of messing up the tag a release is created from on occasion. 20 | - [ ] Verify the release is available on the Terraform provider registry. 21 | - [ ] If this is not a minor patch, create a new branch with the current version 22 | - [ ] Update to upcoming version in [VERSION](https://github.com/oxidecomputer/terraform-provider-oxide/blob/main/VERSION), [internal/provider/version.go](https://github.com/oxidecomputer/terraform-provider-oxide/blob/main/oxide/version.go), and 23 | create new changelog tracker file in [.changelog/](https://github.com/oxidecomputer/terraform-provider-oxide/blob/main/changelog/) for the relevant branches. -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "github-actions" # See documentation for possible values 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "weekly" 16 | -------------------------------------------------------------------------------- /.github/workflows/acceptance.yml: -------------------------------------------------------------------------------- 1 | name: acceptance 2 | on: 3 | release: 4 | types: [published, unpublished, edited] 5 | jobs: 6 | acceptance: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - uses: hashicorp/setup-terraform@v3 11 | - uses: actions/setup-go@v5 12 | with: 13 | go-version-file: 'go.mod' 14 | - name: test 15 | shell: bash 16 | run: | 17 | make testacc 18 | env: 19 | OXIDE_TOKEN: ${{ secrets.COLO_OXIDE_TOKEN }} 20 | OXIDE_HOST: ${{ secrets.COLO_OXIDE_HOST }} 21 | TEST_ACC_NAME: TestAccCloud -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: build & test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - '[0-9].[0-9]+' 7 | paths: 8 | - "**.go" 9 | - .github/workflows/build-test.yml 10 | - "go.mod" 11 | - "go.sum" 12 | - "docs/**" 13 | - "examples/**" 14 | pull_request: 15 | branches: 16 | - main 17 | - '[0-9].[0-9]+' 18 | jobs: 19 | build-test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions/setup-go@v5 24 | with: 25 | go-version-file: 'go.mod' 26 | - name: build 27 | run: make build 28 | - name: test 29 | run: make test 30 | - name: lint 31 | run: sudo make lint 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action can publish assets for release when a tag is created. 2 | # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # This uses an action (crazy-max/ghaction-import-gpg) that assumes you set your 5 | # private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` 6 | # secret. If you would rather own your own GPG handling, please fork this action 7 | # or use an alternative one for key handling. 8 | name: Release 9 | on: 10 | push: 11 | tags: 12 | - 'v*' 13 | permissions: 14 | contents: write 15 | jobs: 16 | goreleaser: 17 | runs-on: ubuntu-latest 18 | environment: release 19 | steps: 20 | - 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 | uses: crazy-max/ghaction-import-gpg@v6 35 | id: import_gpg 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.3.0 42 | with: 43 | distribution: goreleaser 44 | version: "~> v2" 45 | args: release --clean 46 | env: 47 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 48 | # GitHub sets this automatically 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform/ 2 | .terraform.lock.hcl 3 | terraform.tfstate 4 | terraform.tfstate.backup 5 | bin/ 6 | tf/ 7 | .crates.toml 8 | .crates2.json -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | # Visit https://goreleaser.com for documentation on how to customize this 3 | # behavior. 4 | before: 5 | hooks: 6 | - go mod tidy 7 | builds: 8 | - env: 9 | # goreleaser does not work with CGO 10 | - CGO_ENABLED=0 11 | mod_timestamp: '{{ .CommitTimestamp }}' 12 | flags: 13 | - -trimpath 14 | ldflags: 15 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 16 | goos: 17 | - freebsd 18 | - windows 19 | - linux 20 | - darwin 21 | - solaris 22 | goarch: 23 | - amd64 24 | - '386' 25 | - arm 26 | - arm64 27 | ignore: 28 | - goos: darwin 29 | goarch: '386' 30 | - goos: solaris 31 | goarch: '386' 32 | binary: '{{ .ProjectName }}_v{{ .Version }}' 33 | archives: 34 | - formats: [ 'zip' ] 35 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 36 | checksum: 37 | extra_files: 38 | - glob: 'terraform-registry-manifest.json' 39 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 40 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 41 | algorithm: sha256 42 | signs: 43 | - artifacts: checksum 44 | args: 45 | # To use this in a GitHub action or some other automated pipeline, you 46 | # need to pass the batch flag to indicate its not interactive. 47 | - "--batch" 48 | - "--local-user" 49 | - "{{ .Env.GPG_FINGERPRINT }}" 50 | - "--output" 51 | - "${signature}" 52 | - "--detach-sign" 53 | - "${artifact}" 54 | release: 55 | extra_files: 56 | - glob: 'terraform-registry-manifest.json' 57 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 58 | # To manually examine the release before its live, uncomment this line: 59 | draft: true 60 | changelog: 61 | disable: true 62 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Requirements 4 | 5 | - [Terraform](https://www.terraform.io/downloads) 1.x and above, we recommend using the latest stable release whenever possible. When installing on an Illumos machine use the Solaris binary. 6 | - [Go](https://go.dev/dl/) 1.20.x and above (to build the provider plugin) 7 | 8 | ## Building the provider 9 | 10 | There are two make targets to build the provider. 11 | 12 | `make install` will build the binary in the `./bin` directory in the root of this repository, and install the provider in your local Terraform plugins directory. Using this target will enable you to use the provider you've just built with your own Terraform configuration files. 13 | 14 | There is a caveat when installing with an Apple M1 computer. When building the same version with changes you will have to manually delete the previous binary, or change the version in the Makefile. 15 | 16 | `make build` will only build the binary in the `./bin` directory. Terraform will not know to look for the provider there, and will not work with Terraform configuration files. 17 | 18 | ### Building with local SDK changes or other versions 19 | 20 | To use the Terraform provider with a local `oxide.go` Go SDK run `make local-api`. 21 | This target assumes both the `oxide.go` and `terraform-provider-oxide` repositories 22 | are checked out to adjacent directories (e.g., share the same parent directory). 23 | 24 | ``` 25 | . 26 | ├── oxide.go 27 | └── terraform-provider-oxide 28 | ``` 29 | 30 | To undo those changes run `make unset-local-api`. 31 | 32 | To use a specific version of the Go SDK run `SDK_V={GIT_HASH|VERSION} make sdk-version`. 33 | 34 | ## Using the provider 35 | 36 | To try out the provider you'll need to follow these steps: 37 | 38 | - Make sure you've installed the provider using `make install`. 39 | - Set the `$OXIDE_HOST` and `$OXIDE_TOKEN` environment variables. If you do not wish to use these variables, you have the option to set the host and token directly on the provider block. For security reasons this approach is not recommended. 40 | ```hcl 41 | provider "oxide" { 42 | host = "" 43 | token = "" 44 | } 45 | ``` 46 | - Pick an example From the `examples/` directory and cd into it, or create your own Terraform configuration file. You can change the values of the fields of the example files to work with your environment. 47 | - If you want to try out your local changes, make sure you set the version to the one you just built. This will generally be the current version with "-dev" appended (e.g. `version = "0.1.0-beta-dev"`). 48 | - Run `terraform init` and `terraform apply` from within the chosen example directory. This will create resources or read data sources based on a Terraform configuration file. 49 | - To remove all created resources run `terraform destroy`. 50 | 51 | To try out the demo configuration file, use the [examples/demo/](./examples/demo/) directory. 52 | 53 | When trying out the same example with a provider you've recently built with changes, make sure to remove all the files from the example Terraform generated first. 54 | 55 | ## Running the linters 56 | 57 | There is a make target to run the linters. All that's needed is `make lint`. 58 | 59 | ## Running acceptance tests 60 | 61 | To run the acceptance testing suite, you need to make sure to have either the `$OXIDE_HOST` and `$OXIDE_TOKEN` environment variables, or `$OXIDE_TEST_HOST` and `$OXIDE_TEST_TOKEN`. If you wish to use the later for a testing environment, make sure you have unset the previous first. 62 | 63 | Until all resources have been added you'll need to make sure your testing environment has the following: 64 | 65 | - A project named "tf-acc-test". 66 | - At least one image. 67 | 68 | Run `make testacc`. 69 | 70 | Eventually we'll have a GitHub action to create a Nexus server and run these tests, but for now testing will have to be run manually. 71 | 72 | ## Releasing a new version 73 | 74 | Remember to update the changelog before releasing. 75 | 76 | There is a Github action that takes care of creating the artifacts and publishing to the terraform registry. 77 | 78 | To trigger the process create a tag from the local main branch and push to Github. 79 | 80 | ```console 81 | $ git tag v0.1.0 82 | $ git push origin v0.1.0 83 | ``` 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Provider Oxide 2 | 3 | ## Requirements 4 | 5 | - [Terraform](https://www.terraform.io/downloads) 1.11.x and above, we recommend using the latest stable release whenever possible. When installing on an Illumos machine use the Solaris binary. 6 | 7 | ## Using the provider 8 | 9 | As a preferred method of authentication, export the `OXIDE_HOST` and `OXIDE_TOKEN` environment variables with their corresponding values. 10 | 11 | Alternatively, it is possible to authenticate via the optional `host` and `token` arguments. In most cases this method of authentication is not recommended. It is generally preferable to keep credential information out of the configuration. 12 | 13 | To generate a token, follow these steps: 14 | 15 | - Make sure you have installed the Oxide CLI 16 | - Log in via the Oxide console. 17 | - Run `oxide auth login --host ` 18 | - Retrieve the token associated with the host from `$HOME/.config/oxide/credentials.toml`. 19 | 20 | ### Example 21 | 22 | ```hcl 23 | terraform { 24 | required_version = ">= 1.0" 25 | 26 | required_providers { 27 | oxide = { 28 | source = "oxidecomputer/oxide" 29 | version = "0.9.0" 30 | } 31 | } 32 | } 33 | 34 | provider "oxide" { 35 | # The provider will default to use $OXIDE_HOST and $OXIDE_TOKEN. 36 | # If necessary they can be set explicitly (not recommended). 37 | # host = "" 38 | # token = "" 39 | } 40 | 41 | # Create a blank disk 42 | resource "oxide_disk" "example" { 43 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 44 | description = "a test disk" 45 | name = "mydisk" 46 | size = 1073741824 47 | block_size = 512 48 | } 49 | ``` 50 | 51 | There are several examples in the [examples/](./examples/) directory. 52 | 53 | ## Development guides and contributing information 54 | 55 | Read [CONTRIBUTING.md](./CONTRIBUTING.md) to learn more. 56 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.10.0-dev 2 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_anti_affinity_group.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_anti_affinity_group Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_anti_affinity_group (Data Source) 6 | 7 | Retrieve information about a specified anti-affinity group. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_anti_affinity_group" "example" { 13 | project_name = "my-project" 14 | name = "my-group" 15 | timeouts = { 16 | read = "1m" 17 | } 18 | } 19 | ``` 20 | 21 | ## Schema 22 | 23 | ### Required 24 | 25 | - `name` (String) Name of the anti-affinity group. 26 | - `project_name` (String) Name of the project that contains the anti-affinity group. 27 | 28 | ### Optional 29 | 30 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 31 | 32 | ### Read-Only 33 | 34 | - `description` (String) Description of the anti-affinity group. 35 | - `failure_domain` (String) Describes the scope of affinity for the purposes of co-location. 36 | - `id` (String) Unique, immutable, system-controlled identifier for the anti-affinity group. 37 | - `policy` (String) Affinity policy used to describe what to do when a request cannot be satisfied. 38 | - `project_id` (String) ID of the project that contains the anti-affinity group. 39 | - `time_created` (String) Timestamp of when this anti-affinity group was created. 40 | - `time_modified` (String) Timestamp of when this anti-affinity group was last modified. 41 | 42 | 43 | 44 | ### Nested Schema for `timeouts` 45 | 46 | Optional: 47 | 48 | - `read` (String, Default `10m`) 49 | 50 | 51 | 52 | ### Nested Schema for `digest` 53 | 54 | Read-Only: 55 | 56 | - `type` (String) Digest type. 57 | - `value` (String) Digest type value. 58 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_floating_ip.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_floating_ip Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_floating_ip (Data Source) 6 | 7 | Retrieve information about a specified floating IP. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_floating_ip" "example" { 13 | project_name = "my-project" 14 | name = "app-ingress" 15 | } 16 | ``` 17 | 18 | ## Schema 19 | 20 | ### Required 21 | 22 | - `name` (String) Name of the floating IP. 23 | - `project_name` (String) Name of the project that contains the floating IP. 24 | 25 | ### Optional 26 | 27 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 28 | 29 | ### Read-Only 30 | 31 | - `id` (String) Unique, immutable, system-controlled identifier for the floating IP. 32 | - `description` (String) Description for the floating IP. 33 | - `ip` (String) IP address for this floating IP. 34 | - `ip_pool_id` (String) ID of the IP pool where the floating IP was allocated from. 35 | - `instance_id` (String) Instance ID that this floating IP is attached to, if presently attached. 36 | - `time_created` (String) Timestamp of when the floating IP was created. 37 | - `time_modified` (String) Timestamp of when the floating IP was modified. 38 | - `timeouts` (Attribute, Optional) Timeouts for performing API operations. See [below for nested schema](#nestedatt--timeouts). 39 | 40 | 41 | 42 | ### Nested Schema for `timeouts` 43 | 44 | Optional: 45 | 46 | - `read` (String, Default `10m`) 47 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_image.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_image Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_image (Data Source) 6 | 7 | Retrieve information about a specified image. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_image" "example" { 13 | project_name = "my-project" 14 | name = "my-image" 15 | timeouts = { 16 | read = "1m" 17 | } 18 | } 19 | ``` 20 | 21 | ## Schema 22 | 23 | ### Required 24 | 25 | - `name` (String) Name of the image. 26 | 27 | ### Optional 28 | 29 | - `project_name` (String) Name of the project that contains the image. Necessary if the image visibility is scoped to a single project. 30 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 31 | 32 | ### Read-Only 33 | 34 | - `block_size` (Number) Block size in bytes. 35 | - `description` (String) Description of the image. 36 | - `digest` (Object) Hash of the image contents, if applicable (see [below for nested schema](#nestedobject--digest)). 37 | - `id` (String) Unique, immutable, system-controlled identifier for the image. 38 | - `os` (String) OS image distribution. 39 | - `project_id` (String) ID of the project that contains the image. 40 | - `size` (Number) Size of the image in bytes. 41 | - `time_created` (String) Timestamp of when this image was created. 42 | - `time_modified` (String) Timestamp of when this image was last modified. 43 | - `version` (String) Version of the OS. 44 | 45 | 46 | 47 | ### Nested Schema for `timeouts` 48 | 49 | Optional: 50 | 51 | - `read` (String, Default `10m`) 52 | 53 | 54 | 55 | ### Nested Schema for `digest` 56 | 57 | Read-Only: 58 | 59 | - `type` (String) Digest type. 60 | - `value` (String) Digest type value. 61 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_images.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_images Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_images (Data Source) 6 | 7 | Retrieve a list of all images belonging to a silo or project. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_images" "example" {} 13 | ``` 14 | 15 | ## Schema 16 | 17 | ### Optional 18 | 19 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 20 | - `project_id` (String) ID of the project that contains the images. 21 | 22 | ### Read-Only 23 | 24 | - `images` (List of Object) A list of all global images (see [below for nested schema](#nestedatt--images)) 25 | - `id` (String) The ID of this resource. 26 | 27 | 28 | 29 | ### Nested Schema for `timeouts` 30 | 31 | Optional: 32 | 33 | - `read` (String, Default `10m`) 34 | 35 | 36 | 37 | ### Nested Schema for `images` 38 | 39 | Read-Only: 40 | 41 | - `block_size` (Number) Block size in bytes. 42 | - `description` (String) Description of the image. 43 | - `digest` (Object) Hash of the image contents, if applicable (see [below for nested schema](#nestedobject--digest)). 44 | - `os` (String) OS image distribution. 45 | - `id` (String) Unique, immutable, system-controlled identifier for the image. 46 | - `name` (String) Name of the image. 47 | - `size` (Number) Size of the image in bytes. 48 | - `time_created` (String) Timestamp of when this image was created. 49 | - `time_modified` (String) Timestamp of when this image was last modified. 50 | - `version` (String) Version of the OS. 51 | 52 | ### Nested Schema for `digest` 53 | 54 | Read-Only: 55 | 56 | - `type` (String) Digest type. 57 | - `value` (String) Digest type value. 58 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_instance_external_ips.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_instance_external_ips Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_instance_external_ips (Data Source) 6 | 7 | Retrieve information of all external IPs associated to an instance. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_instance_external_ips" "example" { 13 | instance_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | } 15 | ``` 16 | 17 | ## Schema 18 | 19 | ### Required 20 | 21 | - `instance_id` (String) ID of the instance to which the external IPs belong to. 22 | 23 | ### Optional 24 | 25 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 26 | 27 | ### Read-Only 28 | 29 | - `external_ips` (List of Object) A list of all external IPs (see [below for nested schema](#nestedatt--images)) 30 | - `id` (String) The ID of this resource. 31 | 32 | 33 | 34 | ### Nested Schema for `timeouts` 35 | 36 | Optional: 37 | 38 | - `read` (String, Default `10m`) 39 | 40 | 41 | 42 | ### Nested Schema for `images` 43 | 44 | Read-Only: 45 | 46 | - `ip` (String) External IP address. 47 | - `kind` (String) Kind of external IP address. 48 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_ip_pool.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_ip_pool Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_ip_pool (Data Source) 6 | 7 | Retrieve information about a specified IP pool. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_ip_pool" "example" { 13 | name = "default" 14 | timeouts = { 15 | read = "1m" 16 | } 17 | } 18 | ``` 19 | 20 | ## Schema 21 | 22 | ### Required 23 | 24 | - `name` (String) Name of the IP pool. 25 | 26 | ### Optional 27 | 28 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 29 | 30 | ### Read-Only 31 | 32 | - `description` (String) Description for the IP pool. 33 | - `id` (String) Unique, immutable, system-controlled identifier of the IP pool. 34 | - `is_default` (Bool) If a pool is the default for a silo, floating IPs and instance ephemeral IPs 35 | will come from that pool when no other pool is specified. There can be at most one default for a 36 | given silo. 37 | - `time_created` (String) Timestamp of when this IP pool was created. 38 | - `time_modified` (String) Timestamp of when this IP pool was last modified. 39 | 40 | 41 | 42 | ### Nested Schema for `timeouts` 43 | 44 | Optional: 45 | 46 | - `read` (String, Default `10m`) 47 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_project.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_project Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_project (Data Source) 6 | 7 | Retrieve information about a specified project. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_project" "example" { 13 | name = "test" 14 | timeouts = { 15 | read = "1m" 16 | } 17 | } 18 | ``` 19 | 20 | ## Schema 21 | 22 | ### Required 23 | 24 | - `name` (String) Name of the project. 25 | 26 | ### Optional 27 | 28 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 29 | 30 | ### Read-Only 31 | 32 | - `description` (String) Description for the project. 33 | - `id` (String) Unique, immutable, system-controlled identifier of the project. 34 | - `time_created` (String) Timestamp of when this project was created. 35 | - `time_modified` (String) Timestamp of when this project was last modified. 36 | 37 | 38 | 39 | ### Nested Schema for `timeouts` 40 | 41 | Optional: 42 | 43 | - `read` (String, Default `10m`) 44 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_projects.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_projects Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_projects (Data Source) 6 | 7 | Retrieve a list of projects. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_projects" "example" {} 13 | ``` 14 | 15 | ## Schema 16 | 17 | ### Optional 18 | 19 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 20 | 21 | ### Read-Only 22 | 23 | - `id` (String) The ID of this resource. 24 | - `projects` (List of Object) A list of all projects (see [below for nested schema](#nestedatt--projects)) 25 | 26 | 27 | 28 | ### Nested Schema for `timeouts` 29 | 30 | Optional: 31 | 32 | - `read` (String, Default `10m`) 33 | 34 | 35 | 36 | ### Nested Schema for `projects` 37 | 38 | Read-Only: 39 | 40 | - `description` (String) Description for the project. 41 | - `id` (String) Unique, immutable, system-controlled identifier of the project. 42 | - `name` (String) Name of the project. 43 | - `time_created` (String) Timestamp of when this project was created. 44 | - `time_modified` (String) Timestamp of when this project was last modified. 45 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_silo.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_silo Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_silo (Data Source) 6 | 7 | Retrieve information about a specified Silo. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_silo" "example" { 13 | name = "default" 14 | timeouts = { 15 | read = "1m" 16 | } 17 | } 18 | ``` 19 | 20 | ## Schema 21 | 22 | ### Required 23 | 24 | - `name` (String) Name of the Silo. 25 | 26 | ### Optional 27 | 28 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 29 | 30 | ### Read-Only 31 | 32 | - `description` (String) Description for the Silo. 33 | - `id` (String) Unique, immutable, system-controlled identifier of the Silo. 34 | - `identity_mode` (String) How users and groups are managed in this Silo. 35 | - `discoverable` (Bool) A silo where discoverable is false can be retrieved only by its ID - it will not be part of the 'list all silos' output. 36 | - `time_created` (String) Timestamp of when this Silo was created. 37 | - `time_modified` (String) Timestamp of when this Silo was last modified. 38 | 39 | 40 | 41 | ### Nested Schema for `timeouts` 42 | 43 | Optional: 44 | 45 | - `read` (String, Default `10m`) 46 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_ssh_key.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_ssh_key Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_ssh_key (Data Source) 6 | 7 | Retrieve information about a specified SSH key. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_ssh_key" "example" { 13 | name = "example" 14 | timeouts = { 15 | read = "1m" 16 | } 17 | } 18 | ``` 19 | 20 | ## Schema 21 | 22 | ### Required 23 | 24 | - `name` (String) Name of the SSH key. 25 | 26 | ### Optional 27 | 28 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 29 | 30 | ### Read-Only 31 | 32 | - `id` (String) Unique, immutable, system-controlled identifier of the SSH key. 33 | - `description` (String) Description for the SSH key. 34 | - `public_key` (String) The SSH public key (e.g., `ssh-ed25519 AAAAC3NzaC...`). 35 | - `silo_user_id` (String) The ID of the user to whom this SSH key belongs. 36 | - `time_created` (String) Timestamp of when this SSH key was created. 37 | - `time_modified` (String) Timestamp of when this SSH key was last modified. 38 | 39 | 40 | 41 | ### Nested Schema for `timeouts` 42 | 43 | Optional: 44 | 45 | - `read` (String, Default `10m`) 46 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_vpc.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc (Data Source) 6 | 7 | Retrieve information about a specified VPC. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_vpc" "example" { 13 | project_name = "my-project" 14 | name = "default" 15 | timeouts = { 16 | read = "1m" 17 | } 18 | } 19 | ``` 20 | 21 | ## Schema 22 | 23 | ### Required 24 | 25 | - `name` (String) Name of the VPC. 26 | - `project_name` (String) Name of the project that contains the VPC. 27 | 28 | ### Optional 29 | 30 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 31 | 32 | ### Read-Only 33 | 34 | - `description` (String) Description for the VPC. 35 | - `dns_name` (String) DNS name of the VPC. 36 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC. 37 | - `ipv6_prefix` (String) All IPv6 subnets created from this VPC must be taken from this range, which should be a unique local address in the range `fd00::/48`. The default VPC Subnet will have the first `/64` range from this prefix. 38 | - `project_id` (String) ID of the project that will contain the VPC. 39 | - `system_router_id` (String) ID for the system router where subnet default routes are registered. 40 | - `time_created` (String) Timestamp of when this VPC was created. 41 | - `time_modified` (String) Timestamp of when this VPC was last modified. 42 | 43 | 44 | 45 | ### Nested Schema for `timeouts` 46 | 47 | Optional: 48 | 49 | - `read` (String, Default `10m`) 50 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_vpc_internet_gateway.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_internet_gateway Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_internet_gateway (Data Source) 6 | 7 | Retrieve information about a specified VPC internet gateway. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_vpc_internet_gateway" "example" { 13 | project_name = "my-project" 14 | name = "system" 15 | vpc_name = "default" 16 | timeouts = { 17 | read = "1m" 18 | } 19 | } 20 | ``` 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `name` (String) Name of the internet gateway. 27 | - `project_name` (String) Name of the project that contains the internet gateway. 28 | - `vpc_name` (String) Name of the VPC that contains the internet gateway. 29 | 30 | ### Optional 31 | 32 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 33 | 34 | ### Read-Only 35 | 36 | - `description` (String) Description for the VPC internet gateway. 37 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC internet gateway. 38 | - `name` (String) Name of the VPC internet gateway. 39 | - `vpc_id` (String) ID of the VPC that contains the internet gateway. 40 | - `time_created` (String) Timestamp of when this VPC internet gateway was created. 41 | - `time_modified` (String) Timestamp of when this VPC internet gateway was last modified. 42 | 43 | 44 | 45 | ### Nested Schema for `timeouts` 46 | 47 | Optional: 48 | 49 | - `read` (String, Default `10m`) 50 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_vpc_router.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_router Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_router (Data Source) 6 | 7 | Retrieve information about a specified VPC router. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_vpc_router" "example" { 13 | project_name = "my-project" 14 | name = "system" 15 | vpc_name = "default" 16 | timeouts = { 17 | read = "1m" 18 | } 19 | } 20 | ``` 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `name` (String) Name of the router. 27 | - `project_name` (String) Name of the project that contains the router. 28 | - `vpc_name` (String) Name of the VPC that contains the router. 29 | 30 | ### Optional 31 | 32 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 33 | 34 | ### Read-Only 35 | 36 | - `description` (String) Description for the VPC router. 37 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC router. 38 | - `kind` (String) Whether the VPC router is custom or system created. 39 | - `name` (String) Name of the VPC router. 40 | - `vpc_id` (String) ID of the VPC that contains the router. 41 | - `time_created` (String) Timestamp of when this VPC router was created. 42 | - `time_modified` (String) Timestamp of when this VPC router was last modified. 43 | 44 | 45 | 46 | ### Nested Schema for `timeouts` 47 | 48 | Optional: 49 | 50 | - `read` (String, Default `10m`) 51 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_vpc_router_route.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_router_route Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_router_route (Data Source) 6 | 7 | Retrieve information about a specified VPC router route. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_vpc_router_route" "example" { 13 | project_name = "my-project" 14 | name = "default-v4" 15 | vpc_name = "default" 16 | vpc_router_name = "system" 17 | timeouts = { 18 | read = "1m" 19 | } 20 | } 21 | ``` 22 | 23 | ## Schema 24 | 25 | ### Required 26 | 27 | - `name` (String) Name of the VPC router route. 28 | - `project_name` (String) Name of the project that contains the VPC router route. 29 | - `vpc_router_name` (String) Name of the VPC router that contains the VPC router route. 30 | - `vpc_name` (String) Name of the VPC that contains the VPC router route. 31 | 32 | ### Optional 33 | 34 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 35 | 36 | ### Read-Only 37 | 38 | - `description` (String) Description for the VPC router. 39 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC router. 40 | - `destination` (Object) Selects which traffic this routing rule will apply to. (see [below for nested schema](#nestedatt--destination)) 41 | - `kind` (String) Whether the VPC router is custom or system created. 42 | - `name` (String) Name of the VPC router. 43 | - `target` (Object) Location that matched packets should be forwarded to. (see [below for nested schema](#nestedatt--target)) 44 | - `time_created` (String) Timestamp of when this VPC router was created. 45 | - `time_modified` (String) Timestamp of when this VPC router was last modified. 46 | - `vpc_router_id` (String) ID of the VPC router that contains the VPC router route. 47 | 48 | 49 | 50 | ### Nested Schema for `destination` 51 | 52 | Read-Only: 53 | 54 | - `type` (String) Route destination type. Possible values: `vpc`, `subnet`, `ip`, and `ip_net`. 55 | - `value` (String) Depending on the type, it will be one of the following: 56 | - `vpc`: Name of the VPC 57 | - `subnet`: Name of the VPC subnet 58 | - `ip`: IP address 59 | - `ip_net`: IPv4 or IPv6 subnet 60 | 61 | 62 | 63 | ### Nested Schema for `target` 64 | 65 | Read-Only: 66 | 67 | - `type` (String) Route destination type. Possible values: `vpc`, `subnet`, `instance`, `ip`, `internet_gateway`, and `drop`. 68 | - `value` (String) Depending on the type, it will be one of the following: 69 | - `vpc`: Name of the VPC 70 | - `subnet`: Name of the VPC subnet 71 | - `instance`: Name of the instance 72 | - `ip`: IP address 73 | - `internet_gateway`: Name of the internet gateway 74 | 75 | 76 | 77 | ### Nested Schema for `timeouts` 78 | 79 | Optional: 80 | 81 | - `read` (String, Default `10m`) 82 | -------------------------------------------------------------------------------- /docs/data-sources/oxide_vpc_subnet.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_subnet Data Source - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_subnet (Data Source) 6 | 7 | Retrieve information about a specified VPC subnet. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | data "oxide_vpc_subnet" "example" { 13 | project_name = "my-project" 14 | name = "default" 15 | vpc_name = "default" 16 | timeouts = { 17 | read = "1m" 18 | } 19 | } 20 | ``` 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `name` (String) Name of the subnet. 27 | - `project_name` (String) Name of the project that contains the subnet. 28 | - `vpc_name` (String) Name of the VPC that contains the subnet. 29 | 30 | ### Optional 31 | 32 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 33 | 34 | ### Read-Only 35 | 36 | - `description` (String) Description for the VPC subnet. 37 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC subnet. 38 | - `ipv4_block` (String) IPv4 address range for this VPC subnet. It must be allocated from an RFC 1918 private address range, and must not overlap with any other existing subnet in the VPC. 39 | - `name` (String) Name of the VPC subnet. 40 | - `ipv6_block` (String) IPv6 address range for this VPC subnet. It must be allocated from the RFC 4193 Unique Local Address range, with the prefix equal to the parent VPC's prefix. 41 | - `vpc_id` (String) ID of the VPC that contains the subnet. 42 | - `time_created` (String) Timestamp of when this VPC subnet was created. 43 | - `time_modified` (String) Timestamp of when this VPC subnet was last modified. 44 | 45 | 46 | 47 | ### Nested Schema for `timeouts` 48 | 49 | Optional: 50 | 51 | - `read` (String, Default `10m`) 52 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "Oxide Provider" 3 | --- 4 | 5 | # Oxide Provider 6 | 7 | The Oxide Terraform provider can be used to manage an Oxide rack. 8 | 9 | ## Authentication 10 | 11 | As a preferred method of authentication, export the `OXIDE_HOST` and `OXIDE_TOKEN` environment variables with their corresponding values. 12 | 13 | There are a two alternatives to this: 14 | 15 | ### Host and Token Arguments 16 | It is possible to authenticate via the optional `host` and `token` arguments. In most cases this method of authentication is not recommended. It is generally preferable to keep credential information out of the configuration. 17 | 18 | ### Profile Argument 19 | Another option is to use profile-based authentication by passing the `profile` argument. If you have authenticated using the Oxide CLI with `oxide auth login --host https://$YourSiloDnsName`, a `profile` will be created in your `credentials.toml`. You can reference this `profile` directly in your Terraform provider block. 20 | 21 | Note: Cannot use `profile` with `host` and `token` arguments and vice versa. 22 | 23 | ## Example Usage 24 | 25 | ```hcl 26 | terraform { 27 | required_version = ">= 1.0" 28 | 29 | required_providers { 30 | oxide = { 31 | source = "oxidecomputer/oxide" 32 | version = "0.9.0" 33 | } 34 | } 35 | } 36 | 37 | provider "oxide" { 38 | # The provider will default to use $OXIDE_HOST and $OXIDE_TOKEN. 39 | # If necessary they can be set explicitly (not recommended). 40 | # host = "" 41 | # token = "" 42 | 43 | # Can pass in a existing profile that exists in the credentials.toml 44 | # profile = "" 45 | } 46 | 47 | # Create a blank disk 48 | resource "oxide_disk" "example" { 49 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 50 | description = "a test disk" 51 | name = "mydisk" 52 | size = 1073741824 53 | block_size = 512 54 | } 55 | ``` 56 | 57 | ## Schema 58 | 59 | ### Optional 60 | 61 | - `host` (String) URL of the root of the target server 62 | - `token` (String, Sensitive) Token used to authenticate 63 | - `profile` (String, Sensitive) Profile used to authenticate from `credentials.toml` 64 | -------------------------------------------------------------------------------- /docs/resources/oxide_anti_affinity_group.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_anti_affinity_group Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_anti_affinity_group (Resource) 6 | 7 | This resource manages anti-affinity groups. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_anti_affinity_group" "example" { 13 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a test anti-affinity group" 15 | name = "my-anti-affinty-group" 16 | policy = "allow" 17 | timeouts = { 18 | read = "1m" 19 | create = "3m" 20 | delete = "2m" 21 | update = "2m" 22 | } 23 | } 24 | ``` 25 | 26 | ## Schema 27 | 28 | ### Required 29 | 30 | - `description` (String) Description for the anti-affinity group. 31 | - `name` (String) Name of the anti-affinity group. 32 | - `policy` (String) Affinity policy used to describe what to do when a request cannot be satisfied. Possible values are: `allow` or `fail`. 33 | - `project_id` (String) ID of the project that will contain the anti-affinity group. 34 | 35 | ### Optional 36 | 37 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 38 | 39 | ### Read-Only 40 | 41 | - `id` (String) Unique, immutable, system-controlled identifier of the anti-affinity group. 42 | - `failure_domain` (String) Describes the scope of affinity for the purposes of co-location. 43 | - `time_created` (String) Timestamp of when this anti-affinity group was created. 44 | - `time_modified` (String) Timestamp of when this anti-affinity group was last modified. 45 | 46 | 47 | 48 | ### Nested Schema for `timeouts` 49 | 50 | Optional: 51 | 52 | - `create` (String, Default `10m`) 53 | - `delete` (String, Default `10m`) 54 | - `read` (String, Default `10m`) 55 | - `update` (String, Default `10m`) 56 | -------------------------------------------------------------------------------- /docs/resources/oxide_disk.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_disk Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_disk (Resource) 6 | 7 | This resource manages disks. 8 | 9 | To create a blank disk it's necessary to set `block_size`. Otherwise, one of `source_image_id` or `source_snapshot_id` must be set; `block_size` will be automatically calculated. 10 | 11 | !> Disks cannot be deleted while attached to instances. Please detach or delete associated instances before attempting to delete. 12 | 13 | -> This resource currently only provides create, read and delete actions. An update requires a resource replacement 14 | 15 | ## Example Usage 16 | 17 | ```hcl 18 | resource "oxide_disk" "example" { 19 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 20 | description = "a test disk" 21 | name = "mydisk" 22 | size = 1073741824 23 | block_size = 512 24 | } 25 | 26 | resource "oxide_disk" "example2" { 27 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 28 | description = "a test disk" 29 | name = "mydisk2" 30 | size = 1073741824 31 | source_image_id = "49118786-ca55-49b1-ae9a-e03f7ce41d8c" 32 | timeouts = { 33 | read = "1m" 34 | create = "3m" 35 | delete = "2m" 36 | } 37 | } 38 | ``` 39 | 40 | ## Schema 41 | 42 | ### Required 43 | 44 | - `description` (String) Description for the disk. 45 | - `name` (String) Name of the disk. 46 | - `project_id` (String) ID of the project that will contain the disk. 47 | - `size` (Number) Size of the disk in bytes. 48 | 49 | ### Optional 50 | 51 | - `block_size` (Number) Size of blocks in bytes. To be set only when creating a blank disk, will be computed otherwise. 52 | - `source_image_id` (String) ID of the disk source image. To be set only when creating a disk from an image. 53 | - `source_snapshot_id` (String) ID of the disk source snapshot. To be set only when creating a disk from a snapshot. 54 | - `timeouts` (Attribute) (see [below for nested schema](#nestedatt--timeouts)) 55 | 56 | ### Read-Only 57 | 58 | - `device_path` (String) Path of the disk. 59 | - `id` (String) Unique, immutable, system-controlled identifier of the disk. 60 | - `time_created` (String) Timestamp of when this disk was created. 61 | - `time_modified` (String) Timestamp of when this disk was last modified. 62 | 63 | 64 | 65 | ### Nested Schema for `timeouts` 66 | 67 | Optional: 68 | 69 | - `create` (String, Default `10m`) 70 | - `delete` (String, Default `10m`) 71 | - `read` (String, Default `10m`) 72 | -------------------------------------------------------------------------------- /docs/resources/oxide_floating_ip.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_floating_ip Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_floating_ip (Resource) 6 | 7 | This resource manages Oxide floating IPs. 8 | 9 | ## Example Usage 10 | 11 | ### Allocate a floating IP from the silo's default IP pool 12 | 13 | ```hcl 14 | resource "oxide_floating_ip" "example" { 15 | project_id = "5476ccc9-464d-4dc4-bfc0-5154de1c986f" 16 | name = "app-ingress" 17 | description = "Ingress for application." 18 | } 19 | ``` 20 | 21 | ### Allocate a floating IP from the specified IP pool 22 | 23 | ```hcl 24 | resource "oxide_floating_ip" "example" { 25 | project_id = "5476ccc9-464d-4dc4-bfc0-5154de1c986f" 26 | name = "app-ingress" 27 | description = "Ingress for application." 28 | ip_pool_id = "a4720b36-006b-49fc-a029-583528f18a4d" 29 | } 30 | ``` 31 | 32 | ### Allocate a specific floating IP from the specified IP pool 33 | 34 | ```hcl 35 | resource "oxide_floating_ip" "example" { 36 | project_id = "5476ccc9-464d-4dc4-bfc0-5154de1c986f" 37 | name = "app-ingress" 38 | description = "Ingress for application." 39 | ip_pool_id = "a4720b36-006b-49fc-a029-583528f18a4d" 40 | ip = "172.21.252.128" 41 | } 42 | ``` 43 | 44 | ## Schema 45 | 46 | ### Required 47 | 48 | - `name` (String) Name of the floating IP. 49 | - `description` (String) Description for the floating IP. 50 | - `project_id` (String) ID of the project that will contain the floating IP. 51 | 52 | ### Optional 53 | 54 | - `ip` (String) IP address for this floating IP. If unset, an IP address will be chosen from the given `ip_pool_id`, or the silo's default IP pool if the `ip_pool_id` attribute is unset. 55 | - `ip_pool_id` (String) ID of the IP pool where the floating IP will be allocated from. If unset, the silo's default IP pool is used. 56 | - `timeouts` (Attribute, Optional) Timeouts for performing API operations. See [below for nested schema](#nestedatt--timeouts). 57 | 58 | ### Read-Only 59 | 60 | - `id` (String) Unique, immutable, system-controlled identifier for the floating IP. 61 | - `instance_id` (String) Instance ID that this floating IP is attached to, if presently attached. 62 | - `time_created` (String) Timestamp of when the floating IP was created. 63 | - `time_modified` (String) Timestamp of when the floating IP was modified. 64 | 65 | 66 | 67 | ### Nested Schema for `timeouts` 68 | 69 | #### Optional 70 | 71 | - `create` (String, Default `10m`) 72 | - `delete` (String, Default `10m`) 73 | - `read` (String, Default `10m`) 74 | - `update` (String, Default `10m`) 75 | -------------------------------------------------------------------------------- /docs/resources/oxide_image.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_image Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_image (Resource) 6 | 7 | This resource manages images. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_image" "example2" { 13 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a test image" 15 | name = "myimage2" 16 | source_snapshot_id = "eb65d5cb-d8c5-4eae-bcf3-a0e89a633042" 17 | os = "ubuntu" 18 | version = "20.04" 19 | timeouts = { 20 | read = "1m" 21 | create = "3m" 22 | } 23 | } 24 | ``` 25 | 26 | ## Schema 27 | 28 | ### Required 29 | 30 | - `description` (String) Description for the image. 31 | - `os` (String) OS image distribution. Example: "alpine". 32 | - `project_id` (String) ID of the project that will contain the image. 33 | - `source_snapshot_id` (String) Snapshot ID of the image source. 34 | - `version` (String) OS image version. Example: "3.16". 35 | - `name` (String) Name of the image. 36 | 37 | ### Optional 38 | 39 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 40 | 41 | ### Read-Only 42 | 43 | - `block_size` (Number) Size of blocks in bytes. 44 | - `digest` (Object) Hash of the image contents, if applicable (see [below for nested schema](#nestedobject--digest)). 45 | - `id` (String) Unique, immutable, system-controlled identifier of the image. 46 | - `size` (Number) Total size in bytes. 47 | - `time_created` (String) Timestamp of when this image was created. 48 | - `time_modified` (String) Timestamp of when this image was last modified. 49 | 50 | 51 | 52 | ### Nested Schema for `timeouts` 53 | 54 | Optional: 55 | 56 | - `create` (String, Default `10m`) 57 | - `read` (String, Default `10m`) 58 | 59 | ### Nested Schema for `digest` 60 | 61 | Read-Only: 62 | 63 | - `type` (String) Digest type. 64 | - `value` (String) Digest type value. 65 | -------------------------------------------------------------------------------- /docs/resources/oxide_ip_pool.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_ip_pool Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_ip_pool (Resource) 6 | 7 | This resource manages IP pools. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_ip_pool" "example" { 13 | description = "a test IP pool" 14 | name = "myippool" 15 | ranges = [ 16 | { 17 | first_address = "172.20.18.227" 18 | last_address = "172.20.18.239" 19 | } 20 | ] 21 | timeouts = { 22 | read = "1m" 23 | create = "3m" 24 | delete = "2m" 25 | update = "2m" 26 | } 27 | } 28 | ``` 29 | 30 | ## Schema 31 | 32 | ### Required 33 | 34 | - `description` (String) Description for the IP pool. 35 | - `name` (String) Name of the IP pool. 36 | 37 | ### Optional 38 | 39 | - `ranges` (List of Object, Optional) Adds IP ranges to the created IP pool. (see [below for nested schema](#nestedblock--ranges)) 40 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 41 | 42 | ### Read-Only 43 | 44 | - `id` (String) Unique, immutable, system-controlled identifier of the IP pool. 45 | - `time_created` (String) Timestamp of when this IP pool was created. 46 | - `time_modified` (String) Timestamp of when this IP pool was last modified. 47 | 48 | 49 | 50 | ### Nested Schema for `ranges` 51 | 52 | Required: 53 | 54 | - `first_address` (String) First address in the range. 55 | - `last_address` (String) Last address in the range. 56 | 57 | 58 | 59 | ### Nested Schema for `timeouts` 60 | 61 | Optional: 62 | 63 | - `create` (String, Default `10m`) 64 | - `delete` (String, Default `10m`) 65 | - `read` (String, Default `10m`) 66 | - `update` (String, Default `10m`) -------------------------------------------------------------------------------- /docs/resources/oxide_ip_pool_silo_link.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_ip_pool_silo_link Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_ip_pool_silo_link (Resource) 6 | 7 | This resource manages IP pool to silo links. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_ip_pool_silo_link" "example" { 13 | silo_id = "1fec2c21-cf22-40d8-9ebd-e5b57ebec80f" 14 | ip_pool_id = "081a331d-5ee4-4a23-ac8b-328af5e15cdc" 15 | is_default = true 16 | timeouts = { 17 | read = "1m" 18 | create = "3m" 19 | delete = "2m" 20 | update = "2m" 21 | } 22 | } 23 | ``` 24 | 25 | ## Schema 26 | 27 | ### Required 28 | 29 | - `silo_id` (String) Description for the IP pool. 30 | - `ip_pool_id` (String) Name of the IP pool. 31 | - `is_default` (Boolean) Whether a pool is the default for a silo. All floating IPs and instance ephemeral IPs will come from that pool when no other pool is specified. 32 | 33 | -> There can only be one default pool for a given silo. Due to this restriction, changing the default IP pool to another can result in a race condition when running `terraform apply`. To help avoid errors, make sure to use `terraform apply -parallelism=1` when changing the default IP pool for a silo. In some cases, you may still get a `400 ObjectAlreadyExists` error. If this happens, you may try the command again, or set all IP pools to `is_default = false` first, and set the default pool as a second step. 34 | 35 | ### Optional 36 | 37 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 38 | 39 | ### Read-Only 40 | 41 | - `id` (String) Unique, immutable, system-controlled, terraform-specific identifier of the resource. 42 | 43 | 44 | 45 | ### Nested Schema for `timeouts` 46 | 47 | Optional: 48 | 49 | - `create` (String, Default `10m`) 50 | - `delete` (String, Default `10m`) 51 | - `read` (String, Default `10m`) 52 | - `update` (String, Default `10m`) 53 | 54 | -------------------------------------------------------------------------------- /docs/resources/oxide_project.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_project Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_project (Resource) 6 | 7 | This resource manages projects. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_project" "example" { 13 | description = "a test project" 14 | name = "myproject" 15 | timeouts = { 16 | read = "1m" 17 | create = "3m" 18 | delete = "2m" 19 | update = "2m" 20 | } 21 | } 22 | ``` 23 | 24 | ## Schema 25 | 26 | ### Required 27 | 28 | - `description` (String) Description for the project. 29 | - `name` (String) Name of the project. 30 | 31 | ### Optional 32 | 33 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 34 | 35 | ### Read-Only 36 | 37 | - `id` (String) Unique, immutable, system-controlled identifier of the project. 38 | - `time_created` (String) Timestamp of when this project was created. 39 | - `time_modified` (String) Timestamp of when this project was last modified. 40 | 41 | 42 | 43 | ### Nested Schema for `timeouts` 44 | 45 | Optional: 46 | 47 | - `create` (String, Default `10m`) 48 | - `delete` (String, Default `10m`) 49 | - `read` (String, Default `10m`) 50 | - `update` (String, Default `10m`) 51 | -------------------------------------------------------------------------------- /docs/resources/oxide_silo.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_silo Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_silo (Resource) 6 | 7 | This resource manages the creation of an Oxide silo. 8 | 9 | -> Only the `quotas` attribute supports in-place modification. Changes to other 10 | attributes will result in the silo being destroyed and created anew. 11 | 12 | ## Example Usage 13 | 14 | ```hcl 15 | resource "oxide_silo" "example" { 16 | name = "showcase" 17 | description = "Demo and event silo." 18 | admin_group_name = "showcase_admin" 19 | identity_mode = "saml_jit" 20 | discoverable = true 21 | mapped_fleet_roles = { 22 | admin = ["admin", "collaborator"] 23 | viewer = ["viewer"] 24 | } 25 | quotas = { 26 | cpus = 64 27 | memory = 137438953472 # 128 GiB 28 | storage = 549755813888 # 512 GiB 29 | } 30 | tls_certificates = [ 31 | { 32 | name = "wildcard_cert" 33 | description = "Wildcard cert for *.sys.oxide.example.com." 34 | cert = file("cert.pem") 35 | key = file("key.pem") 36 | service = "external_api" 37 | }, 38 | ] 39 | } 40 | ``` 41 | 42 | ## Schema 43 | 44 | ### Required 45 | 46 | - `name` (String) Name of the Oxide silo. 47 | - `description` (String) Description for the Oxide silo. 48 | - `quotas` (Set of Object) Limits the amount of provisionable CPU, memory, and storage in the silo. (See [below for nested schema](#nestedatt--quotas).) 49 | - `tls_certificates` (String, Write-only) TLS certificates to be used for the silo's console and API endpoints. This is a [write-only attribute](https://developer.hashicorp.com/terraform/plugin/framework/resources/write-only-arguments) since TLS certificates can only be specified during silo creation. Refer to the [Silo Management guide](https://docs.oxide.computer/guides/operator/silo-management) for instructions on replacing the TLS certificates of an existing silo _without_ destroying it and creating it anew. Alternatively, if it's acceptable to destroy the silo and create it anew you can modify this attribute and [replace the resource](https://developer.hashicorp.com/terraform/cli/state/taint). (See [below for nested schema](#nestedatt--tls).) 50 | - `discoverable` (Boolean) Whether this silo is present in the silo_list output. Defaults to `true`. 51 | 52 | ### Optional 53 | 54 | - `identity_mode` (String) How identities are managed and users are authenticated in this silo. Valid values are `saml_jit` and `local_only`. Defaults to `local_only`. 55 | - `admin_group_name` (String) This group will be created during silo creation and granted the "Silo Admin" role. Identity providers can assert that users belong to this group and those users can log in and further initialize the Silo. 56 | - `mapped_fleet_roles` (Map) Setting that defines the association between silo roles and fleet roles. By default, silo roles do not grant any fleet roles. To establish a connection, you create entries in this map. The key for each entry must be a silo role: `admin`, `collaborator`, or `viewer`. The value is a list of fleet roles (`admin`, `collaborator`, or `viewer`) that the key silo role will grant. 57 | - `timeouts` (Attribute, Optional) Timeouts for performing API operations. See [below for nested schema](#nestedatt--timeouts). 58 | 59 | ### Read-Only 60 | 61 | - `id` (String) Unique, immutable, system-controlled identifier of the silo. 62 | - `time_created` (String) Timestamp of when this Silo was created. 63 | - `time_modified` (String) Timestamp of when this Silo was last modified. 64 | 65 | 66 | 67 | ### Nested Schema for `quotas` 68 | 69 | ### Required 70 | 71 | - `cpus` (Number) The amount of virtual CPUs available for running instances in the silo. 72 | - `memory` (Number) The amount of RAM, in bytes, available for running instances in the silo. 73 | - `storage` (Number) The amount of storage, in bytes, available for disks or snapshots. 74 | 75 | 76 | 77 | ### Nested Schema for `tls_certificates` 78 | 79 | ### Required 80 | 81 | - `name` (String) The name associated with the certificate. 82 | - `description` (String) Description of the certificate. 83 | - `cert` (String) PEM-formatted string containing public certificate chain. 84 | - `key` (String) PEM-formatted string containing private key. 85 | - `service` (String) The service associated with the certificate. The only valid value is `external_api`. 86 | 87 | 88 | 89 | ### Nested Schema for `timeouts` 90 | 91 | #### Optional 92 | 93 | - `create` (String, Default `10m`) 94 | - `delete` (String, Default `10m`) 95 | - `read` (String, Default `10m`) 96 | - `update` (String, Default `10m`) 97 | -------------------------------------------------------------------------------- /docs/resources/oxide_snapshot.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_snapshot Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_snapshot (Resource) 6 | 7 | This resource manages snapshots. 8 | 9 | -> This resource currently only provides create, read and delete actions. An update requires a resource replacement. 10 | 11 | ## Example Usage 12 | 13 | ```hcl 14 | resource "oxide_snapshot" "example2" { 15 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 16 | description = "a test snapshot" 17 | name = "mysnapshot" 18 | disk_id = "49118786-ca55-49b1-ae9a-e03f7ce41d8c" 19 | timeouts = { 20 | read = "1m" 21 | create = "3m" 22 | delete = "2m" 23 | } 24 | } 25 | ``` 26 | 27 | ## Schema 28 | 29 | ### Required 30 | 31 | - `description` (String) Description for the snapshot. 32 | - `name` (String) Name of the snapshot. 33 | - `project_id` (String) ID of the project that will contain the snapshot. 34 | - `size` (Number) Size of the snapshot in bytes. 35 | - `disk_id` (String) ID of the disk to create the snapshot from. 36 | 37 | ### Optional 38 | 39 | - `timeouts` (Attribute) (see [below for nested schema](#nestedatt--timeouts)) 40 | 41 | ### Read-Only 42 | 43 | - `id` (String) Unique, immutable, system-controlled identifier of the snapshot. 44 | - `size` (Number) Size of the snapshot in bytes. 45 | - `time_created` (String) Timestamp of when this snapshot was created. 46 | - `time_modified` (String) Timestamp of when this snapshot was last modified. 47 | 48 | 49 | 50 | ### Nested Schema for `timeouts` 51 | 52 | Optional: 53 | 54 | - `create` (String, Default `10m`) 55 | - `delete` (String, Default `10m`) 56 | - `read` (String, Default `10m`) 57 | -------------------------------------------------------------------------------- /docs/resources/oxide_ssh_key.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_ssh_key Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_ssh_key (Resource) 6 | 7 | This resource manages SSH keys. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_ssh_key" "example" { 13 | name = "example" 14 | description = "Example SSH key." 15 | public_key = "ssh-ed25519 AAAC3NzaC1lZI1NTE5AAAAIE1clIQrzlQNqxgvpCCUFOcTTFDOaqV+aocfsDZxqB" 16 | } 17 | ``` 18 | 19 | ## Schema 20 | 21 | ### Required 22 | 23 | - `name` (String) Name of the SSH key. Names must begin with a lower case ASCII 24 | letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, 25 | and `-`, and may not end with a `-`. Names cannot be a UUID though they may 26 | contain a UUID. 27 | - `description` (String) Description for the SSH key. 28 | - `public_key` (String) The SSH public key (e.g., `ssh-ed25519 AAAAC3NzaC...`). 29 | 30 | ### Optional 31 | 32 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 33 | 34 | ### Read-Only 35 | 36 | - `id` (String) Unique, immutable, system-controlled identifier of the SSH key. 37 | - `silo_user_id` (String) The ID of the user to whom this SSH key belongs. 38 | - `time_created` (String) Timestamp of when this SSH key was created. 39 | - `time_modified` (String) Timestamp of when this SSH key was last modified. 40 | 41 | 42 | 43 | ### Nested Schema for `timeouts` 44 | 45 | Optional: 46 | 47 | - `create` (String, Default `10m`) 48 | - `delete` (String, Default `10m`) 49 | - `read` (String, Default `10m`) 50 | - `update` (String, Default `10m`) 51 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc (Resource) 6 | 7 | This resource manages VPCs. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_vpc" "example" { 13 | project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a test vpc" 15 | name = "myvpc" 16 | dns_name = "my-vpc-dns" 17 | ipv6_prefix = "fd1e:4947:d4a1::/48" 18 | timeouts = { 19 | read = "1m" 20 | create = "3m" 21 | delete = "2m" 22 | update = "2m" 23 | } 24 | } 25 | ``` 26 | 27 | ## Schema 28 | 29 | ### Required 30 | 31 | - `description` (String) Description for the VPC. 32 | - `dns_name` (String) DNS name of the VPC. 33 | - `name` (String) Name of the VPC. 34 | - `project_id` (String) ID of the project that will contain the VPC. 35 | 36 | ### Optional 37 | 38 | - `ipv6_prefix` (String, Optional) All IPv6 subnets created from this VPC must be taken from this range, which should be a unique local address in the range `fd00::/48`. The default VPC Subnet will have the first `/64` range from this prefix. If no `ipv6_prefix` is defined, a default one will be set. 39 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 40 | 41 | ### Read-Only 42 | 43 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC. 44 | - `system_router_id` (String) ID for the system router where subnet default routes are registered. 45 | - `time_created` (String) Timestamp of when this VPC was created. 46 | - `time_modified` (String) Timestamp of when this VPC was last modified. 47 | 48 | 49 | 50 | ### Nested Schema for `timeouts` 51 | 52 | Optional: 53 | 54 | - `create` (String, Default `10m`) 55 | - `delete` (String, Default `10m`) 56 | - `read` (String, Default `10m`) 57 | - `update` (String, Default `10m`) 58 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc_firewall_rules.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_firewall_rules Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_firewall_rules (Resource) 6 | 7 | This resource manages VPC firewall rules. 8 | 9 | !> Firewall rules defined by this resource are considered exhaustive and will 10 | overwrite any other firewall rules for the VPC once applied. 11 | 12 | ## Example Usage 13 | 14 | ```hcl 15 | resource "oxide_vpc_firewall_rules" "example" { 16 | vpc_id = "6556fc6a-63c0-420b-bb23-c3205410f5cc" 17 | rules = [ 18 | { 19 | action = "allow" 20 | description = "Allow HTTPS." 21 | name = "allow-https" 22 | direction = "inbound" 23 | priority = 50 24 | status = "enabled" 25 | filters = { 26 | hosts = [ 27 | { 28 | type = "vpc" 29 | value = "default" 30 | } 31 | ] 32 | ports = ["443"] 33 | protocols = ["TCP"] 34 | }, 35 | targets = [ 36 | { 37 | type = "subnet" 38 | value = "default" 39 | } 40 | ] 41 | } 42 | ] 43 | } 44 | ``` 45 | 46 | ## Schema 47 | 48 | ### Required 49 | 50 | - `vpc_id` (String) ID of the VPC that will have the firewall rules applied to. 51 | - `rules` (Set) Associated firewall rules. Updates require replacement. (see [below for nested schema](#nestedatt--rules)) 52 | 53 | ### Optional 54 | 55 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 56 | 57 | ### Read-Only 58 | 59 | - `id` (String) Unique, immutable, system-controlled identifier of the firewall rules. Specific only to Terraform. 60 | 61 | 62 | 63 | ### Nested Schema for `rules` 64 | 65 | Required: 66 | 67 | - `action` (String) Whether traffic matching the rule should be allowed or dropped. Possible values are: allow or deny. 68 | - `description` (String) Description for the VPC firewall rule. 69 | - `direction` (String) Whether this rule is for incoming or outgoing traffic. Possible values are: inbound or outbound. 70 | - `filters` (Single Nested Attribute) Reductions on the scope of the rule. (see [below for nested schema](#nestedatt--filters)) 71 | - `name` (String) Name of the firewall rule. 72 | - `priority` (Number) The relative priority of this rule. 73 | - `status` (String) Whether this rule is in effect. Possible values are: enabled or disabled. 74 | - `targets` (Set) Sets of instances that the rule applies to. (see [below for nested schema](#nestedatt--targets)) 75 | 76 | Read-Only: 77 | 78 | - `id` (String) Unique, immutable, system-controlled identifier of the firewall rule. 79 | - `time_created` (String) Timestamp of when this firewall rule was created. 80 | - `time_modified` (String) Timestamp of when this firewall rule was last modified. 81 | 82 | 83 | 84 | ### Nested Schema for `filters` 85 | 86 | Optional: 87 | 88 | - `hosts` (Set) If present, the sources (if incoming) or destinations (if outgoing) this rule applies to. (see [below for nested schema](#nestedatt--hosts)) 89 | - `protocols` (Array of Strings) If present, the networking protocols this rule applies to. Possible values are: TCP, UDP and ICMP. 90 | - `ports` (Array of Strings) If present, the destination ports this rule applies to. Can be a mix of single ports (e.g., `"443"`) and port ranges (e.g., `"30000-32768"`). 91 | 92 | 93 | 94 | ### Nested Schema for `hosts` 95 | 96 | Required: 97 | 98 | - `type` (String) Used to filter traffic on the basis of its source or destination host. Possible values: vpc, subnet, instance, ip and ip_net. 99 | - `value` (String) Depending on the type, it will be one of the following: 100 | - For type vpc: Name of the VPC 101 | - For type subnet: Name of the VPC subnet 102 | - For type instance: Name of the instance 103 | - For type ip: IP address 104 | - For type ip_net: IPv4 or IPv6 subnet 105 | 106 | 107 | 108 | ### Nested Schema for `targets` 109 | 110 | Required: 111 | 112 | - `type` (String) The rule applies to a single or all instances of this type, or specific IPs. Possible values: vpc, subnet, instance, ip, ip_net. 113 | - `value` (String) Depending on the type, it will be one of the following: 114 | - For type vpc: Name of the VPC 115 | - For type subnet: Name of the VPC subnet 116 | - For type instance: Name of the instance 117 | - For type ip: IP address 118 | - For type ip_net: IPv4 or IPv6 subnet 119 | 120 | ### Nested Schema for `timeouts` 121 | 122 | Optional: 123 | 124 | - `create` (String, Default `10m`) 125 | - `delete` (String, Default `10m`) 126 | - `read` (String, Default `10m`) 127 | - `update` (String, Default `10m`) 128 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc_internet_gateway.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_internet_gateway Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_internet_gateway (Resource) 6 | 7 | This resource manages VPC internet gateways. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_vpc_internet_gateway" "example" { 13 | vpc_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a sample VPC internet gateway" 15 | name = "myinternetgateway" 16 | timeouts = { 17 | read = "1m" 18 | create = "3m" 19 | delete = "2m" 20 | update = "2m" 21 | } 22 | } 23 | ``` 24 | 25 | ## Schema 26 | 27 | ### Required 28 | 29 | - `description` (String) Description for the VPC internet gateway. 30 | - `name` (String) Name of the VPC internet gateway. 31 | - `vpc_id` (String) ID of the VPC that will contain the internet gateway. 32 | 33 | ### Optional 34 | 35 | - `cascade_delete` (Bool, Default `false`) Whether to also delete routes targeting the 36 | VPC internet gateway when deleting the VPC internet gateway. 37 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 38 | 39 | ### Read-Only 40 | 41 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC internet gateway. 42 | - `time_created` (String) Timestamp of when this VPC internet gateway was created. 43 | - `time_modified` (String) Timestamp of when this VPC internet gateway was last modified. 44 | 45 | 46 | 47 | ### Nested Schema for `timeouts` 48 | 49 | Optional: 50 | 51 | - `create` (String, Default `10m`) 52 | - `delete` (String, Default `10m`) 53 | - `read` (String, Default `10m`) 54 | - `update` (String, Default `10m`) 55 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc_router.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_router Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_router (Resource) 6 | 7 | This resource manages VPC routers. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_vpc_router" "example" { 13 | vpc_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a sample vpc router" 15 | name = "myrouter" 16 | timeouts = { 17 | read = "1m" 18 | create = "3m" 19 | delete = "2m" 20 | update = "2m" 21 | } 22 | } 23 | ``` 24 | 25 | ## Schema 26 | 27 | ### Required 28 | 29 | - `description` (String) Description for the VPC router. 30 | - `name` (String) Name of the VPC router. 31 | - `vpc_id` (String) ID of the VPC that will contain the router. 32 | 33 | ### Optional 34 | 35 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 36 | 37 | ### Read-Only 38 | 39 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC router. 40 | - `kind` (String) Whether the VPC router is custom or system created. 41 | - `time_created` (String) Timestamp of when this VPC router was created. 42 | - `time_modified` (String) Timestamp of when this VPC router was last modified. 43 | 44 | 45 | 46 | ### Nested Schema for `timeouts` 47 | 48 | Optional: 49 | 50 | - `create` (String, Default `10m`) 51 | - `delete` (String, Default `10m`) 52 | - `read` (String, Default `10m`) 53 | - `update` (String, Default `10m`) 54 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc_router_route.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_router_route Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_router_route (Resource) 6 | 7 | This resource manages VPC router routes. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_vpc_router_route" "example" { 13 | vpc_router_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a sample VPC router route" 15 | name = "myroute" 16 | destination = { 17 | type = "ip_net" 18 | value = "::/0" 19 | } 20 | target = { 21 | type = "ip" 22 | value = "::1" 23 | } 24 | timeouts = { 25 | read = "1m" 26 | create = "3m" 27 | delete = "2m" 28 | update = "2m" 29 | } 30 | } 31 | ``` 32 | 33 | ## Schema 34 | 35 | ### Required 36 | 37 | - `description` (String) Description for the VPC router route. 38 | - `name` (String) Name of the VPC router route. 39 | - `destination` (Object) Selects which traffic this routing rule will apply to. (see [below for nested schema](#nestedatt--destination)) 40 | - `target` (Object) Location that matched packets should be forwarded to. (see [below for nested schema](#nestedatt--target)) 41 | - `vpc_router_id` (String) ID of the VPC router that will contain the router route. 42 | 43 | ### Optional 44 | 45 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 46 | 47 | ### Read-Only 48 | 49 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC router. 50 | - `kind` (String) Whether the VPC router is custom or system created. 51 | - `time_created` (String) Timestamp of when this VPC router was created. 52 | - `time_modified` (String) Timestamp of when this VPC router was last modified. 53 | 54 | 55 | 56 | ### Nested Schema for `destination` 57 | 58 | Required: 59 | 60 | - `type` (String) Route destination type. Possible values: `vpc`, `subnet`, `ip`, and `ip_net`. 61 | - `value` (String) Depending on the type, it will be one of the following: 62 | - `vpc`: Name of the VPC 63 | - `subnet`: Name of the VPC subnet 64 | - `ip`: IP address 65 | - `ip_net`: IPv4 or IPv6 subnet 66 | 67 | 68 | 69 | ### Nested Schema for `target` 70 | 71 | Required: 72 | 73 | - `type` (String) Route target type. Possible values: `vpc`, `subnet`, `instance`, `ip`, `internet_gateway`, and `drop`. 74 | 75 | Optional: 76 | 77 | - `value` (String) Depending on the type, it will be one of the following: 78 | - `vpc`: Name of the VPC 79 | - `subnet`: Name of the VPC subnet 80 | - `instance`: Name of the instance 81 | - `ip`: IP address 82 | - `internet_gateway`: Name of the internet gateway 83 | 84 | 85 | 86 | ### Nested Schema for `timeouts` 87 | 88 | Optional: 89 | 90 | - `create` (String, Default `10m`) 91 | - `delete` (String, Default `10m`) 92 | - `read` (String, Default `10m`) 93 | - `update` (String, Default `10m`) 94 | -------------------------------------------------------------------------------- /docs/resources/oxide_vpc_subnet.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "oxide_vpc_subnet Resource - terraform-provider-oxide" 3 | --- 4 | 5 | # oxide_vpc_subnet (Resource) 6 | 7 | This resource manages VPC subnets. 8 | 9 | ## Example Usage 10 | 11 | ```hcl 12 | resource "oxide_vpc_subnet" "example" { 13 | vpc_id = "c1dee930-a8e4-11ed-afa1-0242ac120002" 14 | description = "a sample vpc subnet" 15 | name = "mysubnet" 16 | ipv4_block = "192.168.0.0/16" 17 | ipv6_block = "fdfe:f6a5:5f06:a643::/64" 18 | timeouts = { 19 | read = "1m" 20 | create = "3m" 21 | delete = "2m" 22 | update = "2m" 23 | } 24 | } 25 | ``` 26 | 27 | ## Schema 28 | 29 | ### Required 30 | 31 | - `description` (String) Description for the VPC subnet. 32 | - `ipv4_block` (String) IPv4 address range for this VPC subnet. It must be allocated from an RFC 1918 private address range, and must not overlap with any other existing subnet in the VPC. 33 | - `name` (String) Name of the VPC subnet. 34 | - `vpc_id` (String) ID of the VPC that will contain the subnet. 35 | 36 | ### Optional 37 | 38 | - `ipv6_block` (String, Optional) IPv6 address range for this VPC subnet. It must be allocated from the RFC 4193 Unique Local Address range, with the prefix equal to the parent VPC's prefix. A random `/64` block will be assigned if one is not provided. It must not overlap with any existing subnet in the VPC. 39 | - `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts)) 40 | 41 | ### Read-Only 42 | 43 | - `id` (String) Unique, immutable, system-controlled identifier of the VPC subnet. 44 | - `time_created` (String) Timestamp of when this VPC subnet was created. 45 | - `time_modified` (String) Timestamp of when this VPC subnet was last modified. 46 | 47 | 48 | 49 | ### Nested Schema for `timeouts` 50 | 51 | Optional: 52 | 53 | - `create` (String, Default `10m`) 54 | - `delete` (String, Default `10m`) 55 | - `read` (String, Default `10m`) 56 | - `update` (String, Default `10m`) 57 | -------------------------------------------------------------------------------- /examples/demo/README.md: -------------------------------------------------------------------------------- 1 | # On-site Demo Example 2 | 3 | This Terraform configuration file provisions 5 instances as per the demo script: 4 | 5 | > Next, they will provision their first 5 instances using Terraform: 3 web instances (2 cpus, 8gb DRAM, default 100GB disks) and 2 for DB (8 cpus, 32gb DRAM, 500GB disks) using an Oxide-provided OS image. The default VPC will be created automatically. 6 | 7 | This configuration file does the following: 8 | 9 | 1. Retrieves data about the project and global image. This configuration file assumes there will only be one of each and those are the ones we'll be using for the demo. 10 | 2. Using the data retrieved from the previous step, 5 disks are created; 3 10GiB disks for the web instances and 2 20GiB disks for the DB instances. 11 | 3. Finally, using data from the first and second steps, the 5 instances are created using the default VPC and subnet; 3 web instances with 2 CPUs and 1GiB of memory, and 2 DB instances with 4 CPUs and 2GiB of memory. 12 | 13 | To try out this configuration file follow the [instructions](https://github.com/oxidecomputer/terraform-provider-oxide/#using-the-provider) from the README. 14 | -------------------------------------------------------------------------------- /examples/demo/demo.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | oxide = { 6 | source = "oxidecomputer/oxide" 7 | version = "0.9.0" 8 | } 9 | } 10 | } 11 | 12 | provider "oxide" {} 13 | 14 | data "oxide_project" "example" { 15 | name = "{YOUR-PROJECT-NAME}" 16 | } 17 | 18 | data "oxide_images" "image_list" {} 19 | 20 | resource "oxide_disk" "web_disk_1" { 21 | project_id = data.oxide_project.example.id 22 | description = "Disk for a web instance" 23 | name = "web-disk-1" 24 | size = var.ten_gib 25 | source_image_id = data.oxide_images.image_list.images.0.id 26 | } 27 | 28 | resource "oxide_disk" "web_disk_2" { 29 | project_id = data.oxide_project.example.id 30 | description = "Disk for a web instance" 31 | name = "web-disk-2" 32 | size = var.ten_gib 33 | source_image_id = data.oxide_images.image_list.images.0.id 34 | } 35 | 36 | resource "oxide_disk" "web_disk_3" { 37 | project_id = data.oxide_project.example.id 38 | description = "Disk for a web instance" 39 | name = "web-disk-3" 40 | size = var.ten_gib 41 | source_image_id = data.oxide_images.image_list.images.0.id 42 | } 43 | 44 | resource "oxide_disk" "db_disk_1" { 45 | project_id = data.oxide_project.example.id 46 | description = "Disk for a DB instance" 47 | name = "db-disk-1" 48 | size = var.twenty_gib 49 | source_image_id = data.oxide_images.image_list.images.0.id 50 | } 51 | 52 | resource "oxide_disk" "db_disk_2" { 53 | project_id = data.oxide_project.example.id 54 | description = "Disk for a DB instance" 55 | name = "db-disk-2" 56 | size = var.twenty_gib 57 | source_image_id = data.oxide_images.image_list.images.0.id 58 | } 59 | 60 | resource "oxide_instance" "web_instance_1" { 61 | project_id = data.oxide_project.example.id 62 | description = "Web instance" 63 | name = "web-instance-1" 64 | host_name = "web-instance-1" 65 | memory = var.one_gib 66 | ncpus = 2 67 | disk_attachments = [oxide_disk.web_disk_1.id] 68 | } 69 | 70 | resource "oxide_instance" "web_instance_2" { 71 | project_id = data.oxide_project.example.id 72 | description = "Web instance" 73 | name = "web-instance-2" 74 | host_name = "web-instance-2" 75 | memory = var.one_gib 76 | ncpus = 2 77 | disk_attachments = [oxide_disk.web_disk_2.id] 78 | } 79 | 80 | resource "oxide_instance" "web_instance_3" { 81 | project_id = data.oxide_project.example.id 82 | description = "Web instance" 83 | name = "web-instance-3" 84 | host_name = "web-instance-3" 85 | memory = var.one_gib 86 | ncpus = 2 87 | disk_attachments = [oxide_disk.web_disk_3.id] 88 | } 89 | 90 | resource "oxide_instance" "db_instance_1" { 91 | project_id = data.oxide_project.example.id 92 | description = "Web instance" 93 | name = "db-instance-1" 94 | host_name = "db-instance-1" 95 | memory = var.two_gib 96 | ncpus = 4 97 | disk_attachments = [oxide_disk.db_disk_1.id] 98 | } 99 | 100 | resource "oxide_instance" "db_instance_2" { 101 | project_id = data.oxide_project.example.id 102 | description = "Web instance" 103 | name = "db-instance-2" 104 | host_name = "db-instance-2" 105 | memory = var.two_gib 106 | ncpus = 4 107 | disk_attachments = [oxide_disk.db_disk_2.id] 108 | } 109 | -------------------------------------------------------------------------------- /examples/demo/variables.tf: -------------------------------------------------------------------------------- 1 | variable "one_gib" { 2 | type = number 3 | default = 1073741824 4 | } 5 | 6 | variable "two_gib" { 7 | type = number 8 | default = 2147483648 9 | } 10 | 11 | variable "ten_gib" { 12 | type = number 13 | default = 10737418240 14 | } 15 | 16 | variable "twenty_gib" { 17 | type = number 18 | default = 21474836480 19 | } 20 | -------------------------------------------------------------------------------- /examples/disk_resource/README.md: -------------------------------------------------------------------------------- 1 | # Disks 2 | 3 | This example Terraform configuration file performs the following: 4 | 5 | 1. Create a blank disk. 6 | 2. Create a disk from a global image. 7 | 8 | To try it out make sure you have the following: 9 | 10 | - Verify that the `global_image` ID within `disk_source` matches the global image you want to use. 11 | - A project already created. 12 | - Previously set `OXIDE_HOST` and `OXIDE_TOKEN` environment variables. 13 | 14 | Alternatively, you can modify the configuration file with your own `project_id`. Although not recommended, if you do not wish to set the environment variables, you can use the `host` and `token` fields in the `oxide` provider block: 15 | 16 | ```hcl 17 | provider "oxide" { 18 | host = "" 19 | token = "" 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /examples/disk_resource/disk.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | oxide = { 6 | source = "oxidecomputer/oxide" 7 | version = "0.9.0" 8 | } 9 | } 10 | } 11 | 12 | provider "oxide" {} 13 | 14 | data "oxide_images" "image_example" {} 15 | 16 | data "oxide_project" "example" { 17 | name = "{YOUR-PROJECT-NAME}" 18 | } 19 | 20 | resource "oxide_disk" "example" { 21 | project_id = data.oxide_project.example.id 22 | description = "a test disk" 23 | name = "mydisk" 24 | size = 1073741824 25 | block_size = 512 26 | } 27 | 28 | resource "oxide_disk" "example2" { 29 | project_id = data.oxide_project.example.id 30 | description = "a test disk" 31 | name = "mydisk2" 32 | size = 1073741824 33 | source_image_id = element(tolist(data.oxide_images.image_example.global_images[*].id), 0) 34 | } 35 | -------------------------------------------------------------------------------- /examples/instance_resource/README.md: -------------------------------------------------------------------------------- 1 | # Create basic instance 2 | 3 | This example Terraform configuration file performs the following: 4 | 5 | 1. Creates a basic instance that starts up a basic ngnix web server. 6 | 7 | To try it out make sure you have the following: 8 | 9 | - A project. 10 | - Previously set `OXIDE_HOST` and `OXIDE_TOKEN` environment variables 11 | 12 | Alternatively, you can modify the configuration file with your own `project_id`. Although not recommended, if you do not wish to set the environment variables, you can use the `host` and `token` fields in the `oxide` provider block: 13 | 14 | ```hcl 15 | provider "oxide" { 16 | host = "" 17 | token = "" 18 | } 19 | ``` 20 | 21 | Once the instance is running and cloud-init has finished (you can check this via the serial console on the UI), copy the external IP from the output. On your browser's 22 | navigation bar paste the external IP followed by port 80 e.g. 45.154.216.150:80. 23 | You should get a basic HTML website with the text: "Heya 0xide!". -------------------------------------------------------------------------------- /examples/instance_resource/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | apt-get update 3 | apt-get install nginx -y 4 | echo "Heya 0xide!" >/var/www/html/index.html -------------------------------------------------------------------------------- /examples/instance_resource/instance.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | oxide = { 6 | source = "oxidecomputer/oxide" 7 | version = "0.9.0" 8 | } 9 | } 10 | } 11 | 12 | provider "oxide" {} 13 | 14 | data "oxide_project" "example" { 15 | name = "{MY_PROJECT_NAME}" 16 | } 17 | 18 | resource "oxide_vpc" "example" { 19 | project_id = data.oxide_project.example.id 20 | description = "a test vpc" 21 | name = "myvpc" 22 | dns_name = "my-vpc-dns" 23 | } 24 | 25 | resource "oxide_vpc_firewall_rules" "example" { 26 | vpc_id = oxide_vpc.example.id 27 | rules = [ 28 | { 29 | action = "allow" 30 | description = "allow inbound TCP connections on ports 22 and 80 from anywhere" 31 | name = "allow-ssh-http" 32 | direction = "inbound" 33 | priority = 65534 34 | status = "enabled" 35 | filters = { 36 | ports = ["22", "80"] 37 | protocols = ["TCP"] 38 | }, 39 | targets = [ 40 | { 41 | type = "vpc" 42 | value = oxide_vpc.example.name 43 | } 44 | ] 45 | }, 46 | { 47 | action = "allow" 48 | description = "allow inbound traffic to all instances within the VPC if originated within the VPC" 49 | name = "allow-internal-inbound" 50 | direction = "inbound" 51 | priority = 65534 52 | status = "enabled" 53 | filters = { 54 | hosts = [ 55 | { 56 | type = "vpc" 57 | value = oxide_vpc.example.name 58 | } 59 | ] 60 | }, 61 | targets = [ 62 | { 63 | type = "vpc" 64 | value = oxide_vpc.example.name 65 | } 66 | ] 67 | }, 68 | { 69 | action = "allow" 70 | description = "allow inbound ICMP traffic from anywhere" 71 | name = "allow-icmp" 72 | direction = "inbound" 73 | priority = 65534 74 | status = "enabled" 75 | filters = { 76 | protocols = ["ICMP"] 77 | }, 78 | targets = [ 79 | { 80 | type = "vpc" 81 | value = oxide_vpc.example.name 82 | } 83 | ] 84 | } 85 | ] 86 | } 87 | 88 | data "oxide_vpc_subnet" "example" { 89 | project_name = data.oxide_project.example.name 90 | vpc_name = oxide_vpc.example.name 91 | name = "default" 92 | } 93 | 94 | resource "oxide_disk" "example" { 95 | project_id = data.oxide_project.example.id 96 | description = "a test disk" 97 | name = "my-disk" 98 | size = 21474836480 99 | source_image_id = "{MY_IMAGE_ID}" 100 | } 101 | 102 | resource "oxide_ssh_key" "example" { 103 | name = "example" 104 | description = "Example SSH key." 105 | public_key = "ssh-ed25519 {MY_PUBLIC_KEY}" 106 | } 107 | 108 | resource "oxide_instance" "test" { 109 | project_id = data.oxide_project.example.id 110 | boot_disk_id = oxide_disk.example.id 111 | description = "a test instance" 112 | name = "my-instance" 113 | host_name = "my-host" 114 | memory = 21474836480 115 | ncpus = 1 116 | start_on_create = true 117 | disk_attachments = [oxide_disk.example.id] 118 | ssh_public_keys = [oxide_ssh_key.example.id] 119 | external_ips = [ 120 | { 121 | type = "ephemeral" 122 | } 123 | ] 124 | network_interfaces = [ 125 | { 126 | subnet_id = data.oxide_vpc_subnet.example.id 127 | vpc_id = data.oxide_vpc_subnet.example.vpc_id 128 | description = "a sample nic" 129 | name = "mynic" 130 | } 131 | ] 132 | user_data = filebase64("./init.sh") 133 | } 134 | 135 | data "oxide_instance_external_ips" "example" { 136 | instance_id = oxide_instance.test.id 137 | } 138 | 139 | output "instance_external_ip" { 140 | value = data.oxide_instance_external_ips.example.external_ips.0.ip 141 | } 142 | -------------------------------------------------------------------------------- /examples/vpc_resource/README.md: -------------------------------------------------------------------------------- 1 | # VPC 2 | 3 | This example Terraform configuration file performs the following: 4 | 5 | 1. Creates a basic VPC. 6 | 7 | To try it out make sure you have the following: 8 | 9 | - A project already created. 10 | - Previously set `OXIDE_HOST` and `OXIDE_TOKEN` environment variables 11 | 12 | Alternatively, you can modify the configuration file with your own `project_id`. Although not recommended, if you do not wish to set the environment variables, you can use the `host` and `token` fields in the `oxide` provider block: 13 | 14 | ```hcl 15 | provider "oxide" { 16 | host = "" 17 | token = "" 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/vpc_resource/vpc.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | oxide = { 6 | source = "oxidecomputer/oxide" 7 | version = "0.9.0" 8 | } 9 | } 10 | } 11 | 12 | provider "oxide" {} 13 | 14 | data "oxide_project" "example" { 15 | name = "{YOUR-PROJECT-NAME}" 16 | } 17 | 18 | resource "oxide_vpc" "example" { 19 | project_id = data.oxide_project.example.id 20 | description = "a test vpc" 21 | name = "myvpc" 22 | dns_name = "my-vpc-dnssd" 23 | ipv6_prefix = "fd1e:4947:d4a1::/48" 24 | } 25 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/oxidecomputer/terraform-provider-oxide 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/google/uuid v1.6.0 7 | github.com/hashicorp/terraform-plugin-framework v1.15.0 8 | github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0 9 | github.com/hashicorp/terraform-plugin-framework-validators v0.18.0 10 | github.com/hashicorp/terraform-plugin-go v0.28.0 11 | github.com/hashicorp/terraform-plugin-log v0.9.0 12 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 13 | github.com/hashicorp/terraform-plugin-testing v1.13.1 14 | github.com/oxidecomputer/oxide.go v0.4.1-0.20250423011427-65b1d0f6b391 15 | github.com/stretchr/testify v1.10.0 16 | ) 17 | 18 | require ( 19 | github.com/ProtonMail/go-crypto v1.1.6 // indirect 20 | github.com/agext/levenshtein v1.2.2 // indirect 21 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 22 | github.com/cloudflare/circl v1.6.0 // indirect 23 | github.com/davecgh/go-spew v1.1.1 // indirect 24 | github.com/fatih/color v1.16.0 // indirect 25 | github.com/golang/protobuf v1.5.4 // indirect 26 | github.com/google/go-cmp v0.7.0 // indirect 27 | github.com/hashicorp/errwrap v1.1.0 // indirect 28 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect 29 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 30 | github.com/hashicorp/go-cty v1.5.0 // indirect 31 | github.com/hashicorp/go-hclog v1.6.3 // indirect 32 | github.com/hashicorp/go-multierror v1.1.1 // indirect 33 | github.com/hashicorp/go-plugin v1.6.3 // indirect 34 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect 35 | github.com/hashicorp/go-uuid v1.0.3 // indirect 36 | github.com/hashicorp/go-version v1.7.0 // indirect 37 | github.com/hashicorp/hc-install v0.9.2 // indirect 38 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 39 | github.com/hashicorp/logutils v1.0.0 // indirect 40 | github.com/hashicorp/terraform-exec v0.23.0 // indirect 41 | github.com/hashicorp/terraform-json v0.25.0 // indirect 42 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect 43 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect 44 | github.com/hashicorp/yamux v0.1.1 // indirect 45 | github.com/kr/pretty v0.3.0 // indirect 46 | github.com/mattn/go-colorable v0.1.13 // indirect 47 | github.com/mattn/go-isatty v0.0.20 // indirect 48 | github.com/mitchellh/copystructure v1.2.0 // indirect 49 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 50 | github.com/mitchellh/go-wordwrap v1.0.0 // indirect 51 | github.com/mitchellh/mapstructure v1.5.0 // indirect 52 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 53 | github.com/oklog/run v1.0.0 // indirect 54 | github.com/pelletier/go-toml v1.9.5 // indirect 55 | github.com/pmezard/go-difflib v1.0.0 // indirect 56 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 57 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 58 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 59 | github.com/zclconf/go-cty v1.16.2 // indirect 60 | golang.org/x/crypto v0.38.0 // indirect 61 | golang.org/x/mod v0.24.0 // indirect 62 | golang.org/x/net v0.39.0 // indirect 63 | golang.org/x/sync v0.14.0 // indirect 64 | golang.org/x/sys v0.33.0 // indirect 65 | golang.org/x/text v0.25.0 // indirect 66 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect 67 | google.golang.org/appengine v1.6.8 // indirect 68 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 69 | google.golang.org/grpc v1.72.1 // indirect 70 | google.golang.org/protobuf v1.36.6 // indirect 71 | gopkg.in/yaml.v3 v3.0.1 // indirect 72 | ) 73 | -------------------------------------------------------------------------------- /golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - deadcode 5 | - errcheck 6 | - gofmt 7 | - gosimple 8 | - ineffassign 9 | - misspell 10 | - staticcheck 11 | - structcheck 12 | - unconvert 13 | - unused 14 | - varcheck 15 | - vet 16 | 17 | linters-settings: 18 | errcheck: 19 | ignore: github.com/hashicorp/terraform-plugin-sdk/helper/schema:ForceNew|Set,fmt:.*,io:Close 20 | 21 | run: 22 | timeout: 10m 23 | -------------------------------------------------------------------------------- /internal/provider/data_source_anti_affinity_group_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceAntiAffinityGroupConfig struct { 15 | BlockName string 16 | Name string 17 | SupportBlockName string 18 | SupportBlockName2 string 19 | } 20 | 21 | var dataSourceAntiAffinityGroupConfigTpl = ` 22 | data "oxide_project" "{{.SupportBlockName}}" { 23 | name = "tf-acc-test" 24 | } 25 | 26 | resource "oxide_anti_affinity_group" "{{.SupportBlockName2}}" { 27 | project_id = data.oxide_project.{{.SupportBlockName}}.id 28 | name = "{{.Name}}" 29 | description = "a group" 30 | policy = "allow" 31 | } 32 | 33 | data "oxide_anti_affinity_group" "{{.BlockName}}" { 34 | project_name = "tf-acc-test" 35 | name = oxide_anti_affinity_group.{{.SupportBlockName2}}.name 36 | timeouts = { 37 | read = "1m" 38 | } 39 | } 40 | ` 41 | 42 | func TestAccCloudDataSourceAntiAffinityGroup_full(t *testing.T) { 43 | blockName := newBlockName("datasource-anti-affinity-group") 44 | resourceName := newResourceName() 45 | config, err := parsedAccConfig( 46 | dataSourceAntiAffinityGroupConfig{ 47 | BlockName: blockName, 48 | SupportBlockName: newBlockName("support"), 49 | SupportBlockName2: newBlockName("support"), 50 | Name: resourceName, 51 | }, 52 | dataSourceAntiAffinityGroupConfigTpl, 53 | ) 54 | if err != nil { 55 | t.Errorf("error parsing config template data: %e", err) 56 | } 57 | 58 | resource.ParallelTest(t, resource.TestCase{ 59 | PreCheck: func() { testAccPreCheck(t) }, 60 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 61 | Steps: []resource.TestStep{ 62 | { 63 | Config: config, 64 | Check: checkDataSourceAntiAffinityGroup( 65 | fmt.Sprintf("data.oxide_anti_affinity_group.%s", blockName), 66 | resourceName, 67 | ), 68 | }, 69 | }, 70 | }) 71 | } 72 | 73 | func checkDataSourceAntiAffinityGroup(dataName, keyName string) resource.TestCheckFunc { 74 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 75 | resource.TestCheckResourceAttrSet(dataName, "id"), 76 | resource.TestCheckResourceAttr(dataName, "name", keyName), 77 | resource.TestCheckResourceAttr(dataName, "description", "a group"), 78 | resource.TestCheckResourceAttr(dataName, "policy", "allow"), 79 | resource.TestCheckResourceAttr(dataName, "failure_domain", "sled"), 80 | resource.TestCheckResourceAttrSet(dataName, "project_id"), 81 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 82 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 83 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 84 | }...) 85 | } 86 | -------------------------------------------------------------------------------- /internal/provider/data_source_floating_ip_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceFloatingIPConfig struct { 15 | BlockName string 16 | Name string 17 | SupportBlockName string 18 | SupportBlockName2 string 19 | } 20 | 21 | var dataSourceFloatingIPConfigTpl = ` 22 | data "oxide_project" "{{.SupportBlockName}}" { 23 | name = "tf-acc-test" 24 | } 25 | 26 | resource "oxide_floating_ip" "{{.SupportBlockName2}}" { 27 | project_id = data.oxide_project.{{.SupportBlockName}}.id 28 | name = "{{.Name}}" 29 | description = "Floating IP." 30 | } 31 | 32 | data "oxide_floating_ip" "{{.BlockName}}" { 33 | project_name = data.oxide_project.{{.SupportBlockName}}.name 34 | name = oxide_floating_ip.{{.SupportBlockName2}}.name 35 | timeouts = { 36 | read = "1m" 37 | } 38 | } 39 | ` 40 | 41 | func TestAccCloudDataSourceFloatingIP_full(t *testing.T) { 42 | blockName := newBlockName("datasource-floating-ip") 43 | resourceName := newResourceName() 44 | config, err := parsedAccConfig( 45 | dataSourceFloatingIPConfig{ 46 | BlockName: blockName, 47 | SupportBlockName: newBlockName("support"), 48 | SupportBlockName2: newBlockName("support"), 49 | Name: resourceName, 50 | }, 51 | dataSourceFloatingIPConfigTpl, 52 | ) 53 | if err != nil { 54 | t.Errorf("error parsing config template data: %e", err) 55 | } 56 | 57 | resource.ParallelTest(t, resource.TestCase{ 58 | PreCheck: func() { testAccPreCheck(t) }, 59 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 60 | Steps: []resource.TestStep{ 61 | { 62 | Config: config, 63 | Check: checkDataSourceFloatingIP( 64 | fmt.Sprintf("data.oxide_floating_ip.%s", blockName), 65 | resourceName, 66 | ), 67 | }, 68 | }, 69 | }) 70 | } 71 | 72 | func checkDataSourceFloatingIP(dataName, keyName string) resource.TestCheckFunc { 73 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 74 | resource.TestCheckResourceAttrSet(dataName, "id"), 75 | resource.TestCheckResourceAttr(dataName, "name", keyName), 76 | resource.TestCheckResourceAttr(dataName, "description", "Floating IP."), 77 | resource.TestCheckResourceAttrSet(dataName, "project_id"), 78 | resource.TestCheckResourceAttrSet(dataName, "project_name"), 79 | resource.TestCheckResourceAttrSet(dataName, "ip"), 80 | resource.TestCheckResourceAttrSet(dataName, "ip_pool_id"), 81 | resource.TestCheckResourceAttr(dataName, "instance_id", ""), 82 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 83 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 84 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 85 | }...) 86 | } 87 | -------------------------------------------------------------------------------- /internal/provider/data_source_image_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceImageConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | SupportBlockName2 string 18 | } 19 | 20 | var dataSourceImageConfigTpl = ` 21 | data "oxide_project" "{{.SupportBlockName}}" { 22 | name = "tf-acc-test" 23 | } 24 | 25 | data "oxide_images" "{{.SupportBlockName2}}" { 26 | project_id = data.oxide_project.{{.SupportBlockName}}.id 27 | } 28 | 29 | data "oxide_image" "{{.BlockName}}" { 30 | project_name = "tf-acc-test" 31 | name = element(tolist(data.oxide_images.{{.SupportBlockName2}}.images[*].name), 0) 32 | timeouts = { 33 | read = "1m" 34 | } 35 | } 36 | ` 37 | 38 | // NB: The project must be populated with at least one image for this test to pass 39 | func TestAccCloudDataSourceImage_full(t *testing.T) { 40 | blockName := newBlockName("datasource-image") 41 | config, err := parsedAccConfig( 42 | dataSourceImageConfig{ 43 | BlockName: blockName, 44 | SupportBlockName: newBlockName("support"), 45 | SupportBlockName2: newBlockName("support"), 46 | }, 47 | dataSourceImageConfigTpl, 48 | ) 49 | if err != nil { 50 | t.Errorf("error parsing config template data: %e", err) 51 | } 52 | 53 | resource.ParallelTest(t, resource.TestCase{ 54 | PreCheck: func() { testAccPreCheck(t) }, 55 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 56 | Steps: []resource.TestStep{ 57 | { 58 | Config: config, 59 | Check: checkDataSourceImage( 60 | fmt.Sprintf("data.oxide_image.%s", blockName), 61 | ), 62 | }, 63 | }, 64 | }) 65 | } 66 | 67 | func checkDataSourceImage(dataName string) resource.TestCheckFunc { 68 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 69 | resource.TestCheckResourceAttrSet(dataName, "id"), 70 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 71 | resource.TestCheckResourceAttrSet(dataName, "block_size"), 72 | resource.TestCheckResourceAttrSet(dataName, "description"), 73 | resource.TestCheckResourceAttrSet(dataName, "os"), 74 | resource.TestCheckResourceAttrSet(dataName, "project_id"), 75 | resource.TestCheckResourceAttrSet(dataName, "project_name"), 76 | resource.TestCheckResourceAttrSet(dataName, "name"), 77 | resource.TestCheckResourceAttrSet(dataName, "size"), 78 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 79 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 80 | resource.TestCheckResourceAttrSet(dataName, "version"), 81 | }...) 82 | } 83 | -------------------------------------------------------------------------------- /internal/provider/data_source_images_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceProjectImagesConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | type dataSourceSiloImagesConfig struct { 20 | BlockName string 21 | } 22 | 23 | var dataSourceProjectImagesConfigTpl = ` 24 | data "oxide_project" "{{.SupportBlockName}}" { 25 | name = "tf-acc-test" 26 | } 27 | 28 | data "oxide_images" "{{.BlockName}}" { 29 | project_id = data.oxide_project.{{.SupportBlockName}}.id 30 | timeouts = { 31 | read = "1m" 32 | } 33 | } 34 | ` 35 | 36 | var dataSourceSiloImagesConfigTpl = ` 37 | data "oxide_images" "{{.BlockName}}" {} 38 | ` 39 | 40 | // NB: The project must be populated with at least one image for this test to pass 41 | func TestAccCloudDataSourceImages_project(t *testing.T) { 42 | blockName := newBlockName("datasource-images") 43 | config, err := parsedAccConfig( 44 | dataSourceProjectImagesConfig{ 45 | BlockName: blockName, 46 | SupportBlockName: newBlockName("support"), 47 | }, 48 | dataSourceProjectImagesConfigTpl, 49 | ) 50 | if err != nil { 51 | t.Errorf("error parsing config template data: %e", err) 52 | } 53 | 54 | resource.ParallelTest(t, resource.TestCase{ 55 | PreCheck: func() { testAccPreCheck(t) }, 56 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 57 | Steps: []resource.TestStep{ 58 | { 59 | Config: config, 60 | Check: checkDataSourceProjectImages( 61 | fmt.Sprintf("data.oxide_images.%s", blockName), 62 | ), 63 | }, 64 | }, 65 | }) 66 | } 67 | 68 | // NB: The silo must be populated with at least one image for this test to pass 69 | func TestAccCloudDataSourceImages_silo(t *testing.T) { 70 | blockName := newBlockName("datasource-images") 71 | config, err := parsedAccConfig( 72 | dataSourceSiloImagesConfig{ 73 | BlockName: blockName, 74 | }, 75 | dataSourceSiloImagesConfigTpl, 76 | ) 77 | if err != nil { 78 | t.Errorf("error parsing config template data: %e", err) 79 | } 80 | 81 | resource.ParallelTest(t, resource.TestCase{ 82 | PreCheck: func() { testAccPreCheck(t) }, 83 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 84 | Steps: []resource.TestStep{ 85 | { 86 | Config: config, 87 | Check: checkDataSourceSiloImages( 88 | fmt.Sprintf("data.oxide_images.%s", blockName), 89 | ), 90 | }, 91 | }, 92 | }) 93 | } 94 | 95 | func checkDataSourceProjectImages(dataName string) resource.TestCheckFunc { 96 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 97 | resource.TestCheckResourceAttrSet(dataName, "id"), 98 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 99 | resource.TestCheckResourceAttrSet(dataName, "images.0.block_size"), 100 | resource.TestCheckResourceAttrSet(dataName, "images.0.description"), 101 | resource.TestCheckResourceAttrSet(dataName, "images.0.os"), 102 | resource.TestCheckResourceAttrSet(dataName, "images.0.id"), 103 | resource.TestCheckResourceAttrSet(dataName, "images.0.name"), 104 | resource.TestCheckResourceAttrSet(dataName, "images.0.size"), 105 | resource.TestCheckResourceAttrSet(dataName, "images.0.time_created"), 106 | resource.TestCheckResourceAttrSet(dataName, "images.0.time_modified"), 107 | resource.TestCheckResourceAttrSet(dataName, "images.0.version"), 108 | }...) 109 | } 110 | 111 | func checkDataSourceSiloImages(dataName string) resource.TestCheckFunc { 112 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 113 | resource.TestCheckResourceAttrSet(dataName, "id"), 114 | resource.TestCheckResourceAttrSet(dataName, "images.0.block_size"), 115 | resource.TestCheckResourceAttrSet(dataName, "images.0.os"), 116 | resource.TestCheckResourceAttrSet(dataName, "images.0.id"), 117 | resource.TestCheckResourceAttrSet(dataName, "images.0.name"), 118 | resource.TestCheckResourceAttrSet(dataName, "images.0.size"), 119 | resource.TestCheckResourceAttrSet(dataName, "images.0.time_created"), 120 | resource.TestCheckResourceAttrSet(dataName, "images.0.time_modified"), 121 | resource.TestCheckResourceAttrSet(dataName, "images.0.version"), 122 | }...) 123 | } 124 | -------------------------------------------------------------------------------- /internal/provider/data_source_instance_external_ips.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/google/uuid" 12 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource" 14 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 15 | "github.com/hashicorp/terraform-plugin-framework/types" 16 | "github.com/hashicorp/terraform-plugin-log/tflog" 17 | "github.com/oxidecomputer/oxide.go/oxide" 18 | ) 19 | 20 | var ( 21 | _ datasource.DataSource = (*instanceExternalIPsDataSource)(nil) 22 | _ datasource.DataSourceWithConfigure = (*instanceExternalIPsDataSource)(nil) 23 | ) 24 | 25 | // NewInstanceExternalIPsDataSource initialises an images datasource 26 | func NewInstanceExternalIPsDataSource() datasource.DataSource { 27 | return &instanceExternalIPsDataSource{} 28 | } 29 | 30 | type instanceExternalIPsDataSource struct { 31 | client *oxide.Client 32 | } 33 | 34 | type instanceExternalIPsDatasourceModel struct { 35 | ID types.String `tfsdk:"id"` 36 | InstanceID types.String `tfsdk:"instance_id"` 37 | Timeouts timeouts.Value `tfsdk:"timeouts"` 38 | ExternalIPs []externalIPDatasourceModel `tfsdk:"external_ips"` 39 | } 40 | 41 | type externalIPDatasourceModel struct { 42 | IP types.String `tfsdk:"ip"` 43 | Kind types.String `tfsdk:"kind"` 44 | } 45 | 46 | func (d *instanceExternalIPsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 47 | resp.TypeName = "oxide_instance_external_ips" 48 | } 49 | 50 | // Configure adds the provider configured client to the data source. 51 | func (d *instanceExternalIPsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 52 | if req.ProviderData == nil { 53 | return 54 | } 55 | 56 | d.client = req.ProviderData.(*oxide.Client) 57 | } 58 | 59 | func (d *instanceExternalIPsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 60 | resp.Schema = schema.Schema{ 61 | Attributes: map[string]schema.Attribute{ 62 | "instance_id": schema.StringAttribute{ 63 | Required: true, 64 | Description: "ID of the instance to which the external IPs belong to.", 65 | }, 66 | "id": schema.StringAttribute{ 67 | Computed: true, 68 | }, 69 | "timeouts": timeouts.Attributes(ctx), 70 | "external_ips": schema.ListNestedAttribute{ 71 | Computed: true, 72 | NestedObject: schema.NestedAttributeObject{ 73 | Attributes: map[string]schema.Attribute{ 74 | "ip": schema.StringAttribute{ 75 | Description: "External IP address.", 76 | Computed: true, 77 | }, 78 | "kind": schema.StringAttribute{ 79 | Computed: true, 80 | Description: "Kind of external IP address.", 81 | }, 82 | }, 83 | }, 84 | }, 85 | }, 86 | } 87 | } 88 | 89 | func (d *instanceExternalIPsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 90 | var state instanceExternalIPsDatasourceModel 91 | 92 | // Read Terraform configuration data into the model 93 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 94 | if resp.Diagnostics.HasError() { 95 | return 96 | } 97 | 98 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 99 | resp.Diagnostics.Append(diags...) 100 | if resp.Diagnostics.HasError() { 101 | return 102 | } 103 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 104 | defer cancel() 105 | 106 | params := oxide.InstanceExternalIpListParams{ 107 | Instance: oxide.NameOrId(state.InstanceID.ValueString()), 108 | } 109 | ips, err := d.client.InstanceExternalIpList(ctx, params) 110 | if err != nil { 111 | resp.Diagnostics.AddError( 112 | "Unable to read external ips:", 113 | "API error: "+err.Error(), 114 | ) 115 | return 116 | } 117 | 118 | tflog.Trace(ctx, fmt.Sprintf("read all external IPs from instance: %v", state.InstanceID.ValueString()), map[string]any{"success": true}) 119 | 120 | // Set a unique ID for the datasource payload 121 | state.ID = types.StringValue(uuid.New().String()) 122 | 123 | // Map response body to model 124 | for _, ip := range ips.Items { 125 | externalIPState := externalIPDatasourceModel{ 126 | IP: types.StringValue(ip.Ip), 127 | Kind: types.StringValue(string(ip.Kind)), 128 | } 129 | state.ExternalIPs = append(state.ExternalIPs, externalIPState) 130 | } 131 | 132 | // Save state into Terraform state 133 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 134 | if resp.Diagnostics.HasError() { 135 | return 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /internal/provider/data_source_instance_external_ips_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceInstanceExternalIPConfig struct { 15 | BlockName string 16 | InstanceName string 17 | InstanceBlockName string 18 | SupportBlockName string 19 | } 20 | 21 | var datasourceInstanceExternalIPsConfigTpl = ` 22 | data "oxide_project" "{{.SupportBlockName}}" { 23 | name = "tf-acc-test" 24 | } 25 | 26 | resource "oxide_instance" "{{.InstanceBlockName}}" { 27 | project_id = data.oxide_project.{{.SupportBlockName}}.id 28 | description = "a test instance" 29 | name = "{{.InstanceName}}" 30 | host_name = "terraform-acc-myhost" 31 | memory = 1073741824 32 | ncpus = 1 33 | start_on_create = false 34 | external_ips = [ 35 | { 36 | type = "ephemeral" 37 | } 38 | ] 39 | } 40 | 41 | data "oxide_instance_external_ips" "{{.BlockName}}" { 42 | instance_id = oxide_instance.{{.InstanceBlockName}}.id 43 | timeouts = { 44 | read = "1m" 45 | } 46 | } 47 | ` 48 | 49 | func TestAccCloudDataSourceInstanceExternalIPs_full(t *testing.T) { 50 | blockName := newBlockName("datasource-instance-external-ips") 51 | config, err := parsedAccConfig( 52 | dataSourceInstanceExternalIPConfig{ 53 | BlockName: blockName, 54 | SupportBlockName: newBlockName("support"), 55 | InstanceName: newResourceName(), 56 | InstanceBlockName: newBlockName("instance"), 57 | }, 58 | datasourceInstanceExternalIPsConfigTpl, 59 | ) 60 | if err != nil { 61 | t.Errorf("error parsing config template data: %e", err) 62 | } 63 | 64 | resource.ParallelTest(t, resource.TestCase{ 65 | PreCheck: func() { testAccPreCheck(t) }, 66 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 67 | Steps: []resource.TestStep{ 68 | { 69 | Config: config, 70 | Check: checkDataSourceInstanceExternalIPs( 71 | fmt.Sprintf("data.oxide_instance_external_ips.%s", blockName), 72 | ), 73 | }, 74 | }, 75 | }) 76 | } 77 | 78 | func checkDataSourceInstanceExternalIPs(dataName string) resource.TestCheckFunc { 79 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 80 | resource.TestCheckResourceAttrSet(dataName, "id"), 81 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 82 | resource.TestCheckResourceAttrSet(dataName, "external_ips.0.ip"), 83 | resource.TestCheckResourceAttrSet(dataName, "external_ips.0.kind"), 84 | }...) 85 | } 86 | -------------------------------------------------------------------------------- /internal/provider/data_source_ip_pool.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var _ datasource.DataSource = (*ipPoolDataSource)(nil) 20 | var _ datasource.DataSourceWithConfigure = (*ipPoolDataSource)(nil) 21 | 22 | type ipPoolDataSource struct { 23 | client *oxide.Client 24 | } 25 | 26 | type ipPoolDataSourceModel struct { 27 | Description types.String `tfsdk:"description"` 28 | ID types.String `tfsdk:"id"` 29 | IsDefault types.Bool `tfsdk:"is_default"` 30 | Name types.String `tfsdk:"name"` 31 | Timeouts timeouts.Value `tfsdk:"timeouts"` 32 | TimeCreated types.String `tfsdk:"time_created"` 33 | TimeModified types.String `tfsdk:"time_modified"` 34 | } 35 | 36 | // NewIpPoolDataSource initialises an ip_pool datasource 37 | func NewIpPoolDataSource() datasource.DataSource { 38 | return &ipPoolDataSource{} 39 | } 40 | 41 | func (d *ipPoolDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 42 | resp.TypeName = "oxide_ip_pool" 43 | } 44 | 45 | // Configure adds the provider configured client to the data source. 46 | func (d *ipPoolDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 47 | if req.ProviderData == nil { 48 | return 49 | } 50 | 51 | d.client = req.ProviderData.(*oxide.Client) 52 | } 53 | 54 | func (d *ipPoolDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 55 | resp.Schema = schema.Schema{ 56 | Attributes: map[string]schema.Attribute{ 57 | "name": schema.StringAttribute{ 58 | Required: true, 59 | Description: "Name of the IP pool.", 60 | }, 61 | "description": schema.StringAttribute{ 62 | Computed: true, 63 | Description: "Description for the IP pool.", 64 | }, 65 | "id": schema.StringAttribute{ 66 | Computed: true, 67 | Description: "Unique, immutable, system-controlled identifier of the IP pool.", 68 | }, 69 | "is_default": schema.BoolAttribute{ 70 | Computed: true, 71 | Description: "If a pool is the default for a silo, floating IPs and instance ephemeral IPs will come from that pool when no other pool is specified. There can be at most one default for a given silo.", 72 | }, 73 | "time_created": schema.StringAttribute{ 74 | Computed: true, 75 | Description: "Timestamp of when this IP pool was created.", 76 | }, 77 | "time_modified": schema.StringAttribute{ 78 | Computed: true, 79 | Description: "Timestamp of when this IP pool was last modified.", 80 | }, 81 | "timeouts": timeouts.Attributes(ctx), 82 | }, 83 | } 84 | } 85 | 86 | func (d *ipPoolDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 87 | var state ipPoolDataSourceModel 88 | 89 | // Read Terraform configuration data into the model 90 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 91 | if resp.Diagnostics.HasError() { 92 | return 93 | } 94 | 95 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 96 | resp.Diagnostics.Append(diags...) 97 | if resp.Diagnostics.HasError() { 98 | return 99 | } 100 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 101 | defer cancel() 102 | 103 | params := oxide.ProjectIpPoolViewParams{ 104 | Pool: oxide.NameOrId(state.Name.ValueString()), 105 | } 106 | ipPool, err := d.client.ProjectIpPoolView(ctx, params) 107 | if err != nil { 108 | resp.Diagnostics.AddError( 109 | "Unable to read IP pool:", 110 | err.Error(), 111 | ) 112 | return 113 | } 114 | 115 | tflog.Trace(ctx, fmt.Sprintf("read IP pool with ID: %v", ipPool.Id), map[string]any{"success": true}) 116 | 117 | // Map response body to model 118 | state.Description = types.StringValue(ipPool.Description) 119 | state.ID = types.StringValue(ipPool.Id) 120 | state.IsDefault = types.BoolPointerValue(ipPool.IsDefault) 121 | state.Name = types.StringValue(string(ipPool.Name)) 122 | state.TimeCreated = types.StringValue(ipPool.TimeCreated.String()) 123 | state.TimeModified = types.StringValue(ipPool.TimeCreated.String()) 124 | 125 | // Save state into Terraform state 126 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 127 | if resp.Diagnostics.HasError() { 128 | return 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /internal/provider/data_source_ip_pool_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceIPPoolConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | var dataSourceIPPoolConfigTpl = ` 20 | data "oxide_ip_pool" "{{.BlockName}}" { 21 | name = "default" 22 | timeouts = { 23 | read = "1m" 24 | } 25 | } 26 | ` 27 | 28 | func TestAccSiloDataSourceIPPool_full(t *testing.T) { 29 | blockName := newBlockName("datasource-ip-pool") 30 | config, err := parsedAccConfig( 31 | dataSourceIPPoolConfig{ 32 | BlockName: blockName, 33 | SupportBlockName: newBlockName("support"), 34 | }, 35 | dataSourceIPPoolConfigTpl, 36 | ) 37 | if err != nil { 38 | t.Errorf("error parsing config template data: %e", err) 39 | } 40 | 41 | resource.ParallelTest(t, resource.TestCase{ 42 | PreCheck: func() { testAccPreCheck(t) }, 43 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 44 | Steps: []resource.TestStep{ 45 | { 46 | Config: config, 47 | Check: checkDataSourceIPPool( 48 | fmt.Sprintf("data.oxide_ip_pool.%s", blockName), 49 | ), 50 | }, 51 | }, 52 | }) 53 | } 54 | 55 | func checkDataSourceIPPool(dataName string) resource.TestCheckFunc { 56 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 57 | resource.TestCheckResourceAttrSet(dataName, "name"), 58 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 59 | resource.TestCheckResourceAttrSet(dataName, "id"), 60 | resource.TestCheckResourceAttrSet(dataName, "is_default"), 61 | resource.TestCheckResourceAttrSet(dataName, "description"), 62 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 63 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 64 | }...) 65 | } 66 | -------------------------------------------------------------------------------- /internal/provider/data_source_project.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var _ datasource.DataSource = (*projectDataSource)(nil) 20 | var _ datasource.DataSourceWithConfigure = (*projectDataSource)(nil) 21 | 22 | type projectDataSource struct { 23 | client *oxide.Client 24 | } 25 | 26 | type projectDataSourceModel struct { 27 | Description types.String `tfsdk:"description"` 28 | ID types.String `tfsdk:"id"` 29 | Timeouts timeouts.Value `tfsdk:"timeouts"` 30 | Name types.String `tfsdk:"name"` 31 | TimeCreated types.String `tfsdk:"time_created"` 32 | TimeModified types.String `tfsdk:"time_modified"` 33 | } 34 | 35 | // NewProjectDataSource initialises a project datasource 36 | func NewProjectDataSource() datasource.DataSource { 37 | return &projectDataSource{} 38 | } 39 | 40 | func (d *projectDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 41 | resp.TypeName = "oxide_project" 42 | } 43 | 44 | // Configure adds the provider configured client to the data source. 45 | func (d *projectDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 46 | if req.ProviderData == nil { 47 | return 48 | } 49 | 50 | d.client = req.ProviderData.(*oxide.Client) 51 | } 52 | 53 | func (d *projectDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 54 | resp.Schema = schema.Schema{ 55 | Attributes: map[string]schema.Attribute{ 56 | "name": schema.StringAttribute{ 57 | Required: true, 58 | Description: "Name of the project.", 59 | }, 60 | "description": schema.StringAttribute{ 61 | Computed: true, 62 | Description: "Description for the project.", 63 | }, 64 | "id": schema.StringAttribute{ 65 | Computed: true, 66 | Description: "Unique, immutable, system-controlled identifier of the project.", 67 | }, 68 | "time_created": schema.StringAttribute{ 69 | Computed: true, 70 | Description: "Timestamp of when this project was created.", 71 | }, 72 | "time_modified": schema.StringAttribute{ 73 | Computed: true, 74 | Description: "Timestamp of when this project was last modified.", 75 | }, 76 | "timeouts": timeouts.Attributes(ctx), 77 | }, 78 | } 79 | } 80 | 81 | func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 82 | var state projectDataSourceModel 83 | 84 | // Read Terraform configuration data into the model 85 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 86 | if resp.Diagnostics.HasError() { 87 | return 88 | } 89 | 90 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 91 | resp.Diagnostics.Append(diags...) 92 | if resp.Diagnostics.HasError() { 93 | return 94 | } 95 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 96 | defer cancel() 97 | 98 | params := oxide.ProjectViewParams{ 99 | Project: oxide.NameOrId(state.Name.ValueString()), 100 | } 101 | project, err := d.client.ProjectView(ctx, params) 102 | if err != nil { 103 | resp.Diagnostics.AddError( 104 | "Unable to read project:", 105 | err.Error(), 106 | ) 107 | return 108 | } 109 | 110 | tflog.Trace(ctx, fmt.Sprintf("read project with ID: %v", project.Id), map[string]any{"success": true}) 111 | 112 | // Map response body to model 113 | state.Description = types.StringValue(project.Description) 114 | state.ID = types.StringValue(project.Id) 115 | state.Name = types.StringValue(string(project.Name)) 116 | state.TimeCreated = types.StringValue(project.TimeCreated.String()) 117 | state.TimeModified = types.StringValue(project.TimeCreated.String()) 118 | 119 | // Save state into Terraform state 120 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 121 | if resp.Diagnostics.HasError() { 122 | return 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /internal/provider/data_source_project_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceProjectConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | var dataSourceProjectConfigTpl = ` 20 | data "oxide_project" "{{.BlockName}}" { 21 | name = "tf-acc-test" 22 | timeouts = { 23 | read = "1m" 24 | } 25 | } 26 | ` 27 | 28 | func TestAccCloudDataSourceProject_full(t *testing.T) { 29 | blockName := newBlockName("datasource-project") 30 | config, err := parsedAccConfig( 31 | dataSourceProjectConfig{ 32 | BlockName: blockName, 33 | SupportBlockName: newBlockName("support"), 34 | }, 35 | dataSourceProjectConfigTpl, 36 | ) 37 | if err != nil { 38 | t.Errorf("error parsing config template data: %e", err) 39 | } 40 | 41 | resource.ParallelTest(t, resource.TestCase{ 42 | PreCheck: func() { testAccPreCheck(t) }, 43 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 44 | Steps: []resource.TestStep{ 45 | { 46 | Config: config, 47 | Check: checkDataSourceProject( 48 | fmt.Sprintf("data.oxide_project.%s", blockName), 49 | ), 50 | }, 51 | }, 52 | }) 53 | } 54 | 55 | func checkDataSourceProject(dataName string) resource.TestCheckFunc { 56 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 57 | resource.TestCheckResourceAttrSet(dataName, "name"), 58 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 59 | resource.TestCheckResourceAttrSet(dataName, "id"), 60 | resource.TestCheckResourceAttrSet(dataName, "description"), 61 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 62 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 63 | }...) 64 | } 65 | -------------------------------------------------------------------------------- /internal/provider/data_source_projects.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/google/uuid" 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var _ datasource.DataSource = (*projectsDataSource)(nil) 20 | var _ datasource.DataSourceWithConfigure = (*projectsDataSource)(nil) 21 | 22 | type projectsDataSource struct { 23 | client *oxide.Client 24 | } 25 | 26 | type projectsDataSourceModel struct { 27 | ID types.String `tfsdk:"id"` 28 | Timeouts timeouts.Value `tfsdk:"timeouts"` 29 | Projects []projectModel `tfsdk:"projects"` 30 | } 31 | 32 | type projectModel struct { 33 | Description types.String `tfsdk:"description"` 34 | ID types.String `tfsdk:"id"` 35 | Name types.String `tfsdk:"name"` 36 | TimeCreated types.String `tfsdk:"time_created"` 37 | TimeModified types.String `tfsdk:"time_modified"` 38 | } 39 | 40 | // NewProjectsDataSource initialises a projects datasource 41 | func NewProjectsDataSource() datasource.DataSource { 42 | return &projectsDataSource{} 43 | } 44 | 45 | func (d *projectsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 46 | resp.TypeName = "oxide_projects" 47 | } 48 | 49 | // Configure adds the provider configured client to the data source. 50 | func (d *projectsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 51 | if req.ProviderData == nil { 52 | return 53 | } 54 | 55 | d.client = req.ProviderData.(*oxide.Client) 56 | } 57 | 58 | func (d *projectsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 59 | resp.Schema = schema.Schema{ 60 | Attributes: map[string]schema.Attribute{ 61 | "id": schema.StringAttribute{ 62 | Computed: true, 63 | }, 64 | "timeouts": timeouts.Attributes(ctx), 65 | "projects": schema.ListNestedAttribute{ 66 | Computed: true, 67 | NestedObject: schema.NestedAttributeObject{ 68 | Attributes: map[string]schema.Attribute{ 69 | "description": schema.StringAttribute{ 70 | Computed: true, 71 | Description: "Description for the project.", 72 | }, 73 | "id": schema.StringAttribute{ 74 | Computed: true, 75 | Description: "Unique, immutable, system-controlled identifier of the project.", 76 | }, 77 | "name": schema.StringAttribute{ 78 | Computed: true, 79 | Description: "Name of the project.", 80 | }, 81 | "time_created": schema.StringAttribute{ 82 | Computed: true, 83 | Description: "Timestamp of when this project was created.", 84 | }, 85 | "time_modified": schema.StringAttribute{ 86 | Computed: true, 87 | Description: "Timestamp of when this project was last modified.", 88 | }, 89 | }, 90 | }, 91 | }, 92 | }, 93 | } 94 | } 95 | 96 | func (d *projectsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 97 | var state projectsDataSourceModel 98 | 99 | // Read Terraform configuration data into the model 100 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 101 | if resp.Diagnostics.HasError() { 102 | return 103 | } 104 | 105 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 106 | resp.Diagnostics.Append(diags...) 107 | if resp.Diagnostics.HasError() { 108 | return 109 | } 110 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 111 | defer cancel() 112 | 113 | // TODO: It would be preferable to us the client.Projects.ListAllPages method instead. 114 | // Unfortunately, currently that method has a bug where it returns twice as many results 115 | // as there are in reality. For now I'll use the List method with a limit of 1,000,000,000 results. 116 | // Seems unlikely anyone will have more than one billion projects. 117 | params := oxide.ProjectListParams{ 118 | Limit: oxide.NewPointer(1000000000), 119 | SortBy: oxide.NameOrIdSortModeNameDescending, 120 | } 121 | projects, err := d.client.ProjectList(ctx, params) 122 | if err != nil { 123 | resp.Diagnostics.AddError( 124 | "Unable to read projects:", 125 | err.Error(), 126 | ) 127 | return 128 | } 129 | 130 | tflog.Trace(ctx, "read all projects", map[string]any{"success": true}) 131 | 132 | // Set a unique ID for the datasource payload 133 | state.ID = types.StringValue(uuid.New().String()) 134 | 135 | // Map response body to model 136 | for _, project := range projects.Items { 137 | projectState := projectModel{ 138 | Description: types.StringValue(project.Description), 139 | ID: types.StringValue(project.Id), 140 | Name: types.StringValue(string(project.Name)), 141 | TimeCreated: types.StringValue(project.TimeCreated.String()), 142 | TimeModified: types.StringValue(project.TimeCreated.String()), 143 | } 144 | 145 | state.Projects = append(state.Projects, projectState) 146 | } 147 | 148 | // Save state into Terraform state 149 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 150 | if resp.Diagnostics.HasError() { 151 | return 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /internal/provider/data_source_projects_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceProjectsConfig struct { 15 | BlockName string 16 | } 17 | 18 | var dataSourceProjectsConfigTpl = ` 19 | data "oxide_projects" "{{.BlockName}}" { 20 | timeouts = { 21 | read = "1m" 22 | } 23 | } 24 | ` 25 | 26 | func TestAccCloudDataSourceProjects_full(t *testing.T) { 27 | blockName := newBlockName("datasource-projects") 28 | config, err := parsedAccConfig( 29 | dataSourceProjectsConfig{ 30 | BlockName: blockName, 31 | }, 32 | dataSourceProjectsConfigTpl, 33 | ) 34 | if err != nil { 35 | t.Errorf("error parsing config template data: %e", err) 36 | } 37 | 38 | resource.ParallelTest(t, resource.TestCase{ 39 | PreCheck: func() { testAccPreCheck(t) }, 40 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 41 | Steps: []resource.TestStep{ 42 | { 43 | Config: config, 44 | Check: checkDataSourceProjects( 45 | fmt.Sprintf("data.oxide_projects.%s", blockName), 46 | ), 47 | }, 48 | }, 49 | }) 50 | } 51 | 52 | func checkDataSourceProjects(dataName string) resource.TestCheckFunc { 53 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 54 | resource.TestCheckResourceAttrSet(dataName, "id"), 55 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 56 | resource.TestCheckResourceAttrSet(dataName, "projects.0.id"), 57 | resource.TestCheckResourceAttrSet(dataName, "projects.0.name"), 58 | resource.TestCheckResourceAttrSet(dataName, "projects.0.time_created"), 59 | resource.TestCheckResourceAttrSet(dataName, "projects.0.time_modified"), 60 | }...) 61 | } 62 | -------------------------------------------------------------------------------- /internal/provider/data_source_silo.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var _ datasource.DataSource = (*siloDataSource)(nil) 20 | var _ datasource.DataSourceWithConfigure = (*siloDataSource)(nil) 21 | 22 | type siloDataSource struct { 23 | client *oxide.Client 24 | } 25 | 26 | type siloDataSourceModel struct { 27 | Description types.String `tfsdk:"description"` 28 | Discoverable types.Bool `tfsdk:"discoverable"` 29 | ID types.String `tfsdk:"id"` 30 | IdentityMode types.String `tfsdk:"identity_mode"` 31 | Name types.String `tfsdk:"name"` 32 | Timeouts timeouts.Value `tfsdk:"timeouts"` 33 | TimeCreated types.String `tfsdk:"time_created"` 34 | TimeModified types.String `tfsdk:"time_modified"` 35 | } 36 | 37 | // NewSiloDataSource initialises a silo datasource 38 | func NewSiloDataSource() datasource.DataSource { 39 | return &siloDataSource{} 40 | } 41 | 42 | func (d *siloDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 43 | resp.TypeName = "oxide_silo" 44 | } 45 | 46 | // Configure adds the provider configured client to the data source. 47 | func (d *siloDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 48 | if req.ProviderData == nil { 49 | return 50 | } 51 | 52 | d.client = req.ProviderData.(*oxide.Client) 53 | } 54 | 55 | func (d *siloDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 56 | resp.Schema = schema.Schema{ 57 | Attributes: map[string]schema.Attribute{ 58 | "name": schema.StringAttribute{ 59 | Required: true, 60 | Description: "Name of the Silo.", 61 | }, 62 | "description": schema.StringAttribute{ 63 | Computed: true, 64 | Description: "Description for the Silo.", 65 | }, 66 | "id": schema.StringAttribute{ 67 | Computed: true, 68 | Description: "Unique, immutable, system-controlled identifier of the Silo.", 69 | }, 70 | "identity_mode": schema.StringAttribute{ 71 | Computed: true, 72 | Description: "How users and groups are managed in this Silo.", 73 | }, 74 | "discoverable": schema.BoolAttribute{ 75 | Computed: true, 76 | Description: "A silo where discoverable is false can be retrieved only by its ID - it will not be part of the 'list all silos' output", 77 | }, 78 | "time_created": schema.StringAttribute{ 79 | Computed: true, 80 | Description: "Timestamp of when this Silo was created.", 81 | }, 82 | "time_modified": schema.StringAttribute{ 83 | Computed: true, 84 | Description: "Timestamp of when this Silo was last modified.", 85 | }, 86 | "timeouts": timeouts.Attributes(ctx), 87 | }, 88 | } 89 | } 90 | 91 | func (d *siloDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 92 | var state siloDataSourceModel 93 | 94 | // Read Terraform configuration data into the model 95 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 96 | if resp.Diagnostics.HasError() { 97 | return 98 | } 99 | 100 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 101 | resp.Diagnostics.Append(diags...) 102 | if resp.Diagnostics.HasError() { 103 | return 104 | } 105 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 106 | defer cancel() 107 | 108 | params := oxide.SiloViewParams{ 109 | Silo: oxide.NameOrId(state.Name.ValueString()), 110 | } 111 | silo, err := d.client.SiloView(ctx, params) 112 | if err != nil { 113 | resp.Diagnostics.AddError( 114 | "Unable to read Silo:", 115 | err.Error(), 116 | ) 117 | return 118 | } 119 | 120 | tflog.Trace(ctx, fmt.Sprintf("read Silo with ID: %v", silo.Id), map[string]any{"success": true}) 121 | 122 | // Map response body to model 123 | state.Description = types.StringValue(silo.Description) 124 | state.ID = types.StringValue(silo.Id) 125 | state.Discoverable = types.BoolPointerValue(silo.Discoverable) 126 | state.IdentityMode = types.StringValue(string(silo.IdentityMode)) 127 | state.Name = types.StringValue(string(silo.Name)) 128 | state.TimeCreated = types.StringValue(silo.TimeCreated.String()) 129 | state.TimeModified = types.StringValue(silo.TimeCreated.String()) 130 | 131 | // Save state into Terraform state 132 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 133 | if resp.Diagnostics.HasError() { 134 | return 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /internal/provider/data_source_silo_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceSiloConfig struct { 15 | BlockName string 16 | } 17 | 18 | var dataSourceSiloConfigTpl = ` 19 | data "oxide_silo" "{{.BlockName}}" { 20 | name = "default" 21 | timeouts = { 22 | read = "1m" 23 | } 24 | } 25 | ` 26 | 27 | func TestAccSiloDataSourceSilo_full(t *testing.T) { 28 | blockName := newBlockName("datasource-silo") 29 | config, err := parsedAccConfig( 30 | dataSourceSiloConfig{ 31 | BlockName: blockName, 32 | }, 33 | dataSourceSiloConfigTpl, 34 | ) 35 | if err != nil { 36 | t.Errorf("error parsing config template data: %e", err) 37 | } 38 | 39 | resource.ParallelTest(t, resource.TestCase{ 40 | PreCheck: func() { testAccPreCheck(t) }, 41 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 42 | Steps: []resource.TestStep{ 43 | { 44 | Config: config, 45 | Check: checkDataSourceSilo( 46 | fmt.Sprintf("data.oxide_silo.%s", blockName), 47 | ), 48 | }, 49 | }, 50 | }) 51 | } 52 | 53 | func checkDataSourceSilo(dataName string) resource.TestCheckFunc { 54 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 55 | resource.TestCheckResourceAttrSet(dataName, "name"), 56 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 57 | resource.TestCheckResourceAttrSet(dataName, "id"), 58 | resource.TestCheckResourceAttrSet(dataName, "discoverable"), 59 | resource.TestCheckResourceAttrSet(dataName, "identity_mode"), 60 | resource.TestCheckResourceAttrSet(dataName, "description"), 61 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 62 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 63 | }...) 64 | } 65 | -------------------------------------------------------------------------------- /internal/provider/data_source_ssh_key.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var ( 20 | _ datasource.DataSource = (*sshKeyDataSource)(nil) 21 | _ datasource.DataSourceWithConfigure = (*sshKeyDataSource)(nil) 22 | ) 23 | 24 | // NewSSHKeyDataSource is a helper function to simplify the provider implementation. 25 | func NewSSHKeyDataSource() datasource.DataSource { 26 | return &sshKeyDataSource{} 27 | } 28 | 29 | // sshKeyDataSource is the data source implementation. 30 | type sshKeyDataSource struct { 31 | client *oxide.Client 32 | } 33 | 34 | // sshKeyDataSourceModel are the attributes that are supported on this data source. 35 | type sshKeyDataSourceModel struct { 36 | ID types.String `tfsdk:"id"` 37 | Name types.String `tfsdk:"name"` 38 | Description types.String `tfsdk:"description"` 39 | PublicKey types.String `tfsdk:"public_key"` 40 | SiloUserID types.String `tfsdk:"silo_user_id"` 41 | TimeCreated types.String `tfsdk:"time_created"` 42 | TimeModified types.String `tfsdk:"time_modified"` 43 | Timeouts timeouts.Value `tfsdk:"timeouts"` 44 | } 45 | 46 | // Metadata sets the resource type name. 47 | func (d *sshKeyDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 48 | resp.TypeName = "oxide_ssh_key" 49 | } 50 | 51 | // Configure adds the provider configured client to the data source. 52 | func (d *sshKeyDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 53 | if req.ProviderData == nil { 54 | return 55 | } 56 | 57 | d.client = req.ProviderData.(*oxide.Client) 58 | } 59 | 60 | // Schema defines the schema for the data source. 61 | func (d *sshKeyDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 62 | resp.Schema = schema.Schema{ 63 | Attributes: map[string]schema.Attribute{ 64 | "id": schema.StringAttribute{ 65 | Computed: true, 66 | Description: "Unique, immutable, system-controlled identifier of the SSH key.", 67 | }, 68 | "name": schema.StringAttribute{ 69 | Required: true, 70 | Description: "Name of the SSH key.", 71 | }, 72 | "description": schema.StringAttribute{ 73 | Computed: true, 74 | Description: "Description for the SSH key.", 75 | }, 76 | "public_key": schema.StringAttribute{ 77 | Computed: true, 78 | Description: "Public SSH key.", 79 | }, 80 | "silo_user_id": schema.StringAttribute{ 81 | Computed: true, 82 | Description: "User ID that owns this SSH key.", 83 | }, 84 | "time_created": schema.StringAttribute{ 85 | Computed: true, 86 | Description: "Timestamp of when this SSH key was created.", 87 | }, 88 | "time_modified": schema.StringAttribute{ 89 | Computed: true, 90 | Description: "Timestamp of when this SSH key was last modified.", 91 | }, 92 | "timeouts": timeouts.Attributes(ctx), 93 | }, 94 | } 95 | } 96 | 97 | // Read refreshes the Terraform state with the latest data. 98 | func (d *sshKeyDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 99 | var state sshKeyDataSourceModel 100 | 101 | // Read Terraform configuration data into the model. 102 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 103 | if resp.Diagnostics.HasError() { 104 | return 105 | } 106 | 107 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 108 | resp.Diagnostics.Append(diags...) 109 | if resp.Diagnostics.HasError() { 110 | return 111 | } 112 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 113 | defer cancel() 114 | 115 | params := oxide.CurrentUserSshKeyViewParams{ 116 | SshKey: oxide.NameOrId(state.Name.ValueString()), 117 | } 118 | sshKey, err := d.client.CurrentUserSshKeyView(ctx, params) 119 | if err != nil { 120 | resp.Diagnostics.AddError( 121 | "Unable to read SSH key:", 122 | "API error: "+err.Error(), 123 | ) 124 | return 125 | } 126 | tflog.Trace(ctx, fmt.Sprintf("read SSH key with ID: %v", sshKey.Id), map[string]any{"success": true}) 127 | 128 | state.ID = types.StringValue(sshKey.Id) 129 | state.Name = types.StringValue(string(sshKey.Name)) 130 | state.Description = types.StringValue(sshKey.Description) 131 | state.PublicKey = types.StringValue(string(sshKey.PublicKey)) 132 | state.SiloUserID = types.StringValue(string(sshKey.SiloUserId)) 133 | state.TimeCreated = types.StringValue(sshKey.TimeCreated.String()) 134 | state.TimeModified = types.StringValue(sshKey.TimeModified.String()) 135 | 136 | // Save retrieved state into Terraform state. 137 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 138 | if resp.Diagnostics.HasError() { 139 | return 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /internal/provider/data_source_ssh_key_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceSSHKeyConfig struct { 15 | BlockName string 16 | Name string 17 | SupportBlockName string 18 | SupportBlockName2 string 19 | } 20 | 21 | var dataSourceSSHKeyConfigTpl = ` 22 | data "oxide_project" "{{.SupportBlockName}}" { 23 | name = "tf-acc-test" 24 | } 25 | 26 | resource "oxide_ssh_key" "{{.SupportBlockName2}}" { 27 | name = "{{.Name}}" 28 | description = "some key" 29 | public_key = "ssh-ed25519 AAAA" 30 | } 31 | 32 | data "oxide_ssh_key" "{{.BlockName}}" { 33 | name = oxide_ssh_key.{{.SupportBlockName2}}.name 34 | timeouts = { 35 | read = "1m" 36 | } 37 | } 38 | ` 39 | 40 | func TestAccCloudDataSourceSSHKey_full(t *testing.T) { 41 | blockName := newBlockName("datasource-ssh-key") 42 | resourceName := newResourceName() 43 | config, err := parsedAccConfig( 44 | dataSourceSSHKeyConfig{ 45 | BlockName: blockName, 46 | SupportBlockName: newBlockName("support"), 47 | SupportBlockName2: newBlockName("support"), 48 | Name: resourceName, 49 | }, 50 | dataSourceSSHKeyConfigTpl, 51 | ) 52 | if err != nil { 53 | t.Errorf("error parsing config template data: %e", err) 54 | } 55 | 56 | resource.ParallelTest(t, resource.TestCase{ 57 | PreCheck: func() { testAccPreCheck(t) }, 58 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 59 | Steps: []resource.TestStep{ 60 | { 61 | Config: config, 62 | Check: checkDataSourceSSHKey( 63 | fmt.Sprintf("data.oxide_ssh_key.%s", blockName), 64 | resourceName, 65 | ), 66 | }, 67 | }, 68 | }) 69 | } 70 | 71 | func checkDataSourceSSHKey(dataName, keyName string) resource.TestCheckFunc { 72 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 73 | resource.TestCheckResourceAttrSet(dataName, "id"), 74 | resource.TestCheckResourceAttr(dataName, "name", keyName), 75 | resource.TestCheckResourceAttr(dataName, "description", "some key"), 76 | resource.TestCheckResourceAttrSet(dataName, "public_key"), 77 | resource.TestCheckResourceAttrSet(dataName, "silo_user_id"), 78 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 79 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 80 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 81 | }...) 82 | } 83 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_internet_gateway.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var ( 20 | _ datasource.DataSource = (*vpcInternetGatewayDataSource)(nil) 21 | _ datasource.DataSourceWithConfigure = (*vpcInternetGatewayDataSource)(nil) 22 | ) 23 | 24 | // NewVPCInternetGatewayDataSource initialises an images datasource 25 | func NewVPCInternetGatewayDataSource() datasource.DataSource { 26 | return &vpcInternetGatewayDataSource{} 27 | } 28 | 29 | type vpcInternetGatewayDataSource struct { 30 | client *oxide.Client 31 | } 32 | 33 | type vpcInternetGatewayDataSourceModel struct { 34 | Description types.String `tfsdk:"description"` 35 | ID types.String `tfsdk:"id"` 36 | Name types.String `tfsdk:"name"` 37 | ProjectName types.String `tfsdk:"project_name"` 38 | VPCID types.String `tfsdk:"vpc_id"` 39 | VPCName types.String `tfsdk:"vpc_name"` 40 | TimeCreated types.String `tfsdk:"time_created"` 41 | TimeModified types.String `tfsdk:"time_modified"` 42 | Timeouts timeouts.Value `tfsdk:"timeouts"` 43 | } 44 | 45 | func (d *vpcInternetGatewayDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 46 | resp.TypeName = "oxide_vpc_internet_gateway" 47 | } 48 | 49 | // Configure adds the provider configured client to the data source. 50 | func (d *vpcInternetGatewayDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 51 | if req.ProviderData == nil { 52 | return 53 | } 54 | 55 | d.client = req.ProviderData.(*oxide.Client) 56 | } 57 | 58 | func (d *vpcInternetGatewayDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 59 | resp.Schema = schema.Schema{ 60 | Attributes: map[string]schema.Attribute{ 61 | "project_name": schema.StringAttribute{ 62 | Required: true, 63 | Description: "Name of the project that contains the VPC internet gateway.", 64 | }, 65 | "name": schema.StringAttribute{ 66 | Required: true, 67 | Description: "Name of the VPC internet gateway.", 68 | }, 69 | "vpc_name": schema.StringAttribute{ 70 | Required: true, 71 | Description: "Name of the VPC that contains the VPC internet gateway.", 72 | }, 73 | "vpc_id": schema.StringAttribute{ 74 | Computed: true, 75 | Description: "ID of the VPC that contains the VPC internet gateway.", 76 | }, 77 | "description": schema.StringAttribute{ 78 | Computed: true, 79 | Description: "Description for the VPC internet gateway.", 80 | }, 81 | "timeouts": timeouts.Attributes(ctx), 82 | "id": schema.StringAttribute{ 83 | Computed: true, 84 | Description: "Unique, immutable, system-controlled identifier of the VPC.", 85 | }, 86 | "time_created": schema.StringAttribute{ 87 | Computed: true, 88 | Description: "Timestamp of when this VPC internet gateway was created.", 89 | }, 90 | "time_modified": schema.StringAttribute{ 91 | Computed: true, 92 | Description: "Timestamp of when this VPC internet gateway was last modified.", 93 | }, 94 | }, 95 | } 96 | } 97 | 98 | func (d *vpcInternetGatewayDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 99 | var state vpcInternetGatewayDataSourceModel 100 | 101 | // Read Terraform configuration data into the model 102 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 103 | if resp.Diagnostics.HasError() { 104 | return 105 | } 106 | 107 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 108 | resp.Diagnostics.Append(diags...) 109 | if resp.Diagnostics.HasError() { 110 | return 111 | } 112 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 113 | defer cancel() 114 | 115 | params := oxide.InternetGatewayViewParams{ 116 | Gateway: oxide.NameOrId(state.Name.ValueString()), 117 | Vpc: oxide.NameOrId(state.VPCName.ValueString()), 118 | Project: oxide.NameOrId(state.ProjectName.ValueString()), 119 | } 120 | vpcInternetGateway, err := d.client.InternetGatewayView(ctx, params) 121 | if err != nil { 122 | resp.Diagnostics.AddError( 123 | "Unable to read VPC internet gateway:", 124 | "API error: "+err.Error(), 125 | ) 126 | return 127 | } 128 | tflog.Trace(ctx, fmt.Sprintf("read VPC internet gateway with ID: %v", vpcInternetGateway.Id), map[string]any{"success": true}) 129 | 130 | state.Description = types.StringValue(vpcInternetGateway.Description) 131 | state.ID = types.StringValue(vpcInternetGateway.Id) 132 | state.Name = types.StringValue(string(vpcInternetGateway.Name)) 133 | state.VPCID = types.StringValue(vpcInternetGateway.VpcId) 134 | state.TimeCreated = types.StringValue(vpcInternetGateway.TimeCreated.String()) 135 | state.TimeModified = types.StringValue(vpcInternetGateway.TimeModified.String()) 136 | 137 | // Save state into Terraform state 138 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 139 | if resp.Diagnostics.HasError() { 140 | return 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_internet_gateway_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceVPCInternetGatewayConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | var dataSourceVPCInternetGatewayConfigTpl = ` 20 | data "oxide_vpc_internet_gateway" "{{.BlockName}}" { 21 | project_name = "tf-acc-test" 22 | vpc_name = "default" 23 | name = "default" 24 | timeouts = { 25 | read = "1m" 26 | } 27 | } 28 | ` 29 | 30 | func TestAccCloudDataSourceVPCInternetGateway_full(t *testing.T) { 31 | blockName := newBlockName("datasource-vpc-router") 32 | config, err := parsedAccConfig( 33 | dataSourceVPCInternetGatewayConfig{ 34 | BlockName: blockName, 35 | SupportBlockName: newBlockName("support"), 36 | }, 37 | dataSourceVPCInternetGatewayConfigTpl, 38 | ) 39 | if err != nil { 40 | t.Errorf("error parsing config template data: %e", err) 41 | } 42 | 43 | resource.ParallelTest(t, resource.TestCase{ 44 | PreCheck: func() { testAccPreCheck(t) }, 45 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: config, 49 | Check: checkDataSourceVPCInternetGateway( 50 | fmt.Sprintf("data.oxide_vpc_internet_gateway.%s", blockName), 51 | ), 52 | }, 53 | }, 54 | }) 55 | } 56 | 57 | func checkDataSourceVPCInternetGateway(dataName string) resource.TestCheckFunc { 58 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 59 | resource.TestCheckResourceAttrSet(dataName, "id"), 60 | resource.TestCheckResourceAttr(dataName, "description", "Default VPC gateway"), 61 | resource.TestCheckResourceAttr(dataName, "name", "default"), 62 | resource.TestCheckResourceAttrSet(dataName, "vpc_id"), 63 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 64 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 65 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 66 | }...) 67 | } 68 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_router.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-log/tflog" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | var ( 20 | _ datasource.DataSource = (*vpcRouterDataSource)(nil) 21 | _ datasource.DataSourceWithConfigure = (*vpcRouterDataSource)(nil) 22 | ) 23 | 24 | // NewVPCRouterDataSource initialises an images datasource 25 | func NewVPCRouterDataSource() datasource.DataSource { 26 | return &vpcRouterDataSource{} 27 | } 28 | 29 | type vpcRouterDataSource struct { 30 | client *oxide.Client 31 | } 32 | 33 | type vpcRouterDataSourceModel struct { 34 | Description types.String `tfsdk:"description"` 35 | ID types.String `tfsdk:"id"` 36 | Kind types.String `tfsdk:"kind"` 37 | Name types.String `tfsdk:"name"` 38 | ProjectName types.String `tfsdk:"project_name"` 39 | VPCID types.String `tfsdk:"vpc_id"` 40 | VPCName types.String `tfsdk:"vpc_name"` 41 | TimeCreated types.String `tfsdk:"time_created"` 42 | TimeModified types.String `tfsdk:"time_modified"` 43 | Timeouts timeouts.Value `tfsdk:"timeouts"` 44 | } 45 | 46 | func (d *vpcRouterDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 47 | resp.TypeName = "oxide_vpc_router" 48 | } 49 | 50 | // Configure adds the provider configured client to the data source. 51 | func (d *vpcRouterDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { 52 | if req.ProviderData == nil { 53 | return 54 | } 55 | 56 | d.client = req.ProviderData.(*oxide.Client) 57 | } 58 | 59 | func (d *vpcRouterDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 60 | resp.Schema = schema.Schema{ 61 | Attributes: map[string]schema.Attribute{ 62 | "project_name": schema.StringAttribute{ 63 | Required: true, 64 | Description: "Name of the project that contains the VPC router.", 65 | }, 66 | "name": schema.StringAttribute{ 67 | Required: true, 68 | Description: "Name of the VPC router.", 69 | }, 70 | "vpc_name": schema.StringAttribute{ 71 | Required: true, 72 | Description: "Name of the VPC that contains the VPC router.", 73 | }, 74 | "vpc_id": schema.StringAttribute{ 75 | Computed: true, 76 | Description: "ID of the VPC that contains the VPC router.", 77 | }, 78 | "description": schema.StringAttribute{ 79 | Computed: true, 80 | Description: "Description for the VPC router.", 81 | }, 82 | "timeouts": timeouts.Attributes(ctx), 83 | "id": schema.StringAttribute{ 84 | Computed: true, 85 | Description: "Unique, immutable, system-controlled identifier of the VPC router.", 86 | }, 87 | "kind": schema.StringAttribute{ 88 | Computed: true, 89 | Description: "Whether the VPC router is custom or system created.", 90 | }, 91 | "time_created": schema.StringAttribute{ 92 | Computed: true, 93 | Description: "Timestamp of when this VPC router was created.", 94 | }, 95 | "time_modified": schema.StringAttribute{ 96 | Computed: true, 97 | Description: "Timestamp of when this VPC router was last modified.", 98 | }, 99 | }, 100 | } 101 | } 102 | 103 | func (d *vpcRouterDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 104 | var state vpcRouterDataSourceModel 105 | 106 | // Read Terraform configuration data into the model 107 | resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) 108 | if resp.Diagnostics.HasError() { 109 | return 110 | } 111 | 112 | readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout()) 113 | resp.Diagnostics.Append(diags...) 114 | if resp.Diagnostics.HasError() { 115 | return 116 | } 117 | ctx, cancel := context.WithTimeout(ctx, readTimeout) 118 | defer cancel() 119 | 120 | params := oxide.VpcRouterViewParams{ 121 | Router: oxide.NameOrId(state.Name.ValueString()), 122 | Vpc: oxide.NameOrId(state.VPCName.ValueString()), 123 | Project: oxide.NameOrId(state.ProjectName.ValueString()), 124 | } 125 | router, err := d.client.VpcRouterView(ctx, params) 126 | if err != nil { 127 | resp.Diagnostics.AddError( 128 | "Unable to read VPC router:", 129 | "API error: "+err.Error(), 130 | ) 131 | return 132 | } 133 | tflog.Trace(ctx, fmt.Sprintf("read VPC router with ID: %v", router.Id), map[string]any{"success": true}) 134 | 135 | state.Description = types.StringValue(router.Description) 136 | state.ID = types.StringValue(router.Id) 137 | state.Kind = types.StringValue(string(router.Kind)) 138 | state.Name = types.StringValue(string(router.Name)) 139 | state.VPCID = types.StringValue(router.VpcId) 140 | state.TimeCreated = types.StringValue(router.TimeCreated.String()) 141 | state.TimeModified = types.StringValue(router.TimeModified.String()) 142 | 143 | // Save state into Terraform state 144 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 145 | if resp.Diagnostics.HasError() { 146 | return 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_router_route_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | "github.com/oxidecomputer/oxide.go/oxide" 13 | ) 14 | 15 | type dataSourceVPCRouterRouteConfig struct { 16 | BlockName string 17 | SupportBlockName string 18 | } 19 | 20 | var dataSourceVPCRouterRouteConfigTpl = ` 21 | data "oxide_vpc_router_route" "{{.BlockName}}" { 22 | project_name = "tf-acc-test" 23 | vpc_name = "default" 24 | vpc_router_name = "system" 25 | name = "default-v4" 26 | timeouts = { 27 | read = "1m" 28 | } 29 | } 30 | ` 31 | 32 | func TestAccCloudDataSourceVPCRouterRoute_full(t *testing.T) { 33 | blockName := newBlockName("datasource-vpc-router") 34 | config, err := parsedAccConfig( 35 | dataSourceVPCRouterRouteConfig{ 36 | BlockName: blockName, 37 | SupportBlockName: newBlockName("support"), 38 | }, 39 | dataSourceVPCRouterRouteConfigTpl, 40 | ) 41 | if err != nil { 42 | t.Errorf("error parsing config template data: %e", err) 43 | } 44 | 45 | resource.ParallelTest(t, resource.TestCase{ 46 | PreCheck: func() { testAccPreCheck(t) }, 47 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 48 | Steps: []resource.TestStep{ 49 | { 50 | Config: config, 51 | Check: checkDataSourceVPCRouterRoute( 52 | fmt.Sprintf("data.oxide_vpc_router_route.%s", blockName), 53 | ), 54 | }, 55 | }, 56 | }) 57 | } 58 | 59 | func checkDataSourceVPCRouterRoute(dataName string) resource.TestCheckFunc { 60 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 61 | resource.TestCheckResourceAttrSet(dataName, "id"), 62 | resource.TestCheckResourceAttr( 63 | dataName, 64 | "description", 65 | "The default route of a vpc", 66 | ), 67 | resource.TestCheckResourceAttr(dataName, "name", "default-v4"), 68 | resource.TestCheckResourceAttr(dataName, "destination.type", string(oxide.RouteDestinationTypeIpNet)), 69 | resource.TestCheckResourceAttr(dataName, "destination.value", "0.0.0.0/0"), 70 | resource.TestCheckResourceAttr(dataName, "target.type", string(oxide.RouteTargetTypeInternetGateway)), 71 | resource.TestCheckResourceAttr(dataName, "target.value", "default"), 72 | resource.TestCheckResourceAttr(dataName, "kind", string(oxide.RouterRouteKindDefault)), 73 | resource.TestCheckResourceAttrSet(dataName, "vpc_router_id"), 74 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 75 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 76 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 77 | }...) 78 | } 79 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_router_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | "github.com/oxidecomputer/oxide.go/oxide" 13 | ) 14 | 15 | type dataSourceVPCRouterConfig struct { 16 | BlockName string 17 | SupportBlockName string 18 | } 19 | 20 | var dataSourceVPCRouterConfigTpl = ` 21 | data "oxide_vpc_router" "{{.BlockName}}" { 22 | project_name = "tf-acc-test" 23 | vpc_name = "default" 24 | name = "system" 25 | timeouts = { 26 | read = "1m" 27 | } 28 | } 29 | ` 30 | 31 | func TestAccCloudDataSourceVPCRouter_full(t *testing.T) { 32 | blockName := newBlockName("datasource-vpc-router") 33 | config, err := parsedAccConfig( 34 | dataSourceVPCRouterConfig{ 35 | BlockName: blockName, 36 | SupportBlockName: newBlockName("support"), 37 | }, 38 | dataSourceVPCRouterConfigTpl, 39 | ) 40 | if err != nil { 41 | t.Errorf("error parsing config template data: %e", err) 42 | } 43 | 44 | resource.ParallelTest(t, resource.TestCase{ 45 | PreCheck: func() { testAccPreCheck(t) }, 46 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 47 | Steps: []resource.TestStep{ 48 | { 49 | Config: config, 50 | Check: checkDataSourceVPCRouter( 51 | fmt.Sprintf("data.oxide_vpc_router.%s", blockName), 52 | ), 53 | }, 54 | }, 55 | }) 56 | } 57 | 58 | func checkDataSourceVPCRouter(dataName string) resource.TestCheckFunc { 59 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 60 | resource.TestCheckResourceAttrSet(dataName, "id"), 61 | resource.TestCheckResourceAttr( 62 | dataName, 63 | "description", 64 | "Routes are automatically added to this router as vpc subnets are created", 65 | ), 66 | resource.TestCheckResourceAttr(dataName, "name", "system"), 67 | resource.TestCheckResourceAttr(dataName, "kind", string(oxide.VpcRouterKindSystem)), 68 | resource.TestCheckResourceAttrSet(dataName, "vpc_id"), 69 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 70 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 71 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 72 | }...) 73 | } 74 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_subnet_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceVPCSubnetConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | var dataSourceVPCSubnetConfigTpl = ` 20 | data "oxide_vpc_subnet" "{{.BlockName}}" { 21 | project_name = "tf-acc-test" 22 | vpc_name = "default" 23 | name = "default" 24 | timeouts = { 25 | read = "1m" 26 | } 27 | } 28 | ` 29 | 30 | func TestAccCloudDataSourceVPCSubnet_full(t *testing.T) { 31 | blockName := newBlockName("datasource-vpc-subnet") 32 | config, err := parsedAccConfig( 33 | dataSourceVPCSubnetConfig{ 34 | BlockName: blockName, 35 | SupportBlockName: newBlockName("support"), 36 | }, 37 | dataSourceVPCSubnetConfigTpl, 38 | ) 39 | if err != nil { 40 | t.Errorf("error parsing config template data: %e", err) 41 | } 42 | 43 | resource.ParallelTest(t, resource.TestCase{ 44 | PreCheck: func() { testAccPreCheck(t) }, 45 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: config, 49 | Check: checkDataSourceVPCSubnet( 50 | fmt.Sprintf("data.oxide_vpc_subnet.%s", blockName), 51 | ), 52 | }, 53 | }, 54 | }) 55 | } 56 | 57 | func checkDataSourceVPCSubnet(dataName string) resource.TestCheckFunc { 58 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 59 | resource.TestCheckResourceAttrSet(dataName, "id"), 60 | resource.TestCheckResourceAttr(dataName, "description", "The default subnet for default"), 61 | resource.TestCheckResourceAttr(dataName, "name", "default"), 62 | resource.TestCheckResourceAttrSet(dataName, "ipv4_block"), 63 | resource.TestCheckResourceAttrSet(dataName, "ipv6_block"), 64 | resource.TestCheckResourceAttrSet(dataName, "vpc_id"), 65 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 66 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 67 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 68 | }...) 69 | } 70 | -------------------------------------------------------------------------------- /internal/provider/data_source_vpc_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | type dataSourceVPCConfig struct { 15 | BlockName string 16 | SupportBlockName string 17 | } 18 | 19 | var dataSourceVPCConfigTpl = ` 20 | data "oxide_vpc" "{{.BlockName}}" { 21 | project_name = "tf-acc-test" 22 | name = "default" 23 | timeouts = { 24 | read = "1m" 25 | } 26 | } 27 | ` 28 | 29 | func TestAccCloudDataSourceVPC_full(t *testing.T) { 30 | blockName := newBlockName("datasource-vpc") 31 | config, err := parsedAccConfig( 32 | dataSourceVPCConfig{ 33 | BlockName: blockName, 34 | SupportBlockName: newBlockName("support"), 35 | }, 36 | dataSourceVPCConfigTpl, 37 | ) 38 | if err != nil { 39 | t.Errorf("error parsing config template data: %e", err) 40 | } 41 | 42 | resource.ParallelTest(t, resource.TestCase{ 43 | PreCheck: func() { testAccPreCheck(t) }, 44 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 45 | Steps: []resource.TestStep{ 46 | { 47 | Config: config, 48 | Check: checkDataSourceVPC( 49 | fmt.Sprintf("data.oxide_vpc.%s", blockName), 50 | ), 51 | }, 52 | }, 53 | }) 54 | } 55 | 56 | func checkDataSourceVPC(dataName string) resource.TestCheckFunc { 57 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 58 | resource.TestCheckResourceAttrSet(dataName, "id"), 59 | resource.TestCheckResourceAttr(dataName, "description", "Default VPC"), 60 | resource.TestCheckResourceAttr(dataName, "name", "default"), 61 | resource.TestCheckResourceAttr(dataName, "dns_name", "default"), 62 | resource.TestCheckResourceAttrSet(dataName, "ipv6_prefix"), 63 | resource.TestCheckResourceAttrSet(dataName, "project_id"), 64 | resource.TestCheckResourceAttrSet(dataName, "system_router_id"), 65 | resource.TestCheckResourceAttrSet(dataName, "time_created"), 66 | resource.TestCheckResourceAttrSet(dataName, "time_modified"), 67 | resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"), 68 | }...) 69 | } 70 | -------------------------------------------------------------------------------- /internal/provider/planmodifiers.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" 7 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" 8 | ) 9 | 10 | // RequiresReplaceUnlessEmptyStringToNull returns a resource.RequiresReplaceIfFunc that 11 | // returns true unless the change is from an empty string or null. 12 | // 13 | // This is particularly helpful for creating new nested objects that cannot be modified 14 | // themselves, but it is possible to add or remove them. 15 | func RequiresReplaceUnlessEmptyStringOrNull() stringplanmodifier.RequiresReplaceIfFunc { 16 | return func(ctx context.Context, req planmodifier.StringRequest, 17 | resp *stringplanmodifier.RequiresReplaceIfFuncResponse) { 18 | // If the configuration is unknown, this cannot be sure what to do yet. 19 | if req.ConfigValue.IsUnknown() { 20 | resp.RequiresReplace = false 21 | return 22 | } 23 | 24 | if req.StateValue.IsNull() || req.StateValue.ValueString() == "" { 25 | resp.RequiresReplace = false 26 | return 27 | } 28 | 29 | resp.RequiresReplace = true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /internal/provider/resource_disk_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 14 | "github.com/hashicorp/terraform-plugin-testing/terraform" 15 | "github.com/oxidecomputer/oxide.go/oxide" 16 | ) 17 | 18 | type resourceDiskConfig struct { 19 | BlockName string 20 | DiskName string 21 | SupportBlockName string 22 | } 23 | 24 | var resourceDiskConfigTpl = ` 25 | data "oxide_project" "{{.SupportBlockName}}" { 26 | name = "tf-acc-test" 27 | } 28 | 29 | resource "oxide_disk" "{{.BlockName}}" { 30 | project_id = data.oxide_project.{{.SupportBlockName}}.id 31 | description = "a test disk" 32 | name = "{{.DiskName}}" 33 | size = 1073741824 34 | block_size = 512 35 | timeouts = { 36 | read = "1m" 37 | create = "3m" 38 | delete = "2m" 39 | } 40 | } 41 | ` 42 | 43 | func TestAccCloudResourceDisk_full(t *testing.T) { 44 | diskName := newResourceName() 45 | blockName := newBlockName("disk") 46 | resourceName := fmt.Sprintf("oxide_disk.%s", blockName) 47 | config, err := parsedAccConfig( 48 | resourceDiskConfig{ 49 | BlockName: blockName, 50 | DiskName: diskName, 51 | SupportBlockName: newBlockName("support"), 52 | }, 53 | resourceDiskConfigTpl, 54 | ) 55 | if err != nil { 56 | t.Errorf("error parsing config template data: %e", err) 57 | } 58 | 59 | resource.ParallelTest(t, resource.TestCase{ 60 | PreCheck: func() { testAccPreCheck(t) }, 61 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 62 | CheckDestroy: testAccDiskDestroy, 63 | Steps: []resource.TestStep{ 64 | { 65 | Config: config, 66 | Check: checkResourceDisk(resourceName, diskName), 67 | }, 68 | { 69 | ResourceName: resourceName, 70 | ImportState: true, 71 | ImportStateVerify: true, 72 | }, 73 | }, 74 | }) 75 | } 76 | 77 | func checkResourceDisk(resourceName, diskName string) resource.TestCheckFunc { 78 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 79 | resource.TestCheckResourceAttrSet(resourceName, "id"), 80 | resource.TestCheckResourceAttr(resourceName, "description", "a test disk"), 81 | resource.TestCheckResourceAttr(resourceName, "name", diskName), 82 | resource.TestCheckResourceAttr(resourceName, "size", "1073741824"), 83 | resource.TestCheckResourceAttr(resourceName, "device_path", "/mnt/"+diskName), 84 | resource.TestCheckResourceAttr(resourceName, "block_size", "512"), 85 | resource.TestCheckResourceAttrSet(resourceName, "project_id"), 86 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 87 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 88 | resource.TestCheckResourceAttr(resourceName, "timeouts.read", "1m"), 89 | resource.TestCheckResourceAttr(resourceName, "timeouts.delete", "2m"), 90 | resource.TestCheckResourceAttr(resourceName, "timeouts.create", "3m"), 91 | // TODO: Eventually we'll want to test creating a disk from images and snapshot 92 | }...) 93 | } 94 | 95 | func testAccDiskDestroy(s *terraform.State) error { 96 | client, err := newTestClient() 97 | if err != nil { 98 | return err 99 | } 100 | 101 | for _, rs := range s.RootModule().Resources { 102 | if rs.Type != "oxide_disk" { 103 | continue 104 | } 105 | 106 | ctx := context.Background() 107 | ctx, cancel := context.WithTimeout(ctx, time.Minute) 108 | defer cancel() 109 | 110 | params := oxide.DiskViewParams{ 111 | Disk: oxide.NameOrId(rs.Primary.Attributes["id"]), 112 | } 113 | res, err := client.DiskView(ctx, params) 114 | 115 | if err != nil && is404(err) { 116 | continue 117 | } 118 | 119 | return fmt.Errorf("disk (%v) still exists", &res.Name) 120 | } 121 | 122 | return nil 123 | } 124 | -------------------------------------------------------------------------------- /internal/provider/resource_image_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 14 | "github.com/hashicorp/terraform-plugin-testing/terraform" 15 | "github.com/oxidecomputer/oxide.go/oxide" 16 | ) 17 | 18 | type resourceImageConfig struct { 19 | BlockName string 20 | ImageName string 21 | DiskName string 22 | SnapshotName string 23 | SupportBlockName string 24 | DiskBlockName string 25 | SnapshotBlockName string 26 | } 27 | 28 | // TODO: Use a fetched snapshot ID when the snapshot data source is implemented 29 | var resourceImageConfigTpl = ` 30 | data "oxide_project" "{{.SupportBlockName}}" { 31 | name = "tf-acc-test" 32 | } 33 | 34 | resource "oxide_disk" "{{.DiskBlockName}}" { 35 | project_id = data.oxide_project.{{.SupportBlockName}}.id 36 | description = "a test disk" 37 | name = "{{.DiskName}}" 38 | size = 1073741824 39 | block_size = 512 40 | timeouts = { 41 | read = "1m" 42 | create = "3m" 43 | delete = "2m" 44 | } 45 | } 46 | 47 | resource "oxide_snapshot" "{{.SnapshotBlockName}}" { 48 | project_id = data.oxide_project.{{.SupportBlockName}}.id 49 | description = "a test snapshot" 50 | name = "{{.SnapshotName}}" 51 | disk_id = oxide_disk.{{.DiskBlockName}}.id 52 | timeouts = { 53 | read = "1m" 54 | create = "3m" 55 | delete = "2m" 56 | } 57 | } 58 | 59 | resource "oxide_image" "{{.BlockName}}" { 60 | project_id = data.oxide_project.{{.SupportBlockName}}.id 61 | description = "a test image" 62 | name = "{{.ImageName}}" 63 | source_snapshot_id = oxide_snapshot.{{.SnapshotBlockName}}.id 64 | os = "alpine" 65 | version = "propolis-blob" 66 | timeouts = { 67 | read = "1m" 68 | create = "3m" 69 | } 70 | } 71 | ` 72 | 73 | func TestAccCloudResourceImage_full(t *testing.T) { 74 | imageName := newResourceName() 75 | blockName := newBlockName("image") 76 | supportBlockName := newBlockName("support") 77 | resourceName := fmt.Sprintf("oxide_image.%s", blockName) 78 | config, err := parsedAccConfig( 79 | resourceImageConfig{ 80 | BlockName: blockName, 81 | ImageName: imageName, 82 | DiskName: newResourceName(), 83 | SnapshotName: newResourceName(), 84 | SupportBlockName: supportBlockName, 85 | DiskBlockName: newBlockName("support"), 86 | SnapshotBlockName: newBlockName("support"), 87 | }, 88 | resourceImageConfigTpl, 89 | ) 90 | if err != nil { 91 | t.Errorf("error parsing config template data: %e", err) 92 | } 93 | 94 | resource.ParallelTest(t, resource.TestCase{ 95 | PreCheck: func() { testAccPreCheck(t) }, 96 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 97 | CheckDestroy: testAccImageDestroy, 98 | Steps: []resource.TestStep{ 99 | { 100 | Config: config, 101 | Check: checkResourceImage(resourceName, imageName), 102 | }, 103 | { 104 | ResourceName: resourceName, 105 | ImportState: true, 106 | ImportStateVerify: true, 107 | ImportStateVerifyIgnore: []string{"source_snapshot_id"}, 108 | }, 109 | }, 110 | }) 111 | } 112 | 113 | func checkResourceImage(resourceName, imageName string) resource.TestCheckFunc { 114 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 115 | resource.TestCheckResourceAttrSet(resourceName, "id"), 116 | resource.TestCheckResourceAttrSet(resourceName, "project_id"), 117 | resource.TestCheckResourceAttr(resourceName, "description", "a test image"), 118 | resource.TestCheckResourceAttr(resourceName, "name", imageName), 119 | resource.TestCheckResourceAttrSet(resourceName, "block_size"), 120 | resource.TestCheckResourceAttrSet(resourceName, "source_snapshot_id"), 121 | resource.TestCheckResourceAttrSet(resourceName, "size"), 122 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 123 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 124 | resource.TestCheckResourceAttr(resourceName, "timeouts.read", "1m"), 125 | resource.TestCheckResourceAttr(resourceName, "timeouts.create", "3m"), 126 | }...) 127 | } 128 | 129 | func testAccImageDestroy(s *terraform.State) error { 130 | client, err := newTestClient() 131 | if err != nil { 132 | return err 133 | } 134 | 135 | for _, rs := range s.RootModule().Resources { 136 | if rs.Type != "oxide_image" { 137 | continue 138 | } 139 | 140 | ctx := context.Background() 141 | ctx, cancel := context.WithTimeout(ctx, time.Minute) 142 | defer cancel() 143 | 144 | params := oxide.ImageViewParams{ 145 | Image: oxide.NameOrId(rs.Primary.Attributes["id"]), 146 | } 147 | res, err := client.ImageView(ctx, params) 148 | 149 | if err != nil && is404(err) { 150 | continue 151 | } 152 | 153 | return fmt.Errorf("image (%v) still exists", &res.Name) 154 | } 155 | 156 | return nil 157 | } 158 | -------------------------------------------------------------------------------- /internal/provider/resource_project_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 14 | "github.com/hashicorp/terraform-plugin-testing/terraform" 15 | "github.com/oxidecomputer/oxide.go/oxide" 16 | ) 17 | 18 | type resourceProjectConfig struct { 19 | BlockName string 20 | ProjectName string 21 | } 22 | 23 | var resourceProjectConfigTpl = ` 24 | resource "oxide_project" "{{.BlockName}}" { 25 | description = "a test project" 26 | name = "{{.ProjectName}}" 27 | timeouts = { 28 | read = "1m" 29 | create = "3m" 30 | delete = "2m" 31 | update = "4m" 32 | } 33 | } 34 | ` 35 | 36 | var resourceProjectUpdateConfigTpl = ` 37 | resource "oxide_project" "{{.BlockName}}" { 38 | description = "a new description for project" 39 | name = "{{.ProjectName}}" 40 | } 41 | ` 42 | 43 | func TestAccCloudResourceProject_full(t *testing.T) { 44 | projectName := newResourceName() 45 | blockName := newBlockName("project") 46 | resourceName := fmt.Sprintf("oxide_project.%s", blockName) 47 | config, err := parsedAccConfig( 48 | resourceProjectConfig{ 49 | BlockName: blockName, 50 | ProjectName: projectName, 51 | }, 52 | resourceProjectConfigTpl, 53 | ) 54 | if err != nil { 55 | t.Errorf("error parsing config template data: %e", err) 56 | } 57 | 58 | projectNameUpdated := projectName + "-updated" 59 | configUpdate, err := parsedAccConfig( 60 | resourceProjectConfig{ 61 | BlockName: blockName, 62 | ProjectName: projectNameUpdated, 63 | }, 64 | resourceProjectUpdateConfigTpl, 65 | ) 66 | if err != nil { 67 | t.Errorf("error parsing config template data: %e", err) 68 | } 69 | 70 | resource.ParallelTest(t, resource.TestCase{ 71 | PreCheck: func() { testAccPreCheck(t) }, 72 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 73 | CheckDestroy: testAccProjectDestroy, 74 | Steps: []resource.TestStep{ 75 | { 76 | Config: config, 77 | Check: checkResourceProject(resourceName, projectName), 78 | }, 79 | { 80 | Config: configUpdate, 81 | Check: checkResourceProjectUpdate(resourceName, projectNameUpdated), 82 | }, 83 | { 84 | ResourceName: resourceName, 85 | ImportState: true, 86 | ImportStateVerify: true, 87 | }, 88 | }, 89 | }) 90 | } 91 | 92 | func checkResourceProject(resourceName, projectName string) resource.TestCheckFunc { 93 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 94 | resource.TestCheckResourceAttrSet(resourceName, "id"), 95 | resource.TestCheckResourceAttr(resourceName, "description", "a test project"), 96 | resource.TestCheckResourceAttr(resourceName, "name", projectName), 97 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 98 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 99 | resource.TestCheckResourceAttr(resourceName, "timeouts.read", "1m"), 100 | resource.TestCheckResourceAttr(resourceName, "timeouts.delete", "2m"), 101 | resource.TestCheckResourceAttr(resourceName, "timeouts.create", "3m"), 102 | resource.TestCheckResourceAttr(resourceName, "timeouts.update", "4m"), 103 | }...) 104 | } 105 | 106 | func checkResourceProjectUpdate(resourceName, projectName string) resource.TestCheckFunc { 107 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 108 | resource.TestCheckResourceAttrSet(resourceName, "id"), 109 | resource.TestCheckResourceAttr(resourceName, "description", "a new description for project"), 110 | resource.TestCheckResourceAttr(resourceName, "name", projectName), 111 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 112 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 113 | }...) 114 | } 115 | 116 | func testAccProjectDestroy(s *terraform.State) error { 117 | client, err := newTestClient() 118 | if err != nil { 119 | return err 120 | } 121 | 122 | for _, rs := range s.RootModule().Resources { 123 | if rs.Type != "oxide_project" { 124 | continue 125 | } 126 | 127 | ctx := context.Background() 128 | ctx, cancel := context.WithTimeout(ctx, time.Minute) 129 | defer cancel() 130 | 131 | params := oxide.ProjectViewParams{ 132 | Project: oxide.NameOrId(rs.Primary.Attributes["id"]), 133 | } 134 | res, err := client.ProjectView(ctx, params) 135 | if err != nil && is404(err) { 136 | continue 137 | } 138 | return fmt.Errorf("project (%v) still exists", &res.Name) 139 | } 140 | 141 | return nil 142 | } 143 | -------------------------------------------------------------------------------- /internal/provider/resource_snapshot_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/google/uuid" 14 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 15 | "github.com/hashicorp/terraform-plugin-testing/terraform" 16 | "github.com/oxidecomputer/oxide.go/oxide" 17 | ) 18 | 19 | type resourceSnapshotConfig struct { 20 | BlockName string 21 | SnapshotName string 22 | DiskBlockName string 23 | DiskName string 24 | SupportBlockName string 25 | } 26 | 27 | var resourceSnapshotConfigTpl = ` 28 | data "oxide_project" "{{.SupportBlockName}}" { 29 | name = "tf-acc-test" 30 | } 31 | 32 | resource "oxide_disk" "{{.DiskBlockName}}" { 33 | project_id = data.oxide_project.{{.SupportBlockName}}.id 34 | description = "a test disk" 35 | name = "{{.DiskName}}" 36 | size = 1073741824 37 | block_size = 512 38 | timeouts = { 39 | read = "1m" 40 | create = "3m" 41 | delete = "2m" 42 | } 43 | } 44 | 45 | resource "oxide_snapshot" "{{.BlockName}}" { 46 | project_id = data.oxide_project.{{.SupportBlockName}}.id 47 | description = "a test snapshot" 48 | name = "{{.SnapshotName}}" 49 | disk_id = oxide_disk.{{.DiskBlockName}}.id 50 | timeouts = { 51 | read = "1m" 52 | create = "3m" 53 | delete = "2m" 54 | } 55 | } 56 | ` 57 | 58 | func TestAccCloudResourceSnapshot_full(t *testing.T) { 59 | diskName := newResourceName() 60 | snapshotName := newResourceName() 61 | blockName := newBlockName("snapshot") 62 | resourceName := fmt.Sprintf("oxide_snapshot.%s", blockName) 63 | config, err := parsedAccConfig( 64 | resourceSnapshotConfig{ 65 | BlockName: blockName, 66 | SnapshotName: snapshotName, 67 | DiskName: diskName, 68 | SupportBlockName: fmt.Sprintf("acc-support-%s", uuid.New()), 69 | DiskBlockName: fmt.Sprintf("acc-resource-disk-%s", uuid.New()), 70 | }, 71 | resourceSnapshotConfigTpl, 72 | ) 73 | if err != nil { 74 | t.Errorf("error parsing config template data: %e", err) 75 | } 76 | 77 | resource.ParallelTest(t, resource.TestCase{ 78 | PreCheck: func() { testAccPreCheck(t) }, 79 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 80 | CheckDestroy: testAccSnapshotDestroy, 81 | Steps: []resource.TestStep{ 82 | { 83 | Config: config, 84 | Check: checkResourceSnapshot(resourceName, snapshotName), 85 | }, 86 | { 87 | ResourceName: resourceName, 88 | ImportState: true, 89 | ImportStateVerify: true, 90 | }, 91 | }, 92 | }) 93 | } 94 | 95 | func checkResourceSnapshot(resourceName, snapshotName string) resource.TestCheckFunc { 96 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 97 | resource.TestCheckResourceAttrSet(resourceName, "id"), 98 | resource.TestCheckResourceAttr(resourceName, "description", "a test snapshot"), 99 | resource.TestCheckResourceAttr(resourceName, "name", snapshotName), 100 | resource.TestCheckResourceAttrSet(resourceName, "size"), 101 | resource.TestCheckResourceAttrSet(resourceName, "disk_id"), 102 | resource.TestCheckResourceAttrSet(resourceName, "project_id"), 103 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 104 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 105 | resource.TestCheckResourceAttr(resourceName, "timeouts.read", "1m"), 106 | resource.TestCheckResourceAttr(resourceName, "timeouts.delete", "2m"), 107 | resource.TestCheckResourceAttr(resourceName, "timeouts.create", "3m"), 108 | // TODO: Eventually we'll want to test creating a disk from images and snapshot 109 | }...) 110 | } 111 | 112 | func testAccSnapshotDestroy(s *terraform.State) error { 113 | client, err := newTestClient() 114 | if err != nil { 115 | return err 116 | } 117 | 118 | for _, rs := range s.RootModule().Resources { 119 | if rs.Type != "oxide_snapshot" { 120 | continue 121 | } 122 | 123 | params := oxide.SnapshotViewParams{ 124 | Snapshot: oxide.NameOrId(rs.Primary.Attributes["id"]), 125 | } 126 | 127 | ctx := context.Background() 128 | ctx, cancel := context.WithTimeout(ctx, time.Minute) 129 | defer cancel() 130 | 131 | res, err := client.SnapshotView(ctx, params) 132 | 133 | if err != nil && is404(err) { 134 | continue 135 | } 136 | 137 | return fmt.Errorf("snapshot (%v) still exists", &res.Name) 138 | } 139 | 140 | return nil 141 | } 142 | -------------------------------------------------------------------------------- /internal/provider/resource_ssh_key_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "testing" 11 | "time" 12 | 13 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 14 | "github.com/hashicorp/terraform-plugin-testing/terraform" 15 | "github.com/oxidecomputer/oxide.go/oxide" 16 | ) 17 | 18 | type resourceSSHKeyConfig struct { 19 | BlockName string 20 | Name string 21 | Description string 22 | PublicKey string 23 | } 24 | 25 | var resourceSSHKeyConfigTpl = ` 26 | resource "oxide_ssh_key" "{{.BlockName}}" { 27 | name = "{{.Name}}" 28 | description = "{{.Description}}" 29 | public_key = "{{.PublicKey}}" 30 | timeouts = { 31 | read = "1m" 32 | create = "3m" 33 | delete = "2m" 34 | update = "4m" 35 | } 36 | } 37 | ` 38 | 39 | func TestAccCloudResourceSSHKey_full(t *testing.T) { 40 | sshKeyName := newResourceName() 41 | description := "An SSH key." 42 | publicKey := "ssh-ed25519 AAAA" 43 | blockName := newBlockName("ssh_key") 44 | resourceName := fmt.Sprintf("oxide_ssh_key.%s", blockName) 45 | config, err := parsedAccConfig( 46 | resourceSSHKeyConfig{ 47 | BlockName: blockName, 48 | Name: sshKeyName, 49 | Description: description, 50 | PublicKey: publicKey, 51 | }, 52 | resourceSSHKeyConfigTpl, 53 | ) 54 | if err != nil { 55 | t.Errorf("error parsing config template data: %e", err) 56 | } 57 | 58 | resource.ParallelTest(t, resource.TestCase{ 59 | PreCheck: func() { testAccPreCheck(t) }, 60 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), 61 | CheckDestroy: testAccSSHKeyDestroy, 62 | Steps: []resource.TestStep{ 63 | { 64 | Config: config, 65 | Check: checkResourceSSHKey(resourceName, sshKeyName), 66 | }, 67 | { 68 | ResourceName: resourceName, 69 | ImportState: true, 70 | ImportStateVerify: true, 71 | }, 72 | }, 73 | }) 74 | } 75 | 76 | func checkResourceSSHKey(resourceName, sshKeyName string) resource.TestCheckFunc { 77 | return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ 78 | resource.TestCheckResourceAttrSet(resourceName, "id"), 79 | resource.TestCheckResourceAttr(resourceName, "name", sshKeyName), 80 | resource.TestCheckResourceAttr(resourceName, "description", "An SSH key."), 81 | resource.TestCheckResourceAttr(resourceName, "public_key", "ssh-ed25519 AAAA"), 82 | resource.TestCheckResourceAttrSet(resourceName, "silo_user_id"), 83 | resource.TestCheckResourceAttrSet(resourceName, "time_created"), 84 | resource.TestCheckResourceAttrSet(resourceName, "time_modified"), 85 | resource.TestCheckResourceAttr(resourceName, "timeouts.read", "1m"), 86 | resource.TestCheckResourceAttr(resourceName, "timeouts.delete", "2m"), 87 | resource.TestCheckResourceAttr(resourceName, "timeouts.create", "3m"), 88 | resource.TestCheckResourceAttr(resourceName, "timeouts.update", "4m"), 89 | }...) 90 | } 91 | 92 | func testAccSSHKeyDestroy(s *terraform.State) error { 93 | client, err := newTestClient() 94 | if err != nil { 95 | return err 96 | } 97 | 98 | for _, rs := range s.RootModule().Resources { 99 | if rs.Type != "oxide_ssh_key" { 100 | continue 101 | } 102 | 103 | params := oxide.CurrentUserSshKeyViewParams{ 104 | SshKey: oxide.NameOrId(rs.Primary.Attributes["id"]), 105 | } 106 | 107 | ctx := context.Background() 108 | ctx, cancel := context.WithTimeout(ctx, time.Minute) 109 | defer cancel() 110 | 111 | res, err := client.CurrentUserSshKeyView(ctx, params) 112 | if err != nil && is404(err) { 113 | continue 114 | } 115 | 116 | return fmt.Errorf("ssh key (%v) still exists", &res.Name) 117 | } 118 | 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /internal/provider/testutils.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "html/template" 11 | "os" 12 | "testing" 13 | 14 | "github.com/google/uuid" 15 | "github.com/hashicorp/terraform-plugin-framework/providerserver" 16 | "github.com/hashicorp/terraform-plugin-go/tfprotov6" 17 | "github.com/oxidecomputer/oxide.go/oxide" 18 | ) 19 | 20 | func testAccProtoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) { 21 | return map[string]func() (tfprotov6.ProviderServer, error){ 22 | "oxide": providerserver.NewProtocol6WithError(New()), 23 | } 24 | } 25 | 26 | func testAccPreCheck(t *testing.T) { 27 | host, token := setAccFromEnvVar() 28 | 29 | if host == "" || token == "" { 30 | t.Fatal("Both host and token need to be set to execute acceptance tests") 31 | } 32 | } 33 | 34 | func newTestClient() (*oxide.Client, error) { 35 | host, token := setAccFromEnvVar() 36 | 37 | config := oxide.Config{ 38 | Token: token, 39 | UserAgent: "terraform-provider-oxide-test", 40 | Host: host, 41 | } 42 | client, err := oxide.NewClient(&config) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | return client, nil 48 | 49 | } 50 | 51 | func parsedAccConfig(config any, tpl string) (string, error) { 52 | var buf bytes.Buffer 53 | tmpl, _ := template.New("test").Parse(tpl) 54 | err := tmpl.Execute(&buf, config) 55 | if err != nil { 56 | return "", err 57 | } 58 | 59 | return buf.String(), nil 60 | } 61 | 62 | func setAccFromEnvVar() (string, string) { 63 | // TODO: Unsure if I should only keep the tests tokens, 64 | // but will leave like this for now 65 | var host, token string 66 | 67 | if k := os.Getenv("OXIDE_HOST"); k != "" { 68 | host = k 69 | } 70 | if k := os.Getenv("OXIDE_TEST_HOST"); k != "" { 71 | host = k 72 | } 73 | 74 | if k := os.Getenv("OXIDE_TOKEN"); k != "" { 75 | token = k 76 | } 77 | if k := os.Getenv("OXIDE_TEST_TOKEN"); k != "" { 78 | token = k 79 | } 80 | 81 | return host, token 82 | } 83 | 84 | func newResourceName() string { 85 | return fmt.Sprintf("acc-terraform-%s", uuid.New()) 86 | } 87 | 88 | func newBlockName(resource string) string { 89 | return fmt.Sprintf("acc-%s-%s", resource, uuid.New()) 90 | } 91 | -------------------------------------------------------------------------------- /internal/provider/testutils_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func Test_newResourceName(t *testing.T) { 14 | tests := []struct { 15 | name string 16 | want string 17 | }{ 18 | { 19 | name: "results are always different and contain prefix", 20 | want: "acc-terraform-", 21 | }, 22 | } 23 | for _, tt := range tests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | name1 := newResourceName() 26 | name2 := newResourceName() 27 | name3 := newResourceName() 28 | name4 := newResourceName() 29 | assert.NotEqual(t, name1, name2, name3, name4) 30 | assert.Contains(t, name1, tt.want) 31 | assert.Contains(t, name2, tt.want) 32 | assert.Contains(t, name3, tt.want) 33 | assert.Contains(t, name4, tt.want) 34 | }) 35 | } 36 | } 37 | 38 | func Test_newBlockName(t *testing.T) { 39 | tests := []struct { 40 | name string 41 | want string 42 | }{ 43 | { 44 | name: "results are always different and contain prefix", 45 | want: "acc-vpc-", 46 | }, 47 | } 48 | for _, tt := range tests { 49 | t.Run(tt.name, func(t *testing.T) { 50 | name1 := newBlockName("vpc") 51 | name2 := newBlockName("vpc") 52 | name3 := newBlockName("vpc") 53 | name4 := newBlockName("vpc") 54 | assert.NotEqual(t, name1, name2, name3, name4) 55 | assert.Contains(t, name1, tt.want) 56 | assert.Contains(t, name2, tt.want) 57 | assert.Contains(t, name3, tt.want) 58 | assert.Contains(t, name4, tt.want) 59 | }) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /internal/provider/utils.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | import ( 8 | "net" 9 | "strconv" 10 | "strings" 11 | "time" 12 | 13 | "github.com/hashicorp/terraform-plugin-framework/diag" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/oxidecomputer/oxide.go/oxide" 16 | ) 17 | 18 | func is404(err error) bool { 19 | return strings.Contains(err.Error(), "Status: 404") 20 | } 21 | 22 | // Original function from https://pkg.go.dev/github.com/asaskevich/govalidator#IsIPv4 23 | // Shamelessly copied here to avoid importing the entire package 24 | // 25 | // isIPv4 checks if the string is an IP version 4. 26 | func isIPv4(str string) bool { 27 | ip := net.ParseIP(str) 28 | return ip != nil && strings.Contains(str, ".") 29 | } 30 | 31 | // Original function from https://pkg.go.dev/github.com/asaskevich/govalidator#IsIPv6 32 | // Shamelessly copied here to avoid importing the entire package 33 | // 34 | // isIPv6 checks if the string is an IP version 6. 35 | func isIPv6(str string) bool { 36 | ip := net.ParseIP(str) 37 | return ip != nil && strings.Contains(str, ":") 38 | } 39 | 40 | func defaultTimeout() time.Duration { 41 | return 10 * time.Minute 42 | } 43 | 44 | // sliceDiff returns a string slice of the elements in `a` that aren't in `b`. 45 | // This function is a bit expensive, but given the fact that 46 | // the expected number of elements is relatively slow 47 | // it's not a big deal. 48 | func sliceDiff[S []E, E any](a, b S) S { 49 | mb := make(map[any]struct{}, len(b)) 50 | for _, x := range b { 51 | mb[x] = struct{}{} 52 | } 53 | 54 | var diff S 55 | for _, x := range a { 56 | if _, found := mb[x]; !found { 57 | diff = append(diff, x) 58 | } 59 | } 60 | return diff 61 | } 62 | 63 | // newNameOrIdList takes a terraform set and converts is into a slice NameOrIds. 64 | func newNameOrIdList(nameOrIDs types.Set) ([]oxide.NameOrId, diag.Diagnostics) { 65 | var diags diag.Diagnostics 66 | var list = []oxide.NameOrId{} 67 | for _, item := range nameOrIDs.Elements() { 68 | id, err := strconv.Unquote(item.String()) 69 | if err != nil { 70 | diags.AddError( 71 | "Error retrieving name or ID information", 72 | "name or ID parse error: "+err.Error(), 73 | ) 74 | return []oxide.NameOrId{}, diags 75 | } 76 | 77 | n := oxide.NameOrId(id) 78 | list = append(list, n) 79 | } 80 | 81 | return list, diags 82 | } 83 | -------------------------------------------------------------------------------- /internal/provider/version.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package provider 6 | 7 | // TODO: Make sure this variable is updated every time a new version is released 8 | 9 | // Version contains the current terraform provider version. 10 | const Version = "0.10.0" 11 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | package main 6 | 7 | import ( 8 | "context" 9 | "flag" 10 | "log" 11 | 12 | "github.com/oxidecomputer/terraform-provider-oxide/internal/provider" 13 | 14 | "github.com/hashicorp/terraform-plugin-framework/providerserver" 15 | ) 16 | 17 | func main() { 18 | var debug bool 19 | 20 | flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") 21 | flag.Parse() 22 | 23 | if err := providerserver.Serve( 24 | context.Background(), 25 | provider.New, 26 | providerserver.ServeOpts{ 27 | Address: "registry.terraform.io/oxidecomputer/oxide", 28 | Debug: debug, 29 | }, 30 | ); err != nil { 31 | log.Fatal(err.Error()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /terraform-registry-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "metadata": { 4 | "protocol_versions": ["6.0"] 5 | } 6 | } 7 | --------------------------------------------------------------------------------