diff --git a/builder/googlecompute/config.go b/builder/googlecompute/config.go index 7f59aa183..762976385 100644 --- a/builder/googlecompute/config.go +++ b/builder/googlecompute/config.go @@ -35,6 +35,7 @@ type Config struct { SourceImageProjectId string `mapstructure:"source_image_project_id"` RawStateTimeout string `mapstructure:"state_timeout"` Tags []string `mapstructure:"tags"` + UseInternalIP bool `mapstructure:"use_internal_ip"` Zone string `mapstructure:"zone"` account accountFile diff --git a/builder/googlecompute/config_test.go b/builder/googlecompute/config_test.go index 4a7a1ed67..c28c35a0f 100644 --- a/builder/googlecompute/config_test.go +++ b/builder/googlecompute/config_test.go @@ -116,6 +116,21 @@ func TestConfigPrepare(t *testing.T) { "5s", false, }, + { + "use_internal_ip", + nil, + false, + }, + { + "use_internal_ip", + false, + false, + }, + { + "use_internal_ip", + "SO VERY BAD", + true, + }, } for _, tc := range cases { diff --git a/builder/googlecompute/driver.go b/builder/googlecompute/driver.go index 6f035c562..be697fe6b 100644 --- a/builder/googlecompute/driver.go +++ b/builder/googlecompute/driver.go @@ -24,6 +24,9 @@ type Driver interface { // GetNatIP gets the NAT IP address for the instance. GetNatIP(zone, name string) (string, error) + // GetInternalIP gets the GCE-internal IP address for the instance. + GetInternalIP(zone, name string) (string, error) + // RunInstance takes the given config and launches an instance. RunInstance(*InstanceConfig) (<-chan error, error) diff --git a/builder/googlecompute/driver_gce.go b/builder/googlecompute/driver_gce.go index b9ed4693e..f52ee6321 100644 --- a/builder/googlecompute/driver_gce.go +++ b/builder/googlecompute/driver_gce.go @@ -157,7 +157,6 @@ func (d *driverGCE) GetNatIP(zone, name string) (string, error) { if ni.AccessConfigs == nil { continue } - for _, ac := range ni.AccessConfigs { if ac.NatIP != "" { return ac.NatIP, nil @@ -168,6 +167,22 @@ func (d *driverGCE) GetNatIP(zone, name string) (string, error) { return "", nil } +func (d *driverGCE) GetInternalIP(zone, name string) (string, error) { + instance, err := d.service.Instances.Get(d.projectId, zone, name).Do() + if err != nil { + return "", err + } + + for _, ni := range instance.NetworkInterfaces { + if ni.NetworkIP == "" { + continue + } + return ni.NetworkIP, nil + } + + return "", nil +} + func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) { // Get the zone d.ui.Message(fmt.Sprintf("Loading zone: %s", c.Zone)) diff --git a/builder/googlecompute/driver_mock.go b/builder/googlecompute/driver_mock.go index 1a9c03ae9..196aa1d81 100644 --- a/builder/googlecompute/driver_mock.go +++ b/builder/googlecompute/driver_mock.go @@ -30,6 +30,11 @@ type DriverMock struct { GetNatIPResult string GetNatIPErr error + GetInternalIPZone string + GetInternalIPName string + GetInternalIPResult string + GetInternalIPErr error + RunInstanceConfig *InstanceConfig RunInstanceErrCh <-chan error RunInstanceErr error @@ -108,6 +113,12 @@ func (d *DriverMock) GetNatIP(zone, name string) (string, error) { return d.GetNatIPResult, d.GetNatIPErr } +func (d *DriverMock) GetInternalIP(zone, name string) (string, error) { + d.GetInternalIPZone = zone + d.GetInternalIPName = name + return d.GetInternalIPResult, d.GetInternalIPErr +} + func (d *DriverMock) RunInstance(c *InstanceConfig) (<-chan error, error) { d.RunInstanceConfig = c diff --git a/builder/googlecompute/step_instance_info.go b/builder/googlecompute/step_instance_info.go index b79e7c042..92f382f06 100644 --- a/builder/googlecompute/step_instance_info.go +++ b/builder/googlecompute/step_instance_info.go @@ -40,23 +40,41 @@ func (s *StepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - ip, err := driver.GetNatIP(config.Zone, instanceName) - if err != nil { - err := fmt.Errorf("Error retrieving instance nat ip address: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if s.Debug { - if ip != "" { - ui.Message(fmt.Sprintf("Public IP: %s", ip)) + if config.UseInternalIP { + ip, err := driver.GetInternalIP(config.Zone, instanceName) + if err != nil { + err := fmt.Errorf("Error retrieving instance internal ip address: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt } - } - ui.Message(fmt.Sprintf("IP: %s", ip)) - state.Put("instance_ip", ip) - return multistep.ActionContinue + if s.Debug { + if ip != "" { + ui.Message(fmt.Sprintf("Internal IP: %s", ip)) + } + } + ui.Message(fmt.Sprintf("IP: %s", ip)) + state.Put("instance_ip", ip) + return multistep.ActionContinue + } else { + ip, err := driver.GetNatIP(config.Zone, instanceName) + if err != nil { + err := fmt.Errorf("Error retrieving instance nat ip address: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + if s.Debug { + if ip != "" { + ui.Message(fmt.Sprintf("Public IP: %s", ip)) + } + } + ui.Message(fmt.Sprintf("IP: %s", ip)) + state.Put("instance_ip", ip) + return multistep.ActionContinue + } } // Cleanup. diff --git a/builder/googlecompute/step_instance_info_test.go b/builder/googlecompute/step_instance_info_test.go index 8566ce722..5b6c01d0a 100644 --- a/builder/googlecompute/step_instance_info_test.go +++ b/builder/googlecompute/step_instance_info_test.go @@ -49,6 +49,46 @@ func TestStepInstanceInfo(t *testing.T) { } } +func TestStepInstanceInfo_InternalIP(t *testing.T) { + state := testState(t) + step := new(StepInstanceInfo) + defer step.Cleanup(state) + + state.Put("instance_name", "foo") + + config := state.Get("config").(*Config) + config.UseInternalIP = true + driver := state.Get("driver").(*DriverMock) + driver.GetNatIPResult = "1.2.3.4" + driver.GetInternalIPResult = "5.6.7.8" + + // run the step + if action := step.Run(state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + + // Verify state + if driver.WaitForInstanceState != "RUNNING" { + t.Fatalf("bad: %#v", driver.WaitForInstanceState) + } + if driver.WaitForInstanceZone != config.Zone { + t.Fatalf("bad: %#v", driver.WaitForInstanceZone) + } + if driver.WaitForInstanceName != "foo" { + t.Fatalf("bad: %#v", driver.WaitForInstanceName) + } + + ipRaw, ok := state.GetOk("instance_ip") + if !ok { + t.Fatal("should have ip") + } + if ip, ok := ipRaw.(string); !ok { + t.Fatal("ip is not a string") + } else if ip != "5.6.7.8" { + t.Fatalf("bad ip: %s", ip) + } +} + func TestStepInstanceInfo_getNatIPError(t *testing.T) { state := testState(t) step := new(StepInstanceInfo)