Skip to content

Commit d834932

Browse files
authored
feat: add support for private networks (#294)
* feat: add support for private networks * update webdocs
1 parent 48ccec6 commit d834932

File tree

8 files changed

+196
-4
lines changed

8 files changed

+196
-4
lines changed

.web-docs/components/builder/scaleway/README.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ can also be supplied to override the typical auto-generated key:
110110

111111
- `tags` ([]string) - A list of tags to apply on the created image, volumes, and snapshots
112112

113+
- `private_network_ids` ([]string) - A list of private network IDs to attach to the instance during the build
114+
113115
- `api_token` (string) - Deprecated: use SecretKey instead
114116

115117
- `organization_id` (string) - Deprecated: use ProjectID instead
@@ -175,7 +177,6 @@ build {
175177
}
176178
```
177179

178-
179180
**JSON**
180181

181182
```json
@@ -192,7 +193,44 @@ build {
192193
}
193194
```
194195

195-
196196
When you do not specify the `ssh_private_key_file`, a temporary SSH keypair
197197
is generated to connect the server. This key will only allow the `root` user to
198198
connect the server.
199+
200+
## Private Network Example
201+
202+
If you need to access internal resources (like a private package repository) during the build,
203+
you can attach the instance to one or more private networks:
204+
205+
**HCL2**
206+
207+
```hcl
208+
source "scaleway" "with_private_network" {
209+
project_id = "YOUR PROJECT ID"
210+
access_key = "YOUR ACCESS KEY"
211+
secret_key = "YOUR SECRET KEY"
212+
image = "ubuntu_jammy"
213+
zone = "fr-par-1"
214+
commercial_type = "DEV1-S"
215+
ssh_username = "root"
216+
ssh_private_key_file = "~/.ssh/id_rsa"
217+
218+
private_network_ids = [
219+
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
220+
]
221+
}
222+
223+
build {
224+
sources = ["source.scaleway.with_private_network"]
225+
226+
provisioner "shell" {
227+
inline = [
228+
"apt-get update",
229+
"apt-get install -y curl",
230+
"curl http://internal-repo.private.local/package.deb -o /tmp/package.deb"
231+
]
232+
}
233+
}
234+
```
235+
236+
The private networks are attached after the instance is started and are available to provisioners.

builder/scaleway/builder.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
104104
},
105105
new(stepCreateVolume),
106106
new(stepCreateServer),
107+
new(stepCreatePrivateNICs),
107108
new(stepServerInfo),
108109
&communicator.StepConnect{
109110
Config: &b.Config.Comm,

builder/scaleway/builder_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,49 @@ func TestBuilderPrepare_ServerName(t *testing.T) {
259259
t.Fatal("should have error")
260260
}
261261
}
262+
263+
func TestBuilderPrepare_PrivateNetworkIDs(t *testing.T) {
264+
var b scaleway.Builder
265+
266+
config := testConfig()
267+
expected := []string{
268+
"11111111-1111-1111-1111-111111111111",
269+
"22222222-2222-2222-2222-222222222222",
270+
}
271+
config["private_network_ids"] = expected
272+
273+
_, warnings, err := b.Prepare(config)
274+
if len(warnings) > 0 {
275+
t.Fatalf("bad: %#v", warnings)
276+
}
277+
278+
if err != nil {
279+
t.Fatalf("should not have error: %s", err)
280+
}
281+
282+
if len(b.Config.PrivateNetworkIDs) != len(expected) {
283+
t.Fatalf("found %d private networks, expected %d", len(b.Config.PrivateNetworkIDs), len(expected))
284+
}
285+
286+
for i, want := range expected {
287+
if got := b.Config.PrivateNetworkIDs[i]; got != want {
288+
t.Fatalf("found %s, expected %s", got, want)
289+
}
290+
}
291+
}
292+
293+
func TestBuilderPrepare_PrivateNetworkIDsRejectsEmptyValues(t *testing.T) {
294+
var b scaleway.Builder
295+
296+
config := testConfig()
297+
config["private_network_ids"] = []string{"valid-id", " "}
298+
299+
_, warnings, err := b.Prepare(config)
300+
if len(warnings) > 0 {
301+
t.Fatalf("bad: %#v", warnings)
302+
}
303+
304+
if err == nil {
305+
t.Fatal("should have error")
306+
}
307+
}

builder/scaleway/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"log"
99
"os"
10+
"strings"
1011
"time"
1112

1213
"github.com/hashicorp/packer-plugin-sdk/common"
@@ -128,6 +129,9 @@ type Config struct {
128129
// A list of tags to apply on the created image, volumes, and snapshots
129130
Tags []string `mapstructure:"tags" required:"false"`
130131

132+
// A list of private network IDs to attach to the instance during the build
133+
PrivateNetworkIDs []string `mapstructure:"private_network_ids" required:"false"`
134+
131135
UserAgent string `mapstructure-to-hcl2:",skip"`
132136
ctx interpolate.Context
133137

@@ -336,6 +340,15 @@ func (c *Config) Prepare(raws ...any) ([]string, error) { //nolint:gocyclo
336340
}
337341
}
338342

343+
for _, id := range c.PrivateNetworkIDs {
344+
if strings.TrimSpace(id) == "" {
345+
errs = packersdk.MultiErrorAppend(
346+
errs, errors.New("private_network_ids must not contain empty values"))
347+
348+
break
349+
}
350+
}
351+
339352
if errs != nil && len(errs.Errors) > 0 {
340353
return warnings, errs
341354
}

builder/scaleway/config.hcl2spec.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/packer-plugin-sdk/multistep"
8+
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
9+
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
)
12+
13+
type stepCreatePrivateNICs struct{}
14+
15+
func (s *stepCreatePrivateNICs) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
16+
instanceAPI := instance.NewAPI(state.Get("client").(*scw.Client))
17+
ui := state.Get("ui").(packersdk.Ui)
18+
c := state.Get("config").(*Config)
19+
serverID := state.Get("server_id").(string)
20+
21+
if len(c.PrivateNetworkIDs) == 0 {
22+
return multistep.ActionContinue
23+
}
24+
25+
for _, pnID := range c.PrivateNetworkIDs {
26+
ui.Say(fmt.Sprintf("Attaching private network %s...", pnID))
27+
28+
nicResp, err := instanceAPI.CreatePrivateNIC(&instance.CreatePrivateNICRequest{
29+
Zone: scw.Zone(c.Zone),
30+
ServerID: serverID,
31+
PrivateNetworkID: pnID,
32+
}, scw.WithContext(ctx))
33+
if err != nil {
34+
return putErrorAndHalt(state, ui, fmt.Errorf("error attaching private network %s: %w", pnID, err))
35+
}
36+
37+
_, err = instanceAPI.WaitForPrivateNIC(&instance.WaitForPrivateNICRequest{
38+
ServerID: serverID,
39+
PrivateNicID: nicResp.PrivateNic.ID,
40+
Zone: scw.Zone(c.Zone),
41+
}, scw.WithContext(ctx))
42+
if err != nil {
43+
return putErrorAndHalt(state, ui, fmt.Errorf("error waiting for private NIC %s: %w", nicResp.PrivateNic.ID, err))
44+
}
45+
46+
ui.Say(fmt.Sprintf("Private network %s attached successfully", pnID))
47+
}
48+
49+
return multistep.ActionContinue
50+
}
51+
52+
func (s *stepCreatePrivateNICs) Cleanup(_ multistep.StateBag) {
53+
// Private NICs are automatically removed when the server is deleted.
54+
}

docs-partials/builder/scaleway/Config-not-required.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444

4545
- `tags` ([]string) - A list of tags to apply on the created image, volumes, and snapshots
4646

47+
- `private_network_ids` ([]string) - A list of private network IDs to attach to the instance during the build
48+
4749
- `api_token` (string) - Deprecated: use SecretKey instead
4850

4951
- `organization_id` (string) - Deprecated: use ProjectID instead

docs/builders/scaleway.mdx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ build {
8181
}
8282
```
8383

84-
8584
**JSON**
8685

8786
```json
@@ -98,7 +97,44 @@ build {
9897
}
9998
```
10099

101-
102100
When you do not specify the `ssh_private_key_file`, a temporary SSH keypair
103101
is generated to connect the server. This key will only allow the `root` user to
104102
connect the server.
103+
104+
## Private Network Example
105+
106+
If you need to access internal resources (like a private package repository) during the build,
107+
you can attach the instance to one or more private networks:
108+
109+
**HCL2**
110+
111+
```hcl
112+
source "scaleway" "with_private_network" {
113+
project_id = "YOUR PROJECT ID"
114+
access_key = "YOUR ACCESS KEY"
115+
secret_key = "YOUR SECRET KEY"
116+
image = "ubuntu_jammy"
117+
zone = "fr-par-1"
118+
commercial_type = "DEV1-S"
119+
ssh_username = "root"
120+
ssh_private_key_file = "~/.ssh/id_rsa"
121+
122+
private_network_ids = [
123+
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
124+
]
125+
}
126+
127+
build {
128+
sources = ["source.scaleway.with_private_network"]
129+
130+
provisioner "shell" {
131+
inline = [
132+
"apt-get update",
133+
"apt-get install -y curl",
134+
"curl http://internal-repo.private.local/package.deb -o /tmp/package.deb"
135+
]
136+
}
137+
}
138+
```
139+
140+
The private networks are attached after the instance is started and are available to provisioners.

0 commit comments

Comments
 (0)