2013-12-12 21:38:34 -08:00
package googlecompute
import (
2018-01-22 16:03:49 -08:00
"context"
2013-12-12 21:38:34 -08:00
"errors"
2020-06-25 21:21:10 -04:00
"fmt"
2016-11-03 12:45:52 -04:00
"strings"
2013-12-12 21:38:34 -08:00
"testing"
2019-10-31 15:49:34 +01:00
"time"
2016-09-07 19:00:30 -07:00
2020-12-17 13:29:25 -08:00
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/template/config"
2016-09-07 19:00:30 -07:00
"github.com/stretchr/testify/assert"
2013-12-12 21:38:34 -08:00
)
func TestStepCreateInstance_impl ( t * testing . T ) {
var _ multistep . Step = new ( StepCreateInstance )
}
func TestStepCreateInstance ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
2016-09-07 19:00:30 -07:00
c := state . Get ( "config" ).( * Config )
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
2013-12-12 22:34:47 -08:00
2013-12-12 21:38:34 -08:00
// run the step
2018-01-22 16:03:49 -08:00
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
2013-12-12 21:38:34 -08:00
// Verify state
2013-12-12 22:34:47 -08:00
nameRaw , ok := state . GetOk ( "instance_name" )
2016-09-07 19:00:30 -07:00
assert . True ( t , ok , "State should have an instance name." )
2013-12-12 22:34:47 -08:00
// cleanup
step . Cleanup ( state )
2016-09-07 19:00:30 -07:00
// Check args passed to the driver.
assert . Equal ( t , d . DeleteInstanceName , nameRaw .( string ), "Incorrect instance name passed to driver." )
assert . Equal ( t , d . DeleteInstanceZone , c . Zone , "Incorrect instance zone passed to driver." )
assert . Equal ( t , d . DeleteDiskName , c . InstanceName , "Incorrect disk name passed to driver." )
assert . Equal ( t , d . DeleteDiskZone , c . Zone , "Incorrect disk zone passed to driver." )
2013-12-12 21:38:34 -08:00
}
2016-11-13 16:53:45 +01:00
func TestStepCreateInstance_fromFamily ( t * testing . T ) {
cases := [] struct {
Name string
Family string
Expect bool
}{
{ "test-image" , "" , false },
{ "test-image" , "test-family" , false }, // name trumps family
{ "" , "test-family" , true },
}
for _ , tc := range cases {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
c . SourceImage = tc . Name
c . SourceImageFamily = tc . Family
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
// run the step
2018-01-22 16:03:49 -08:00
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
2016-11-13 16:53:45 +01:00
// cleanup
step . Cleanup ( state )
// Check args passed to the driver.
if tc . Expect {
assert . True ( t , d . GetImageFromFamily , "Driver wasn't instructed to use an image family" )
} else {
assert . False ( t , d . GetImageFromFamily , "Driver was unexpectedly instructed to use an image family" )
}
}
}
2016-09-25 22:46:52 -04:00
func TestStepCreateInstance_windowsNeedsPassword ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string { "windows" }, 100 )
c . Comm . Type = "winrm"
// run the step
2018-01-22 16:03:49 -08:00
if action := step . Run ( context . Background (), state ); action != multistep . ActionContinue {
2016-09-25 22:46:52 -04:00
t . Fatalf ( "bad action: %#v" , action )
}
// Verify state
nameRaw , ok := state . GetOk ( "instance_name" )
if ! ok {
t . Fatal ( "should have instance name" )
}
createPassword , ok := state . GetOk ( "create_windows_password" )
if ! ok || ! createPassword .( bool ) {
t . Fatal ( "should need to create a windows password" )
}
// cleanup
step . Cleanup ( state )
if d . DeleteInstanceName != nameRaw .( string ) {
t . Fatal ( "should've deleted instance" )
}
if d . DeleteInstanceZone != c . Zone {
t . Fatalf ( "bad instance zone: %#v" , d . DeleteInstanceZone )
}
if d . DeleteDiskName != c . InstanceName {
t . Fatal ( "should've deleted disk" )
}
if d . DeleteDiskZone != c . Zone {
t . Fatalf ( "bad disk zone: %#v" , d . DeleteDiskZone )
}
}
func TestStepCreateInstance_windowsPasswordSet ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
config := state . Get ( "config" ).( * Config )
driver := state . Get ( "driver" ).( * DriverMock )
driver . GetImageResult = StubImage ( "test-image" , "test-project" , [] string { "windows" }, 100 )
config . Comm . Type = "winrm"
config . Comm . WinRMPassword = "password"
// run the step
2018-01-22 16:03:49 -08:00
if action := step . Run ( context . Background (), state ); action != multistep . ActionContinue {
2016-09-25 22:46:52 -04:00
t . Fatalf ( "bad action: %#v" , action )
}
// Verify state
nameRaw , ok := state . GetOk ( "instance_name" )
if ! ok {
t . Fatal ( "should have instance name" )
}
_ , ok = state . GetOk ( "create_windows_password" )
if ok {
t . Fatal ( "should not need to create windows password" )
}
// cleanup
step . Cleanup ( state )
if driver . DeleteInstanceName != nameRaw .( string ) {
t . Fatal ( "should've deleted instance" )
}
if driver . DeleteInstanceZone != config . Zone {
t . Fatalf ( "bad instance zone: %#v" , driver . DeleteInstanceZone )
}
if driver . DeleteDiskName != config . InstanceName {
t . Fatal ( "should've deleted disk" )
}
if driver . DeleteDiskZone != config . Zone {
t . Fatalf ( "bad disk zone: %#v" , driver . DeleteDiskZone )
}
}
2013-12-12 21:38:34 -08:00
func TestStepCreateInstance_error ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
2016-09-07 19:00:30 -07:00
d := state . Get ( "driver" ).( * DriverMock )
d . RunInstanceErr = errors . New ( "error" )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
2013-12-12 21:38:34 -08:00
// run the step
2018-01-22 16:03:49 -08:00
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionHalt , "Step should have failed and halted." )
2013-12-12 21:38:34 -08:00
// Verify state
2016-09-07 19:00:30 -07:00
_ , ok := state . GetOk ( "error" )
assert . True ( t , ok , "State should have an error." )
_ , ok = state . GetOk ( "instance_name" )
assert . False ( t , ok , "State should not have an instance name." )
2013-12-12 21:38:34 -08:00
}
func TestStepCreateInstance_errorOnChannel ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
2016-09-07 19:00:30 -07:00
state . Put ( "ssh_public_key" , "key" )
2013-12-12 21:38:34 -08:00
errCh := make ( chan error , 1 )
errCh <- errors . New ( "error" )
2016-09-07 19:00:30 -07:00
d := state . Get ( "driver" ).( * DriverMock )
d . RunInstanceErrCh = errCh
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
2013-12-12 21:38:34 -08:00
// run the step
2018-01-22 16:03:49 -08:00
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionHalt , "Step should have failed and halted." )
2013-12-12 21:38:34 -08:00
// Verify state
2016-09-07 19:00:30 -07:00
_ , ok := state . GetOk ( "error" )
assert . True ( t , ok , "State should have an error." )
_ , ok = state . GetOk ( "instance_name" )
assert . False ( t , ok , "State should not have an instance name." )
2013-12-12 21:38:34 -08:00
}
func TestStepCreateInstance_errorTimeout ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
2016-09-07 19:00:30 -07:00
state . Put ( "ssh_public_key" , "key" )
2013-12-12 21:38:34 -08:00
errCh := make ( chan error , 1 )
config := state . Get ( "config" ).( * Config )
2019-10-31 15:49:34 +01:00
config . StateTimeout = 1 * time . Millisecond
2013-12-12 21:38:34 -08:00
2016-09-07 19:00:30 -07:00
d := state . Get ( "driver" ).( * DriverMock )
d . RunInstanceErrCh = errCh
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
2013-12-12 21:38:34 -08:00
// run the step
2018-01-22 16:03:49 -08:00
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionHalt , "Step should have failed and halted." )
2013-12-12 21:38:34 -08:00
// Verify state
2016-09-07 19:00:30 -07:00
_ , ok := state . GetOk ( "error" )
assert . True ( t , ok , "State should have an error." )
_ , ok = state . GetOk ( "instance_name" )
assert . False ( t , ok , "State should not have an instance name." )
2013-12-12 21:38:34 -08:00
}
2016-11-03 12:45:52 -04:00
2018-03-07 15:35:01 -08:00
func TestStepCreateInstance_noServiceAccount ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
c . DisableDefaultServiceAccount = true
c . ServiceAccountEmail = ""
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
// run the step
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
// cleanup
step . Cleanup ( state )
// Check args passed to the driver.
assert . Equal ( t , d . RunInstanceConfig . DisableDefaultServiceAccount , c . DisableDefaultServiceAccount , "Incorrect value for DisableDefaultServiceAccount passed to driver." )
assert . Equal ( t , d . RunInstanceConfig . ServiceAccountEmail , c . ServiceAccountEmail , "Incorrect value for ServiceAccountEmail passed to driver." )
}
func TestStepCreateInstance_customServiceAccount ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
c . DisableDefaultServiceAccount = true
c . ServiceAccountEmail = "custom-service-account"
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
// run the step
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
// cleanup
step . Cleanup ( state )
// Check args passed to the driver.
assert . Equal ( t , d . RunInstanceConfig . DisableDefaultServiceAccount , c . DisableDefaultServiceAccount , "Incorrect value for DisableDefaultServiceAccount passed to driver." )
assert . Equal ( t , d . RunInstanceConfig . ServiceAccountEmail , c . ServiceAccountEmail , "Incorrect value for ServiceAccountEmail passed to driver." )
}
2016-11-03 12:45:52 -04:00
func TestCreateInstanceMetadata ( t * testing . T ) {
state := testState ( t )
c := state . Get ( "config" ).( * Config )
image := StubImage ( "test-image" , "test-project" , [] string {}, 100 )
key := "abcdefgh12345678"
// create our metadata
2020-12-01 14:50:36 +00:00
_ , metadataSSHKeys , err := c . createInstanceMetadata ( image , key )
2016-11-03 12:45:52 -04:00
assert . True ( t , err == nil , "Metadata creation should have succeeded." )
// ensure our key is listed
2020-12-01 14:50:36 +00:00
assert . True ( t , strings . Contains ( metadataSSHKeys [ "ssh-keys" ], key ), "Instance metadata should contain provided key" )
2016-11-03 12:45:52 -04:00
}
func TestCreateInstanceMetadata_noPublicKey ( t * testing . T ) {
state := testState ( t )
c := state . Get ( "config" ).( * Config )
image := StubImage ( "test-image" , "test-project" , [] string {}, 100 )
2020-03-24 08:33:55 +01:00
sshKeys := c . Metadata [ "ssh-keys" ]
2016-11-03 12:45:52 -04:00
// create our metadata
2020-12-01 14:50:36 +00:00
_ , metadataSSHKeys , err := c . createInstanceMetadata ( image , "" )
2016-11-03 12:45:52 -04:00
assert . True ( t , err == nil , "Metadata creation should have succeeded." )
// ensure the ssh metadata hasn't changed
2020-12-01 14:50:36 +00:00
assert . Equal ( t , metadataSSHKeys [ "ssh-keys" ], sshKeys , "Instance metadata should not have been modified" )
2016-11-03 12:45:52 -04:00
}
2019-06-11 17:45:30 +05:30
func TestCreateInstanceMetadata_metadataFile ( t * testing . T ) {
state := testState ( t )
c := state . Get ( "config" ).( * Config )
image := StubImage ( "test-image" , "test-project" , [] string {}, 100 )
content := testMetadataFileContent
fileName := testMetadataFile ( t )
c . MetadataFiles [ "user-data" ] = fileName
// create our metadata
2020-12-02 11:16:16 +00:00
metadataNoSSHKeys , _ , err := c . createInstanceMetadata ( image , "" )
2019-06-11 17:45:30 +05:30
assert . True ( t , err == nil , "Metadata creation should have succeeded." )
// ensure the user-data key in metadata is updated with file content
2020-12-01 14:50:36 +00:00
assert . Equal ( t , metadataNoSSHKeys [ "user-data" ], content , "user-data field of the instance metadata should have been updated." )
2019-06-11 17:45:30 +05:30
}
2020-06-25 21:21:10 -04:00
func TestCreateInstanceMetadata_withWrapStartupScript ( t * testing . T ) {
tt := [] struct {
WrapStartupScript config . Trilean
StartupScriptContents string
WrappedStartupScriptContents string
WrappedStartupScriptStatus string
}{
{
WrapStartupScript : config . TriUnset ,
StartupScriptContents : testMetadataFileContent ,
},
{
WrapStartupScript : config . TriFalse ,
StartupScriptContents : testMetadataFileContent ,
},
{
WrapStartupScript : config . TriTrue ,
StartupScriptContents : StartupScriptLinux ,
WrappedStartupScriptContents : testMetadataFileContent ,
WrappedStartupScriptStatus : StartupScriptStatusNotDone ,
},
}
for _ , tc := range tt {
tc := tc
state := testState ( t )
image := StubImage ( "test-image" , "test-project" , [] string {}, 100 )
c := state . Get ( "config" ).( * Config )
c . StartupScriptFile = testMetadataFile ( t )
c . WrapStartupScriptFile = tc . WrapStartupScript
// create our metadata
2020-12-01 14:50:36 +00:00
metadataNoSSHKeys , _ , err := c . createInstanceMetadata ( image , "" )
2020-06-25 21:21:10 -04:00
assert . True ( t , err == nil , "Metadata creation should have succeeded." )
2020-12-01 14:50:36 +00:00
assert . Equal ( t , tc . StartupScriptContents , metadataNoSSHKeys [ StartupScriptKey ], fmt . Sprintf ( "Instance metadata for startup script should be %q." , tc . StartupScriptContents ))
assert . Equal ( t , tc . WrappedStartupScriptContents , metadataNoSSHKeys [ StartupWrappedScriptKey ], fmt . Sprintf ( "Instance metadata for wrapped startup script should be %q." , tc . WrappedStartupScriptContents ))
assert . Equal ( t , tc . WrappedStartupScriptStatus , metadataNoSSHKeys [ StartupScriptStatusKey ], fmt . Sprintf ( "Instance metadata startup script status should be %q." , tc . WrappedStartupScriptStatus ))
2020-06-25 21:21:10 -04:00
}
}
2020-12-01 14:50:36 +00:00
func TestCreateInstanceMetadataWaitToAddSSHKeys ( t * testing . T ) {
state := testState ( t )
c := state . Get ( "config" ).( * Config )
image := StubImage ( "test-image" , "test-project" , [] string {}, 100 )
key := "abcdefgh12345678"
2020-12-02 11:16:16 +00:00
2020-12-01 14:50:36 +00:00
var waitTime int = 4
c . WaitToAddSSHKeys = time . Duration ( waitTime ) * time . Second
c . Metadata = map [ string ] string {
"metadatakey1" : "xyz" ,
"metadatakey2" : "123" ,
}
2020-12-02 11:16:16 +00:00
2020-12-01 14:50:36 +00:00
// create our metadata
metadataNoSSHKeys , metadataSSHKeys , err := c . createInstanceMetadata ( image , key )
assert . True ( t , err == nil , "Metadata creation should have succeeded." )
// ensure our metadata is listed
assert . True ( t , strings . Contains ( metadataSSHKeys [ "ssh-keys" ], key ), "Instance metadata should contain provided SSH key" )
2020-12-02 11:16:16 +00:00
assert . True ( t , strings . Contains ( metadataNoSSHKeys [ "metadatakey1" ], "xyz" ), "Instance metadata should contain provided key: metadatakey1" )
assert . True ( t , strings . Contains ( metadataNoSSHKeys [ "metadatakey2" ], "123" ), "Instance metadata should contain provided key: metadatakey2" )
2020-12-01 14:50:36 +00:00
}
func TestStepCreateInstanceWaitToAddSSHKeys ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
key := "abcdefgh12345678"
2020-12-02 11:16:16 +00:00
2020-12-01 14:50:36 +00:00
var waitTime int = 5
c . WaitToAddSSHKeys = time . Duration ( waitTime ) * time . Second
c . Comm . SSHPublicKey = [] byte ( key )
c . Metadata = map [ string ] string {
"metadatakey1" : "xyz" ,
"metadatakey2" : "123" ,
}
// run the step
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
// Verify state
_ , ok := state . GetOk ( "instance_name" )
assert . True ( t , ok , "State should have an instance name." )
// cleanup
step . Cleanup ( state )
}
func TestStepCreateInstanceNoWaitToAddSSHKeys ( t * testing . T ) {
state := testState ( t )
step := new ( StepCreateInstance )
defer step . Cleanup ( state )
state . Put ( "ssh_public_key" , "key" )
c := state . Get ( "config" ).( * Config )
d := state . Get ( "driver" ).( * DriverMock )
d . GetImageResult = StubImage ( "test-image" , "test-project" , [] string {}, 100 )
key := "abcdefgh12345678"
2020-12-02 11:16:16 +00:00
2020-12-01 14:50:36 +00:00
c . Comm . SSHPublicKey = [] byte ( key )
c . Metadata = map [ string ] string {
"metadatakey1" : "xyz" ,
"metadatakey2" : "123" ,
}
2020-12-02 11:16:16 +00:00
2020-12-01 14:50:36 +00:00
// run the step
assert . Equal ( t , step . Run ( context . Background (), state ), multistep . ActionContinue , "Step should have passed and continued." )
// Verify state
_ , ok := state . GetOk ( "instance_name" )
assert . True ( t , ok , "State should have an instance name." )
// cleanup
step . Cleanup ( state )
2020-12-02 11:16:16 +00:00
}