Implement key pair resource (#578)
* feat: Implement key pair resource * feat: Implement acceptance test * fix: Minor fixes to server and public IP resources * fix: Lint fixes * fix: Generalize description * feat: Update examples to read key from file; Add datasource example * fix: Fix field descriptions * fix: Fix example * feat: Add link to key pair resource in server example * feat: Add links to key pair resource in other examples
This commit is contained in:
parent
c1ada319ce
commit
153947fd7b
16 changed files with 1261 additions and 117 deletions
36
docs/data-sources/key_pair.md
Normal file
36
docs/data-sources/key_pair.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "stackit_key_pair Data Source - stackit"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
Key pair resource schema. Must have a region specified in the provider configuration.
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
||||
---
|
||||
|
||||
# stackit_key_pair (Data Source)
|
||||
|
||||
Key pair resource schema. Must have a `region` specified in the provider configuration.
|
||||
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "stackit_key_pair" "example" {
|
||||
name = "example-key-pair-name"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `name` (String) The name of the SSH key pair.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `fingerprint` (String) The fingerprint of the public SSH key.
|
||||
- `id` (String) Terraform's internal resource ID. It takes the value of the key pair "`name`".
|
||||
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container.
|
||||
- `public_key` (String) A string representation of the public SSH key. E.g., `ssh-rsa <key_data>` or `ssh-ed25519 <key-data>`.
|
||||
|
|
@ -3,13 +3,13 @@
|
|||
page_title: "stackit_public_ip Data Source - stackit"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
Volume resource schema. Must have a region specified in the provider configuration.
|
||||
Public IP resource schema. Must have a region specified in the provider configuration.
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
||||
---
|
||||
|
||||
# stackit_public_ip (Data Source)
|
||||
|
||||
Volume resource schema. Must have a `region` specified in the provider configuration.
|
||||
Public IP resource schema. Must have a `region` specified in the provider configuration.
|
||||
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
||||
|
||||
|
|
|
|||
74
docs/resources/key_pair.md
Normal file
74
docs/resources/key_pair.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "stackit_key_pair Resource - stackit"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
Key pair resource schema. Must have a region specified in the provider configuration. Allows uploading an SSH public key to be used for server authentication.
|
||||
Usage with server
|
||||
```terraform
|
||||
resource "stackitkeypair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
publickey = chomp(file("path/to/idrsa.pub"))
|
||||
}
|
||||
resource "stackitserver" "example-server" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
bootvolume = {
|
||||
size = 64
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availabilityzone = "eu01-1"
|
||||
machinetype = "g1.1"
|
||||
keypairname = "example-key-pair"
|
||||
}
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
||||
---
|
||||
|
||||
# stackit_key_pair (Resource)
|
||||
|
||||
Key pair resource schema. Must have a `region` specified in the provider configuration. Allows uploading an SSH public key to be used for server authentication.
|
||||
|
||||
|
||||
|
||||
### Usage with server
|
||||
```terraform
|
||||
resource "stackit_key_pair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
public_key = chomp(file("path/to/id_rsa.pub"))
|
||||
}
|
||||
|
||||
resource "stackit_server" "example-server" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-key-pair"
|
||||
}
|
||||
|
||||
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
||||
|
||||
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `name` (String) The name of the SSH key pair.
|
||||
- `public_key` (String) A string representation of the public SSH key. E.g., `ssh-rsa <key_data>` or `ssh-ed25519 <key-data>`.
|
||||
|
||||
### Optional
|
||||
|
||||
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `fingerprint` (String) The fingerprint of the public SSH key.
|
||||
- `id` (String) Terraform's internal resource ID. It takes the value of the key pair "`name`".
|
||||
|
|
@ -6,26 +6,44 @@ description: |-
|
|||
Server resource schema. Must have a region specified in the provider configuration.
|
||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
||||
Example Usage
|
||||
Boot from volume
|
||||
|
||||
resource "stackit_server" "boot-from-volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
With key pair
|
||||
```terraform
|
||||
resource "stackitkeypair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
publickey = chomp(file("path/to/idrsa.pub"))
|
||||
}
|
||||
|
||||
|
||||
resource "stackitserver" "user-data-from-file" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
bootvolume = {
|
||||
size = 64
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
name = "example-server"
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkeypair.keypair.name
|
||||
userdata = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
```
|
||||
Boot from volume
|
||||
```terraform
|
||||
resource "stackitserver" "boot-from-volume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
bootvolume = {
|
||||
size = 64
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availabilityzone = "eu01-1"
|
||||
machinetype = "g1.1"
|
||||
keypairname = "example-keypair"
|
||||
}
|
||||
```
|
||||
Boot from existing volume
|
||||
|
||||
resource "stackit_volume" "example-volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
```terraform
|
||||
resource "stackitvolume" "example-volume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
size = 12
|
||||
source = {
|
||||
type = "image"
|
||||
|
|
@ -34,129 +52,117 @@ description: |-
|
|||
name = "example-volume"
|
||||
availability_zone = "eu01-1"
|
||||
}
|
||||
|
||||
resource "stackit_server" "boot-from-volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
resource "stackitserver" "boot-from-volume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
source_type = "volume"
|
||||
source_id = stackit_volume.example-volume.volume_id
|
||||
bootvolume = {
|
||||
sourcetype = "volume"
|
||||
sourceid = stackitvolume.example-volume.volumeid
|
||||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
availabilityzone = "eu01-1"
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkeypair.keypair.name
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
Network setup
|
||||
|
||||
resource "stackit_server" "server-with-network" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
```terraform
|
||||
resource "stackitserver" "server-with-network" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
bootvolume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkey_pair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_network" "network" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
resource "stackitnetwork" "network" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-network"
|
||||
nameservers = ["192.0.2.0", "198.51.100.0", "203.0.113.0"]
|
||||
ipv4_prefix_length = 24
|
||||
ipv4prefixlength = 24
|
||||
}
|
||||
|
||||
resource "stackit_security_group" "sec-group" {
|
||||
resource "stackitsecuritygroup" "sec-group" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-security-group"
|
||||
stateful = true
|
||||
}
|
||||
|
||||
resource "stackit_security_group_rule" "rule" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
security_group_id = stackit_security_group.sec-group.security_group_id
|
||||
resource "stackitsecuritygrouprule" "rule" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
securitygroupid = stackitsecuritygroup.sec-group.securitygroupid
|
||||
direction = "ingress"
|
||||
ether_type = "IPv4"
|
||||
}
|
||||
|
||||
resource "stackit_network_interface" "nic" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
network_id = stackit_network.network.network_id
|
||||
security_group_ids = [stackit_security_group.sec-group.security_group_id]
|
||||
resource "stackitnetworkinterface" "nic" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
networkid = stackitnetwork.network.networkid
|
||||
securitygroupids = [stackitsecuritygroup.sec-group.securitygroupid]
|
||||
}
|
||||
|
||||
resource "stackit_public_ip" "public-ip" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
network_interface_id = stackit_network_interface.nic.network_interface_id
|
||||
resource "stackitpublicip" "public-ip" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
networkinterfaceid = stackitnetworkinterface.nic.networkinterface_id
|
||||
}
|
||||
|
||||
resource "stackit_server_network_interface_attach" "nic-attachment" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
server_id = stackit_server.server-with-network.server_id
|
||||
network_interface_id = stackit_network_interface.nic.network_interface_id
|
||||
resource "stackitservernetworkinterfaceattach" "nic-attachment" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
serverid = stackitserver.server-with-network.serverid
|
||||
networkinterfaceid = stackitnetworkinterface.nic.networkinterfaceid
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
Server with attached volume
|
||||
|
||||
resource "stackit_volume" "example-volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
```terraform
|
||||
resource "stackitvolume" "example-volume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
size = 12
|
||||
performance_class = "storage_premium_perf6"
|
||||
performanceclass = "storagepremiumperf6"
|
||||
name = "example-volume"
|
||||
availability_zone = "eu01-1"
|
||||
availabilityzone = "eu01-1"
|
||||
}
|
||||
|
||||
resource "stackit_server" "server-with-volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
resource "stackitserver" "server-with-volume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
bootvolume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
availabilityzone = "eu01-1"
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkeypair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_server_volume_attach" "attach_volume" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
server_id = stackit_server.server-with-volume.server_id
|
||||
volume_id = stackit_volume.example-volume.volume_id
|
||||
resource "stackitservervolumeattach" "attachvolume" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
serverid = stackitserver.server-with-volume.serverid
|
||||
volumeid = stackitvolume.example-volume.volume_id
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
Server with user data (cloud-init)
|
||||
|
||||
resource "stackit_server" "user-data" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
boot_volume = {
|
||||
```terraform
|
||||
resource "stackitserver" "user-data" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
bootvolume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
user_data = "#!/bin/bash\n/bin/su"
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkeypair.keypair.name
|
||||
userdata = "#!/bin/bash\n/bin/su"
|
||||
}
|
||||
|
||||
resource "stackit_server" "user-data-from-file" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
boot_volume = {
|
||||
resource "stackitserver" "user-data-from-file" {
|
||||
projectid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
bootvolume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
sourcetype = "image"
|
||||
sourceid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
user_data = file("${path.module}/cloud-init.yaml")
|
||||
machinetype = "g1.1"
|
||||
keypairname = stackitkeypair.keypair.name
|
||||
userdata = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
# stackit_server (Resource)
|
||||
|
|
@ -167,6 +173,28 @@ Server resource schema. Must have a region specified in the provider configurati
|
|||
## Example Usage
|
||||
|
||||
|
||||
### With key pair
|
||||
```terraform
|
||||
resource "stackit_key_pair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
public_key = chomp(file("path/to/id_rsa.pub"))
|
||||
}
|
||||
|
||||
resource "stackit_server" "user-data-from-file" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
boot_volume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Boot from volume
|
||||
```terraform
|
||||
resource "stackit_server" "boot-from-volume" {
|
||||
|
|
@ -206,7 +234,7 @@ resource "stackit_server" "boot-from-volume" {
|
|||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -222,7 +250,7 @@ resource "stackit_server" "server-with-network" {
|
|||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_network" "network" {
|
||||
|
|
@ -284,7 +312,7 @@ resource "stackit_server" "server-with-volume" {
|
|||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_server_volume_attach" "attach_volume" {
|
||||
|
|
@ -306,7 +334,7 @@ resource "stackit_server" "user-data" {
|
|||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = "#!/bin/bash\n/bin/su"
|
||||
}
|
||||
|
||||
|
|
@ -319,7 +347,7 @@ resource "stackit_server" "user-data-from-file" {
|
|||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
|
||||
|
|
|
|||
3
examples/data-sources/stackit_key_pair/data-source.tf
Normal file
3
examples/data-sources/stackit_key_pair/data-source.tf
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
data "stackit_key_pair" "example" {
|
||||
name = "example-key-pair-name"
|
||||
}
|
||||
1
go.mod
1
go.mod
|
|
@ -15,6 +15,7 @@ require (
|
|||
github.com/stackitcloud/stackit-sdk-go/services/argus v0.11.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/dns v0.11.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.15.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.12-alpha
|
||||
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v0.17.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/logme v0.20.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.20.0
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -157,6 +157,8 @@ github.com/stackitcloud/stackit-sdk-go/services/dns v0.11.0 h1:+OZ82DwFy4JIJThad
|
|||
github.com/stackitcloud/stackit-sdk-go/services/dns v0.11.0/go.mod h1:mv8U7kuclXo+0VpDHtBCkve/3i9h1yT+RAId/MUi+C8=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.15.0 h1:bPNv+PuSykBcKCYVXHiYOcqNP+KLCA7XMFSY4V6J6ug=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.15.0/go.mod h1:YfuN+eXuqr846xeRyW2Vf1JM2jU0ikeQa76dDI66RsM=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.12-alpha h1:jwpif4t2gthmKmCXsQ84rmtDdcZkw4QQTFiCd7nTW8M=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.12-alpha/go.mod h1:nW/6vvumUHA7o1/JOOqsrEOBNrRHombEKB1U4jmg2wU=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v0.17.0 h1:06CGP64CEk3Zg6i9kZCMRdmCzLLiyMWQqGK1teBr9Oc=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v0.17.0/go.mod h1:JL94zc8K0ebWs+DBGXR28vNCF0EFV54ZLUtrlXOvWgA=
|
||||
github.com/stackitcloud/stackit-sdk-go/services/logme v0.20.0 h1:V0UGP7JEa4Q8SsZFUJsKgLGaoPruLn2KVKnqQtaoWCU=
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/stackitcloud/stackit-sdk-go/core/config"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/utils"
|
||||
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
|
||||
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil"
|
||||
)
|
||||
|
|
@ -96,6 +97,14 @@ var publicIpResource = map[string]string{
|
|||
"network_interface_id": testutil.IaaSNetworkInterfaceId,
|
||||
}
|
||||
|
||||
// Key pair resource data
|
||||
var keyPairResource = map[string]string{
|
||||
"name": "key-pair-name",
|
||||
"public_key": `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIDsPd27M449akqCtdFg2+AmRVJz6eWio0oMP9dVg7XZ`,
|
||||
"label1": "value1",
|
||||
"label1-updated": "value1-updated",
|
||||
}
|
||||
|
||||
func networkResourceConfig(name, nameservers string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "stackit_network" "network" {
|
||||
|
|
@ -323,6 +332,13 @@ func testAccPublicIpConfig(publicIpResourceConfig string) string {
|
|||
)
|
||||
}
|
||||
|
||||
func testAccKeyPairConfig(keyPairResourceConfig string) string {
|
||||
return fmt.Sprintf("%s\n\n%s",
|
||||
testutil.IaaSProviderConfig(),
|
||||
keyPairResourceConfig,
|
||||
)
|
||||
}
|
||||
|
||||
func TestAccNetworkArea(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
|
||||
|
|
@ -1113,6 +1129,117 @@ func TestAccPublicIp(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccKeyPair(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
|
||||
CheckDestroy: testAccCheckIaaSKeyPairDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
|
||||
// Creation
|
||||
{
|
||||
Config: testAccKeyPairConfig(
|
||||
fmt.Sprintf(`
|
||||
resource "stackit_key_pair" "key_pair" {
|
||||
name = "%s"
|
||||
public_key = "%s"
|
||||
labels = {
|
||||
"label1" = "%s"
|
||||
}
|
||||
}
|
||||
`,
|
||||
keyPairResource["name"],
|
||||
keyPairResource["public_key"],
|
||||
keyPairResource["label1"],
|
||||
),
|
||||
),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "name", keyPairResource["name"]),
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "labels.label1", keyPairResource["label1"]),
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "public_key", keyPairResource["public_key"]),
|
||||
resource.TestCheckResourceAttrSet("stackit_key_pair.key_pair", "fingerprint"),
|
||||
),
|
||||
},
|
||||
// Data source
|
||||
{
|
||||
Config: fmt.Sprintf(`
|
||||
%s
|
||||
|
||||
data "stackit_key_pair" "key_pair" {
|
||||
name = stackit_key_pair.key_pair.name
|
||||
}
|
||||
`,
|
||||
testAccKeyPairConfig(
|
||||
fmt.Sprintf(`
|
||||
resource "stackit_key_pair" "key_pair" {
|
||||
name = "%s"
|
||||
public_key = "%s"
|
||||
labels = {
|
||||
"label1" = "%s"
|
||||
}
|
||||
}
|
||||
`,
|
||||
keyPairResource["name"],
|
||||
keyPairResource["public_key"],
|
||||
keyPairResource["label1"],
|
||||
),
|
||||
),
|
||||
),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Instance
|
||||
resource.TestCheckResourceAttr("data.stackit_key_pair.key_pair", "name", keyPairResource["name"]),
|
||||
resource.TestCheckResourceAttr("data.stackit_key_pair.key_pair", "public_key", keyPairResource["public_key"]),
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "labels.label1", keyPairResource["label1"]),
|
||||
resource.TestCheckResourceAttrPair(
|
||||
"stackit_key_pair.key_pair", "fingerprint",
|
||||
"data.stackit_key_pair.key_pair", "fingerprint",
|
||||
),
|
||||
),
|
||||
},
|
||||
// Import
|
||||
{
|
||||
ResourceName: "stackit_key_pair.key_pair",
|
||||
ImportStateIdFunc: func(s *terraform.State) (string, error) {
|
||||
r, ok := s.RootModule().Resources["stackit_key_pair.key_pair"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("couldn't find resource stackit_key_pair.key_pair")
|
||||
}
|
||||
keyPairName, ok := r.Primary.Attributes["name"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("couldn't find attribute name")
|
||||
}
|
||||
return keyPairName, nil
|
||||
},
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
// Update
|
||||
{
|
||||
Config: testAccKeyPairConfig(
|
||||
fmt.Sprintf(`
|
||||
resource "stackit_key_pair" "key_pair" {
|
||||
name = "%s"
|
||||
public_key = "%s"
|
||||
labels = {
|
||||
"label1" = "%s"
|
||||
}
|
||||
}
|
||||
`,
|
||||
keyPairResource["name"],
|
||||
keyPairResource["public_key"],
|
||||
keyPairResource["label1-updated"],
|
||||
),
|
||||
),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "name", keyPairResource["name"]),
|
||||
resource.TestCheckResourceAttr("stackit_key_pair.key_pair", "labels.label1", keyPairResource["label1-updated"]),
|
||||
resource.TestCheckResourceAttrSet("stackit_key_pair.key_pair", "fingerprint"),
|
||||
),
|
||||
},
|
||||
// Deletion is done by the framework implicitly
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckNetworkAreaDestroy(s *terraform.State) error {
|
||||
ctx := context.Background()
|
||||
var client *iaas.APIClient
|
||||
|
|
@ -1388,3 +1515,49 @@ func testAccCheckIaaSPublicIpDestroy(s *terraform.State) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckIaaSKeyPairDestroy(s *terraform.State) error {
|
||||
ctx := context.Background()
|
||||
var client *iaasalpha.APIClient
|
||||
var err error
|
||||
if testutil.IaaSCustomEndpoint == "" {
|
||||
client, err = iaasalpha.NewAPIClient(
|
||||
config.WithRegion("eu01"),
|
||||
)
|
||||
} else {
|
||||
client, err = iaasalpha.NewAPIClient(
|
||||
config.WithEndpoint(testutil.IaaSCustomEndpoint),
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating client: %w", err)
|
||||
}
|
||||
|
||||
keyPairsToDestroy := []string{}
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "stackit_key_pair" {
|
||||
continue
|
||||
}
|
||||
// Key pair terraform ID: "[name]"
|
||||
keyPairsToDestroy = append(keyPairsToDestroy, rs.Primary.ID)
|
||||
}
|
||||
|
||||
keyPairsResp, err := client.ListKeyPairsExecute(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting key pairs: %w", err)
|
||||
}
|
||||
|
||||
keyPairs := *keyPairsResp.Items
|
||||
for i := range keyPairs {
|
||||
if keyPairs[i].Name == nil {
|
||||
continue
|
||||
}
|
||||
if utils.Contains(keyPairsToDestroy, *keyPairs[i].Name) {
|
||||
err := client.DeleteKeyPairExecute(ctx, *keyPairs[i].Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("destroying key pair %s during CheckDestroy: %w", *keyPairs[i].Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
25
stackit/internal/services/iaas/keypair/const.go
Normal file
25
stackit/internal/services/iaas/keypair/const.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package keypair
|
||||
|
||||
const exampleUsageWithServer = `
|
||||
|
||||
### Usage with server` + "\n" +
|
||||
|
||||
"```terraform" + `
|
||||
resource "stackit_key_pair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
public_key = chomp(file("path/to/id_rsa.pub"))
|
||||
}
|
||||
|
||||
resource "stackit_server" "example-server" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
name = "example-server"
|
||||
boot_volume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-key-pair"
|
||||
}
|
||||
`
|
||||
155
stackit/internal/services/iaas/keypair/datasource.go
Normal file
155
stackit/internal/services/iaas/keypair/datasource.go
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
package keypair
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/config"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
|
||||
)
|
||||
|
||||
// keyPairDataSourceBetaCheckDone is used to prevent multiple checks for beta resources.
|
||||
// This is a workaround for the lack of a global state in the provider and
|
||||
// needs to exist because the Configure method is called twice.
|
||||
var keyPairDataSourceBetaCheckDone bool
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &keyPairDataSource{}
|
||||
)
|
||||
|
||||
// NewVolumeDataSource is a helper function to simplify the provider implementation.
|
||||
func NewKeyPairDataSource() datasource.DataSource {
|
||||
return &keyPairDataSource{}
|
||||
}
|
||||
|
||||
// keyPairDataSource is the data source implementation.
|
||||
type keyPairDataSource struct {
|
||||
client *iaasalpha.APIClient
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *keyPairDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_key_pair"
|
||||
}
|
||||
|
||||
func (d *keyPairDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
// Prevent panic if the provider has not been configured.
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var apiClient *iaasalpha.APIClient
|
||||
var err error
|
||||
|
||||
providerData, ok := req.ProviderData.(core.ProviderData)
|
||||
if !ok {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
|
||||
return
|
||||
}
|
||||
|
||||
if !keyPairDataSourceBetaCheckDone {
|
||||
features.CheckBetaResourcesEnabled(ctx, &providerData, &resp.Diagnostics, "stackit_key_pair", "data source")
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
keyPairDataSourceBetaCheckDone = true
|
||||
}
|
||||
|
||||
if providerData.IaaSCustomEndpoint != "" {
|
||||
apiClient, err = iaasalpha.NewAPIClient(
|
||||
config.WithCustomAuth(providerData.RoundTripper),
|
||||
config.WithEndpoint(providerData.IaaSCustomEndpoint),
|
||||
)
|
||||
} else {
|
||||
apiClient, err = iaasalpha.NewAPIClient(
|
||||
config.WithCustomAuth(providerData.RoundTripper),
|
||||
config.WithRegion(providerData.Region),
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the data source configuration", err))
|
||||
return
|
||||
}
|
||||
|
||||
d.client = apiClient
|
||||
tflog.Info(ctx, "iaasalpha client configured")
|
||||
}
|
||||
|
||||
// Schema defines the schema for the resource.
|
||||
func (r *keyPairDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
description := "Key pair resource schema. Must have a `region` specified in the provider configuration."
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: features.AddBetaDescription(description),
|
||||
Description: description,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "Terraform's internal resource ID. It takes the value of the key pair \"`name`\".",
|
||||
Computed: true,
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Description: "The name of the SSH key pair.",
|
||||
Required: true,
|
||||
},
|
||||
"public_key": schema.StringAttribute{
|
||||
Description: "A string representation of the public SSH key. E.g., `ssh-rsa <key_data>` or `ssh-ed25519 <key-data>`.",
|
||||
Computed: true,
|
||||
},
|
||||
"fingerprint": schema.StringAttribute{
|
||||
Description: "The fingerprint of the public SSH key.",
|
||||
Computed: true,
|
||||
},
|
||||
"labels": schema.MapAttribute{
|
||||
Description: "Labels are key-value string pairs which can be attached to a resource container.",
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Read refreshes the Terraform state with the latest data.
|
||||
func (r *keyPairDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
var model Model
|
||||
diags := req.Config.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
name := model.Name.ValueString()
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
keypairResp, err := r.client.GetKeyPair(ctx, name).Execute()
|
||||
if err != nil {
|
||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
||||
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
||||
resp.State.RemoveResource(ctx)
|
||||
return
|
||||
}
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading key pair", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, keypairResp, &model)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading key pair", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
}
|
||||
// Set refreshed state
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
tflog.Info(ctx, "Key pair read")
|
||||
}
|
||||
411
stackit/internal/services/iaas/keypair/resource.go
Normal file
411
stackit/internal/services/iaas/keypair/resource.go
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
package keypair
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/config"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
|
||||
)
|
||||
|
||||
// resourceBetaCheckDone is used to prevent multiple checks for beta resources.
|
||||
// This is a workaround for the lack of a global state in the provider and
|
||||
// needs to exist because the Configure method is called twice.
|
||||
var resourceBetaCheckDone bool
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ resource.Resource = &keyPairResource{}
|
||||
_ resource.ResourceWithConfigure = &keyPairResource{}
|
||||
_ resource.ResourceWithImportState = &keyPairResource{}
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
Id types.String `tfsdk:"id"` // needed by TF
|
||||
Name types.String `tfsdk:"name"`
|
||||
PublicKey types.String `tfsdk:"public_key"`
|
||||
Fingerprint types.String `tfsdk:"fingerprint"`
|
||||
Labels types.Map `tfsdk:"labels"`
|
||||
}
|
||||
|
||||
// NewKeyPairResource is a helper function to simplify the provider implementation.
|
||||
func NewKeyPairResource() resource.Resource {
|
||||
return &keyPairResource{}
|
||||
}
|
||||
|
||||
// keyPairResource is the resource implementation.
|
||||
type keyPairResource struct {
|
||||
client *iaasalpha.APIClient
|
||||
}
|
||||
|
||||
// Metadata returns the resource type name.
|
||||
func (r *keyPairResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_key_pair"
|
||||
}
|
||||
|
||||
// Configure adds the provider configured client to the resource.
|
||||
func (r *keyPairResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
||||
// Prevent panic if the provider has not been configured.
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
providerData, ok := req.ProviderData.(core.ProviderData)
|
||||
if !ok {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData))
|
||||
return
|
||||
}
|
||||
|
||||
if !resourceBetaCheckDone {
|
||||
features.CheckBetaResourcesEnabled(ctx, &providerData, &resp.Diagnostics, "stackit_key_pair", "resource")
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
resourceBetaCheckDone = true
|
||||
}
|
||||
|
||||
var apiClient *iaasalpha.APIClient
|
||||
var err error
|
||||
if providerData.IaaSCustomEndpoint != "" {
|
||||
ctx = tflog.SetField(ctx, "iaasalpha_custom_endpoint", providerData.IaaSCustomEndpoint)
|
||||
apiClient, err = iaasalpha.NewAPIClient(
|
||||
config.WithCustomAuth(providerData.RoundTripper),
|
||||
config.WithEndpoint(providerData.IaaSCustomEndpoint),
|
||||
)
|
||||
} else {
|
||||
apiClient, err = iaasalpha.NewAPIClient(
|
||||
config.WithCustomAuth(providerData.RoundTripper),
|
||||
config.WithRegion(providerData.Region),
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err))
|
||||
return
|
||||
}
|
||||
|
||||
r.client = apiClient
|
||||
tflog.Info(ctx, "iaasalpha client configured")
|
||||
}
|
||||
|
||||
// Schema defines the schema for the resource.
|
||||
func (r *keyPairResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
description := "Key pair resource schema. Must have a `region` specified in the provider configuration. Allows uploading an SSH public key to be used for server authentication."
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: features.AddBetaDescription(description + "\n\n" + exampleUsageWithServer),
|
||||
Description: description,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "Terraform's internal resource ID. It takes the value of the key pair \"`name`\".",
|
||||
Computed: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Description: "The name of the SSH key pair.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"public_key": schema.StringAttribute{
|
||||
Description: "A string representation of the public SSH key. E.g., `ssh-rsa <key_data>` or `ssh-ed25519 <key-data>`.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"fingerprint": schema.StringAttribute{
|
||||
Description: "The fingerprint of the public SSH key.",
|
||||
Computed: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"labels": schema.MapAttribute{
|
||||
Description: "Labels are key-value string pairs which can be attached to a resource container.",
|
||||
ElementType: types.StringType,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ModifyPlan will be called in the Plan phase.
|
||||
// It will check if the plan contains a change that requires replacement. If yes, it will show a warning to the user.
|
||||
func (r *keyPairResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// If the state is empty we are creating a new resource
|
||||
// If the plan is empty we are deleting the resource
|
||||
// In both cases we don't need to check for replacement
|
||||
if req.Plan.Raw.IsNull() || req.State.Raw.IsNull() {
|
||||
return
|
||||
}
|
||||
|
||||
var planModel Model
|
||||
diags := req.Plan.Get(ctx, &planModel)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
var stateModel Model
|
||||
diags = req.State.Get(ctx, &stateModel)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
if planModel.PublicKey.ValueString() != stateModel.PublicKey.ValueString() {
|
||||
core.LogAndAddWarning(ctx, &resp.Diagnostics, "Key pair public key change", "Changing the public key will trigger a replacement of the key pair resource. The new key pair will not be valid to access servers on which the old key was used, as the key is only registered during server creation.")
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates the resource and sets the initial Terraform state.
|
||||
func (r *keyPairResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from plan
|
||||
var model Model
|
||||
diags := req.Plan.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
name := model.Name.ValueString()
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toCreatePayload(ctx, &model)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating key pair", fmt.Sprintf("Creating API payload: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Create new key pair
|
||||
|
||||
keyPair, err := r.client.CreateKeyPair(ctx).CreateKeyPairPayload(*payload).Execute()
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating key pair", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, keyPair, &model)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating key pair", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
}
|
||||
// Set state to fully populated data
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
tflog.Info(ctx, "Key pair created")
|
||||
}
|
||||
|
||||
// Read refreshes the Terraform state with the latest data.
|
||||
func (r *keyPairResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
var model Model
|
||||
diags := req.State.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
name := model.Name.ValueString()
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
keyPairResp, err := r.client.GetKeyPair(ctx, name).Execute()
|
||||
if err != nil {
|
||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
||||
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
||||
resp.State.RemoveResource(ctx)
|
||||
return
|
||||
}
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading key pair", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, keyPairResp, &model)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading key pair", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
}
|
||||
// Set refreshed state
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
tflog.Info(ctx, "Key pair read")
|
||||
}
|
||||
|
||||
// Update updates the resource and sets the updated Terraform state on success.
|
||||
func (r *keyPairResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from plan
|
||||
var model Model
|
||||
diags := req.Plan.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
name := model.Name.ValueString()
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
// Retrieve values from state
|
||||
var stateModel Model
|
||||
diags = req.State.Get(ctx, &stateModel)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toUpdatePayload(ctx, &model, stateModel.Labels)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating key pair", fmt.Sprintf("Creating API payload: %v", err))
|
||||
return
|
||||
}
|
||||
// Update existing key pair
|
||||
updatedKeyPair, err := r.client.UpdateKeyPair(ctx, name).UpdateKeyPairPayload(*payload).Execute()
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating key pair", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = mapFields(ctx, updatedKeyPair, &model)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating key pair", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
}
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
tflog.Info(ctx, "key pair updated")
|
||||
}
|
||||
|
||||
// Delete deletes the resource and removes the Terraform state on success.
|
||||
func (r *keyPairResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from state
|
||||
var model Model
|
||||
diags := req.State.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
name := model.Name.ValueString()
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
// Delete existing key pair
|
||||
err := r.client.DeleteKeyPair(ctx, name).Execute()
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting key pair", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
tflog.Info(ctx, "Key pair deleted")
|
||||
}
|
||||
|
||||
// ImportState imports a resource into the Terraform state on success.
|
||||
// The expected format of the resource import identifier is: project_id,key_pair_id
|
||||
func (r *keyPairResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
|
||||
idParts := strings.Split(req.ID, core.Separator)
|
||||
|
||||
if len(idParts) != 1 || idParts[0] == "" {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics,
|
||||
"Error importing key pair",
|
||||
fmt.Sprintf("Expected import identifier with format: [name] Got: %q", req.ID),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
name := idParts[0]
|
||||
ctx = tflog.SetField(ctx, "name", name)
|
||||
|
||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), name)...)
|
||||
tflog.Info(ctx, "Key pair state imported")
|
||||
}
|
||||
|
||||
func mapFields(ctx context.Context, keyPairResp *iaasalpha.Keypair, model *Model) error {
|
||||
if keyPairResp == nil {
|
||||
return fmt.Errorf("response input is nil")
|
||||
}
|
||||
if model == nil {
|
||||
return fmt.Errorf("model input is nil")
|
||||
}
|
||||
|
||||
var name string
|
||||
if model.Name.ValueString() != "" {
|
||||
name = model.Name.ValueString()
|
||||
} else if keyPairResp.Name != nil {
|
||||
name = *keyPairResp.Name
|
||||
} else {
|
||||
return fmt.Errorf("key pair name not present")
|
||||
}
|
||||
|
||||
model.Id = types.StringValue(name)
|
||||
model.PublicKey = types.StringPointerValue(keyPairResp.PublicKey)
|
||||
model.Fingerprint = types.StringPointerValue(keyPairResp.Fingerprint)
|
||||
|
||||
labels, diags := types.MapValueFrom(ctx, types.StringType, map[string]interface{}{})
|
||||
if diags.HasError() {
|
||||
return fmt.Errorf("converting labels to StringValue map: %w", core.DiagsToError(diags))
|
||||
}
|
||||
if keyPairResp.Labels != nil && len(*keyPairResp.Labels) != 0 {
|
||||
var diags diag.Diagnostics
|
||||
labels, diags = types.MapValueFrom(ctx, types.StringType, *keyPairResp.Labels)
|
||||
if diags.HasError() {
|
||||
return fmt.Errorf("converting labels to StringValue map: %w", core.DiagsToError(diags))
|
||||
}
|
||||
} else if model.Labels.IsNull() {
|
||||
labels = types.MapNull(types.StringType)
|
||||
}
|
||||
model.Labels = labels
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toCreatePayload(ctx context.Context, model *Model) (*iaasalpha.CreateKeyPairPayload, error) {
|
||||
if model == nil {
|
||||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
|
||||
labels, err := conversion.ToStringInterfaceMap(ctx, model.Labels)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting to Go map: %w", err)
|
||||
}
|
||||
|
||||
return &iaasalpha.CreateKeyPairPayload{
|
||||
Name: conversion.StringValueToPointer(model.Name),
|
||||
PublicKey: conversion.StringValueToPointer(model.PublicKey),
|
||||
Labels: &labels,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toUpdatePayload(ctx context.Context, model *Model, currentLabels types.Map) (*iaasalpha.UpdateKeyPairPayload, error) {
|
||||
if model == nil {
|
||||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
|
||||
labels, err := conversion.ToJSONMapPartialUpdatePayload(ctx, currentLabels, model.Labels)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting to Go map: %w", err)
|
||||
}
|
||||
|
||||
return &iaasalpha.UpdateKeyPairPayload{
|
||||
Labels: &labels,
|
||||
}, nil
|
||||
}
|
||||
211
stackit/internal/services/iaas/keypair/resource_test.go
Normal file
211
stackit/internal/services/iaas/keypair/resource_test.go
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
package keypair
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/utils"
|
||||
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
|
||||
)
|
||||
|
||||
func TestMapFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
state Model
|
||||
input *iaasalpha.Keypair
|
||||
expected Model
|
||||
isValid bool
|
||||
}{
|
||||
{
|
||||
"default_values",
|
||||
Model{
|
||||
Name: types.StringValue("name"),
|
||||
},
|
||||
&iaasalpha.Keypair{
|
||||
Name: utils.Ptr("name"),
|
||||
},
|
||||
Model{
|
||||
Id: types.StringValue("name"),
|
||||
Name: types.StringValue("name"),
|
||||
PublicKey: types.StringNull(),
|
||||
Fingerprint: types.StringNull(),
|
||||
Labels: types.MapNull(types.StringType),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"simple_values",
|
||||
Model{
|
||||
Name: types.StringValue("name"),
|
||||
},
|
||||
&iaasalpha.Keypair{
|
||||
Name: utils.Ptr("name"),
|
||||
PublicKey: utils.Ptr("public_key"),
|
||||
Fingerprint: utils.Ptr("fingerprint"),
|
||||
Labels: &map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
},
|
||||
Model{
|
||||
Id: types.StringValue("name"),
|
||||
Name: types.StringValue("name"),
|
||||
PublicKey: types.StringValue("public_key"),
|
||||
Fingerprint: types.StringValue("fingerprint"),
|
||||
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
||||
"key": types.StringValue("value"),
|
||||
}),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"empty_labels",
|
||||
Model{
|
||||
Name: types.StringValue("name"),
|
||||
},
|
||||
&iaasalpha.Keypair{
|
||||
Name: utils.Ptr("name"),
|
||||
PublicKey: utils.Ptr("public_key"),
|
||||
Fingerprint: utils.Ptr("fingerprint"),
|
||||
Labels: &map[string]interface{}{},
|
||||
},
|
||||
Model{
|
||||
Id: types.StringValue("name"),
|
||||
Name: types.StringValue("name"),
|
||||
PublicKey: types.StringValue("public_key"),
|
||||
Fingerprint: types.StringValue("fingerprint"),
|
||||
Labels: types.MapNull(types.StringType),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"response_nil_fail",
|
||||
Model{},
|
||||
nil,
|
||||
Model{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"no_resource_id",
|
||||
Model{},
|
||||
&iaasalpha.Keypair{
|
||||
PublicKey: utils.Ptr("public_key"),
|
||||
Fingerprint: utils.Ptr("fingerprint"),
|
||||
Labels: &map[string]interface{}{},
|
||||
},
|
||||
Model{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
err := mapFields(context.Background(), tt.input, &tt.state)
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
if tt.isValid && err != nil {
|
||||
t.Fatalf("Should not have failed: %v", err)
|
||||
}
|
||||
if tt.isValid {
|
||||
diff := cmp.Diff(tt.state, tt.expected)
|
||||
if diff != "" {
|
||||
t.Fatalf("Data does not match: %s", diff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToCreatePayload(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
input *Model
|
||||
expected *iaasalpha.CreateKeyPairPayload
|
||||
isValid bool
|
||||
}{
|
||||
{
|
||||
"default_ok",
|
||||
&Model{
|
||||
Name: types.StringValue("name"),
|
||||
PublicKey: types.StringValue("public_key"),
|
||||
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
||||
"key1": types.StringValue("value1"),
|
||||
"key2": types.StringValue("value2"),
|
||||
}),
|
||||
},
|
||||
&iaasalpha.CreateKeyPairPayload{
|
||||
Name: utils.Ptr("name"),
|
||||
PublicKey: utils.Ptr("public_key"),
|
||||
Labels: &map[string]interface{}{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
output, err := toCreatePayload(context.Background(), tt.input)
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
if tt.isValid && err != nil {
|
||||
t.Fatalf("Should not have failed: %v", err)
|
||||
}
|
||||
if tt.isValid {
|
||||
diff := cmp.Diff(output, tt.expected, cmp.AllowUnexported(iaasalpha.NullableString{}))
|
||||
if diff != "" {
|
||||
t.Fatalf("Data does not match: %s", diff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUpdatePayload(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
input *Model
|
||||
expected *iaasalpha.UpdateKeyPairPayload
|
||||
isValid bool
|
||||
}{
|
||||
{
|
||||
"default_ok",
|
||||
&Model{
|
||||
Name: types.StringValue("name"),
|
||||
PublicKey: types.StringValue("public_key"),
|
||||
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
||||
"key1": types.StringValue("value1"),
|
||||
"key2": types.StringValue("value2"),
|
||||
}),
|
||||
},
|
||||
&iaasalpha.UpdateKeyPairPayload{
|
||||
Labels: &map[string]interface{}{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
output, err := toUpdatePayload(context.Background(), tt.input, types.MapNull(types.StringType))
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
if tt.isValid && err != nil {
|
||||
t.Fatalf("Should not have failed: %v", err)
|
||||
}
|
||||
if tt.isValid {
|
||||
diff := cmp.Diff(output, tt.expected, cmp.AllowUnexported(iaasalpha.NullableString{}))
|
||||
if diff != "" {
|
||||
t.Fatalf("Data does not match: %s", diff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -89,8 +89,8 @@ func (d *publicIpDataSource) Configure(ctx context.Context, req datasource.Confi
|
|||
// Schema defines the schema for the resource.
|
||||
func (r *publicIpDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: features.AddBetaDescription("Volume resource schema. Must have a `region` specified in the provider configuration."),
|
||||
Description: "Volume resource schema. Must have a `region` specified in the provider configuration.",
|
||||
MarkdownDescription: features.AddBetaDescription("Public IP resource schema. Must have a `region` specified in the provider configuration."),
|
||||
Description: "Public IP resource schema. Must have a `region` specified in the provider configuration.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "Terraform's internal datasource ID. It is structured as \"`project_id`,`public_ip_id`\".",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,28 @@ Server resource schema. Must have a region specified in the provider configurati
|
|||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
||||
## Example Usage` + "\n" + `
|
||||
|
||||
### With key pair` + "\n" +
|
||||
|
||||
"```terraform" + `
|
||||
resource "stackit_key_pair" "keypair" {
|
||||
name = "example-key-pair"
|
||||
public_key = chomp(file("path/to/id_rsa.pub"))
|
||||
}
|
||||
|
||||
resource "stackit_server" "user-data-from-file" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
boot_volume = {
|
||||
size = 64
|
||||
source_type = "image"
|
||||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
` + "\n```" + `
|
||||
|
||||
### Boot from volume` + "\n" +
|
||||
|
||||
"```terraform" + `
|
||||
|
|
@ -45,7 +67,7 @@ resource "stackit_server" "boot-from-volume" {
|
|||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
` + "\n```" + `
|
||||
|
||||
|
|
@ -61,7 +83,7 @@ resource "stackit_server" "server-with-network" {
|
|||
source_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_network" "network" {
|
||||
|
|
@ -123,7 +145,7 @@ resource "stackit_server" "server-with-volume" {
|
|||
}
|
||||
availability_zone = "eu01-1"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
}
|
||||
|
||||
resource "stackit_server_volume_attach" "attach_volume" {
|
||||
|
|
@ -145,7 +167,7 @@ resource "stackit_server" "user-data" {
|
|||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = "#!/bin/bash\n/bin/su"
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +180,7 @@ resource "stackit_server" "user-data-from-file" {
|
|||
}
|
||||
name = "example-server"
|
||||
machine_type = "g1.1"
|
||||
keypair_name = "example-keypair"
|
||||
keypair_name = stackit_key_pair.keypair.name
|
||||
user_data = file("${path.module}/cloud-init.yaml")
|
||||
}
|
||||
` + "\n```"
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ func mapFields(ctx context.Context, serverResp *iaas.Server, model *Model) error
|
|||
} else if serverResp.Id != nil {
|
||||
serverId = *serverResp.Id
|
||||
} else {
|
||||
return fmt.Errorf("Server id not present")
|
||||
return fmt.Errorf("server id not present")
|
||||
}
|
||||
|
||||
idParts := []string{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
argusScrapeConfig "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/argus/scrapeconfig"
|
||||
dnsRecordSet "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/recordset"
|
||||
dnsZone "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/dns/zone"
|
||||
iaasKeyPair "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/keypair"
|
||||
iaasNetwork "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/network"
|
||||
iaasNetworkArea "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/networkarea"
|
||||
iaasNetworkAreaRoute "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/networkarearoute"
|
||||
|
|
@ -412,6 +413,7 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
|
|||
iaasNetworkInterface.NewNetworkInterfaceDataSource,
|
||||
iaasVolume.NewVolumeDataSource,
|
||||
iaasPublicIp.NewPublicIpDataSource,
|
||||
iaasKeyPair.NewKeyPairDataSource,
|
||||
iaasServer.NewServerDataSource,
|
||||
iaasSecurityGroup.NewSecurityGroupDataSource,
|
||||
iaasSecurityGroupRule.NewSecurityGroupRuleDataSource,
|
||||
|
|
@ -462,6 +464,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource {
|
|||
iaasNetworkInterface.NewNetworkInterfaceResource,
|
||||
iaasVolume.NewVolumeResource,
|
||||
iaasPublicIp.NewPublicIpResource,
|
||||
iaasKeyPair.NewKeyPairResource,
|
||||
iaasVolumeAttach.NewVolumeAttachResource,
|
||||
iaasNetworkInterfaceAttach.NewNetworkInterfaceAttachResource,
|
||||
iaasServiceAccountAttach.NewServiceAccountAttachResource,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue