Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ad1024bd8 | |||
| c23b6a1b12 | |||
| 7583fd9d85 | |||
| d6904502ac | |||
| 2061aa9e69 | |||
| cbe06050b4 | |||
| d22ba61ae0 | |||
| 9eaad88ac0 | |||
| 20faaef05c | |||
| d0a4a71da8 | |||
| 3af472be9a | |||
| 5a00020830 | |||
| 6094c97998 | |||
| 1a41eac70b | |||
| 7a85b7328e | |||
| 3dac34766c | |||
| 642ed07476 | |||
| 88f8feecfe | |||
| b448c3182c | |||
| 9230a06920 | |||
| 16658a9f47 | |||
| ceb96d061a | |||
| bb1a025f60 | |||
| 87ba7258b3 | |||
| da312e2785 | |||
| 84af0ba6da | |||
| 3c6b7841bc | |||
| c7ee5f1efd | |||
| a00846102b | |||
| 41c66d6935 | |||
| f6854f5528 | |||
| 38fe79948b | |||
| a6c5958c67 | |||
| c17f236e85 | |||
| bb5d7b6c40 | |||
| 1ea5a547e2 | |||
| 86b8ce8df0 | |||
| b51bf9250e | |||
| 2d5a32629a | |||
| 3e2db82cab | |||
| bc9dd69669 | |||
| 734e91b97c | |||
| ab0d1ee363 | |||
| cf94fd1778 | |||
| 15a2e59bba | |||
| 8c4eb5f4aa | |||
| 86788220a9 | |||
| e3bcb4f2ac | |||
| ccd0430fda | |||
| 49474f8f37 | |||
| e0614cabf4 | |||
| eaec3e5564 | |||
| eaaf22dcde | |||
| f2f33fa344 | |||
| 9189f1228e | |||
| 5e7b5729e6 | |||
| 9365c90c0b | |||
| f27bdf85f4 | |||
| 9f7bb4da25 | |||
| b1967e99c7 | |||
| 7efb41868f | |||
| 260906c3e4 | |||
| f65e1d5d55 | |||
| 23e8684aae | |||
| e22d9861aa | |||
| 1c8fc65223 | |||
| 42ca66752f | |||
| 33461126e2 | |||
| 1f834e229a | |||
| 4417f8b3bf | |||
| 8db540a935 | |||
| e8780bf7b8 | |||
| 3b0226d496 | |||
| 4c08789642 | |||
| 634bf87d99 | |||
| d566419c45 | |||
| cce1f5c1e3 | |||
| 7f26429a2a | |||
| d81c02b456 | |||
| 794e83b171 | |||
| 58fb58c2ea | |||
| 15a9e1b20a | |||
| 3f23a5ec74 | |||
| f4cbb5d7dc | |||
| fb04fa7a25 | |||
| 830140157d | |||
| cdcdf6a618 | |||
| 74434b3c3e | |||
| 3a11352dfa | |||
| 56728a937b | |||
| f044a64014 | |||
| cd370aaaad | |||
| af865b1591 |
@@ -20,6 +20,7 @@ async function checkPluginDocs() {
|
||||
console.log(`\n${COLOR_BLUE}${repo}${COLOR_RESET} | ${title}`);
|
||||
console.log(`Fetching docs from release "${version}" …`);
|
||||
try {
|
||||
// Validate that all required properties are present
|
||||
const undefinedProps = ["title", "repo", "version", "path"].filter(
|
||||
(key) => typeof pluginEntry[key] == "undefined"
|
||||
);
|
||||
@@ -34,6 +35,22 @@ async function checkPluginDocs() {
|
||||
)} are defined. Additional information on this configuration can be found in "website/README.md".`
|
||||
);
|
||||
}
|
||||
// Validate pluginTier property
|
||||
const { pluginTier } = pluginEntry;
|
||||
if (typeof pluginTier !== "undefined") {
|
||||
const validPluginTiers = ["official", "community"];
|
||||
const isValid = validPluginTiers.indexOf(pluginTier) !== -1;
|
||||
if (!isValid) {
|
||||
throw new Error(
|
||||
`Failed to validate plugin docs config. Invalid pluginTier "${pluginTier}" found for "${
|
||||
title || pluginEntry.path || repo
|
||||
}". In "website/data/docs-remote-plugins.json", the optional pluginTier property must be one of ${JSON.stringify(
|
||||
validPluginTiers
|
||||
)}. The pluginTier property can also be omitted, in which case it will be determined from the plugin repository owner.`
|
||||
);
|
||||
}
|
||||
}
|
||||
// Attempt to fetch plugin docs files
|
||||
const docsMdxFiles = await fetchPluginDocs({ repo, tag: version });
|
||||
const mdxFilesByComponent = docsMdxFiles.reduce((acc, mdxFile) => {
|
||||
const componentType = mdxFile.filePath.split("/")[1];
|
||||
|
||||
+15
-1
@@ -1,4 +1,18 @@
|
||||
## 1.7.2 (Upcoming)
|
||||
## 1.7.3 (Upcoming)
|
||||
|
||||
## 1.7.2 (April 05, 2021)
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
* builder/alicloud: Add `ramrole` configuration to ECS instance. [GH-10845]
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/proxmox: Update Proxmox Go API to ensure only the first non-loopback
|
||||
IPv4 address gets returned. [GH-10858]
|
||||
* builder/vsphere: Fix primary disk resize on clone. [GH-10848]
|
||||
* core: Fix bug where call to "packer version" sent output to stderr instead of
|
||||
stdout. [GH-10850]
|
||||
|
||||
## 1.7.1 (March 31, 2021)
|
||||
|
||||
|
||||
@@ -43,9 +43,6 @@
|
||||
/builder/triton/ @sean-
|
||||
/website/pages/docs/builders/triton* @sean-
|
||||
|
||||
/builder/ncloud/ @YuSungDuk
|
||||
/website/pages/docs/builders/ncloud* @YuSungDuk
|
||||
|
||||
/builder/proxmox/ @carlpett
|
||||
/website/pages/docs/builders/proxmox* @carlpett
|
||||
|
||||
@@ -68,15 +65,10 @@
|
||||
/builder/yandex/ @GennadySpb @alexanderKhaustov @seukyaso
|
||||
/website/pages/docs/builders/yandex* @GennadySpb @alexanderKhaustov @seukyaso
|
||||
|
||||
/builder/osc/ @marinsalinas @Hakujou
|
||||
/website/pages/docs/builders/osc* @marinsalinas @Hakujou
|
||||
|
||||
/examples/tencentcloud/ @likexian
|
||||
/builder/tencentcloud/ @likexian
|
||||
/website/pages/docs/builders/tencentcloud* @likexian
|
||||
|
||||
|
||||
|
||||
# provisioners
|
||||
|
||||
/examples/ansible/ @bhcleek
|
||||
|
||||
@@ -58,8 +58,7 @@ install-gen-deps: ## Install dependencies for code generation
|
||||
# install` seems to install the last tagged version and we want to install
|
||||
# master.
|
||||
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/alvaroloes/enumer@master)
|
||||
@go install ./cmd/struct-markdown
|
||||
@go install ./cmd/mapstructure-to-hcl2
|
||||
@go install github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc@latest
|
||||
|
||||
install-lint-deps: ## Install linter dependencies
|
||||
# Pinning golangci-lint at v1.23.8 as --new-from-rev seems to work properly; the latest 1.24.0 has caused issues with memory consumption
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// component_acc_test.go should contain acceptance tests for plugin components
|
||||
// to make sure all component types can be discovered and started.
|
||||
package plugin
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
amazonacc "github.com/hashicorp/packer-plugin-amazon/builder/ebs/acceptance"
|
||||
"github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
"github.com/hashicorp/packer/hcl2template/addrs"
|
||||
)
|
||||
|
||||
//go:embed test-fixtures/basic-amazon-ami-datasource.pkr.hcl
|
||||
var basicAmazonAmiDatasourceHCL2Template string
|
||||
|
||||
func TestAccInitAndBuildBasicAmazonAmiDatasource(t *testing.T) {
|
||||
plugin := addrs.Plugin{
|
||||
Hostname: "github.com",
|
||||
Namespace: "hashicorp",
|
||||
Type: "amazon",
|
||||
}
|
||||
testCase := &acctest.PluginTestCase{
|
||||
Name: "amazon-ami_basic_datasource_test",
|
||||
Setup: func() error {
|
||||
return cleanupPluginInstallation(plugin)
|
||||
},
|
||||
Teardown: func() error {
|
||||
helper := amazonacc.AWSHelper{
|
||||
Region: "us-west-2",
|
||||
AMIName: "packer-amazon-ami-test",
|
||||
}
|
||||
return helper.CleanUpAmi()
|
||||
},
|
||||
Template: basicAmazonAmiDatasourceHCL2Template,
|
||||
Type: "amazon-ami",
|
||||
Init: true,
|
||||
CheckInit: func(initCommand *exec.Cmd, logfile string) error {
|
||||
if initCommand.ProcessState != nil {
|
||||
if initCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
logs, err := os.Open(logfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable find %s", logfile)
|
||||
}
|
||||
defer logs.Close()
|
||||
|
||||
logsBytes, err := ioutil.ReadAll(logs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to read %s", logfile)
|
||||
}
|
||||
initOutput := string(logsBytes)
|
||||
return checkPluginInstallation(initOutput, plugin)
|
||||
},
|
||||
Check: func(buildCommand *exec.Cmd, logfile string) error {
|
||||
if buildCommand.ProcessState != nil {
|
||||
if buildCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
acctest.TestPlugin(t, testCase)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// plugin_acc_test.go should contain acceptance tests for features related to
|
||||
// installing, discovering and running plugins.
|
||||
package plugin
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
amazonacc "github.com/hashicorp/packer-plugin-amazon/builder/ebs/acceptance"
|
||||
"github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
"github.com/hashicorp/packer-plugin-sdk/acctest/testutils"
|
||||
"github.com/hashicorp/packer/hcl2template/addrs"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
//go:embed test-fixtures/basic-amazon-ebs.pkr.hcl
|
||||
var basicAmazonEbsHCL2Template string
|
||||
|
||||
func TestAccInitAndBuildBasicAmazonEbs(t *testing.T) {
|
||||
plugin := addrs.Plugin{
|
||||
Hostname: "github.com",
|
||||
Namespace: "hashicorp",
|
||||
Type: "amazon",
|
||||
}
|
||||
testCase := &acctest.PluginTestCase{
|
||||
Name: "amazon-ebs_basic_plugin_init_and_build_test",
|
||||
Setup: func() error {
|
||||
return cleanupPluginInstallation(plugin)
|
||||
},
|
||||
Teardown: func() error {
|
||||
helper := amazonacc.AWSHelper{
|
||||
Region: "us-east-1",
|
||||
AMIName: "packer-plugin-amazon-ebs-test",
|
||||
}
|
||||
return helper.CleanUpAmi()
|
||||
},
|
||||
Template: basicAmazonEbsHCL2Template,
|
||||
Type: "amazon-ebs",
|
||||
Init: true,
|
||||
CheckInit: func(initCommand *exec.Cmd, logfile string) error {
|
||||
if initCommand.ProcessState != nil {
|
||||
if initCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
logs, err := os.Open(logfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable find %s", logfile)
|
||||
}
|
||||
defer logs.Close()
|
||||
|
||||
logsBytes, err := ioutil.ReadAll(logs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to read %s", logfile)
|
||||
}
|
||||
initOutput := string(logsBytes)
|
||||
return checkPluginInstallation(initOutput, plugin)
|
||||
},
|
||||
Check: func(buildCommand *exec.Cmd, logfile string) error {
|
||||
if buildCommand.ProcessState != nil {
|
||||
if buildCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
acctest.TestPlugin(t, testCase)
|
||||
}
|
||||
|
||||
func cleanupPluginInstallation(plugin addrs.Plugin) error {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pluginPath := filepath.Join(home,
|
||||
".packer.d",
|
||||
"plugins",
|
||||
plugin.Hostname,
|
||||
plugin.Namespace,
|
||||
plugin.Type)
|
||||
testutils.CleanupFiles(pluginPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkPluginInstallation(initOutput string, plugin addrs.Plugin) error {
|
||||
expectedInitLog := "Installed plugin " + plugin.String()
|
||||
if matched, _ := regexp.MatchString(expectedInitLog+".*", initOutput); !matched {
|
||||
return fmt.Errorf("logs doesn't contain expected foo value %q", initOutput)
|
||||
}
|
||||
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pluginPath := filepath.Join(home,
|
||||
".packer.d",
|
||||
"plugins",
|
||||
plugin.Hostname,
|
||||
plugin.Namespace,
|
||||
plugin.Type)
|
||||
if !testutils.FileExists(pluginPath) {
|
||||
return fmt.Errorf("%s plugin installation not found", plugin.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
amazon = {
|
||||
version = ">= 0.0.1"
|
||||
source = "github.com/hashicorp/amazon"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "amazon-ami" "test" {
|
||||
filters = {
|
||||
name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*"
|
||||
root-device-type = "ebs"
|
||||
virtualization-type = "hvm"
|
||||
}
|
||||
most_recent = true
|
||||
owners = ["099720109477"]
|
||||
}
|
||||
|
||||
source "amazon-ebs" "basic-example" {
|
||||
region = "us-west-2"
|
||||
source_ami = data.amazon-ami.test.id
|
||||
ami_name = "packer-amazon-ami-test"
|
||||
communicator = "ssh"
|
||||
instance_type = "t2.micro"
|
||||
ssh_username = "ubuntu"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.amazon-ebs.basic-example"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
amazon = {
|
||||
version = ">= 0.0.1"
|
||||
source = "github.com/hashicorp/amazon"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "amazon-ebs" "basic-test" {
|
||||
region = "us-east-1"
|
||||
instance_type = "m3.medium"
|
||||
source_ami = "ami-76b2a71e"
|
||||
ssh_username = "ubuntu"
|
||||
ami_name = "packer-plugin-amazon-ebs-test"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.amazon-ebs.basic-test"]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package acctest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testTesting = true
|
||||
|
||||
if err := os.Setenv(TestEnvVar, "1"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTest_noEnv(t *testing.T) {
|
||||
// Unset the variable
|
||||
if err := os.Setenv(TestEnvVar, ""); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Setenv(TestEnvVar, "1")
|
||||
|
||||
mt := new(mockT)
|
||||
Test(mt, TestCase{})
|
||||
|
||||
if !mt.SkipCalled {
|
||||
t.Fatal("skip not called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTest_preCheck(t *testing.T) {
|
||||
called := false
|
||||
|
||||
mt := new(mockT)
|
||||
Test(mt, TestCase{
|
||||
PreCheck: func() { called = true },
|
||||
})
|
||||
|
||||
if !called {
|
||||
t.Fatal("precheck should be called")
|
||||
}
|
||||
}
|
||||
|
||||
// mockT implements TestT for testing
|
||||
type mockT struct {
|
||||
ErrorCalled bool
|
||||
ErrorArgs []interface{}
|
||||
FatalCalled bool
|
||||
FatalArgs []interface{}
|
||||
SkipCalled bool
|
||||
SkipArgs []interface{}
|
||||
|
||||
f bool
|
||||
}
|
||||
|
||||
func (t *mockT) Error(args ...interface{}) {
|
||||
t.ErrorCalled = true
|
||||
t.ErrorArgs = args
|
||||
t.f = true
|
||||
}
|
||||
|
||||
func (t *mockT) Fatal(args ...interface{}) {
|
||||
t.FatalCalled = true
|
||||
t.FatalArgs = args
|
||||
t.f = true
|
||||
}
|
||||
|
||||
func (t *mockT) Skip(args ...interface{}) {
|
||||
t.SkipCalled = true
|
||||
t.SkipArgs = args
|
||||
t.f = true
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate packer-sdc struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate mapstructure-to-hcl2 -type Config,AlicloudDiskDevice
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,AlicloudDiskDevice
|
||||
|
||||
// The alicloud contains a packersdk.Builder implementation that
|
||||
// builds ecs images for alicloud.
|
||||
@@ -135,6 +135,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
|
||||
InstanceType: b.config.InstanceType,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
RamRoleName: b.config.RamRoleName,
|
||||
RegionId: b.config.AlicloudRegion,
|
||||
InternetChargeType: b.config.InternetChargeType,
|
||||
InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config,AlicloudDiskDevice"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package ecs
|
||||
|
||||
@@ -88,6 +88,7 @@ type FlatConfig struct {
|
||||
AlicloudSourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||
ForceStopInstance *bool `mapstructure:"force_stop_instance" required:"false" cty:"force_stop_instance" hcl:"force_stop_instance"`
|
||||
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance" hcl:"disable_stop_instance"`
|
||||
RamRoleName *string `mapstructure:"ram_role_name" required:"false" cty:"ram_role_name" hcl:"ram_role_name"`
|
||||
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id" hcl:"security_group_id"`
|
||||
SecurityGroupName *string `mapstructure:"security_group_name" required:"false" cty:"security_group_name" hcl:"security_group_name"`
|
||||
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"`
|
||||
@@ -205,6 +206,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||
"force_stop_instance": &hcldec.AttrSpec{Name: "force_stop_instance", Type: cty.Bool, Required: false},
|
||||
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
|
||||
"ram_role_name": &hcldec.AttrSpec{Name: "ram_role_name", Type: cty.String, Required: false},
|
||||
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
|
||||
"security_group_name": &hcldec.AttrSpec{Name: "security_group_name", Type: cty.String, Required: false},
|
||||
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
const defaultTestRegion = "cn-beijing"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate packer-sdc struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate packer-sdc struct-markdown
|
||||
|
||||
package ecs
|
||||
|
||||
@@ -47,6 +47,8 @@ type RunConfig struct {
|
||||
// E.g., Sysprep a windows which may shutdown the instance within its command.
|
||||
// The default value is false.
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance" required:"false"`
|
||||
// Ram Role to apply when launching the instance.
|
||||
RamRoleName string `mapstructure:"ram_role_name" required:"false"`
|
||||
// ID of the security group to which a newly
|
||||
// created instance belongs. Mutual access is allowed between instances in one
|
||||
// security group. If not specified, the newly created instance will be added
|
||||
|
||||
@@ -23,6 +23,7 @@ type stepCreateAlicloudInstance struct {
|
||||
UserData string
|
||||
UserDataFile string
|
||||
instanceId string
|
||||
RamRoleName string
|
||||
RegionId string
|
||||
InternetChargeType string
|
||||
InternetMaxBandwidthOut int
|
||||
@@ -115,6 +116,7 @@ func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.
|
||||
request.RegionId = s.RegionId
|
||||
request.InstanceType = s.InstanceType
|
||||
request.InstanceName = s.InstanceName
|
||||
request.RamRoleName = s.RamRoleName
|
||||
request.ZoneId = s.ZoneId
|
||||
|
||||
sourceImage := state.Get("source_image").(*ecs.Image)
|
||||
|
||||
@@ -30,8 +30,8 @@ import (
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,PlanInformation
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,PlanInformation
|
||||
|
||||
package arm
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,PlanInformation"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package arm
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
// Package chroot is able to create an Azure managed image without requiring the
|
||||
// launch of a new virtual machine for every build. It does this by attaching and
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package chroot
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion
|
||||
|
||||
package chroot
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package chroot
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate packer-sdc struct-markdown
|
||||
|
||||
package client
|
||||
|
||||
|
||||
@@ -181,7 +181,6 @@ func NewAzureClient(subscriptionID, resourceGroupName string,
|
||||
azureClient.GalleryImageVersionsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
|
||||
azureClient.GalleryImageVersionsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImageVersionsClient.UserAgent)
|
||||
azureClient.GalleryImageVersionsClient.Client.PollingDuration = SharedGalleryTimeout
|
||||
azureClient.GalleryImageVersionsClient.Client.PollingDuration = PollingDuration
|
||||
|
||||
azureClient.GalleryImagesClient = newCompute.NewGalleryImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
|
||||
azureClient.GalleryImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
|
||||
|
||||
@@ -28,7 +28,7 @@ package dtl
|
||||
import (
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,DtlArtifact,ArtifactParameter
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,DtlArtifact,ArtifactParameter
|
||||
|
||||
package dtl
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,DtlArtifact,ArtifactParameter"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package dtl
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package cloudstack
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package cloudstack
|
||||
|
||||
|
||||
@@ -80,10 +80,17 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
&stepCreateSSHKey{
|
||||
Debug: b.config.PackerDebug,
|
||||
DebugKeyPath: fmt.Sprintf("do_%s.pem", b.config.PackerBuildName),
|
||||
&communicator.StepSSHKeyGen{
|
||||
CommConf: &b.config.Comm,
|
||||
SSHTemporaryKeyPair: b.config.Comm.SSH.SSHTemporaryKeyPair,
|
||||
},
|
||||
multistep.If(b.config.PackerDebug && b.config.Comm.SSHPrivateKeyFile == "",
|
||||
&communicator.StepDumpSSHKey{
|
||||
Path: fmt.Sprintf("do_%s.pem", b.config.PackerBuildName),
|
||||
SSH: &b.config.Comm.SSH,
|
||||
},
|
||||
),
|
||||
&stepCreateSSHKey{},
|
||||
new(stepCreateDroplet),
|
||||
new(stepDropletInfo),
|
||||
&communicator.StepConnect{
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/digitalocean/godo"
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package digitalocean
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package digitalocean
|
||||
|
||||
|
||||
@@ -2,26 +2,16 @@ package digitalocean
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/digitalocean/godo"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/uuid"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type stepCreateSSHKey struct {
|
||||
Debug bool
|
||||
DebugKeyPath string
|
||||
|
||||
keyId int
|
||||
}
|
||||
|
||||
@@ -30,31 +20,12 @@ func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
c := state.Get("config").(*Config)
|
||||
|
||||
ui.Say("Creating temporary ssh key for droplet...")
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2014)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error generating RSA key: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
if c.Comm.SSHPublicKey == nil {
|
||||
ui.Say("No public SSH key found; skipping SSH public key import...")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// ASN.1 DER encoded form
|
||||
priv_der := x509.MarshalPKCS1PrivateKey(priv)
|
||||
priv_blk := pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Headers: nil,
|
||||
Bytes: priv_der,
|
||||
}
|
||||
|
||||
// Set the private key in the config for later
|
||||
c.Comm.SSHPrivateKey = pem.EncodeToMemory(&priv_blk)
|
||||
|
||||
// Marshal the public key into SSH compatible format
|
||||
// TODO properly handle the public key error
|
||||
pub, _ := ssh.NewPublicKey(&priv.PublicKey)
|
||||
pub_sshformat := string(ssh.MarshalAuthorizedKey(pub))
|
||||
ui.Say("Importing SSH public key...")
|
||||
|
||||
// The name of the public key on DO
|
||||
name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
||||
@@ -62,7 +33,7 @@ func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
// Create the key!
|
||||
key, _, err := client.Keys.Create(context.TODO(), &godo.KeyCreateRequest{
|
||||
Name: name,
|
||||
PublicKey: pub_sshformat,
|
||||
PublicKey: string(c.Comm.SSHPublicKey),
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
|
||||
@@ -79,31 +50,6 @@ func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
// Remember some state for the future
|
||||
state.Put("ssh_key_id", key.ID)
|
||||
|
||||
// If we're in debug mode, output the private key to the working directory.
|
||||
if s.Debug {
|
||||
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
|
||||
f, err := os.Create(s.DebugKeyPath)
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Write the key out
|
||||
if _, err := f.Write(pem.EncodeToMemory(&priv_blk)); err != nil {
|
||||
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Chmod it so that it is SSH ready
|
||||
if runtime.GOOS != "windows" {
|
||||
if err := f.Chmod(0600); err != nil {
|
||||
state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
func TestBuilder_implBuilder(t *testing.T) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package file
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package file
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestArtifact_impl(t *testing.T) {
|
||||
var _ packersdk.Artifact = new(Artifact)
|
||||
}
|
||||
|
||||
func TestArtifactState_StateData(t *testing.T) {
|
||||
expectedData := "this is the data"
|
||||
artifact := &Artifact{
|
||||
StateData: map[string]interface{}{"state_data": expectedData},
|
||||
}
|
||||
|
||||
// Valid state
|
||||
result := artifact.State("state_data")
|
||||
if result != expectedData {
|
||||
t.Fatalf("Bad: State data was %s instead of %s", result, expectedData)
|
||||
}
|
||||
|
||||
// Invalid state
|
||||
result = artifact.State("invalid_key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for invalid state data name")
|
||||
}
|
||||
|
||||
// Nil StateData should not fail and should return nil
|
||||
artifact = &Artifact{}
|
||||
result = artifact.State("key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for nil StateData")
|
||||
}
|
||||
}
|
||||
@@ -1,692 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
)
|
||||
|
||||
func TestConfigPrepare(t *testing.T) {
|
||||
cases := []struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"unknown_key",
|
||||
"bad",
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
"private_key_file",
|
||||
"/tmp/i/should/not/exist",
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
"project_id",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"project_id",
|
||||
"foo",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"source_image",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"source_image",
|
||||
"foo",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"source_image_family",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"source_image_family",
|
||||
"foo",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"zone",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"zone",
|
||||
"foo",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"ssh_timeout",
|
||||
"SO BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"ssh_timeout",
|
||||
"5s",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"wait_to_add_ssh_keys",
|
||||
"SO BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"wait_to_add_ssh_keys",
|
||||
"5s",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"state_timeout",
|
||||
"SO BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"state_timeout",
|
||||
"5s",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"use_internal_ip",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"use_internal_ip",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"use_internal_ip",
|
||||
"SO VERY BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"on_host_maintenance",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"on_host_maintenance",
|
||||
"TERMINATE",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"on_host_maintenance",
|
||||
"SO VERY BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"preemptible",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"preemptible",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"preemptible",
|
||||
"SO VERY BAD",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"image_family",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"image_family",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"image_family",
|
||||
"foo-bar",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"image_family",
|
||||
"foo bar",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// underscore is not allowed
|
||||
"image_name",
|
||||
"foo_bar",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// too long
|
||||
"image_name",
|
||||
"foobar123xyz_abc-456-one-two_three_five_nine_seventeen_eleventy-seven",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// starts with non-alphabetic character
|
||||
"image_name",
|
||||
"1boohoo",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"image_encryption_key",
|
||||
map[string]string{"kmsKeyName": "foo"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"image_encryption_key",
|
||||
map[string]string{"No such key": "foo"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"image_encryption_key",
|
||||
map[string]string{"kmsKeyName": "foo", "RawKey": "foo"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"scopes",
|
||||
[]string{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"scopes",
|
||||
[]string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/sqlservice.admin"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"scopes",
|
||||
[]string{"https://www.googleapis.com/auth/cloud-platform"},
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"disable_default_service_account",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"disable_default_service_account",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"disable_default_service_account",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"disable_default_service_account",
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"disable_default_service_account",
|
||||
"NOT A BOOL",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
if tc.Value == nil {
|
||||
delete(raw, tc.Key)
|
||||
} else {
|
||||
raw[tc.Key] = tc.Value
|
||||
}
|
||||
|
||||
var c Config
|
||||
warns, errs := c.Prepare(raw)
|
||||
|
||||
if tc.Err {
|
||||
testConfigErr(t, warns, errs, tc.Key)
|
||||
} else {
|
||||
testConfigOk(t, warns, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigPrepareAccelerator(t *testing.T) {
|
||||
cases := []struct {
|
||||
Keys []string
|
||||
Values []interface{}
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
|
||||
[]interface{}{1, "MIGRATE", "something_valid"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
|
||||
[]interface{}{1, "TERMINATE", "something_valid"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
|
||||
[]interface{}{1, "TERMINATE", nil},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
|
||||
[]interface{}{1, "TERMINATE", ""},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
|
||||
[]interface{}{1, "TERMINATE", "something_valid"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
errStr := ""
|
||||
for k := range tc.Keys {
|
||||
|
||||
// Create the string for error reporting
|
||||
// convert value to string if it can be converted
|
||||
errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k])
|
||||
if tc.Values[k] == nil {
|
||||
delete(raw, tc.Keys[k])
|
||||
} else {
|
||||
raw[tc.Keys[k]] = tc.Values[k]
|
||||
}
|
||||
}
|
||||
|
||||
var c Config
|
||||
warns, errs := c.Prepare(raw)
|
||||
|
||||
if tc.Err {
|
||||
testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
|
||||
} else {
|
||||
testConfigOk(t, warns, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigPrepareServiceAccount(t *testing.T) {
|
||||
cases := []struct {
|
||||
Keys []string
|
||||
Values []interface{}
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
[]string{"disable_default_service_account", "service_account_email"},
|
||||
[]interface{}{true, "service@account.email.com"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]string{"disable_default_service_account", "service_account_email"},
|
||||
[]interface{}{false, "service@account.email.com"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
[]string{"disable_default_service_account", "service_account_email"},
|
||||
[]interface{}{true, ""},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
errStr := ""
|
||||
for k := range tc.Keys {
|
||||
|
||||
// Create the string for error reporting
|
||||
// convert value to string if it can be converted
|
||||
errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k])
|
||||
if tc.Values[k] == nil {
|
||||
delete(raw, tc.Keys[k])
|
||||
} else {
|
||||
raw[tc.Keys[k]] = tc.Values[k]
|
||||
}
|
||||
}
|
||||
|
||||
var c Config
|
||||
warns, errs := c.Prepare(raw)
|
||||
|
||||
if tc.Err {
|
||||
testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
|
||||
} else {
|
||||
testConfigOk(t, warns, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigPrepareStartupScriptFile(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"project_id": "project",
|
||||
"source_image": "foo",
|
||||
"ssh_username": "packer",
|
||||
"startup_script_file": "no-such-file",
|
||||
"zone": "us-central1-a",
|
||||
}
|
||||
|
||||
var c Config
|
||||
_, errs := c.Prepare(config)
|
||||
|
||||
if errs == nil || !strings.Contains(errs.Error(), "startup_script_file") {
|
||||
t.Fatalf("should error: startup_script_file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigPrepareIAP_SSH(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"project_id": "project",
|
||||
"source_image": "foo",
|
||||
"ssh_username": "packer",
|
||||
"zone": "us-central1-a",
|
||||
"communicator": "ssh",
|
||||
"use_iap": true,
|
||||
}
|
||||
|
||||
var c Config
|
||||
_, err := c.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have errors. Err = %s", err)
|
||||
}
|
||||
if c.Comm.SSHHost != "localhost" {
|
||||
t.Fatalf("Should have set SSHHost")
|
||||
}
|
||||
|
||||
testIAPScript(t, &c)
|
||||
}
|
||||
|
||||
func TestConfigPrepareIAP_WinRM(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"project_id": "project",
|
||||
"source_image": "foo",
|
||||
"winrm_username": "packer",
|
||||
"zone": "us-central1-a",
|
||||
"communicator": "winrm",
|
||||
"use_iap": true,
|
||||
}
|
||||
|
||||
var c Config
|
||||
_, err := c.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have errors. Err = %s", err)
|
||||
}
|
||||
if c.Comm.WinRMHost != "localhost" {
|
||||
t.Fatalf("Should have set WinRMHost")
|
||||
}
|
||||
|
||||
testIAPScript(t, &c)
|
||||
}
|
||||
|
||||
func TestConfigPrepareIAP_failures(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"project_id": "project",
|
||||
"source_image": "foo",
|
||||
"winrm_username": "packer",
|
||||
"zone": "us-central1-a",
|
||||
"communicator": "none",
|
||||
"iap_hashbang": "/bin/bash",
|
||||
"iap_ext": ".ps1",
|
||||
"use_iap": true,
|
||||
}
|
||||
|
||||
var c Config
|
||||
_, errs := c.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Should have errored because we're using none.")
|
||||
}
|
||||
if c.IAPHashBang != "/bin/bash" {
|
||||
t.Fatalf("IAP hashbang defaulted even though set.")
|
||||
}
|
||||
if c.IAPExt != ".ps1" {
|
||||
t.Fatalf("IAP tempfile defaulted even though set.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigDefaults(t *testing.T) {
|
||||
cases := []struct {
|
||||
Read func(c *Config) interface{}
|
||||
Value interface{}
|
||||
}{
|
||||
{
|
||||
func(c *Config) interface{} { return c.Comm.Type },
|
||||
"ssh",
|
||||
},
|
||||
|
||||
{
|
||||
func(c *Config) interface{} { return c.Comm.SSHPort },
|
||||
22,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
var c Config
|
||||
warns, errs := c.Prepare(raw)
|
||||
testConfigOk(t, warns, errs)
|
||||
|
||||
actual := tc.Read(&c)
|
||||
if actual != tc.Value {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageName(t *testing.T) {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
var c Config
|
||||
c.Prepare(raw)
|
||||
if !strings.HasPrefix(c.ImageName, "packer-") {
|
||||
t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName)
|
||||
}
|
||||
if strings.Contains(c.ImageName, "{{timestamp}}") {
|
||||
t.Errorf("ImageName should be interpolated; found %s", c.ImageName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegion(t *testing.T) {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
var c Config
|
||||
c.Prepare(raw)
|
||||
if c.Region != "us-east1" {
|
||||
t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIAPTunnel_SSH(t *testing.T) {
|
||||
c := &communicator.Config{
|
||||
Type: "ssh",
|
||||
SSH: communicator.SSH{
|
||||
SSHHost: "example",
|
||||
SSHPort: 1234,
|
||||
},
|
||||
}
|
||||
|
||||
err := ApplyIAPTunnel(c, 8447)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have errors")
|
||||
}
|
||||
if c.SSHPort != 8447 {
|
||||
t.Fatalf("Should have set SSHPort")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIAPTunnel_WinRM(t *testing.T) {
|
||||
c := &communicator.Config{
|
||||
Type: "winrm",
|
||||
WinRM: communicator.WinRM{
|
||||
WinRMHost: "example",
|
||||
WinRMPort: 1234,
|
||||
},
|
||||
}
|
||||
|
||||
err := ApplyIAPTunnel(c, 8447)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have errors")
|
||||
}
|
||||
if c.WinRMPort != 8447 {
|
||||
t.Fatalf("Should have set WinRMPort")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIAPTunnel_none(t *testing.T) {
|
||||
c := &communicator.Config{
|
||||
Type: "none",
|
||||
}
|
||||
|
||||
err := ApplyIAPTunnel(c, 8447)
|
||||
if err == nil {
|
||||
t.Fatalf("Should have errors, none is not supported")
|
||||
}
|
||||
}
|
||||
|
||||
// Helper stuff below
|
||||
|
||||
func testConfig(t *testing.T) (config map[string]interface{}, tempAccountFile string) {
|
||||
tempAccountFile = testAccountFile(t)
|
||||
|
||||
config = map[string]interface{}{
|
||||
"account_file": tempAccountFile,
|
||||
"project_id": "hashicorp",
|
||||
"source_image": "foo",
|
||||
"ssh_username": "root",
|
||||
"image_family": "bar",
|
||||
"image_labels": map[string]string{
|
||||
"label-1": "value-1",
|
||||
"label-2": "value-2",
|
||||
},
|
||||
"image_licenses": []string{
|
||||
"test-license",
|
||||
},
|
||||
"image_storage_locations": []string{
|
||||
"us-east1",
|
||||
},
|
||||
"metadata_files": map[string]string{},
|
||||
"zone": "us-east1-a",
|
||||
}
|
||||
|
||||
return config, tempAccountFile
|
||||
}
|
||||
|
||||
func testConfigStruct(t *testing.T) *Config {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
var c Config
|
||||
warns, errs := c.Prepare(raw)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", len(warns))
|
||||
}
|
||||
if errs != nil {
|
||||
t.Fatalf("bad: %#v", errs)
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func testConfigErr(t *testing.T, warns []string, err error, extra string) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("should error: %s", extra)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigOk(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccountFile(t *testing.T) string {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer tf.Close()
|
||||
|
||||
if _, err := tf.Write([]byte(testAccountContent)); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
return tf.Name()
|
||||
}
|
||||
|
||||
func testIAPScript(t *testing.T, c *Config) {
|
||||
if runtime.GOOS == "windows" {
|
||||
if c.IAPExt != ".cmd" {
|
||||
t.Fatalf("IAP tempfile extension didn't default correctly to .cmd")
|
||||
}
|
||||
if c.IAPHashBang != "" {
|
||||
t.Fatalf("IAP hashbang didn't default correctly to nothing.")
|
||||
}
|
||||
} else {
|
||||
if c.IAPExt != "" {
|
||||
t.Fatalf("IAP tempfile extension should default to empty on unix mahcines")
|
||||
}
|
||||
if c.IAPHashBang != "/bin/sh" {
|
||||
t.Fatalf("IAP hashbang didn't default correctly to /bin/sh.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testMetadataFileContent = `testMetadata`
|
||||
|
||||
func testMetadataFile(t *testing.T) string {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer tf.Close()
|
||||
if _, err := tf.Write([]byte(testMetadataFileContent)); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
return tf.Name()
|
||||
}
|
||||
|
||||
// This is just some dummy data that doesn't actually work
|
||||
const testAccountContent = `{
|
||||
"type": "service_account",
|
||||
"project_id": "test-project-123456789",
|
||||
"private_key_id": "bananaphone",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nring_ring_ring_ring_ring_ring_ring_BANANAPHONE\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "raffi-compute@developer.gserviceaccount.com",
|
||||
"client_id": "1234567890",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/12345-compute%40developer.gserviceaccount.com"
|
||||
}`
|
||||
@@ -1,26 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func StubImage(name, project string, licenses []string, sizeGb int64) *Image {
|
||||
return &Image{
|
||||
Licenses: licenses,
|
||||
Name: name,
|
||||
ProjectId: project,
|
||||
SelfLink: fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/images/%s", project, name),
|
||||
SizeGb: sizeGb,
|
||||
}
|
||||
}
|
||||
|
||||
func TestImage_IsWindows(t *testing.T) {
|
||||
i := StubImage("foo", "foo-project", []string{"license-foo", "license-bar"}, 100)
|
||||
assert.False(t, i.IsWindows())
|
||||
|
||||
i = StubImage("foo", "foo-project", []string{"license-foo", "windows-license"}, 100)
|
||||
assert.True(t, i.IsWindows())
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetNetworking(t *testing.T) {
|
||||
cases := []struct {
|
||||
c *InstanceConfig
|
||||
expectedNetwork string
|
||||
expectedSubnetwork string
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
c: &InstanceConfig{
|
||||
Network: "default",
|
||||
Subnetwork: "",
|
||||
NetworkProjectId: "project-id",
|
||||
Region: "region-id",
|
||||
},
|
||||
expectedNetwork: "global/networks/default",
|
||||
expectedSubnetwork: "",
|
||||
error: false,
|
||||
},
|
||||
{
|
||||
c: &InstanceConfig{
|
||||
Network: "",
|
||||
Subnetwork: "",
|
||||
NetworkProjectId: "project-id",
|
||||
Region: "region-id",
|
||||
},
|
||||
expectedNetwork: "",
|
||||
expectedSubnetwork: "",
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
c: &InstanceConfig{
|
||||
Network: "some/network/path",
|
||||
Subnetwork: "some/subnetwork/path",
|
||||
NetworkProjectId: "project-id",
|
||||
Region: "region-id",
|
||||
},
|
||||
expectedNetwork: "some/network/path",
|
||||
expectedSubnetwork: "some/subnetwork/path",
|
||||
error: false,
|
||||
},
|
||||
{
|
||||
c: &InstanceConfig{
|
||||
Network: "network-value",
|
||||
Subnetwork: "subnetwork-value",
|
||||
NetworkProjectId: "project-id",
|
||||
Region: "region-id",
|
||||
},
|
||||
expectedNetwork: "projects/project-id/global/networks/network-value",
|
||||
expectedSubnetwork: "projects/project-id/regions/region-id/subnetworks/subnetwork-value",
|
||||
error: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
n, sn, err := getNetworking(tc.c)
|
||||
if n != tc.expectedNetwork {
|
||||
t.Errorf("Expected network %q but got network %q", tc.expectedNetwork, n)
|
||||
}
|
||||
if sn != tc.expectedSubnetwork {
|
||||
t.Errorf("Expected subnetwork %q but got subnetwork %q", tc.expectedSubnetwork, sn)
|
||||
}
|
||||
if !tc.error && err != nil {
|
||||
t.Errorf("Did not expect an error but got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCheckExistingImage_impl(t *testing.T) {
|
||||
var _ multistep.Step = new(StepCheckExistingImage)
|
||||
}
|
||||
|
||||
func TestStepCheckExistingImage(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCheckExistingImage)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("instance_name", "foo")
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.ImageExistsResult = true
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if driver.ImageExistsName != config.ImageName {
|
||||
t.Fatalf("bad: %#v", driver.ImageExistsName)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStepCreateImage_impl(t *testing.T) {
|
||||
var _ multistep.Step = new(StepCreateImage)
|
||||
}
|
||||
|
||||
func TestStepCreateImage(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCreateImage)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
c := state.Get("config").(*Config)
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
|
||||
// These are the values of the image the driver will return.
|
||||
d.CreateImageResultProjectId = "test-project"
|
||||
d.CreateImageResultSizeGb = 100
|
||||
|
||||
// run the step
|
||||
action := step.Run(context.Background(), state)
|
||||
assert.Equal(t, action, multistep.ActionContinue, "Step did not pass.")
|
||||
|
||||
uncastImage, ok := state.GetOk("image")
|
||||
assert.True(t, ok, "State does not have resulting image.")
|
||||
image, ok := uncastImage.(*Image)
|
||||
assert.True(t, ok, "Image in state is not an Image.")
|
||||
|
||||
// Verify created Image results.
|
||||
assert.Equal(t, image.Name, c.ImageName, "Created image does not match config name.")
|
||||
assert.Equal(t, image.ProjectId, d.CreateImageResultProjectId, "Created image project does not match driver project.")
|
||||
assert.Equal(t, image.SizeGb, d.CreateImageResultSizeGb, "Created image size does not match the size returned by the driver.")
|
||||
|
||||
// Verify proper args passed to driver.CreateImage.
|
||||
assert.Equal(t, d.CreateImageName, c.ImageName, "Incorrect image name passed to driver.")
|
||||
assert.Equal(t, d.CreateImageDesc, c.ImageDescription, "Incorrect image description passed to driver.")
|
||||
assert.Equal(t, d.CreateImageFamily, c.ImageFamily, "Incorrect image family passed to driver.")
|
||||
assert.Equal(t, d.CreateImageZone, c.Zone, "Incorrect image zone passed to driver.")
|
||||
assert.Equal(t, d.CreateImageDisk, c.DiskName, "Incorrect disk passed to driver.")
|
||||
assert.Equal(t, d.CreateImageLabels, c.ImageLabels, "Incorrect image_labels passed to driver.")
|
||||
assert.Equal(t, d.CreateImageLicenses, c.ImageLicenses, "Incorrect image_licenses passed to driver.")
|
||||
assert.Equal(t, d.CreateImageEncryptionKey, c.ImageEncryptionKey.ComputeType(), "Incorrect image_encryption_key passed to driver.")
|
||||
assert.Equal(t, d.CreateImageStorageLocations, c.ImageStorageLocations, "Incorrect image_storage_locations passed to driver.")
|
||||
}
|
||||
|
||||
func TestStepCreateImage_errorOnChannel(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCreateImage)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
errCh <- errors.New("error")
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.CreateImageErrCh = errCh
|
||||
|
||||
// run the step
|
||||
action := step.Run(context.Background(), state)
|
||||
assert.Equal(t, action, multistep.ActionHalt, "Step should not have passed.")
|
||||
_, ok := state.GetOk("error")
|
||||
assert.True(t, ok, "State should have an error.")
|
||||
_, ok = state.GetOk("image_name")
|
||||
assert.False(t, ok, "State should not have a resulting image.")
|
||||
}
|
||||
@@ -1,475 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
c := state.Get("config").(*Config)
|
||||
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.")
|
||||
|
||||
// Verify state
|
||||
nameRaw, ok := state.GetOk("instance_name")
|
||||
assert.True(t, ok, "State should have an instance name.")
|
||||
|
||||
// cleanup
|
||||
step.Cleanup(state)
|
||||
|
||||
// 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.")
|
||||
}
|
||||
|
||||
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
|
||||
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.
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
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
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateInstance_error(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCreateInstance)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("ssh_public_key", "key")
|
||||
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
d.RunInstanceErr = errors.New("error")
|
||||
d.GetImageResult = StubImage("test-image", "test-project", []string{}, 100)
|
||||
|
||||
// run the step
|
||||
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionHalt, "Step should have failed and halted.")
|
||||
|
||||
// Verify state
|
||||
_, 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.")
|
||||
}
|
||||
|
||||
func TestStepCreateInstance_errorOnChannel(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCreateInstance)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("ssh_public_key", "key")
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
errCh <- errors.New("error")
|
||||
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
d.RunInstanceErrCh = errCh
|
||||
d.GetImageResult = StubImage("test-image", "test-project", []string{}, 100)
|
||||
|
||||
// run the step
|
||||
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionHalt, "Step should have failed and halted.")
|
||||
|
||||
// Verify state
|
||||
_, 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.")
|
||||
}
|
||||
|
||||
func TestStepCreateInstance_errorTimeout(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepCreateInstance)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("ssh_public_key", "key")
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.StateTimeout = 1 * time.Millisecond
|
||||
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
d.RunInstanceErrCh = errCh
|
||||
d.GetImageResult = StubImage("test-image", "test-project", []string{}, 100)
|
||||
|
||||
// run the step
|
||||
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionHalt, "Step should have failed and halted.")
|
||||
|
||||
// Verify state
|
||||
_, 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.")
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
|
||||
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
|
||||
_, metadataSSHKeys, err := c.createInstanceMetadata(image, key)
|
||||
|
||||
assert.True(t, err == nil, "Metadata creation should have succeeded.")
|
||||
|
||||
// ensure our key is listed
|
||||
assert.True(t, strings.Contains(metadataSSHKeys["ssh-keys"], key), "Instance metadata should contain provided key")
|
||||
}
|
||||
|
||||
func TestCreateInstanceMetadata_noPublicKey(t *testing.T) {
|
||||
state := testState(t)
|
||||
c := state.Get("config").(*Config)
|
||||
image := StubImage("test-image", "test-project", []string{}, 100)
|
||||
sshKeys := c.Metadata["ssh-keys"]
|
||||
|
||||
// create our metadata
|
||||
_, metadataSSHKeys, err := c.createInstanceMetadata(image, "")
|
||||
|
||||
assert.True(t, err == nil, "Metadata creation should have succeeded.")
|
||||
|
||||
// ensure the ssh metadata hasn't changed
|
||||
assert.Equal(t, metadataSSHKeys["ssh-keys"], sshKeys, "Instance metadata should not have been modified")
|
||||
}
|
||||
|
||||
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
|
||||
metadataNoSSHKeys, _, err := c.createInstanceMetadata(image, "")
|
||||
|
||||
assert.True(t, err == nil, "Metadata creation should have succeeded.")
|
||||
|
||||
// ensure the user-data key in metadata is updated with file content
|
||||
assert.Equal(t, metadataNoSSHKeys["user-data"], content, "user-data field of the instance metadata should have been updated.")
|
||||
}
|
||||
|
||||
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
|
||||
metadataNoSSHKeys, _, err := c.createInstanceMetadata(image, "")
|
||||
|
||||
assert.True(t, err == nil, "Metadata creation should have succeeded.")
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateInstanceMetadataWaitToAddSSHKeys(t *testing.T) {
|
||||
state := testState(t)
|
||||
c := state.Get("config").(*Config)
|
||||
image := StubImage("test-image", "test-project", []string{}, 100)
|
||||
key := "abcdefgh12345678"
|
||||
|
||||
var waitTime int = 4
|
||||
c.WaitToAddSSHKeys = time.Duration(waitTime) * time.Second
|
||||
c.Metadata = map[string]string{
|
||||
"metadatakey1": "xyz",
|
||||
"metadatakey2": "123",
|
||||
}
|
||||
|
||||
// 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")
|
||||
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")
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword(t *testing.T) {
|
||||
state := testState(t)
|
||||
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
state.Put("create_windows_password", true)
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if password, ok := state.GetOk("winrm_password"); !ok || password.(string) != "MOCK_PASSWORD" {
|
||||
t.Fatal("should have a password", password, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword_passwordSet(t *testing.T) {
|
||||
state := testState(t)
|
||||
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
|
||||
c := state.Get("config").(*Config)
|
||||
|
||||
c.Comm.WinRMPassword = "password"
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if password, ok := state.GetOk("winrm_password"); !ok || password.(string) != "password" {
|
||||
t.Fatal("should have used existing password", password, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword_dontNeedPassword(t *testing.T) {
|
||||
state := testState(t)
|
||||
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword_debug(t *testing.T) {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
tf.Close()
|
||||
|
||||
state := testState(t)
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
state.Put("create_windows_password", true)
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
|
||||
step.Debug = true
|
||||
step.DebugKeyPath = tf.Name()
|
||||
|
||||
defer step.Cleanup(state)
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if password, ok := state.GetOk("winrm_password"); !ok || password.(string) != "MOCK_PASSWORD" {
|
||||
t.Fatal("should have a password", password, ok)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tf.Name()); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword_error(t *testing.T) {
|
||||
state := testState(t)
|
||||
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
state.Put("create_windows_password", true)
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.CreateOrResetWindowsPasswordErr = errors.New("error")
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if _, ok := state.GetOk("error"); !ok {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
if _, ok := state.GetOk("winrm_password"); ok {
|
||||
t.Fatal("should NOT have instance name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateOrResetWindowsPassword_errorOnChannel(t *testing.T) {
|
||||
state := testState(t)
|
||||
|
||||
// Step is run after the instance is created so we will have an instance name set
|
||||
state.Put("instance_name", "mock_instance")
|
||||
state.Put("create_windows_password", true)
|
||||
|
||||
step := new(StepCreateWindowsPassword)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
errCh <- errors.New("error")
|
||||
|
||||
driver.CreateOrResetWindowsPasswordErrCh = errCh
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if _, ok := state.GetOk("error"); !ok {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if _, ok := state.GetOk("winrm_password"); ok {
|
||||
t.Fatal("should NOT have instance name")
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"google.golang.org/api/oauth2/v2"
|
||||
)
|
||||
|
||||
func TestStepImportOSLoginSSHKey_impl(t *testing.T) {
|
||||
var _ multistep.Step = new(StepImportOSLoginSSHKey)
|
||||
}
|
||||
|
||||
func TestStepImportOSLoginSSHKey(t *testing.T) {
|
||||
tt := []struct {
|
||||
Name string
|
||||
UseOSLogin bool
|
||||
ExpectedEmail string
|
||||
ExpectedAction multistep.StepAction
|
||||
PubKeyExpected bool
|
||||
}{
|
||||
{
|
||||
Name: "UseOSLoginDisabled",
|
||||
ExpectedAction: multistep.ActionContinue,
|
||||
},
|
||||
{
|
||||
Name: "UseOSLoginWithAccountFile",
|
||||
UseOSLogin: true,
|
||||
ExpectedAction: multistep.ActionContinue,
|
||||
ExpectedEmail: "raffi-compute@developer.gserviceaccount.com",
|
||||
PubKeyExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
tc := tc
|
||||
state := testState(t)
|
||||
step := new(StepImportOSLoginSSHKey)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.UseOSLogin = tc.UseOSLogin
|
||||
|
||||
if tc.PubKeyExpected {
|
||||
config.Comm.SSHPublicKey = []byte{'k', 'e', 'y'}
|
||||
}
|
||||
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if step.accountEmail != tc.ExpectedEmail {
|
||||
t.Fatalf("expected accountEmail to be %q but got %q", tc.ExpectedEmail, step.accountEmail)
|
||||
}
|
||||
|
||||
if _, ok := state.GetOk("ssh_key_public_sha256"); !ok && tc.PubKeyExpected {
|
||||
t.Fatal("expected to see a public key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepImportOSLoginSSHKey_withAccountFile(t *testing.T) {
|
||||
// default teststate contains an account file
|
||||
state := testState(t)
|
||||
step := new(StepImportOSLoginSSHKey)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.UseOSLogin = true
|
||||
config.Comm.SSHPublicKey = []byte{'k', 'e', 'y'}
|
||||
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
fakeAccountEmail := "raffi-compute@developer.gserviceaccount.com"
|
||||
if step.accountEmail != fakeAccountEmail {
|
||||
t.Fatalf("expected accountEmail to be %q but got %q", fakeAccountEmail, step.accountEmail)
|
||||
}
|
||||
|
||||
pubKey, ok := state.GetOk("ssh_key_public_sha256")
|
||||
if !ok {
|
||||
t.Fatal("expected to see a public key")
|
||||
}
|
||||
|
||||
sha256sum := sha256.Sum256(config.Comm.SSHPublicKey)
|
||||
if pubKey != hex.EncodeToString(sha256sum[:]) {
|
||||
t.Errorf("expected to see a matching public key, but got %q", pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepImportOSLoginSSHKey_withNoAccountFile(t *testing.T) {
|
||||
state := testState(t)
|
||||
fakeAccountEmail := "testing@packer.io"
|
||||
step := &StepImportOSLoginSSHKey{
|
||||
TokeninfoFunc: func(ctx context.Context) (*oauth2.Tokeninfo, error) {
|
||||
return &oauth2.Tokeninfo{Email: fakeAccountEmail}, nil
|
||||
},
|
||||
}
|
||||
defer step.Cleanup(state)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.account = nil
|
||||
config.UseOSLogin = true
|
||||
config.Comm.SSHPublicKey = []byte{'k', 'e', 'y'}
|
||||
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if step.accountEmail != fakeAccountEmail {
|
||||
t.Fatalf("expected accountEmail to be %q but got %q", fakeAccountEmail, step.accountEmail)
|
||||
}
|
||||
|
||||
pubKey, ok := state.GetOk("ssh_key_public_sha256")
|
||||
if !ok {
|
||||
t.Fatal("expected to see a public key")
|
||||
}
|
||||
|
||||
sha256sum := sha256.Sum256(config.Comm.SSHPublicKey)
|
||||
if pubKey != hex.EncodeToString(sha256sum[:]) {
|
||||
t.Errorf("expected to see a matching public key, but got %q", pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepImportOSLoginSSHKey_withPrivateSSHKey(t *testing.T) {
|
||||
// default teststate contains an account file
|
||||
state := testState(t)
|
||||
step := new(StepImportOSLoginSSHKey)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.UseOSLogin = true
|
||||
config.Comm.SSHPrivateKey = []byte{'k', 'e', 'y'}
|
||||
config.Comm.SSHPublicKey = nil
|
||||
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if step.accountEmail != "" {
|
||||
t.Fatalf("expected accountEmail to be unset but got %q", step.accountEmail)
|
||||
}
|
||||
|
||||
pubKey, ok := state.GetOk("ssh_key_public_sha256")
|
||||
if ok {
|
||||
t.Errorf("expected to not see a public key when using a dedicated private key, but got %q", pubKey)
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepInstanceInfo_impl(t *testing.T) {
|
||||
var _ multistep.Step = new(StepInstanceInfo)
|
||||
}
|
||||
|
||||
func TestStepInstanceInfo(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepInstanceInfo)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("instance_name", "foo")
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.GetNatIPResult = "1.2.3.4"
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), 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 != "1.2.3.4" {
|
||||
t.Fatalf("bad ip: %s", ip)
|
||||
}
|
||||
}
|
||||
|
||||
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(context.Background(), 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)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("instance_name", "foo")
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.GetNatIPErr = errors.New("error")
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if _, ok := state.GetOk("error"); !ok {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if _, ok := state.GetOk("instance_ip"); ok {
|
||||
t.Fatal("should NOT have instance IP")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepInstanceInfo_waitError(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepInstanceInfo)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
state.Put("instance_name", "foo")
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
errCh <- errors.New("error")
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.WaitForInstanceErrCh = errCh
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if _, ok := state.GetOk("error"); !ok {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if _, ok := state.GetOk("instance_ip"); ok {
|
||||
t.Fatal("should NOT have instance IP")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepInstanceInfo_errorTimeout(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepInstanceInfo)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
<-time.After(50 * time.Millisecond)
|
||||
errCh <- nil
|
||||
}()
|
||||
|
||||
state.Put("instance_name", "foo")
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
config.StateTimeout = 1 * time.Millisecond
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.WaitForInstanceErrCh = errCh
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
// Verify state
|
||||
if _, ok := state.GetOk("error"); !ok {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if _, ok := state.GetOk("instance_ip"); ok {
|
||||
t.Fatal("should NOT have instance IP")
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
)
|
||||
|
||||
type MockTunnelDriver struct {
|
||||
StopTunnelCalled bool
|
||||
StartTunnelCalled bool
|
||||
StartTunnelTimeout int
|
||||
}
|
||||
|
||||
func (m *MockTunnelDriver) StopTunnel() {
|
||||
m.StopTunnelCalled = true
|
||||
}
|
||||
|
||||
func (m *MockTunnelDriver) StartTunnel(_ context.Context, _ string, timeout int) error {
|
||||
m.StartTunnelCalled = true
|
||||
m.StartTunnelTimeout = timeout
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTestStepStartTunnel() *StepStartTunnel {
|
||||
return &StepStartTunnel{
|
||||
IAPConf: &IAPConfig{
|
||||
IAP: true,
|
||||
IAPLocalhostPort: 0,
|
||||
IAPHashBang: "/bin/bash",
|
||||
IAPExt: "",
|
||||
},
|
||||
CommConf: &communicator.Config{
|
||||
SSH: communicator.SSH{
|
||||
SSHPort: 1234,
|
||||
},
|
||||
},
|
||||
AccountFile: "/path/to/account_file.json",
|
||||
ProjectId: "fake-project-123",
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepStartTunnel_CreateTempScript(t *testing.T) {
|
||||
s := getTestStepStartTunnel()
|
||||
|
||||
args := []string{"compute", "start-iap-tunnel", "fakeinstance-12345",
|
||||
"1234", "--local-host-port=localhost:8774", "--zone", "us-central-b",
|
||||
"--project", "fake-project-123"}
|
||||
|
||||
scriptPath, err := s.createTempGcloudScript(args)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have error building script file.")
|
||||
}
|
||||
defer os.Remove(scriptPath)
|
||||
|
||||
f, err := ioutil.ReadFile(scriptPath)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't read created inventoryfile: %s", err)
|
||||
}
|
||||
|
||||
expected := `#!/bin/bash
|
||||
|
||||
gcloud auth activate-service-account --key-file='/path/to/account_file.json'
|
||||
gcloud compute start-iap-tunnel fakeinstance-12345 1234 --local-host-port=localhost:8774 --zone us-central-b --project fake-project-123
|
||||
`
|
||||
if runtime.GOOS == "windows" {
|
||||
// in real life you'd not be passing a HashBang here, but GIGO.
|
||||
expected = `#!/bin/bash
|
||||
|
||||
call gcloud auth activate-service-account --key-file "/path/to/account_file.json"
|
||||
call gcloud compute start-iap-tunnel fakeinstance-12345 1234 --local-host-port=localhost:8774 --zone us-central-b --project fake-project-123
|
||||
`
|
||||
}
|
||||
if fmt.Sprintf("%s", f) != expected {
|
||||
t.Fatalf("script didn't match expected:\n\n expected: \n%s\n; recieved: \n%s\n", expected, f)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepStartTunnel_Cleanup(t *testing.T) {
|
||||
// Check IAP true
|
||||
s := getTestStepStartTunnel()
|
||||
td := &MockTunnelDriver{}
|
||||
s.tunnelDriver = td
|
||||
|
||||
state := testState(t)
|
||||
s.Cleanup(state)
|
||||
|
||||
if !td.StopTunnelCalled {
|
||||
t.Fatalf("Should have called StopTunnel, since IAP is true")
|
||||
}
|
||||
|
||||
// Check IAP false
|
||||
s = getTestStepStartTunnel()
|
||||
td = &MockTunnelDriver{}
|
||||
s.tunnelDriver = td
|
||||
|
||||
s.IAPConf.IAP = false
|
||||
|
||||
s.Cleanup(state)
|
||||
|
||||
if td.StopTunnelCalled {
|
||||
t.Fatalf("Should not have called StopTunnel, since IAP is false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepStartTunnel_ConfigurePort_port_set_by_user(t *testing.T) {
|
||||
s := getTestStepStartTunnel()
|
||||
s.IAPConf.IAPLocalhostPort = 8447
|
||||
|
||||
ctx := context.TODO()
|
||||
err := s.ConfigureLocalHostPort(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have error detecting port")
|
||||
}
|
||||
if s.IAPConf.IAPLocalhostPort != 8447 {
|
||||
t.Fatalf("Shouldn't have found new port; one was configured.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepStartTunnel_ConfigurePort_port_not_set_by_user(t *testing.T) {
|
||||
s := getTestStepStartTunnel()
|
||||
s.IAPConf.IAPLocalhostPort = 0
|
||||
|
||||
ctx := context.TODO()
|
||||
err := s.ConfigureLocalHostPort(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have error detecting port")
|
||||
}
|
||||
if s.IAPConf.IAPLocalhostPort == 0 {
|
||||
t.Fatalf("Should have found new port; none was configured.")
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepTeardownInstance_impl(t *testing.T) {
|
||||
var _ multistep.Step = new(StepTeardownInstance)
|
||||
}
|
||||
|
||||
func TestStepTeardownInstance(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepTeardownInstance)
|
||||
defer step.Cleanup(state)
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
|
||||
// run the step
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
|
||||
if driver.DeleteInstanceName != config.InstanceName {
|
||||
t.Fatal("should've deleted instance")
|
||||
}
|
||||
if driver.DeleteInstanceZone != config.Zone {
|
||||
t.Fatalf("bad zone: %#v", driver.DeleteInstanceZone)
|
||||
}
|
||||
|
||||
// cleanup
|
||||
step.Cleanup(state)
|
||||
|
||||
if driver.DeleteDiskName != config.InstanceName {
|
||||
t.Fatal("should've deleted disk")
|
||||
}
|
||||
if driver.DeleteDiskZone != config.Zone {
|
||||
t.Fatalf("bad zone: %#v", driver.DeleteDiskZone)
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testState(t *testing.T) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", testConfigStruct(t))
|
||||
state.Put("driver", &DriverMock{})
|
||||
state.Put("hook", &packersdk.MockHook{})
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
return state
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStepWaitStartupScript(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepWaitStartupScript)
|
||||
c := state.Get("config").(*Config)
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
|
||||
testZone := "test-zone"
|
||||
testInstanceName := "test-instance-name"
|
||||
|
||||
c.Zone = testZone
|
||||
state.Put("instance_name", testInstanceName)
|
||||
|
||||
// This step stops when it gets Done back from the metadata.
|
||||
d.GetInstanceMetadataResult = StartupScriptStatusDone
|
||||
|
||||
// Run the step.
|
||||
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionContinue, "Step should have passed and continued.")
|
||||
|
||||
// Check that GetInstanceMetadata was called properly.
|
||||
assert.Equal(t, d.GetInstanceMetadataZone, testZone, "Incorrect zone passed to GetInstanceMetadata.")
|
||||
assert.Equal(t, d.GetInstanceMetadataName, testInstanceName, "Incorrect instance name passed to GetInstanceMetadata.")
|
||||
}
|
||||
|
||||
func TestStepWaitStartupScript_withWrapStartupScript(t *testing.T) {
|
||||
tt := []struct {
|
||||
WrapStartup config.Trilean
|
||||
Result, Zone, MetadataName string
|
||||
}{
|
||||
{WrapStartup: config.TriTrue, Result: StartupScriptStatusDone, Zone: "test-zone", MetadataName: "test-instance-name"},
|
||||
{WrapStartup: config.TriFalse},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
tc := tc
|
||||
state := testState(t)
|
||||
step := new(StepWaitStartupScript)
|
||||
c := state.Get("config").(*Config)
|
||||
d := state.Get("driver").(*DriverMock)
|
||||
|
||||
c.StartupScriptFile = "startup.sh"
|
||||
c.WrapStartupScriptFile = tc.WrapStartup
|
||||
c.Zone = "test-zone"
|
||||
state.Put("instance_name", "test-instance-name")
|
||||
|
||||
// This step stops when it gets Done back from the metadata.
|
||||
d.GetInstanceMetadataResult = tc.Result
|
||||
|
||||
// Run the step.
|
||||
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionContinue, "Step should have continued.")
|
||||
|
||||
assert.Equal(t, d.GetInstanceMetadataResult, tc.Result, "MetadataResult was not the expected value.")
|
||||
assert.Equal(t, d.GetInstanceMetadataZone, tc.Zone, "Zone was not the expected value.")
|
||||
assert.Equal(t, d.GetInstanceMetadataName, tc.MetadataName, "Instance name was not the expected value.")
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package googlecompute
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_templateCleanImageName(t *testing.T) {
|
||||
vals := []struct {
|
||||
origName string
|
||||
expected string
|
||||
}{
|
||||
// test that valid name is unchanged
|
||||
{
|
||||
origName: "abcde-012345xyz",
|
||||
expected: "abcde-012345xyz",
|
||||
},
|
||||
|
||||
//test that capital letters are converted to lowercase
|
||||
{
|
||||
origName: "ABCDE-012345xyz",
|
||||
expected: "abcde-012345xyz",
|
||||
},
|
||||
// test that periods and colons are converted to hyphens
|
||||
{
|
||||
origName: "abcde-012345v1.0:0",
|
||||
expected: "abcde-012345v1-0-0",
|
||||
},
|
||||
// Name starting with number is not valid, but not in scope of this
|
||||
// function to correct
|
||||
{
|
||||
origName: "012345v1.0:0",
|
||||
expected: "012345v1-0-0",
|
||||
},
|
||||
// Name over 64 chars is not valid, but not corrected by this function.
|
||||
{
|
||||
origName: "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
|
||||
expected: "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range vals {
|
||||
name := templateCleanImageName(v.origName)
|
||||
if name != v.expected {
|
||||
t.Fatalf("template names do not match: expected %s got %s\n", v.expected, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_basic(t *testing.T) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate mapstructure-to-hcl2 -type Config,imageFilter
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,imageFilter
|
||||
|
||||
package hcloud
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config,imageFilter"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package hcloud
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_basic(t *testing.T) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package hyperone
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package hyperone
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate packer-sdc struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type OutputConfig
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type OutputConfig
|
||||
|
||||
package common
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type OutputConfig"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package common
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package iso
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package iso
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package vmcx
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package vmcx
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package jdcloud
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package jdcloud
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_basic(t *testing.T) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package linode
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package linode
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package lxc
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package lxc
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type Config
|
||||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package lxd
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
||||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package lxd
|
||||
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
// Builder assume this implements packersdk.Builder
|
||||
type Builder struct {
|
||||
config Config
|
||||
stateBag multistep.StateBag
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
||||
warnings, errs := b.config.Prepare(raws...)
|
||||
if errs != nil {
|
||||
return nil, warnings, errs
|
||||
}
|
||||
|
||||
b.stateBag = new(multistep.BasicStateBag)
|
||||
|
||||
return nil, warnings, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
|
||||
ui.Message("Creating Naver Cloud Platform Connection ...")
|
||||
config := Config{
|
||||
AccessKey: b.config.AccessKey,
|
||||
SecretKey: b.config.SecretKey,
|
||||
}
|
||||
|
||||
conn, err := config.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.stateBag.Put("hook", hook)
|
||||
b.stateBag.Put("ui", ui)
|
||||
|
||||
var steps []multistep.Step
|
||||
|
||||
steps = []multistep.Step{}
|
||||
|
||||
if b.config.Comm.Type == "ssh" {
|
||||
steps = []multistep.Step{
|
||||
NewStepValidateTemplate(conn, ui, &b.config),
|
||||
NewStepCreateLoginKey(conn, ui),
|
||||
NewStepCreateServerInstance(conn, ui, &b.config),
|
||||
NewStepCreateBlockStorageInstance(conn, ui, &b.config),
|
||||
NewStepGetRootPassword(conn, ui, &b.config),
|
||||
NewStepCreatePublicIPInstance(conn, ui, &b.config),
|
||||
&communicator.StepConnectSSH{
|
||||
Config: &b.config.Comm,
|
||||
Host: func(stateBag multistep.StateBag) (string, error) {
|
||||
return stateBag.Get("PublicIP").(string), nil
|
||||
},
|
||||
SSHConfig: b.config.Comm.SSHConfigFunc(),
|
||||
},
|
||||
&commonsteps.StepProvision{},
|
||||
&commonsteps.StepCleanupTempKeys{
|
||||
Comm: &b.config.Comm,
|
||||
},
|
||||
NewStepStopServerInstance(conn, ui),
|
||||
NewStepCreateServerImage(conn, ui, &b.config),
|
||||
NewStepDeleteBlockStorageInstance(conn, ui, &b.config),
|
||||
NewStepTerminateServerInstance(conn, ui),
|
||||
}
|
||||
} else if b.config.Comm.Type == "winrm" {
|
||||
steps = []multistep.Step{
|
||||
NewStepValidateTemplate(conn, ui, &b.config),
|
||||
NewStepCreateLoginKey(conn, ui),
|
||||
NewStepCreateServerInstance(conn, ui, &b.config),
|
||||
NewStepCreateBlockStorageInstance(conn, ui, &b.config),
|
||||
NewStepGetRootPassword(conn, ui, &b.config),
|
||||
NewStepCreatePublicIPInstance(conn, ui, &b.config),
|
||||
&communicator.StepConnectWinRM{
|
||||
Config: &b.config.Comm,
|
||||
Host: func(stateBag multistep.StateBag) (string, error) {
|
||||
return stateBag.Get("PublicIP").(string), nil
|
||||
},
|
||||
WinRMConfig: func(state multistep.StateBag) (*communicator.WinRMConfig, error) {
|
||||
return &communicator.WinRMConfig{
|
||||
Username: b.config.Comm.WinRMUser,
|
||||
Password: b.config.Comm.WinRMPassword,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
&commonsteps.StepProvision{},
|
||||
NewStepStopServerInstance(conn, ui),
|
||||
NewStepCreateServerImage(conn, ui, &b.config),
|
||||
NewStepDeleteBlockStorageInstance(conn, ui, &b.config),
|
||||
NewStepTerminateServerInstance(conn, ui),
|
||||
}
|
||||
}
|
||||
|
||||
// Run!
|
||||
b.runner = commonsteps.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, b.stateBag)
|
||||
b.runner.Run(ctx, b.stateBag)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := b.stateBag.GetOk("Error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &Artifact{
|
||||
StateData: map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")},
|
||||
}
|
||||
|
||||
if serverImage, ok := b.stateBag.GetOk("memberServerImage"); ok {
|
||||
artifact.MemberServerImage = serverImage.(*server.MemberServerImage)
|
||||
}
|
||||
|
||||
return artifact, nil
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "access_key",
|
||||
"secret_key": "secret_key",
|
||||
"server_image_product_code": "SPSW0WINNT000016",
|
||||
"server_product_code": "SPSVRSSD00000011",
|
||||
"server_image_name": "packer-test {{timestamp}}",
|
||||
"server_image_description": "server description",
|
||||
"block_storage_size": 100,
|
||||
"user_data": "#!/bin/sh\nyum install -y httpd\ntouch /var/www/html/index.html\nchkconfig --level 2345 httpd on",
|
||||
"region": "Korea",
|
||||
"access_control_group_configuration_no": "33",
|
||||
"communicator": "ssh",
|
||||
"ssh_username": "root",
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigForMemberServerImage() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "access_key",
|
||||
"secret_key": "secret_key",
|
||||
"server_product_code": "SPSVRSSD00000011",
|
||||
"member_server_image_no": "2440",
|
||||
"server_image_name": "packer-test {{timestamp}}",
|
||||
"server_image_description": "server description",
|
||||
"block_storage_size": 100,
|
||||
"user_data": "#!/bin/sh\nyum install -y httpd\ntouch /var/www/html/index.html\nchkconfig --level 2345 httpd on",
|
||||
"region": "Korea",
|
||||
"access_control_group_configuration_no": "33",
|
||||
"communicator": "ssh",
|
||||
"ssh_username": "root",
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigWithServerImageProductCode(t *testing.T) {
|
||||
raw := testConfig()
|
||||
|
||||
var c Config
|
||||
c.Prepare(raw)
|
||||
|
||||
if c.AccessKey != "access_key" {
|
||||
t.Errorf("Expected 'access_key' to be set to '%s', but got '%s'.", raw["access_key"], c.AccessKey)
|
||||
}
|
||||
|
||||
if c.SecretKey != "secret_key" {
|
||||
t.Errorf("Expected 'secret_key' to be set to '%s', but got '%s'.", raw["secret_key"], c.SecretKey)
|
||||
}
|
||||
|
||||
if c.ServerImageProductCode != "SPSW0WINNT000016" {
|
||||
t.Errorf("Expected 'server_image_product_code' to be set to '%s', but got '%s'.", raw["server_image_product_code"], c.ServerImageProductCode)
|
||||
}
|
||||
|
||||
if c.ServerProductCode != "SPSVRSSD00000011" {
|
||||
t.Errorf("Expected 'server_product_code' to be set to '%s', but got '%s'.", raw["server_product_code"], c.ServerProductCode)
|
||||
}
|
||||
|
||||
if c.BlockStorageSize != 100 {
|
||||
t.Errorf("Expected 'block_storage_size' to be set to '%d', but got '%d'.", raw["block_storage_size"], c.BlockStorageSize)
|
||||
}
|
||||
|
||||
if c.ServerImageDescription != "server description" {
|
||||
t.Errorf("Expected 'server_image_description_key' to be set to '%s', but got '%s'.", raw["server_image_description"], c.ServerImageDescription)
|
||||
}
|
||||
|
||||
if c.Region != "Korea" {
|
||||
t.Errorf("Expected 'region' to be set to '%s', but got '%s'.", raw["server_image_description"], c.Region)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigWithMemberServerImageCode(t *testing.T) {
|
||||
raw := testConfigForMemberServerImage()
|
||||
|
||||
var c Config
|
||||
c.Prepare(raw)
|
||||
|
||||
if c.AccessKey != "access_key" {
|
||||
t.Errorf("Expected 'access_key' to be set to '%s', but got '%s'.", raw["access_key"], c.AccessKey)
|
||||
}
|
||||
|
||||
if c.SecretKey != "secret_key" {
|
||||
t.Errorf("Expected 'secret_key' to be set to '%s', but got '%s'.", raw["secret_key"], c.SecretKey)
|
||||
}
|
||||
|
||||
if c.MemberServerImageNo != "2440" {
|
||||
t.Errorf("Expected 'member_server_image_no' to be set to '%s', but got '%s'.", raw["member_server_image_no"], c.MemberServerImageNo)
|
||||
}
|
||||
|
||||
if c.ServerProductCode != "SPSVRSSD00000011" {
|
||||
t.Errorf("Expected 'server_product_code' to be set to '%s', but got '%s'.", raw["server_product_code"], c.ServerProductCode)
|
||||
}
|
||||
|
||||
if c.BlockStorageSize != 100 {
|
||||
t.Errorf("Expected 'block_storage_size' to be set to '%d', but got '%d'.", raw["block_storage_size"], c.BlockStorageSize)
|
||||
}
|
||||
|
||||
if c.ServerImageDescription != "server description" {
|
||||
t.Errorf("Expected 'server_image_description_key' to be set to '%s', but got '%s'.", raw["server_image_description"], c.ServerImageDescription)
|
||||
}
|
||||
|
||||
if c.Region != "Korea" {
|
||||
t.Errorf("Expected 'region' to be set to '%s', but got '%s'.", raw["server_image_description"], c.Region)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyConfig(t *testing.T) {
|
||||
raw := new(map[string]interface{})
|
||||
|
||||
var c Config
|
||||
_, err := c.Prepare(raw)
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected Config to require 'access_key', 'secret_key' and some mandatory fields, but it did not")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "access_key is required") {
|
||||
t.Error("Expected Config to require 'access_key', but it did not")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "secret_key is required") {
|
||||
t.Error("Expected Config to require 'secret_key', but it did not")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "server_image_product_code or member_server_image_no is required") {
|
||||
t.Error("Expected Config to require 'server_image_product_code' or 'member_server_image_no', but it did not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExistsBothServerImageProductCodeAndMemberServerImageNoConfig(t *testing.T) {
|
||||
raw := map[string]interface{}{
|
||||
"access_key": "access_key",
|
||||
"secret_key": "secret_key",
|
||||
"server_image_product_code": "SPSW0WINNT000016",
|
||||
"server_product_code": "SPSVRSSD00000011",
|
||||
"member_server_image_no": "2440",
|
||||
}
|
||||
|
||||
var c Config
|
||||
_, err := c.Prepare(raw)
|
||||
|
||||
if !strings.Contains(err.Error(), "Only one of server_image_product_code and member_server_image_no can be set") {
|
||||
t.Error("Expected Config to require Only one of 'server_image_product_code' and 'member_server_image_no' can be set, but it did not")
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud"
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
// StepCreateBlockStorageInstance struct is for making extra block storage
|
||||
type StepCreateBlockStorageInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
CreateBlockStorageInstance func(serverInstanceNo string) (*string, error)
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
}
|
||||
|
||||
// NewStepCreateBlockStorageInstance make StepCreateBlockStorage struct to make extra block storage
|
||||
func NewStepCreateBlockStorageInstance(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepCreateBlockStorageInstance {
|
||||
var step = &StepCreateBlockStorageInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.CreateBlockStorageInstance = step.createBlockStorageInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreateBlockStorageInstance) createBlockStorageInstance(serverInstanceNo string) (*string, error) {
|
||||
|
||||
reqParams := new(server.CreateBlockStorageInstanceRequest)
|
||||
reqParams.BlockStorageSize = ncloud.Int64(int64(s.Config.BlockStorageSize))
|
||||
reqParams.ServerInstanceNo = &serverInstanceNo
|
||||
|
||||
resp, err := s.Conn.server.V2Api.CreateBlockStorageInstance(reqParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockStorageInstance := resp.BlockStorageInstanceList[0]
|
||||
log.Println("Block Storage Instance information : ", blockStorageInstance.BlockStorageInstanceNo)
|
||||
|
||||
if err := waiterBlockStorageInstanceStatus(s.Conn, blockStorageInstance.BlockStorageInstanceNo, "ATTAC", 10*time.Minute); err != nil {
|
||||
return nil, errors.New("TIMEOUT : Block Storage instance status is not attached")
|
||||
}
|
||||
|
||||
return blockStorageInstance.BlockStorageInstanceNo, nil
|
||||
}
|
||||
|
||||
func (s *StepCreateBlockStorageInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
if s.Config.BlockStorageSize == 0 {
|
||||
return processStepResult(nil, s.Error, state)
|
||||
}
|
||||
|
||||
s.Say("Create extra block storage instance")
|
||||
|
||||
serverInstanceNo := state.Get("InstanceNo").(string)
|
||||
|
||||
blockStorageInstanceNo, err := s.CreateBlockStorageInstance(serverInstanceNo)
|
||||
if err == nil {
|
||||
state.Put("BlockStorageInstanceNo", *blockStorageInstanceNo)
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (s *StepCreateBlockStorageInstance) Cleanup(state multistep.StateBag) {
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if !cancelled && !halted {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Config.BlockStorageSize == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if blockStorageInstanceNo, ok := state.GetOk("BlockStorageInstanceNo"); ok {
|
||||
s.Say("Clean up Block Storage Instance")
|
||||
reqParams := server.DeleteBlockStorageInstancesRequest{
|
||||
BlockStorageInstanceNoList: []*string{blockStorageInstanceNo.(*string)},
|
||||
}
|
||||
blockStorageInstanceList, err := s.Conn.server.V2Api.DeleteBlockStorageInstances(&reqParams)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Block Storage Instance is deleted. Block Storage InstanceNo is %s", blockStorageInstanceNo.(string)))
|
||||
log.Println("Block Storage Instance information : ", blockStorageInstanceList.BlockStorageInstanceList[0])
|
||||
|
||||
if err := waiterBlockStorageInstanceStatus(s.Conn, blockStorageInstanceNo.(*string), "DETAC", time.Minute); err != nil {
|
||||
s.Say("TIMEOUT : Block Storage instance status is not deattached")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCreateBlockStorageInstanceShouldFailIfOperationCreateBlockStorageInstanceFails(t *testing.T) {
|
||||
|
||||
var testSubject = &StepCreateBlockStorageInstance{
|
||||
CreateBlockStorageInstance: func(serverInstanceNo string) (*string, error) { return nil, fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: new(Config),
|
||||
}
|
||||
|
||||
testSubject.Config.BlockStorageSize = 10
|
||||
|
||||
stateBag := createTestStateBagStepCreateBlockStorageInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateBlockStorageInstanceShouldPassIfOperationCreateBlockStorageInstancePasses(t *testing.T) {
|
||||
var instanceNo = "a"
|
||||
var testSubject = &StepCreateBlockStorageInstance{
|
||||
CreateBlockStorageInstance: func(serverInstanceNo string) (*string, error) { return &instanceNo, nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: new(Config),
|
||||
}
|
||||
|
||||
testSubject.Config.BlockStorageSize = 10
|
||||
|
||||
stateBag := createTestStateBagStepCreateBlockStorageInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepCreateBlockStorageInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type LoginKey struct {
|
||||
KeyName string
|
||||
PrivateKey string
|
||||
}
|
||||
|
||||
type StepCreateLoginKey struct {
|
||||
Conn *NcloudAPIClient
|
||||
CreateLoginKey func() (*LoginKey, error)
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
}
|
||||
|
||||
func NewStepCreateLoginKey(conn *NcloudAPIClient, ui packersdk.Ui) *StepCreateLoginKey {
|
||||
var step = &StepCreateLoginKey{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
}
|
||||
|
||||
step.CreateLoginKey = step.createLoginKey
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreateLoginKey) createLoginKey() (*LoginKey, error) {
|
||||
keyName := fmt.Sprintf("packer-%d", time.Now().Unix())
|
||||
reqParams := &server.CreateLoginKeyRequest{KeyName: &keyName}
|
||||
|
||||
privateKey, err := s.Conn.server.V2Api.CreateLoginKey(reqParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LoginKey{keyName, *privateKey.PrivateKey}, nil
|
||||
}
|
||||
|
||||
func (s *StepCreateLoginKey) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Create Login Key")
|
||||
|
||||
loginKey, err := s.CreateLoginKey()
|
||||
if err == nil {
|
||||
state.Put("LoginKey", loginKey)
|
||||
s.Say(fmt.Sprintf("Login Key[%s] is created", loginKey.KeyName))
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (s *StepCreateLoginKey) Cleanup(state multistep.StateBag) {
|
||||
if loginKey, ok := state.GetOk("LoginKey"); ok {
|
||||
s.Say("Clean up login key")
|
||||
reqParams := &server.DeleteLoginKeyRequest{KeyName: &loginKey.(*LoginKey).KeyName}
|
||||
s.Conn.server.V2Api.DeleteLoginKey(reqParams)
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCreateLoginKeyShouldFailIfOperationCreateLoginKeyFails(t *testing.T) {
|
||||
var testSubject = &StepCreateLoginKey{
|
||||
CreateLoginKey: func() (*LoginKey, error) { return nil, fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateLoginKey()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateLoginKeyShouldPassIfOperationCreateLoginKeyPasses(t *testing.T) {
|
||||
var testSubject = &StepCreateLoginKey{
|
||||
CreateLoginKey: func() (*LoginKey, error) { return &LoginKey{"a", "b"}, nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateLoginKey()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepCreateLoginKey() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud"
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepCreatePublicIPInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
CreatePublicIPInstance func(serverInstanceNo string) (*server.PublicIpInstance, error)
|
||||
WaiterAssociatePublicIPToServerInstance func(serverInstanceNo string, publicIP string) error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
}
|
||||
|
||||
func NewStepCreatePublicIPInstance(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepCreatePublicIPInstance {
|
||||
var step = &StepCreatePublicIPInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.CreatePublicIPInstance = step.createPublicIPInstance
|
||||
step.WaiterAssociatePublicIPToServerInstance = step.waiterAssociatePublicIPToServerInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreatePublicIPInstance) waiterAssociatePublicIPToServerInstance(serverInstanceNo string, publicIP string) error {
|
||||
reqParams := new(server.GetServerInstanceListRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&serverInstanceNo}
|
||||
|
||||
c1 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
serverInstanceList, err := s.Conn.server.V2Api.GetServerInstanceList(reqParams)
|
||||
|
||||
if err != nil {
|
||||
c1 <- err
|
||||
return
|
||||
}
|
||||
|
||||
if publicIP == *serverInstanceList.ServerInstanceList[0].PublicIp {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
s.Say("Wait to associate public ip serverInstance")
|
||||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-c1:
|
||||
return res
|
||||
case <-time.After(time.Second * 60):
|
||||
return fmt.Errorf("TIMEOUT : association public ip[%s] to server instance[%s] Failed", publicIP, serverInstanceNo)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepCreatePublicIPInstance) createPublicIPInstance(serverInstanceNo string) (*server.PublicIpInstance, error) {
|
||||
reqParams := new(server.CreatePublicIpInstanceRequest)
|
||||
reqParams.ServerInstanceNo = &serverInstanceNo
|
||||
|
||||
publicIPInstanceList, err := s.Conn.server.V2Api.CreatePublicIpInstance(reqParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
publicIPInstance := publicIPInstanceList.PublicIpInstanceList[0]
|
||||
publicIP := publicIPInstance.PublicIp
|
||||
s.Say(fmt.Sprintf("Public IP Instance [%s:%s] is created", *publicIPInstance.PublicIpInstanceNo, *publicIP))
|
||||
|
||||
err = s.waiterAssociatePublicIPToServerInstance(serverInstanceNo, *publicIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return publicIPInstance, nil
|
||||
}
|
||||
|
||||
func (s *StepCreatePublicIPInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Create Public IP Instance")
|
||||
|
||||
serverInstanceNo := state.Get("InstanceNo").(string)
|
||||
|
||||
publicIPInstance, err := s.CreatePublicIPInstance(serverInstanceNo)
|
||||
if err == nil {
|
||||
state.Put("PublicIP", *publicIPInstance.PublicIp)
|
||||
state.Put("PublicIPInstance", publicIPInstance)
|
||||
// instance_id is the generic term used so that users can have access to the
|
||||
// instance id inside of the provisioners, used in step_provision.
|
||||
state.Put("instance_id", *publicIPInstance)
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (s *StepCreatePublicIPInstance) Cleanup(state multistep.StateBag) {
|
||||
publicIPInstance, ok := state.GetOk("PublicIPInstance")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
s.Say("Clean up Public IP Instance")
|
||||
publicIPInstanceNo := publicIPInstance.(*server.PublicIpInstance).PublicIpInstanceNo
|
||||
s.waitPublicIPInstanceStatus(publicIPInstanceNo, "USED")
|
||||
|
||||
log.Println("Disassociate Public IP Instance ", publicIPInstanceNo)
|
||||
reqParams := &server.DisassociatePublicIpFromServerInstanceRequest{PublicIpInstanceNo: publicIPInstanceNo}
|
||||
s.Conn.server.V2Api.DisassociatePublicIpFromServerInstance(reqParams)
|
||||
|
||||
s.waitPublicIPInstanceStatus(publicIPInstanceNo, "CREAT")
|
||||
|
||||
reqDeleteParams := &server.DeletePublicIpInstancesRequest{
|
||||
PublicIpInstanceNoList: ncloud.StringList([]string{*publicIPInstanceNo}),
|
||||
}
|
||||
|
||||
log.Println("Delete Public IP Instance ", publicIPInstanceNo)
|
||||
s.Conn.server.V2Api.DeletePublicIpInstances(reqDeleteParams)
|
||||
}
|
||||
|
||||
func (s *StepCreatePublicIPInstance) waitPublicIPInstanceStatus(publicIPInstanceNo *string, status string) {
|
||||
c1 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
reqParams := new(server.GetPublicIpInstanceListRequest)
|
||||
reqParams.PublicIpInstanceNoList = []*string{publicIPInstanceNo}
|
||||
|
||||
for {
|
||||
resp, err := s.Conn.server.V2Api.GetPublicIpInstanceList(reqParams)
|
||||
if err != nil {
|
||||
log.Printf(err.Error())
|
||||
c1 <- err
|
||||
return
|
||||
}
|
||||
|
||||
if *resp.TotalRows == 0 {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
instance := resp.PublicIpInstanceList[0]
|
||||
if *instance.PublicIpInstanceStatus.Code == status && *instance.PublicIpInstanceOperation.Code == "NULL" {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-c1:
|
||||
return
|
||||
case <-time.After(time.Second * 60):
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud"
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCreatePublicIPInstanceShouldFailIfOperationCreatePublicIPInstanceFails(t *testing.T) {
|
||||
var testSubject = &StepCreatePublicIPInstance{
|
||||
CreatePublicIPInstance: func(serverInstanceNo string) (*server.PublicIpInstance, error) {
|
||||
return nil, fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateServerImage()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreatePublicIPInstanceShouldPassIfOperationCreatePublicIPInstancePasses(t *testing.T) {
|
||||
c := new(Config)
|
||||
c.Comm.Prepare(nil)
|
||||
c.Comm.Type = "ssh"
|
||||
|
||||
var testSubject = &StepCreatePublicIPInstance{
|
||||
CreatePublicIPInstance: func(serverInstanceNo string) (*server.PublicIpInstance, error) {
|
||||
return &server.PublicIpInstance{PublicIpInstanceNo: ncloud.String("a"), PublicIp: ncloud.String("b")}, nil
|
||||
},
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: c,
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreatePublicIPInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepCreatePublicIPInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepCreateServerImage struct {
|
||||
Conn *NcloudAPIClient
|
||||
CreateServerImage func(serverInstanceNo string) (*server.MemberServerImage, error)
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
}
|
||||
|
||||
func NewStepCreateServerImage(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepCreateServerImage {
|
||||
var step = &StepCreateServerImage{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.CreateServerImage = step.createServerImage
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreateServerImage) createServerImage(serverInstanceNo string) (*server.MemberServerImage, error) {
|
||||
// Can't create server image when status of server instance is stopping (not stopped)
|
||||
if err := waiterServerInstanceStatus(s.Conn, serverInstanceNo, "NSTOP", 1*time.Minute); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqParams := new(server.CreateMemberServerImageRequest)
|
||||
reqParams.MemberServerImageName = &s.Config.ServerImageName
|
||||
reqParams.MemberServerImageDescription = &s.Config.ServerImageDescription
|
||||
reqParams.ServerInstanceNo = &serverInstanceNo
|
||||
|
||||
memberServerImageList, err := s.Conn.server.V2Api.CreateMemberServerImage(reqParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverImage := memberServerImageList.MemberServerImageList[0]
|
||||
|
||||
s.Say(fmt.Sprintf("Server Image[%s:%s] is creating...", *serverImage.MemberServerImageName, *serverImage.MemberServerImageNo))
|
||||
|
||||
if err := waiterMemberServerImageStatus(s.Conn, *serverImage.MemberServerImageNo, "CREAT", 6*time.Hour); err != nil {
|
||||
return nil, errors.New("TIMEOUT : Server Image is not created")
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Server Image[%s:%s] is created", *serverImage.MemberServerImageName, *serverImage.MemberServerImageNo))
|
||||
|
||||
return serverImage, nil
|
||||
}
|
||||
|
||||
func (s *StepCreateServerImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Create Server Image")
|
||||
|
||||
serverInstanceNo := state.Get("InstanceNo").(string)
|
||||
|
||||
serverImage, err := s.CreateServerImage(serverInstanceNo)
|
||||
if err == nil {
|
||||
state.Put("memberServerImage", serverImage)
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (*StepCreateServerImage) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCreateServerImageShouldFailIfOperationCreateServerImageFails(t *testing.T) {
|
||||
var testSubject = &StepCreateServerImage{
|
||||
CreateServerImage: func(serverInstanceNo string) (*server.MemberServerImage, error) {
|
||||
return nil, fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateServerImage()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
func TestStepCreateServerImageShouldPassIfOperationCreateServerImagePasses(t *testing.T) {
|
||||
var testSubject = &StepCreateServerImage{
|
||||
CreateServerImage: func(serverInstanceNo string) (*server.MemberServerImage, error) { return nil, nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateServerImage()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepCreateServerImage() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud"
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepCreateServerInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
CreateServerInstance func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error)
|
||||
CheckServerInstanceStatusIsRunning func(serverInstanceNo string) error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
serverInstanceNo string
|
||||
}
|
||||
|
||||
func NewStepCreateServerInstance(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepCreateServerInstance {
|
||||
var step = &StepCreateServerInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.CreateServerInstance = step.createServerInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) {
|
||||
reqParams := new(server.CreateServerInstancesRequest)
|
||||
reqParams.ServerProductCode = &s.Config.ServerProductCode
|
||||
reqParams.MemberServerImageNo = &s.Config.MemberServerImageNo
|
||||
if s.Config.MemberServerImageNo == "" {
|
||||
reqParams.ServerImageProductCode = &s.Config.ServerImageProductCode
|
||||
}
|
||||
reqParams.LoginKeyName = &loginKeyName
|
||||
reqParams.ZoneNo = &zoneNo
|
||||
reqParams.FeeSystemTypeCode = &feeSystemTypeCode
|
||||
|
||||
if s.Config.UserData != "" {
|
||||
reqParams.UserData = &s.Config.UserData
|
||||
}
|
||||
|
||||
if s.Config.UserDataFile != "" {
|
||||
contents, err := ioutil.ReadFile(s.Config.UserDataFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Problem reading user data file: %s", err)
|
||||
}
|
||||
|
||||
reqParams.UserData = ncloud.String(string(contents))
|
||||
}
|
||||
|
||||
if s.Config.AccessControlGroupConfigurationNo != "" {
|
||||
reqParams.AccessControlGroupConfigurationNoList = []*string{&s.Config.AccessControlGroupConfigurationNo}
|
||||
}
|
||||
|
||||
serverInstanceList, err := s.Conn.server.V2Api.CreateServerInstances(reqParams)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
s.serverInstanceNo = *serverInstanceList.ServerInstanceList[0].ServerInstanceNo
|
||||
s.Say(fmt.Sprintf("Server Instance is creating. Server InstanceNo is %s", s.serverInstanceNo))
|
||||
log.Println("Server Instance information : ", serverInstanceList.ServerInstanceList[0])
|
||||
|
||||
if err := waiterServerInstanceStatus(s.Conn, s.serverInstanceNo, "RUN", 30*time.Minute); err != nil {
|
||||
return "", errors.New("TIMEOUT : server instance status is not running")
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Server Instance is created. Server InstanceNo is %s", s.serverInstanceNo))
|
||||
|
||||
return s.serverInstanceNo, nil
|
||||
}
|
||||
|
||||
func (s *StepCreateServerInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Create Server Instance")
|
||||
|
||||
var loginKey = state.Get("LoginKey").(*LoginKey)
|
||||
var zoneNo = state.Get("ZoneNo").(string)
|
||||
|
||||
feeSystemTypeCode := "MTRAT"
|
||||
if _, ok := state.GetOk("FeeSystemTypeCode"); ok {
|
||||
feeSystemTypeCode = state.Get("FeeSystemTypeCode").(string)
|
||||
}
|
||||
|
||||
serverInstanceNo, err := s.CreateServerInstance(loginKey.KeyName, zoneNo, feeSystemTypeCode)
|
||||
if err == nil {
|
||||
state.Put("InstanceNo", serverInstanceNo)
|
||||
// instance_id is the generic term used so that users can have access to the
|
||||
// instance id inside of the provisioners, used in step_provision.
|
||||
state.Put("instance_id", serverInstanceNo)
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (s *StepCreateServerInstance) Cleanup(state multistep.StateBag) {
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if !cancelled && !halted {
|
||||
return
|
||||
}
|
||||
|
||||
if s.serverInstanceNo == "" {
|
||||
return
|
||||
}
|
||||
|
||||
reqParams := new(server.GetServerInstanceListRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&s.serverInstanceNo}
|
||||
|
||||
serverInstanceList, err := s.Conn.server.V2Api.GetServerInstanceList(reqParams)
|
||||
if err != nil || *serverInstanceList.TotalRows == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
s.Say("Clean up Server Instance")
|
||||
|
||||
serverInstance := serverInstanceList.ServerInstanceList[0]
|
||||
// stop server instance
|
||||
if *serverInstance.ServerInstanceStatus.Code != "NSTOP" && *serverInstance.ServerInstanceStatus.Code != "TERMT" {
|
||||
reqParams := new(server.StopServerInstancesRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&s.serverInstanceNo}
|
||||
|
||||
log.Println("Stop Server Instance")
|
||||
s.Conn.server.V2Api.StopServerInstances(reqParams)
|
||||
waiterServerInstanceStatus(s.Conn, s.serverInstanceNo, "NSTOP", time.Minute)
|
||||
}
|
||||
|
||||
// terminate server instance
|
||||
if *serverInstance.ServerInstanceStatus.Code != "TERMT" {
|
||||
reqParams := new(server.TerminateServerInstancesRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&s.serverInstanceNo}
|
||||
|
||||
log.Println("Terminate Server Instance")
|
||||
s.Conn.server.V2Api.TerminateServerInstances(reqParams)
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) {
|
||||
var testSubject = &StepCreateServerInstance{
|
||||
CreateServerInstance: func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) {
|
||||
return "", fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateServerInstanceShouldPassIfOperationCreatePasses(t *testing.T) {
|
||||
var testSubject = &StepCreateServerInstance{
|
||||
CreateServerInstance: func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) { return "", nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepCreateServerInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("LoginKey", &LoginKey{"a", "b"})
|
||||
stateBag.Put("ZoneNo", "1")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepDeleteBlockStorageInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
DeleteBlockStorageInstance func(blockStorageInstanceNo string) error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
}
|
||||
|
||||
func NewStepDeleteBlockStorageInstance(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepDeleteBlockStorageInstance {
|
||||
var step = &StepDeleteBlockStorageInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.DeleteBlockStorageInstance = step.deleteBlockStorageInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepDeleteBlockStorageInstance) getBlockInstanceList(serverInstanceNo string) []*string {
|
||||
reqParams := new(server.GetBlockStorageInstanceListRequest)
|
||||
reqParams.ServerInstanceNo = &serverInstanceNo
|
||||
|
||||
blockStorageInstanceList, err := s.Conn.server.V2Api.GetBlockStorageInstanceList(reqParams)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if *blockStorageInstanceList.TotalRows == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var instanceList []*string
|
||||
|
||||
for _, blockStorageInstance := range blockStorageInstanceList.BlockStorageInstanceList {
|
||||
log.Println(blockStorageInstance)
|
||||
if *blockStorageInstance.BlockStorageType.Code != "BASIC" {
|
||||
instanceList = append(instanceList, blockStorageInstance.BlockStorageInstanceNo)
|
||||
}
|
||||
}
|
||||
|
||||
return instanceList
|
||||
}
|
||||
|
||||
func (s *StepDeleteBlockStorageInstance) deleteBlockStorageInstance(serverInstanceNo string) error {
|
||||
blockStorageInstanceList := s.getBlockInstanceList(serverInstanceNo)
|
||||
if blockStorageInstanceList == nil || len(blockStorageInstanceList) == 0 {
|
||||
return nil
|
||||
}
|
||||
reqParams := server.DeleteBlockStorageInstancesRequest{
|
||||
BlockStorageInstanceNoList: blockStorageInstanceList,
|
||||
}
|
||||
_, err := s.Conn.server.V2Api.DeleteBlockStorageInstances(&reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Block Storage Instance is deleted. Block Storage Instance List is %v", blockStorageInstanceList))
|
||||
|
||||
if err := waiterDetachedBlockStorageInstance(s.Conn, serverInstanceNo, time.Minute); err != nil {
|
||||
return errors.New("TIMEOUT : Block Storage instance status is not deattached")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepDeleteBlockStorageInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
if s.Config.BlockStorageSize == 0 {
|
||||
return processStepResult(nil, s.Error, state)
|
||||
}
|
||||
|
||||
s.Say("Delete Block Storage Instance")
|
||||
|
||||
var serverInstanceNo = state.Get("InstanceNo").(string)
|
||||
|
||||
err := s.DeleteBlockStorageInstance(serverInstanceNo)
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (*StepDeleteBlockStorageInstance) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepDeleteBlockStorageInstanceShouldFailIfOperationDeleteBlockStorageInstanceFails(t *testing.T) {
|
||||
var testSubject = &StepDeleteBlockStorageInstance{
|
||||
DeleteBlockStorageInstance: func(blockStorageInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: &Config{BlockStorageSize: 10},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepDeleteBlockStorageInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteBlockStorageInstanceShouldPassIfOperationDeleteBlockStorageInstancePasses(t *testing.T) {
|
||||
var testSubject = &StepDeleteBlockStorageInstance{
|
||||
DeleteBlockStorageInstance: func(blockStorageInstanceNo string) error { return nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: &Config{BlockStorageSize: 10},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepDeleteBlockStorageInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepDeleteBlockStorageInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "1")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepGetRootPasswordShouldFailIfOperationGetRootPasswordFails(t *testing.T) {
|
||||
var testSubject = &StepGetRootPassword{
|
||||
GetRootPassword: func(string, string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: &Config{},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepGetRootPassword()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepGetRootPasswordShouldPassIfOperationGetRootPasswordPasses(t *testing.T) {
|
||||
var testSubject = &StepGetRootPassword{
|
||||
GetRootPassword: func(string, string) (string, error) { return "a", nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
Config: &Config{},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepGetRootPassword()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteTestStateBagStepGetRootPassword() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("LoginKey", &LoginKey{"a", "b"})
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepStopServerInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
StopServerInstance func(serverInstanceNo string) error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
}
|
||||
|
||||
func NewStepStopServerInstance(conn *NcloudAPIClient, ui packersdk.Ui) *StepStopServerInstance {
|
||||
var step = &StepStopServerInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
}
|
||||
|
||||
step.StopServerInstance = step.stopServerInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepStopServerInstance) stopServerInstance(serverInstanceNo string) error {
|
||||
reqParams := new(server.StopServerInstancesRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&serverInstanceNo}
|
||||
|
||||
serverInstanceList, err := s.Conn.server.V2Api.StopServerInstances(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Server Instance is stopping. Server InstanceNo is %s", *serverInstanceList.ServerInstanceList[0].ServerInstanceNo))
|
||||
log.Println("Server Instance information : ", serverInstanceList.ServerInstanceList[0])
|
||||
|
||||
if err := waiterServerInstanceStatus(s.Conn, serverInstanceNo, "NSTOP", 5*time.Minute); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Say(fmt.Sprintf("Server Instance stopped. Server InstanceNo is %s", *serverInstanceList.ServerInstanceList[0].ServerInstanceNo))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepStopServerInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Stop Server Instance")
|
||||
|
||||
var serverInstanceNo = state.Get("InstanceNo").(string)
|
||||
|
||||
err := s.StopServerInstance(serverInstanceNo)
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (*StepStopServerInstance) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepStopServerInstanceShouldFailIfOperationStopFails(t *testing.T) {
|
||||
var testSubject = &StepStopServerInstance{
|
||||
StopServerInstance: func(serverInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepStopServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepStopServerInstanceShouldPassIfOperationStopPasses(t *testing.T) {
|
||||
var testSubject = &StepStopServerInstance{
|
||||
StopServerInstance: func(serverInstanceNo string) error { return nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepStopServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepStopServerInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type StepTerminateServerInstance struct {
|
||||
Conn *NcloudAPIClient
|
||||
TerminateServerInstance func(serverInstanceNo string) error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
}
|
||||
|
||||
func NewStepTerminateServerInstance(conn *NcloudAPIClient, ui packersdk.Ui) *StepTerminateServerInstance {
|
||||
var step = &StepTerminateServerInstance{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
}
|
||||
|
||||
step.TerminateServerInstance = step.terminateServerInstance
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo string) error {
|
||||
reqParams := new(server.TerminateServerInstancesRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&serverInstanceNo}
|
||||
|
||||
_, err := s.Conn.server.V2Api.TerminateServerInstances(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c1 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
reqParams := new(server.GetServerInstanceListRequest)
|
||||
reqParams.ServerInstanceNoList = []*string{&serverInstanceNo}
|
||||
|
||||
for {
|
||||
|
||||
serverInstanceList, err := s.Conn.server.V2Api.GetServerInstanceList(reqParams)
|
||||
if err != nil {
|
||||
c1 <- err
|
||||
return
|
||||
} else if *serverInstanceList.TotalRows == 0 {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-c1:
|
||||
return res
|
||||
case <-time.After(time.Second * 60):
|
||||
return errors.New("TIMEOUT : Can't terminate server instance")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepTerminateServerInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Terminate Server Instance")
|
||||
|
||||
var serverInstanceNo = state.Get("InstanceNo").(string)
|
||||
|
||||
err := s.TerminateServerInstance(serverInstanceNo)
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
func (*StepTerminateServerInstance) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepTerminateServerInstanceShouldFailIfOperationTerminationFails(t *testing.T) {
|
||||
var testSubject = &StepTerminateServerInstance{
|
||||
TerminateServerInstance: func(serverInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepTerminateServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepTerminateServerInstanceShouldPassIfOperationTerminationPasses(t *testing.T) {
|
||||
var testSubject = &StepTerminateServerInstance{
|
||||
TerminateServerInstance: func(serverInstanceNo string) error { return nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepTerminateServerInstance()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepTerminateServerInstance() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put("InstanceNo", "a")
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud"
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
//StepValidateTemplate : struct for Validation a template
|
||||
type StepValidateTemplate struct {
|
||||
Conn *NcloudAPIClient
|
||||
Validate func() error
|
||||
Say func(message string)
|
||||
Error func(e error)
|
||||
Config *Config
|
||||
zoneNo string
|
||||
regionNo string
|
||||
FeeSystemTypeCode string
|
||||
}
|
||||
|
||||
// NewStepValidateTemplate : function for Validation a template
|
||||
func NewStepValidateTemplate(conn *NcloudAPIClient, ui packersdk.Ui, config *Config) *StepValidateTemplate {
|
||||
var step = &StepValidateTemplate{
|
||||
Conn: conn,
|
||||
Say: func(message string) { ui.Say(message) },
|
||||
Error: func(e error) { ui.Error(e.Error()) },
|
||||
Config: config,
|
||||
}
|
||||
|
||||
step.Validate = step.validateTemplate
|
||||
|
||||
return step
|
||||
}
|
||||
|
||||
// getZoneNo : get zoneNo
|
||||
func (s *StepValidateTemplate) getZoneNo() error {
|
||||
if s.Config.Region == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
regionList, err := s.Conn.server.V2Api.GetRegionList(&server.GetRegionListRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var regionNo string
|
||||
for _, region := range regionList.RegionList {
|
||||
if strings.EqualFold(*region.RegionName, s.Config.Region) {
|
||||
regionNo = *region.RegionNo
|
||||
}
|
||||
}
|
||||
|
||||
if regionNo == "" {
|
||||
return fmt.Errorf("region %s is invalid", s.Config.Region)
|
||||
}
|
||||
|
||||
s.regionNo = regionNo
|
||||
|
||||
// Get ZoneNo
|
||||
resp, err := s.Conn.server.V2Api.GetZoneList(&server.GetZoneListRequest{RegionNo: ®ionNo})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.ZoneList) > 0 {
|
||||
s.zoneNo = *resp.ZoneList[0].ZoneNo
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepValidateTemplate) validateMemberServerImage() error {
|
||||
var serverImageName = s.Config.ServerImageName
|
||||
|
||||
reqParams := new(server.GetMemberServerImageListRequest)
|
||||
reqParams.RegionNo = &s.regionNo
|
||||
|
||||
memberServerImageList, err := s.Conn.server.V2Api.GetMemberServerImageList(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var isExistMemberServerImageNo = false
|
||||
for _, image := range memberServerImageList.MemberServerImageList {
|
||||
// Check duplicate server_image_name
|
||||
if *image.MemberServerImageName == serverImageName {
|
||||
return fmt.Errorf("server_image_name %s is exists", serverImageName)
|
||||
}
|
||||
|
||||
if *image.MemberServerImageNo == s.Config.MemberServerImageNo {
|
||||
isExistMemberServerImageNo = true
|
||||
if s.Config.ServerProductCode == "" {
|
||||
s.Config.ServerProductCode = *image.OriginalServerProductCode
|
||||
s.Say("server_product_code for member server image '" + *image.OriginalServerProductCode + "' is configured automatically")
|
||||
}
|
||||
s.Config.ServerImageProductCode = *image.OriginalServerImageProductCode
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.MemberServerImageNo != "" && !isExistMemberServerImageNo {
|
||||
return fmt.Errorf("member_server_image_no %s does not exist", s.Config.MemberServerImageNo)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepValidateTemplate) validateServerImageProduct() error {
|
||||
var serverImageProductCode = s.Config.ServerImageProductCode
|
||||
if serverImageProductCode == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
reqParams := new(server.GetServerImageProductListRequest)
|
||||
reqParams.RegionNo = &s.regionNo
|
||||
|
||||
serverImageProductList, err := s.Conn.server.V2Api.GetServerImageProductList(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var isExistServerImage = false
|
||||
var buf bytes.Buffer
|
||||
var productName string
|
||||
table := tablewriter.NewWriter(&buf)
|
||||
table.SetHeader([]string{"Name", "Code"})
|
||||
|
||||
for _, product := range serverImageProductList.ProductList {
|
||||
// Check exist server image product code
|
||||
if *product.ProductCode == serverImageProductCode {
|
||||
isExistServerImage = true
|
||||
productName = *product.ProductName
|
||||
break
|
||||
}
|
||||
|
||||
table.Append([]string{*product.ProductName, *product.ProductCode})
|
||||
}
|
||||
|
||||
if !isExistServerImage {
|
||||
reqParams.BlockStorageSize = ncloud.Int32(100)
|
||||
|
||||
serverImageProductList, err := s.Conn.server.V2Api.GetServerImageProductList(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, product := range serverImageProductList.ProductList {
|
||||
// Check exist server image product code
|
||||
if *product.ProductCode == serverImageProductCode {
|
||||
isExistServerImage = true
|
||||
productName = *product.ProductName
|
||||
break
|
||||
}
|
||||
|
||||
table.Append([]string{*product.ProductName, *product.ProductCode})
|
||||
}
|
||||
}
|
||||
|
||||
if !isExistServerImage {
|
||||
table.Render()
|
||||
s.Say(buf.String())
|
||||
|
||||
return fmt.Errorf("server_image_product_code %s does not exist", serverImageProductCode)
|
||||
}
|
||||
|
||||
if strings.Contains(productName, "mssql") {
|
||||
s.FeeSystemTypeCode = "FXSUM"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepValidateTemplate) validateServerProductCode() error {
|
||||
var serverImageProductCode = s.Config.ServerImageProductCode
|
||||
var productCode = s.Config.ServerProductCode
|
||||
|
||||
reqParams := new(server.GetServerProductListRequest)
|
||||
reqParams.ServerImageProductCode = &serverImageProductCode
|
||||
reqParams.RegionNo = &s.regionNo
|
||||
|
||||
resp, err := s.Conn.server.V2Api.GetServerProductList(reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var isExistProductCode = false
|
||||
for _, product := range resp.ProductList {
|
||||
// Check exist server image product code
|
||||
if *product.ProductCode == productCode {
|
||||
isExistProductCode = true
|
||||
if strings.Contains(*product.ProductName, "mssql") {
|
||||
s.FeeSystemTypeCode = "FXSUM"
|
||||
}
|
||||
|
||||
if *product.ProductType.Code == "VDS" {
|
||||
return errors.New("You cannot create my server image for VDS servers")
|
||||
}
|
||||
|
||||
break
|
||||
} else if productCode == "" && *product.ProductType.Code == "STAND" {
|
||||
isExistProductCode = true
|
||||
s.Config.ServerProductCode = *product.ProductCode
|
||||
s.Say("server_product_code '" + *product.ProductCode + "' is configured automatically")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isExistProductCode {
|
||||
var buf bytes.Buffer
|
||||
table := tablewriter.NewWriter(&buf)
|
||||
table.SetHeader([]string{"Name", "Code"})
|
||||
for _, product := range resp.ProductList {
|
||||
table.Append([]string{*product.ProductName, *product.ProductCode})
|
||||
}
|
||||
table.Render()
|
||||
|
||||
s.Say(buf.String())
|
||||
|
||||
return fmt.Errorf("server_product_code %s does not exist", productCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check ImageName / Product Code / Server Image Product Code / Server Product Code...
|
||||
func (s *StepValidateTemplate) validateTemplate() error {
|
||||
// Get RegionNo, ZoneNo
|
||||
if err := s.getZoneNo(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate member_server_image_no and member_server_image_no
|
||||
if err := s.validateMemberServerImage(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate server_image_product_code
|
||||
if err := s.validateServerImageProduct(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate server_product_code
|
||||
return s.validateServerProductCode()
|
||||
}
|
||||
|
||||
// Run : main function for validation a template
|
||||
func (s *StepValidateTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.Say("Validating deployment template ...")
|
||||
|
||||
err := s.Validate()
|
||||
|
||||
state.Put("ZoneNo", s.zoneNo)
|
||||
|
||||
if s.FeeSystemTypeCode != "" {
|
||||
state.Put("FeeSystemTypeCode", s.FeeSystemTypeCode)
|
||||
}
|
||||
|
||||
return processStepResult(err, s.Error, state)
|
||||
}
|
||||
|
||||
// Cleanup : cleanup on error
|
||||
func (s *StepValidateTemplate) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) {
|
||||
var testSubject = &StepValidateTemplate{
|
||||
Validate: func() error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepValidateTemplate()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == false {
|
||||
t.Fatal("Expected the step to set stateBag['Error'], but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepValidateTemplateShouldPassIfValidatePasses(t *testing.T) {
|
||||
var testSubject = &StepValidateTemplate{
|
||||
Validate: func() error { return nil },
|
||||
Say: func(message string) {},
|
||||
Error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepValidateTemplate()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk("Error"); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['Error'], but it was.")
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepValidateTemplate() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
return stateBag
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var NCloudPluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
NCloudPluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package ncloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server"
|
||||
)
|
||||
|
||||
func waiterBlockStorageInstanceStatus(conn *NcloudAPIClient, blockStorageInstanceNo *string, status string, timeout time.Duration) error {
|
||||
reqParams := new(server.GetBlockStorageInstanceListRequest)
|
||||
reqParams.BlockStorageInstanceNoList = []*string{blockStorageInstanceNo}
|
||||
|
||||
c1 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
blockStorageInstanceList, err := conn.server.V2Api.GetBlockStorageInstanceList(reqParams)
|
||||
if err != nil {
|
||||
c1 <- err
|
||||
return
|
||||
}
|
||||
|
||||
if status == "DETAC" && len(blockStorageInstanceList.BlockStorageInstanceList) == 0 {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
blockStorageInstance := blockStorageInstanceList.BlockStorageInstanceList[0]
|
||||
code := blockStorageInstance.BlockStorageInstanceStatus.Code
|
||||
operationCode := blockStorageInstance.BlockStorageInstanceOperation.Code
|
||||
|
||||
if *code == status && *operationCode == "NULL" {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
log.Println(blockStorageInstance)
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-c1:
|
||||
return res
|
||||
case <-time.After(timeout):
|
||||
return fmt.Errorf("TIMEOUT : block storage instance status is not changed into status %s", status)
|
||||
}
|
||||
}
|
||||
|
||||
func waiterDetachedBlockStorageInstance(conn *NcloudAPIClient, serverInstanceNo string, timeout time.Duration) error {
|
||||
reqParams := new(server.GetBlockStorageInstanceListRequest)
|
||||
reqParams.ServerInstanceNo = &serverInstanceNo
|
||||
|
||||
c1 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
blockStorageInstanceList, err := conn.server.V2Api.GetBlockStorageInstanceList(reqParams)
|
||||
if err != nil {
|
||||
c1 <- err
|
||||
return
|
||||
}
|
||||
|
||||
if *blockStorageInstanceList.TotalRows == 1 {
|
||||
c1 <- nil
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-c1:
|
||||
return res
|
||||
case <-time.After(timeout):
|
||||
return fmt.Errorf("TIMEOUT : attached block storage instance is not detached")
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user