diff --git a/internal/e2etests/server/resource_test.go b/internal/e2etests/server/resource_test.go index 0eabc6dd9..aec530106 100644 --- a/internal/e2etests/server/resource_test.go +++ b/internal/e2etests/server/resource_test.go @@ -10,7 +10,6 @@ import ( "github.com/hetznercloud/terraform-provider-hcloud/internal/firewall" "github.com/hetznercloud/terraform-provider-hcloud/internal/network" "github.com/hetznercloud/terraform-provider-hcloud/internal/sshkey" - "github.com/stretchr/testify/assert" "github.com/hetznercloud/terraform-provider-hcloud/internal/server" @@ -301,6 +300,9 @@ func TestServerResource_DirectAttachToNetwork(t *testing.T) { testsupport.CheckResourceExists(nwRes.TFID(), network.ByID(t, &nw)), testsupport.CheckResourceExists(sResWithNet.TFID(), server.ByID(t, &s)), testsupport.LiftTCF(hasServerNetwork(t, &s, &nw, "10.0.1.5", "10.0.1.6", "10.0.1.7")), + resource.TestCheckResourceAttr(sResWithNet.TFID(), "network.#", "1"), + resource.TestCheckResourceAttr(sResWithNet.TFID(), "network.0.ip", "10.0.1.5"), + resource.TestCheckResourceAttr(sResWithNet.TFID(), "network.0.alias_ips.#", "2"), ), }, { diff --git a/internal/server/resource.go b/internal/server/resource.go index 0608a34b6..0924d5d9a 100644 --- a/internal/server/resource.go +++ b/internal/server/resource.go @@ -131,6 +131,12 @@ func Resource() *schema.Resource { "network": { Type: schema.TypeSet, Optional: true, + DiffSuppressFunc: func(_, _, _ string, d *schema.ResourceData) bool { + // Diff is only valid if "network" resource is set in + // terraform configuration. + _, ok := d.GetOk("network") + return !ok // Negate because we do **not** want to suppress the diff. + }, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "network_id": { @@ -721,4 +727,33 @@ func setServerSchema(d *schema.ResourceData, s *hcloud.Server) { firewallIDs[i] = firewall.Firewall.ID } d.Set("firewall_ids", firewallIDs) + + // Only write the networks to the resource data if it already contains + // such an entry. This avoids setting the "network" property which is not + // marked as "computed" if the user uses the "server_network_subnet" + // resource. Setting the "network" property as computed is not possible + // because this would lead to loosing any updates. + // + // The easiest would be to use schema.ComputedWhen but this is marked + // as currently not working. + if _, ok := d.GetOk("network"); ok { + d.Set("network", networkToTerraformNetworks(s.PrivateNet)) + } +} + +func networkToTerraformNetworks(privateNetworks []hcloud.ServerPrivateNet) []map[string]interface{} { + tfPrivateNetworks := make([]map[string]interface{}, len(privateNetworks)) + for i, privateNetwork := range privateNetworks { + tfPrivateNetwork := make(map[string]interface{}) + tfPrivateNetwork["network_id"] = privateNetwork.Network.ID + tfPrivateNetwork["ip"] = privateNetwork.IP.String() + tfPrivateNetwork["mac_address"] = privateNetwork.MACAddress + aliasIPs := make([]string, len(privateNetwork.Aliases)) + for in, ip := range privateNetwork.Aliases { + aliasIPs[in] = ip.String() + } + tfPrivateNetwork["alias_ips"] = aliasIPs + tfPrivateNetworks[i] = tfPrivateNetwork + } + return tfPrivateNetworks } diff --git a/website/docs/r/server.html.md b/website/docs/r/server.html.md index 5b5837acd..98c4d415a 100644 --- a/website/docs/r/server.html.md +++ b/website/docs/r/server.html.md @@ -80,6 +80,13 @@ The following arguments are supported: - `labels` - (Optional, map) User-defined labels (key-value pairs) should be created with. - `backups` - (Optional, boolean) Enable or disable backups. - `firewall_ids` - (Optional, list) Firewall IDs the server should be attached to on creation. +- `network` - (Optional) Network the server should be attached to on creation. (Can be specified multiple times) + +`network` support the following fields: +- `network_id` - (Required, int) ID of the network +- `ip` - (Optional, string) Specify the IP the server should get in the network +- `alias_ips` - (Optional, list) Alias IPs the server should have in the Network. + ## Attributes Reference @@ -107,6 +114,14 @@ The following attributes are exported: issue. It is therefore necessary to use `depends_on` to link the server to the respective subnetwork. See examples. - `firewall_ids` - (Optional, list) Firewall IDs the server is attached to. +- `network` - (Optional, list) Network the server should be attached to on creation. (Can be specified multiple times) + +a single entry in `network` support the following fields: +- `network_id` - (Required, int) ID of the network +- `ip` - (Optional, string) Specify the IP the server should get in the network +- `alias_ips` - (Optional, list) Alias IPs the server should have in the Network. +- `mac_address` - (Optional, string) The MAC address the private interface of the server has + ## Import