Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove server network interface workaround #1021

Merged
merged 7 commits into from
Nov 11, 2024
Merged
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
12 changes: 0 additions & 12 deletions internal/server/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,18 +418,6 @@ func resourceServerCreate(ctx context.Context, d *schema.ResourceData, m interfa
// if the server was created without public net, the server is now still offline and has to be powered on after
// network assignment
if err := onServerCreateWithoutPublicNet(&opts, d, func(_ *hcloud.ServerCreateOpts) error {
if err := powerOnServer(ctx, c, res.Server); err != nil {
return err
}

// Workaround for network interface issue
powerOffTwo, _, err := c.Server.Poweroff(ctx, res.Server)
if err != nil {
return err
}
if err := hcloudutil.WaitForAction(ctx, &c.Action, powerOffTwo); err != nil {
return fmt.Errorf("power off server: %v", err)
}
return powerOnServer(ctx, c, res.Server)
}); err != nil {
return err
Expand Down
119 changes: 113 additions & 6 deletions internal/server/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,10 @@ func TestServerResource_ChangeUserData(t *testing.T) {
),
Check: resource.ComposeTestCheckFunc(
testsupport.CheckResourceExists(res.TFID(), server.ByID(t, &s)),
resource.TestCheckResourceAttr(res.TFID(), "name",
fmt.Sprintf("server-userdata--%d", tmplMan.RandInt)),
resource.TestCheckResourceAttr(res.TFID(), "name", fmt.Sprintf("server-userdata--%d", tmplMan.RandInt)),
resource.TestCheckResourceAttr(res.TFID(), "server_type", res.Type),
resource.TestCheckResourceAttr(res.TFID(), "image", res.Image),
resource.TestCheckResourceAttr(res.TFID(), "user_data", userDataHashSum(res.UserData)),
resource.TestCheckResourceAttr(res.TFID(), "user_data", userDataHashSum(res.UserData+"\n")),
),
},
{
Expand All @@ -226,11 +225,10 @@ func TestServerResource_ChangeUserData(t *testing.T) {
),
Check: resource.ComposeAggregateTestCheckFunc(
testsupport.CheckResourceExists(res.TFID(), server.ByID(t, &s2)),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "name",
fmt.Sprintf("server-userdata--%d", tmplMan.RandInt)),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "name", fmt.Sprintf("server-userdata--%d", tmplMan.RandInt)),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "server_type", res.Type),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "image", res.Image),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "user_data", userDataHashSum(resChangedUserdata.UserData)),
resource.TestCheckResourceAttr(resChangedUserdata.TFID(), "user_data", userDataHashSum(resChangedUserdata.UserData+"\n")),
testsupport.LiftTCF(isRecreated(&s2, &s)),
),
},
Expand Down Expand Up @@ -814,6 +812,115 @@ func TestServerResource_PrimaryIPNetworkTests(t *testing.T) {
})
}

func TestServerResource_PrivateNetworkBastion(t *testing.T) {
name := "server-private-network-bastion"

sshKeyRes := sshkey.NewRData(t, name)

networkRes := &network.RData{Name: name, IPRange: "10.0.0.0/16"}
networkRes.SetRName("network")

subnetRes := &network.RDataSubnet{
Type: "cloud",
NetworkID: networkRes.TFID() + ".id",
NetworkZone: "eu-central",
IPRange: "10.0.1.0/24",
}
subnetRes.SetRName("network")

bastionRes := &server.RData{
Name: name + "-bastion",
Type: teste2e.TestServerType,
LocationName: teste2e.TestLocationName,
Image: teste2e.TestImage,
SSHKeys: []string{sshKeyRes.TFID() + ".id"},
Networks: []server.RDataInlineNetwork{{
NetworkID: networkRes.TFID() + ".id",
}},
PublicNet: map[string]interface{}{
"ipv4_enabled": true,
"ipv6_enabled": true,
},
UserData: `#cloud-config
users:
- default
- name: test
shell: /bin/bash

runcmd:
- echo "hello from bastion!"
`,
DependsOn: []string{subnetRes.TFID()},
}
bastionRes.SetRName("bastion")

hostRes := &server.RData{
Name: name + "-host",
Type: teste2e.TestServerType,
LocationName: teste2e.TestLocationName,
Image: teste2e.TestImage,
SSHKeys: []string{sshKeyRes.TFID() + ".id"},
Networks: []server.RDataInlineNetwork{{
NetworkID: networkRes.TFID() + ".id",
}},
PublicNet: map[string]interface{}{
"ipv4_enabled": false,
"ipv6_enabled": false,
},
UserData: `#cloud-config
users:
- default
- name: test
shell: /bin/bash

runcmd:
- echo "hello from host!"
`,
DependsOn: []string{subnetRes.TFID()},
}
hostRes.SetRName("host")

tmplMan := testtemplate.Manager{}
resource.ParallelTest(t, resource.TestCase{
PreCheck: teste2e.PreCheck(t),
ProtoV6ProviderFactories: teste2e.ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
Config: tmplMan.Render(t,
"testdata/r/hcloud_ssh_key", sshKeyRes,
"testdata/r/hcloud_network", networkRes,
"testdata/r/hcloud_network_subnet", subnetRes,
"testdata/r/hcloud_server", bastionRes,
"testdata/r/hcloud_server", hostRes,
"testdata/r/any",
fmt.Sprintf(`
resource "terraform_data" "wait" {
triggers_replace = [
hcloud_server.bastion.id,
hcloud_server.host.id,
]

connection {
type = "ssh"
user = "root"
host = one(hcloud_server.host.network[*].ip)
private_key = %q

bastion_user = "root"
bastion_host = hcloud_server.bastion.ipv4_address
}

provisioner "remote-exec" {
inline = ["cloud-init status --wait --long"]
}
}
`, sshKeyRes.PrivateKey),
),
},
},
})
}

func TestServerResource_Firewalls(t *testing.T) {
var s hcloud.Server

Expand Down
16 changes: 9 additions & 7 deletions internal/sshkey/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ func (d *DDataList) TFID() string {
type RData struct {
testtemplate.DataCommon

Name string
PublicKey string
Labels map[string]string
Name string
PublicKey string
PrivateKey string
Labels map[string]string
}

// TFID returns the resource identifier.
Expand All @@ -104,15 +105,16 @@ func (d *RData) TFID() string {

// NewRData creates data for a new sshkey resource.
func NewRData(t *testing.T, name string) *RData {
publicKeyMaterial, _, err := acctest.RandSSHKeyPair("hcloud@ssh-acceptance-test")
publicKeyMaterial, privateKeyMaterial, err := acctest.RandSSHKeyPair("hcloud@ssh-acceptance-test")
rInt := acctest.RandInt()
if err != nil {
t.Fatal(err)
}
r := &RData{
Name: name,
PublicKey: publicKeyMaterial,
Labels: map[string]string{"key": strconv.Itoa(rInt)},
Name: name,
PublicKey: publicKeyMaterial,
PrivateKey: privateKeyMaterial,
Labels: map[string]string{"key": strconv.Itoa(rInt)},
}
r.SetRName(name)
return r
Expand Down
1 change: 1 addition & 0 deletions internal/testdata/r/any.tf.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ . }}
7 changes: 6 additions & 1 deletion internal/testdata/r/hcloud_server.tf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ resource "hcloud_server" "{{ .RName }}" {
{{ end }}
{{- if .AliasIPs }}
alias_ips = {{ with DQuoteS .AliasIPs }}[{{ StringsJoin . ", " }}]{{ end }}
{{- else }}
# Workaround for https://github.com/hetznercloud/terraform-provider-hcloud/issues/650
alias_ips = []
{{- end }}
}
{{ end }}{{ end }}
Expand All @@ -63,7 +66,9 @@ resource "hcloud_server" "{{ .RName }}" {
{{ end }}

{{- if .UserData }}
user_data = "{{ .UserData }}"
user_data = <<EOF
{{ .UserData }}
EOF
{{ end }}

{{ if .FirewallIDs }}
Expand Down
21 changes: 14 additions & 7 deletions internal/testtemplate/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,21 @@ func (ts *Manager) Render(t *testing.T, args ...interface{}) string {
if !ok {
t.Fatalf("args[%d]: string required: %T", i, args[i])
}
data, ok := args[i+1].(Data)
if !ok {
t.Fatalf("args[%d]: data required: %T", i+1, args[i+1])
}
data.SetRInt(ts.RandInt)
if data.RName() == "" {
data.SetRName(ts.RandName)

var data any
switch arg := args[i+1].(type) {
case Data:
arg.SetRInt(ts.RandInt)
if arg.RName() == "" {
arg.SetRName(ts.RandName)
}
data = arg
case string:
data = arg
default:
t.Fatalf("args[%d]: data or string required: %T", i+1, args[i+1])
}

tmpl := ts.tmpl.Lookup(tmplName)
if tmpl == nil {
t.Fatalf("template %s: not found", tmplName)
Expand Down