Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 44 additions & 43 deletions docs/resources/server_network.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
---
page_title: "Hetzner Cloud: hcloud_server_network"
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "hcloud_server_network Resource - hcloud"
subcategory: ""
description: |-
Provides a Hetzner Cloud Server Network to represent a private network on a server in the Hetzner Cloud.
Manage the attachment of a Server in a Network in the Hetzner Cloud.
If subnet_id or ip are not provided, the Server will be assigned an IP in the last created subnet.
---

# hcloud_server_network
# hcloud_server_network (Resource)

Provides a Hetzner Cloud Server Network to represent a private network on a server in the Hetzner Cloud.
Manage the attachment of a Server in a Network in the Hetzner Cloud.

If `subnet_id` or `ip` are not provided, the Server will be assigned an IP in the last created subnet.

## Example Usage

Expand All @@ -16,57 +21,53 @@ resource "hcloud_server" "node1" {
image = "debian-11"
server_type = "cx22"
}
resource "hcloud_network" "mynet" {
name = "my-net"
ip_range = "10.0.0.0/8"

resource "hcloud_network" "network" {
name = "network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_network_subnet" "foonet" {
network_id = hcloud_network.mynet.id

resource "hcloud_network_subnet" "subnet1" {
network_id = hcloud_network.network.id
type = "cloud"
network_zone = "eu-central"
ip_range = "10.0.1.0/24"
}

resource "hcloud_server_network" "srvnetwork" {
server_id = hcloud_server.node1.id
network_id = hcloud_network.mynet.id
ip = "10.0.1.5"
resource "hcloud_server_network" "node1_subnet1" {
server_id = hcloud_server.node1.id
subnet_id = hcloud_network_subnet.subnet1.id
ip = "10.0.1.5"
alias_ips = [
"10.0.1.10"
]
}
```

## Argument Reference

- `server_id` - (Required, int) ID of the server.
- `alias_ips` - (Optional, list[string]) Additional IPs to be assigned
to this server.
- `network_id` - (Optional, int) ID of the network which should be added
to the server. Required if `subnet_id` is not set. Successful creation
of the resource depends on the existence of a subnet in the Hetzner
Cloud Backend. Using `network_id` will not create an explicit
dependency between server and subnet. Therefore `depends_on` may need
to be used. Alternatively the `subnet_id` property can be used, which
will create an explicit dependency between `hcloud_server_network` and
the existence of a subnet.
- `subnet_id` - (Optional, string) ID of the sub-network which should be
added to the Server. Required if `network_id` is not set.
_Note_: if the `ip` property is missing, the Server is currently added
to the last created subnet.
- `ip` - (Optional, string) IP to request to be assigned to this server.
If you do not provide this then you will be auto assigned an IP
address.

## Attributes Reference

- `id` - (string) ID of the server network.
- `network_id` - (int) ID of the network.
- `server_id` - (int) ID of the server.
- `ip` - (string) IP assigned to this server.
- `alias_ips` - (list[string]) Additional IPs assigned to this server.
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `server_id` (Number) ID of the Server.

### Optional

- `alias_ips` (Set of String) Additional IPs to assign to the Server.
- `ip` (String) IP to assign to the Server.
- `network_id` (Number) ID of the Network to attach the Server to. Using `subnet_id` is preferred. Required if `subnet_id` is not set.
- `subnet_id` (String) ID of the Subnet to attach the Server to. Required if `network_id` is not set.

### Read-Only

- `id` (String) The ID of this resource.
- `mac_address` (String) MAC address of the Server on the Network.

## Import

Server Network entries can be imported using a compound ID with the following format:
`<server-id>-<network-id>`
Import is supported using the following syntax:

The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:

```shell
terraform import hcloud_server_network.example "$SERVER_ID-$NETWORK_ID"
Expand Down
23 changes: 14 additions & 9 deletions examples/resources/hcloud_server_network/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ resource "hcloud_server" "node1" {
image = "debian-11"
server_type = "cx22"
}
resource "hcloud_network" "mynet" {
name = "my-net"
ip_range = "10.0.0.0/8"

resource "hcloud_network" "network" {
name = "network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_network_subnet" "foonet" {
network_id = hcloud_network.mynet.id

resource "hcloud_network_subnet" "subnet1" {
network_id = hcloud_network.network.id
type = "cloud"
network_zone = "eu-central"
ip_range = "10.0.1.0/24"
}

resource "hcloud_server_network" "srvnetwork" {
server_id = hcloud_server.node1.id
network_id = hcloud_network.mynet.id
ip = "10.0.1.5"
resource "hcloud_server_network" "node1_subnet1" {
server_id = hcloud_server.node1.id
subnet_id = hcloud_network_subnet.subnet1.id
ip = "10.0.1.5"
alias_ips = [
"10.0.1.10"
]
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ require (
google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/hetznercloud/hcloud-go/v2 => github.com/hetznercloud/hcloud-go/v2 v2.27.1-0.20251016133902-68c6e74316de
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/hetznercloud/hcloud-go/v2 v2.27.0 h1:SOGpAP3kQ6+aevB4Hxr63ukNsdYJjHhuWNB1C3NsiJo=
github.com/hetznercloud/hcloud-go/v2 v2.27.0/go.mod h1:OVlbjfoEuvNPI8ji3Sm/jPkjOxO7MKEiPyfctZ0R8jw=
github.com/hetznercloud/hcloud-go/v2 v2.27.1-0.20251015153801-9da946bf0d47 h1:lGhcGeYIrWuzHeWlppjTzmYVU7rIE5R7/FIZULzyM3M=
github.com/hetznercloud/hcloud-go/v2 v2.27.1-0.20251015153801-9da946bf0d47/go.mod h1:XBU4+EDH2KVqu2KU7Ws0+ciZcX4ygukQl/J0L5GS8P8=
github.com/hetznercloud/hcloud-go/v2 v2.27.1-0.20251016133902-68c6e74316de h1:7nKClhs/pRrZ1EFwOJIOygdEJzVJTJszsYcuO0sahAs=
github.com/hetznercloud/hcloud-go/v2 v2.27.1-0.20251016133902-68c6e74316de/go.mod h1:XBU4+EDH2KVqu2KU7Ws0+ciZcX4ygukQl/J0L5GS8P8=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
Expand Down
2 changes: 2 additions & 0 deletions hcloud/plugin_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/hetznercloud/terraform-provider-hcloud/internal/datacenter"
"github.com/hetznercloud/terraform-provider-hcloud/internal/loadbalancertype"
"github.com/hetznercloud/terraform-provider-hcloud/internal/location"
"github.com/hetznercloud/terraform-provider-hcloud/internal/server"
"github.com/hetznercloud/terraform-provider-hcloud/internal/servertype"
"github.com/hetznercloud/terraform-provider-hcloud/internal/sshkey"
"github.com/hetznercloud/terraform-provider-hcloud/internal/util/tflogutil"
Expand Down Expand Up @@ -205,6 +206,7 @@ func (p *PluginProvider) DataSources(_ context.Context) []func() datasource.Data
// the Metadata method. All resources must have unique names.
func (p *PluginProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
server.NewNetworkResource,
sshkey.NewResource,
zone.NewResource,
zonerrset.NewResource,
Expand Down
1 change: 0 additions & 1 deletion hcloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ func Provider() *schema.Provider {
network.RouteResourceType: network.RouteResource(),
network.SubnetResourceType: network.SubnetResource(),
rdns.ResourceType: rdns.Resource(),
server.NetworkResourceType: server.NetworkResource(),
server.ResourceType: server.Resource(),
snapshot.ResourceType: snapshot.Resource(),
volume.AttachmentResourceType: volume.AttachmentResource(),
Expand Down
1 change: 0 additions & 1 deletion hcloud/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ func TestProvider_Resources(t *testing.T) {
network.RouteResourceType,
network.SubnetResourceType,
rdns.ResourceType,
server.NetworkResourceType,
server.ResourceType,
snapshot.ResourceType,
volume.AttachmentResourceType,
Expand Down
2 changes: 2 additions & 0 deletions internal/network/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ type RDataSubnet struct {
NetworkZone string
IPRange string
VSwitchID string

DependsOn []string
}

// TFID returns the resource identifier.
Expand Down
100 changes: 100 additions & 0 deletions internal/server/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package server

import (
"context"
"fmt"
"log"
"net"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/hetznercloud/hcloud-go/v2/hcloud"
"github.com/hetznercloud/terraform-provider-hcloud/internal/util/control"
"github.com/hetznercloud/terraform-provider-hcloud/internal/util/hcloudutil"
)

func attachServerToNetwork(ctx context.Context, c *hcloud.Client, srv *hcloud.Server, nw *hcloud.Network, ip net.IP, aliasIPs []net.IP) error {
var a *hcloud.Action

opts := hcloud.ServerAttachToNetworkOpts{
Network: nw,
IP: ip,
AliasIPs: aliasIPs,
}

err := control.Retry(control.DefaultRetries, func() error {
var err error

a, _, err = c.Server.AttachToNetwork(ctx, srv, opts)
if hcloud.IsError(err, hcloud.ErrorCodeConflict) ||
hcloud.IsError(err, hcloud.ErrorCodeLocked) ||
hcloud.IsError(err, hcloud.ErrorCodeServiceError) ||
hcloud.IsError(err, hcloud.ErrorCodeNoSubnetAvailable) {
return err
}
if err != nil {
return control.AbortRetry(err)
}
return nil
})
if hcloud.IsError(err, hcloud.ErrorCodeServerAlreadyAttached) {
log.Printf("[INFO] Server (%v) already attachted to network %v", srv.ID, nw.ID)
return nil
}
if err != nil {
return fmt.Errorf("attach server to network: %w", err)
}
if err := hcloudutil.WaitForAction(ctx, &c.Action, a); err != nil {
return fmt.Errorf("attach server to network: %w", err)
}
return nil
}

func updateServerAliasIPs(ctx context.Context, c *hcloud.Client, s *hcloud.Server, n *hcloud.Network, aliasIPs *schema.Set) error {
const op = "hcloud/updateServerAliasIPs"

opts := hcloud.ServerChangeAliasIPsOpts{
Network: n,
AliasIPs: make([]net.IP, aliasIPs.Len()),
}
for i, v := range aliasIPs.List() {
opts.AliasIPs[i] = net.ParseIP(v.(string))
}
a, _, err := c.Server.ChangeAliasIPs(ctx, s, opts)
if err != nil {
return fmt.Errorf("%s: %w", op, err)
}
if err := hcloudutil.WaitForAction(ctx, &c.Action, a); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
return nil
}

func detachServerFromNetwork(ctx context.Context, c *hcloud.Client, s *hcloud.Server, n *hcloud.Network) error {
const op = "hcloud/detachServerFromNetwork"
var a *hcloud.Action

err := control.Retry(control.DefaultRetries, func() error {
var err error

a, _, err = c.Server.DetachFromNetwork(ctx, s, hcloud.ServerDetachFromNetworkOpts{Network: n})
if hcloud.IsError(err, hcloud.ErrorCodeConflict) ||
hcloud.IsError(err, hcloud.ErrorCodeLocked) ||
hcloud.IsError(err, hcloud.ErrorCodeServiceError) {
return err
}
return control.AbortRetry(err)
})
if err != nil {
if hcloud.IsError(err, hcloud.ErrorCodeNotFound) {
// network has already been deleted
return nil
}
return fmt.Errorf("%s: %w", op, err)
}

if err := hcloudutil.WaitForAction(ctx, &c.Action, a); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
return nil
}
Loading
Loading