Compare commits

...

93 Commits

Author SHA1 Message Date
Adrien Delorme 6ad1024bd8 up modules.txt 2021-04-20 17:22:25 +02:00
Adrien Delorme c23b6a1b12 up mods 2021-04-20 17:20:34 +02:00
sylviamoss 7583fd9d85 remove outscale, vendor it and add remote docs 2021-04-20 17:20:13 +02:00
Sylvia Moss d6904502ac Extract outscale (#10941)
* remove outscale, vendor it and add remote docs

* fix lint

* add community plugin tier

* Update go.mod

* up mods

Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-04-20 17:18:45 +02:00
Wilken Rivera 2061aa9e69 Add pluginTier to community plugins (#10942) 2021-04-20 10:49:35 -04:00
Zachary Shilton cbe06050b4 website: enable plugin tier override (#10919)
* website: enable plugin tier override

* website: validate remote plugins config pluginTier
2021-04-20 10:28:41 -04:00
Adrien Delorme d22ba61ae0 ncloud breakout (#10937) 2021-04-20 15:09:11 +02:00
Adrien Delorme 9eaad88ac0 Move proxmox builder out + vendor it (#10930)
* use vendored proxmox builders

* Update docs-nav-data.json

remove proxmox ref

* Update docs-remote-plugins.json

* remove builder/proxmox dir

* remove website/content/docs/builders/proxmox/

* up vendors

* Update modules.txt

* Update HTTPConfig-not-required.mdx

* Update HTTPConfig-not-required.mdx

* tidy mod

* fmt

* Update modules.txt
2021-04-20 14:59:34 +02:00
Megan Marsh 20faaef05c Merge pull request #10929 from hashicorp/extract_qemu
Extract QEMU plugin
2021-04-19 15:39:44 -07:00
Megan Marsh d0a4a71da8 Merge pull request #10927 from hashicorp/fix_typo
Fix TEMPATE to TEMPLATE in fmt cmd help text
2021-04-19 09:24:50 -07:00
sylviamoss 3af472be9a update qemu to latest version 2021-04-19 17:47:09 +02:00
sylviamoss 5a00020830 add qemu to docs-remote-plugins.json 2021-04-19 17:45:51 +02:00
Adrien Delorme 6094c97998 Update docs-remote-plugins.json
order alphabetically
2021-04-19 17:20:46 +02:00
Adrien Delorme 1a41eac70b Update vendored_plugins.go
order alphabetically
2021-04-19 17:05:21 +02:00
sylviamoss 7a85b7328e vendor qemu plugin 2021-04-19 16:32:04 +02:00
Sylvia Moss 3dac34766c add legacy_isotime docs (#10928) 2021-04-19 16:29:43 +02:00
sylviamoss 642ed07476 remote qemu plugin 2021-04-19 16:28:12 +02:00
Sylvia Moss 88f8feecfe Extract vmware plugin (#10920) 2021-04-19 14:28:48 +02:00
sylviamoss b448c3182c fix TEMPATE to TEMPLATE in fmt cmd 2021-04-19 14:07:22 +02:00
Adrien Delorme 9230a06920 move googlecompute plugin to github.com/hashicorp/packer-plugin-googlecompute (#10890) 2021-04-19 11:10:15 +02:00
Sylvia Moss 16658a9f47 Extract virtualbox plugin (#10910) 2021-04-16 17:38:02 +02:00
Wilken Rivera ceb96d061a Extract ansible plugins (#10912)
* Remove ansible components and docs

* Vendored packer-plugin-ansible

* Add remote ansible docs
2021-04-16 10:31:09 -04:00
Romain Lecat bb1a025f60 Add outscale-mgo to osc codeowners (#10917) 2021-04-16 15:25:44 +02:00
Adrien Delorme 87ba7258b3 Use packer-sdc in packer + remove mapstructure-to-hcl2 & struct-markdown (#10913)
* start using `go:generate packer-sdc struct-markdown`

* Update Makefile

remove @go install ./cmd/struct-markdown

* run go generate for struct-markdown

* use //go:generate packer-sdc mapstructure-to-hcl2

* run go generate for mapstructure-to-hcl2

* remove struct-markdown and mapstructure-to-hcl2

* vendor vendors
2021-04-16 11:52:03 +02:00
Megan Marsh da312e2785 Merge pull request #10896 from hashicorp/extract_vsphere
Extract vSphere plugin
2021-04-15 16:30:27 -07:00
Megan Marsh 84af0ba6da go mod tidy 2021-04-15 16:25:58 -07:00
sylviamoss 3c6b7841bc fix vsphere link 2021-04-15 16:25:36 -07:00
sylviamoss c7ee5f1efd update packer-plugin-vsphere and sdk 2021-04-15 16:25:36 -07:00
sylviamoss a00846102b add vsphere to docs-remote-plugins.json 2021-04-15 16:25:36 -07:00
sylviamoss 41c66d6935 vendor vsphere plugin 2021-04-15 16:25:31 -07:00
sylviamoss f6854f5528 update go vendor 2021-04-15 16:24:57 -07:00
sylviamoss 38fe79948b remove vsphere components and docs 2021-04-15 16:24:57 -07:00
Daniel Finneran a6c5958c67 Adds bzip2 support to post-processor (#10867)
* compress post processor: add bzip2 + tests

* post-processor/compress/post-processor_test.go: refactor tests and add tests for bzip2

* post-processor_test.go: test write/read for all compression algos

* check artifact.Destroy() errors

* close archive before deleting it

Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-04-15 18:05:09 +02:00
Jeff Escalante c17f236e85 Upgrade Downloads Page (#10907)
* upgrade downloads page

* fix syntax errors on builders/ncloud page
2021-04-14 14:51:29 -04:00
Megan Marsh bb5d7b6c40 Merge pull request #10870 from NaverCloudPlatform/master
Support ncloud vpc version
2021-04-13 10:32:16 -07:00
sangkyu-kim 1ea5a547e2 Merge branch 'master' into master 2021-04-13 13:46:48 +09:00
Megan Marsh 86b8ce8df0 Postprocessor only docs (#10899)
* add a note for only/except from cli to the post-processor template section

* typo; missing space

* Update website/content/docs/templates/hcl_templates/blocks/build/post-processor.mdx

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>

* tweak wording

Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
2021-04-12 15:39:27 -04:00
Megan Marsh b51bf9250e Merge pull request #10900 from hashicorp/digitalocean-import-docs-fix
Update URL to custom-images overview page
2021-04-12 12:18:00 -07:00
Wilken Rivera 2d5a32629a Update URL to custom-images overview page 2021-04-12 10:30:25 -04:00
Kerim Satirli 3e2db82cab fixes typo (#10894) 2021-04-09 11:59:08 +02:00
Megan Marsh bc9dd69669 Merge pull request #10880 from hashicorp/amazon_acc_test
Add plugin acceptance test using the Amazon plugin
2021-04-08 13:31:32 -07:00
Megan Marsh 734e91b97c Merge pull request #10878 from hashicorp/rewrite_acctests
Move acctest pkg from the SDK to core and update acceptance tests
2021-04-08 13:21:18 -07:00
Zachary Shilton ab0d1ee363 website: fix edit links for remote plugins (#10884)
* website: fix issue with edits links, use branch name, not version

* website: patch layout shift issue related to global style

* website: update plugin config docs with sourceBranch

* website: tweak spacing above plugin tier label

* website: add note on default value for sourceBranch
2021-04-08 10:09:58 -04:00
Kerim Satirli cf94fd1778 switches JSON and HCL2 tabs (#10888)
* switches JSON and HCL2 tabs for all provisioners

* corrects `packer` to `Packer`

* corrects `http` to `HTTP`

* corrects typos and highlighting consistency issues

* corrects typos and highlighting consistency issues

* corrects typos and highlighting consistency issues

* `ansible` -> `Ansible`

* `packer fmt` for HCL2 blocks in provisioners

* linting and spelling

* fixes formatting

* fixes formatting

* Update website/content/docs/provisioners/ansible.mdx

Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>

* fixes formatting

* improves example

* generate stuff

Co-authored-by: Adrien Delorme <azr@users.noreply.github.com>
2021-04-08 15:02:57 +02:00
George Wilson 15a2e59bba Autogenerated docs for ansible local provisioner (#10829) 2021-04-08 12:18:49 +02:00
Kerim Satirli 8c4eb5f4aa corrects default value and adds highlighting (#10886)
* value is expected to be `ssh` not `SSH`

* highlighting default values
2021-04-08 12:02:05 +02:00
Kendall Strautman 86788220a9 Merge pull request #10875 from hashicorp/ks.style/branding-refresh
style(website): upgrade react-components, colors, logos
2021-04-07 08:02:13 -07:00
Kerim Satirli e3bcb4f2ac adds highlighting to locals stanza (#10881) 2021-04-07 16:38:23 +02:00
Kendall Strautman ccd0430fda Update website/pages/downloads/style.css
Co-authored-by: Zachary Shilton <4624598+zchsh@users.noreply.github.com>
2021-04-07 07:35:05 -07:00
sylviamoss 49474f8f37 add plugin acceptance test using amazon plugin 2021-04-07 16:21:15 +02:00
sylviamoss e0614cabf4 move acctest pkg from sdk to core and update acceptance tests 2021-04-07 11:52:19 +02:00
Shaun McEvoy eaec3e5564 Add Image Storage Locations field to Google Compute Import post-processor (#10864)
* add image storage locations to Google Compute Import
2021-04-07 10:36:08 +02:00
James eaaf22dcde builder/digitalocean: support ecdsa, ed25519, dsa temporary key types via packer-plugin-sdk/communicator step… (#10856)
* support ecdsa, ed25519 temporary key algos via temporary_key_pair_algorith config

* builder/digitalocean: improve public key marshalling error handling

* builder/digitalocean: use packer-plugin-sdk to manage temporary ssh keys

* builder/digitalocean: clean up unused properties

Co-authored-by: tserkov <tserkov@penguin>
2021-04-07 10:33:05 +02:00
Qingchuan Hao f2f33fa344 Correct SIG timout (#10816) 2021-04-07 10:00:17 +02:00
Kendall Strautman 9189f1228e chore: adds comment 2021-04-06 15:37:05 -07:00
Kendall Strautman 5e7b5729e6 style: override product-downloader colors 2021-04-06 15:35:23 -07:00
Megan Marsh 9365c90c0b revendor 2021-04-06 13:52:07 -07:00
Megan Marsh f27bdf85f4 upgrade exoscale dependency 2021-04-06 13:51:14 -07:00
Kendall Strautman 9f7bb4da25 chore: fix deps 2021-04-06 13:48:00 -07:00
Kendall Strautman b1967e99c7 chore: upgrade react-components, colors, logos 2021-04-06 13:47:58 -07:00
Brandon Romano 7efb41868f Upgrade StackMenu to latest (#10874) 2021-04-06 16:40:48 -04:00
Wilken Rivera 260906c3e4 Add redirect for Docker post-processor pages (#10872)
Remote plugin docs such as Docker now fall under a top level path named
after the provider (e.g https://packer.io/docs/docker/...). This change
adds a redirect for the old URLs to the new location.
2021-04-06 10:37:05 -04:00
Roshan Padaki f65e1d5d55 Fix tiny typo in hcl2_upgrade.mdx (#10868) 2021-04-06 11:51:10 +02:00
sangkyu.kim 23e8684aae fix lint, fmt, generate 2021-04-06 11:40:41 +09:00
sangkyu.kim e22d9861aa update modules 2021-04-06 10:56:16 +09:00
sangkyu-kim 1c8fc65223 Merge branch 'master' into master 2021-04-06 10:35:58 +09:00
sangkyu-kim 42ca66752f Merge pull request #1 from NaverCloudPlatform/ncloud_vpc
Implement VPC
2021-04-06 10:27:50 +09:00
packer-ci 33461126e2 Putting source back into Dev Mode 2021-04-05 23:32:25 +00:00
packer-ci 1f834e229a Cut version 1.7.2 2021-04-05 22:55:12 +00:00
packer-ci 4417f8b3bf cut version 1.7.2 2021-04-05 22:55:11 +00:00
packer-ci 8db540a935 update changelog 2021-04-05 22:55:11 +00:00
Megan Marsh e8780bf7b8 add massive warning about error logging to WrappedMain 2021-04-05 15:03:39 -07:00
Megan Marsh 3b0226d496 update changelog 2021-04-05 11:16:39 -07:00
Megan Marsh 4c08789642 Merge pull request #10850 from hashicorp/ui_fix
Switch to using ui once it is initialized
2021-04-05 11:14:20 -07:00
Wilken Rivera 634bf87d99 Update CHANGELOG 2021-04-05 12:51:05 -04:00
Wilken Rivera d566419c45 Update unmaintained-plugins partial 2021-04-05 08:14:43 -04:00
Recai Oktaş cce1f5c1e3 Update index.mdx (#10865)
Fix a minor typo.
2021-04-05 06:40:32 -04:00
elsnepal 7f26429a2a feature[alicloud]: add ramrole to ecs instance (#10845)
* add RamRole support for ecs instance

* ordering of attributes

* run make generate
2021-04-02 15:02:13 -04:00
Sylvia Moss d81c02b456 Fix primary disk resize on clone and add tests (#10848)
* Fix primary disk resize on clone and add tests

* remove commented tests
2021-04-02 14:41:11 -04:00
mmassez 794e83b171 Proxmox builder return first ipv4 address (#10858)
* Check if IP address is IPv4 before returning it

Returns the first IPv4 address instead of the first IP address which is an IPv6 for Windows VMs

* Updated the go module

* Reversed the order of checks

First check if it's a loopback and check for ipv4 afterwards
2021-04-02 14:37:20 -04:00
Zachary Shilton 58fb58c2ea website: fix issue with bloated static props (#10860)
* website: fix issue with bloated static props

* website: remove script to check static props size
2021-04-02 11:29:31 -04:00
sangkyu.kim 15a9e1b20a skip validate product_code if empty 2021-04-02 18:18:59 +09:00
sangkyu.kim 3f23a5ec74 Remove getClassicServerImageProductList within block storage size 100GB 2021-04-02 16:38:58 +09:00
sangkyu.kim f4cbb5d7dc fix length validation message 2021-04-02 14:55:05 +09:00
Brian Choy fb04fa7a25 Fix vault function docs example (#10851)
The given example is missing a `,`.
2021-04-01 15:18:06 +02:00
Zachary Shilton 830140157d website: remove obselete nav data (#10811)
* website: remove obselete sidebar_title frontmatter from docs

* website: bump to latest docs-page

* website: update plugin creation and registration docs

* website: fix broken links
2021-03-31 15:07:00 -04:00
sangkyu.kim cdcdf6a618 fix checking subnet type 2021-03-31 18:22:22 +09:00
sangkyu.kim 74434b3c3e create temporary ACG for VPC 2021-03-31 15:15:57 +09:00
sangkyu.kim 3a11352dfa Fix ncloud builder unhandled buildvar type 2021-03-30 13:59:59 +09:00
sangkyu.kim 56728a937b update ncloud guide 2021-03-30 11:53:42 +09:00
sangkyu.kim f044a64014 fix test code 2021-03-29 22:51:04 +09:00
sangkyu.kim cd370aaaad implement vpc environment 2021-03-29 22:51:04 +09:00
sangkyu.kim af865b1591 update ncloud-sdk-go-v2 vendor 2021-03-29 22:51:03 +09:00
3148 changed files with 202922 additions and 141601 deletions
+17
View File
@@ -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
View File
@@ -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)
-8
View File
@@ -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
+1 -2
View File
@@ -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
+71
View File
@@ -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)
}
+112
View File
@@ -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"]
}
+72
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
//go:generate struct-markdown
//go:generate packer-sdc struct-markdown
package ecs
+2 -1
View File
@@ -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,
+3 -1
View File
@@ -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},
+1 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
//go:generate struct-markdown
//go:generate packer-sdc struct-markdown
package ecs
+3 -1
View File
@@ -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)
+1 -1
View File
@@ -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"
+2 -2
View File
@@ -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 -1
View File
@@ -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
+2 -2
View File
@@ -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 -1
View 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 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 -1
View File
@@ -1,4 +1,4 @@
//go:generate struct-markdown
//go:generate packer-sdc struct-markdown
package client
-1
View File
@@ -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)
+1 -1
View File
@@ -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"
+2 -2
View File
@@ -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 -1
View File
@@ -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
+2 -2
View File
@@ -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 -1
View 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 cloudstack
+10 -3
View File
@@ -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{
+1 -1
View File
@@ -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"
)
+2 -2
View File
@@ -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 -1
View 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 digitalocean
+5 -59
View File
@@ -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
}
+1 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
//go:generate mapstructure-to-hcl2 -type Config
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
package file
+1 -1
View 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
-37
View 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")
}
}
-692
View File
@@ -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"
}`
-26
View File
@@ -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())
}
-72
View File
@@ -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)
}
}
-21
View File
@@ -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-----
+1 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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 -1
View 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 hyperone
+1 -1
View File
@@ -1,4 +1,4 @@
//go:generate struct-markdown
//go:generate packer-sdc struct-markdown
package common
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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 -1
View 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 iso
+2 -2
View File
@@ -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 -1
View 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 vmcx
+1 -1
View File
@@ -1,4 +1,4 @@
//go:generate mapstructure-to-hcl2 -type Config
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
package jdcloud
+1 -1
View 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 jdcloud
+1 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
//go:generate mapstructure-to-hcl2 -type Config
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
package linode
+1 -1
View 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 linode
+2 -2
View File
@@ -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 -1
View 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 lxc
+2 -2
View File
@@ -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 -1
View 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 lxd
-124
View File
@@ -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
}
-150
View File
@@ -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
}
-67
View File
@@ -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
}
-270
View File
@@ -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: &regionNo})
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
}
-13
View File
@@ -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