diff --git a/builder/digitalocean/builder_test.go b/builder/digitalocean/builder_test.go index 5113495cf..a767d52b9 100644 --- a/builder/digitalocean/builder_test.go +++ b/builder/digitalocean/builder_test.go @@ -362,3 +362,55 @@ func TestBuilderPrepare_DropletName(t *testing.T) { } } + +func TestBuilderPrepare_VPCUUID(t *testing.T) { + var b Builder + config := testConfig() + + // Test with the case vpc_uuid is defined but private_networking is not enabled + config["vpc_uuid"] = "554c41b3-425f-5403-8860-7f24fb108098" + _, warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err == nil { + t.Fatalf("should have error: 'private networking should be enabled to use vpc_uuid'") + } + + // Test with the case both vpc_uuid and private_networking are defined/enabled + config["private_networking"] = true + b = Builder{} + _, warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatal("should not have error") + } +} + +func TestBuilderPrepare_ConnectWithPrivateIP(t *testing.T) { + var b Builder + config := testConfig() + + // Test with the case connect_with_private_ip is defined but private_networking is not enabled + config["connect_with_private_ip"] = true + _, warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err == nil { + t.Fatalf("should have error: 'private networking should be enabled to use connect_with_private_ip'") + } + + // Test with the case both connect_with_private_ip and private_networking are enabled + config["private_networking"] = true + b = Builder{} + _, warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatal("should not have error") + } +} diff --git a/builder/digitalocean/config.go b/builder/digitalocean/config.go index 9f68ca001..958b04f66 100644 --- a/builder/digitalocean/config.go +++ b/builder/digitalocean/config.go @@ -85,6 +85,14 @@ type Config struct { UserDataFile string `mapstructure:"user_data_file" required:"false"` // Tags to apply to the droplet when it is created Tags []string `mapstructure:"tags" required:"false"` + // UUID of the VPC which the droplet will be created in. Before using this, + // private_networking should be enabled. + VPCUUID string `mapstructure:"vpc_uuid" required:"false"` + // Wheter the communicators should use private IP or not (public IP in that case). + // If the droplet is or going to be accessible only from the local network because + // it is at behind a firewall, then communicators should use the private IP + // instead of the public IP. Before using this, private_networking should be enabled. + ConnectWithPrivateIP bool `mapstructure:"connect_with_private_ip" required:"false"` ctx interpolate.Context } @@ -187,6 +195,20 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { } } + // Check if the PrivateNetworking is enabled by user before use VPC UUID + if c.VPCUUID != "" { + if c.PrivateNetworking != true { + errs = packer.MultiErrorAppend(errs, errors.New("private networking should be enabled to use vpc_uuid")) + } + } + + // Check if the PrivateNetworking is enabled by user before use ConnectWithPrivateIP + if c.ConnectWithPrivateIP == true { + if c.PrivateNetworking != true { + errs = packer.MultiErrorAppend(errs, errors.New("private networking should be enabled to use connect_with_private_ip")) + } + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } diff --git a/builder/digitalocean/config.hcl2spec.go b/builder/digitalocean/config.hcl2spec.go index 29cbae1a1..ef07b3626 100644 --- a/builder/digitalocean/config.hcl2spec.go +++ b/builder/digitalocean/config.hcl2spec.go @@ -82,6 +82,8 @@ type FlatConfig struct { UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"` UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file" hcl:"user_data_file"` Tags []string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"` + VPCUUID *string `mapstructure:"vpc_uuid" required:"false" cty:"vpc_uuid" hcl:"vpc_uuid"` + ConnectWithPrivateIP *bool `mapstructure:"connect_with_private_ip" required:"false" cty:"connect_with_private_ip" hcl:"connect_with_private_ip"` } // FlatMapstructure returns a new FlatConfig. @@ -169,6 +171,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false}, "user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false}, "tags": &hcldec.AttrSpec{Name: "tags", Type: cty.List(cty.String), Required: false}, + "vpc_uuid": &hcldec.AttrSpec{Name: "vpc_uuid", Type: cty.String, Required: false}, + "connect_with_private_ip": &hcldec.AttrSpec{Name: "connect_with_private_ip", Type: cty.Bool, Required: false}, } return s } diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index 021534677..e24a4de46 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -52,6 +52,7 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m IPv6: c.IPv6, UserData: userData, Tags: c.Tags, + VPCUUID: c.VPCUUID, } log.Printf("[DEBUG] Droplet create paramaters: %s", godo.Stringify(dropletCreateReq)) diff --git a/builder/digitalocean/step_droplet_info.go b/builder/digitalocean/step_droplet_info.go index 7f4c50149..44e5f5e4e 100644 --- a/builder/digitalocean/step_droplet_info.go +++ b/builder/digitalocean/step_droplet_info.go @@ -46,10 +46,11 @@ func (s *stepDropletInfo) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionHalt } - // Find a public IPv4 network + // Find the ip address which will be used by communicator foundNetwork := false for _, network := range droplet.Networks.V4 { - if network.Type == "public" { + if (c.ConnectWithPrivateIP && network.Type == "private") || + (!(c.ConnectWithPrivateIP) && network.Type == "public") { state.Put("droplet_ip", network.IPAddress) foundNetwork = true break diff --git a/website/pages/partials/builder/digitalocean/Config-not-required.mdx b/website/pages/partials/builder/digitalocean/Config-not-required.mdx index 3f2cb0abf..4eabeacce 100644 --- a/website/pages/partials/builder/digitalocean/Config-not-required.mdx +++ b/website/pages/partials/builder/digitalocean/Config-not-required.mdx @@ -43,3 +43,11 @@ data when launching the Droplet. - `tags` ([]string) - Tags to apply to the droplet when it is created + +- `vpc_uuid` (string) - UUID of the VPC which the droplet will be created in. Before using this, + private_networking should be enabled. + +- `connect_with_private_ip` (bool) - Wheter the communicators should use private IP or not (public IP in that case). + If the droplet is or going to be accessible only from the local network because + it is at behind a firewall, then communicators should use the private IP + instead of the public IP. Before using this, private_networking should be enabled.