Extract Hyperone (#10949)
This commit is contained in:
parent
0f6a081724
commit
2db338e322
|
@ -52,12 +52,6 @@
|
|||
/builder/hcloud/ @LKaemmerling
|
||||
/website/pages/docs/builders/hcloud* @LKaemmerling
|
||||
|
||||
/examples/hyperone/ @m110 @gregorybrzeski @ad-m
|
||||
/builder/hyperone/ @m110 @gregorybrzeski @ad-m
|
||||
/website/pages/docs/builders/hyperone* @m110 @gregorybrzeski @ad-m
|
||||
/test/builder_hyperone* @m110 @gregorybrzeski @ad-m
|
||||
/test/fixtures/builder-hyperone/ @m110 @gregorybrzeski @ad-m
|
||||
|
||||
/examples/ucloud/ @shawnmssu
|
||||
/builder/ucloud/ @shawnmssu
|
||||
/website/pages/docs/builders/ucloud* @shawnmssu
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type Artifact struct {
|
||||
imageName string
|
||||
imageID string
|
||||
client *openapi.APIClient
|
||||
|
||||
// StateData should store data such as GeneratedData
|
||||
// to be shared with post-processors
|
||||
StateData map[string]interface{}
|
||||
}
|
||||
|
||||
func (a *Artifact) BuilderId() string {
|
||||
return BuilderID
|
||||
}
|
||||
|
||||
func (a *Artifact) Files() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Artifact) Id() string {
|
||||
return a.imageID
|
||||
}
|
||||
|
||||
func (a *Artifact) String() string {
|
||||
return fmt.Sprintf("Image '%s' created, ID: %s", a.imageName, a.imageID)
|
||||
}
|
||||
|
||||
func (a *Artifact) State(name string) interface{} {
|
||||
return a.StateData[name]
|
||||
}
|
||||
|
||||
func (a *Artifact) Destroy() error {
|
||||
if a.imageID == "" {
|
||||
// No image to destroy
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := a.client.ImageApi.ImageDelete(context.TODO(), a.imageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
const BuilderID = "hyperone.builder"
|
||||
|
||||
type Builder struct {
|
||||
config Config
|
||||
runner multistep.Runner
|
||||
client *openapi.APIClient
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
cfg := openapi.NewConfiguration()
|
||||
cfg.AddDefaultHeader("x-auth-token", b.config.Token)
|
||||
if b.config.Project != "" {
|
||||
cfg.AddDefaultHeader("x-project", b.config.Project)
|
||||
}
|
||||
|
||||
if b.config.APIURL != "" {
|
||||
cfg.BasePath = b.config.APIURL
|
||||
}
|
||||
|
||||
prefer := fmt.Sprintf("respond-async,wait=%d", int(b.config.StateTimeout.Seconds()))
|
||||
cfg.AddDefaultHeader("Prefer", prefer)
|
||||
|
||||
b.client = openapi.NewAPIClient(cfg)
|
||||
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
type wrappedCommandTemplate struct {
|
||||
Command string
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
|
||||
wrappedCommand := func(command string) (string, error) {
|
||||
ictx := b.config.ctx
|
||||
ictx.Data = &wrappedCommandTemplate{Command: command}
|
||||
return interpolate.Render(b.config.ChrootCommandWrapper, &ictx)
|
||||
}
|
||||
|
||||
state := &multistep.BasicStateBag{}
|
||||
state.Put("config", &b.config)
|
||||
state.Put("client", b.client)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
state.Put("wrappedCommand", CommandWrapper(wrappedCommand))
|
||||
|
||||
steps := []multistep.Step{
|
||||
&stepCreateSSHKey{},
|
||||
&stepCreateVM{},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.Comm,
|
||||
Host: getPublicIP,
|
||||
SSHConfig: b.config.Comm.SSHConfigFunc(),
|
||||
},
|
||||
}
|
||||
|
||||
if b.config.ChrootDisk {
|
||||
steps = append(steps,
|
||||
&stepPrepareDevice{},
|
||||
&stepPreMountCommands{},
|
||||
&stepMountChroot{},
|
||||
&stepPostMountCommands{},
|
||||
&stepMountExtra{},
|
||||
&stepCopyFiles{},
|
||||
&stepChrootProvision{},
|
||||
&stepStopVM{},
|
||||
&stepDetachDisk{},
|
||||
&stepCreateVMFromDisk{},
|
||||
&stepCreateImage{},
|
||||
)
|
||||
} else {
|
||||
steps = append(steps,
|
||||
&commonsteps.StepProvision{},
|
||||
&stepStopVM{},
|
||||
&stepCreateImage{},
|
||||
)
|
||||
}
|
||||
|
||||
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
b.runner.Run(ctx, state)
|
||||
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
artifact := &Artifact{
|
||||
imageID: state.Get("image_id").(string),
|
||||
imageName: state.Get("image_name").(string),
|
||||
client: b.client,
|
||||
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
|
||||
}
|
||||
|
||||
return artifact, nil
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_basic(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccBasic,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_chroot(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccChroot,
|
||||
})
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
if v := os.Getenv("HYPERONE_TOKEN"); v == "" {
|
||||
t.Fatal("HYPERONE_TOKEN must be set for acceptance tests")
|
||||
}
|
||||
}
|
||||
|
||||
const testBuilderAccBasic = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"vm_type": "a1.nano",
|
||||
"source_image": "ubuntu",
|
||||
"disk_size": 10,
|
||||
"image_tags": {
|
||||
"key":"value"
|
||||
},
|
||||
"vm_tags": {
|
||||
"key_vm":"value_vm"
|
||||
}
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccChroot = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"source_image": "ubuntu",
|
||||
"disk_size": 10,
|
||||
"vm_type": "a1.nano",
|
||||
"chroot_disk": true,
|
||||
"chroot_command_wrapper": "sudo {{.Command}}",
|
||||
"pre_mount_commands": [
|
||||
"parted {{.Device}} mklabel msdos mkpart primary 1M 100% set 1 boot on print",
|
||||
"mkfs.ext4 {{.Device}}1"
|
||||
],
|
||||
"post_mount_commands": [
|
||||
"apt-get update",
|
||||
"apt-get install debootstrap",
|
||||
"debootstrap --arch amd64 bionic {{.MountPath}}"
|
||||
]
|
||||
}]
|
||||
}
|
||||
`
|
|
@ -1,55 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type CommandWrapper func(string) (string, error)
|
||||
|
||||
// ChrootCommunicator works as a wrapper on SSHCommunicator, modyfing paths in
|
||||
// flight to be run in a chroot.
|
||||
type ChrootCommunicator struct {
|
||||
Chroot string
|
||||
CmdWrapper CommandWrapper
|
||||
Wrapped packersdk.Communicator
|
||||
}
|
||||
|
||||
func (c *ChrootCommunicator) Start(ctx context.Context, cmd *packersdk.RemoteCmd) error {
|
||||
command := strconv.Quote(cmd.Command)
|
||||
chrootCommand, err := c.CmdWrapper(
|
||||
fmt.Sprintf("sudo chroot %s /bin/sh -c %s", c.Chroot, command))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.Command = chrootCommand
|
||||
|
||||
return c.Wrapped.Start(ctx, cmd)
|
||||
}
|
||||
|
||||
func (c *ChrootCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
||||
dst = filepath.Join(c.Chroot, dst)
|
||||
return c.Wrapped.Upload(dst, r, fi)
|
||||
}
|
||||
|
||||
func (c *ChrootCommunicator) UploadDir(dst string, src string, exclude []string) error {
|
||||
dst = filepath.Join(c.Chroot, dst)
|
||||
return c.Wrapped.UploadDir(dst, src, exclude)
|
||||
}
|
||||
|
||||
func (c *ChrootCommunicator) Download(src string, w io.Writer) error {
|
||||
src = filepath.Join(c.Chroot, src)
|
||||
return c.Wrapped.Download(src, w)
|
||||
}
|
||||
|
||||
func (c *ChrootCommunicator) DownloadDir(src string, dst string, exclude []string) error {
|
||||
src = filepath.Join(c.Chroot, src)
|
||||
return c.Wrapped.DownloadDir(src, dst, exclude)
|
||||
}
|
|
@ -1,352 +0,0 @@
|
|||
//go:generate packer-sdc struct-markdown
|
||||
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||
|
||||
package hyperone
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/json"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer-plugin-sdk/uuid"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
const (
|
||||
configPath = "~/.h1-cli/conf.json"
|
||||
tokenEnv = "HYPERONE_TOKEN"
|
||||
|
||||
defaultDiskType = "ssd"
|
||||
defaultImageService = "564639bc052c084e2f2e3266"
|
||||
defaultStateTimeout = 5 * time.Minute
|
||||
defaultUserName = "guru"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
// Custom API endpoint URL, compatible with HyperOne.
|
||||
// It can also be specified via environment variable HYPERONE_API_URL.
|
||||
APIURL string `mapstructure:"api_url" required:"false"`
|
||||
// The authentication token used to access your account.
|
||||
// This can be either a session token or a service account token.
|
||||
// If not defined, the builder will attempt to find it in the following order:
|
||||
Token string `mapstructure:"token" required:"true"`
|
||||
// The id or name of the project. This field is required
|
||||
// only if using session tokens. It should be skipped when using service
|
||||
// account authentication.
|
||||
Project string `mapstructure:"project" required:"true"`
|
||||
// Login (an e-mail) on HyperOne platform. Set this
|
||||
// if you want to fetch the token by SSH authentication.
|
||||
TokenLogin string `mapstructure:"token_login" required:"false"`
|
||||
// Timeout for waiting on the API to complete
|
||||
// a request. Defaults to 5m.
|
||||
StateTimeout time.Duration `mapstructure:"state_timeout" required:"false"`
|
||||
// ID or name of the image to launch server from.
|
||||
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// The name of the resulting image. Defaults to
|
||||
// `packer-{{timestamp}}`
|
||||
// (see configuration templates for more info).
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The description of the resulting image.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// Key/value pair tags to add to the created image.
|
||||
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
|
||||
// Same as [`image_tags`](#image_tags) but defined as a singular repeatable
|
||||
// block containing a `key` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
ImageTag config.KeyValues `mapstructure:"image_tag" required:"false"`
|
||||
// The service of the resulting image.
|
||||
ImageService string `mapstructure:"image_service" required:"false"`
|
||||
// ID or name of the type this server should be created with.
|
||||
VmType string `mapstructure:"vm_type" required:"true"`
|
||||
// The name of the created server.
|
||||
VmName string `mapstructure:"vm_name" required:"false"`
|
||||
// Key/value pair tags to add to the created server.
|
||||
VmTags map[string]string `mapstructure:"vm_tags" required:"false"`
|
||||
// Same as [`vm_tags`](#vm_tags) but defined as a singular repeatable block
|
||||
// containing a `key` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
VmTag config.NameValues `mapstructure:"vm_tag" required:"false"`
|
||||
// The name of the created disk.
|
||||
DiskName string `mapstructure:"disk_name" required:"false"`
|
||||
// The type of the created disk. Defaults to ssd.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// Size of the created disk, in GiB.
|
||||
DiskSize float32 `mapstructure:"disk_size" required:"true"`
|
||||
// The ID of the network to attach to the created server.
|
||||
Network string `mapstructure:"network" required:"false"`
|
||||
// The ID of the private IP within chosen network
|
||||
// that should be assigned to the created server.
|
||||
PrivateIP string `mapstructure:"private_ip" required:"false"`
|
||||
// The ID of the public IP that should be assigned to
|
||||
// the created server. If network is chosen, the public IP will be associated
|
||||
// with server's private IP.
|
||||
PublicIP string `mapstructure:"public_ip" required:"false"`
|
||||
// Custom service of public network adapter.
|
||||
// Can be useful when using custom api_url. Defaults to public.
|
||||
PublicNetAdpService string `mapstructure:"public_netadp_service" required:"false"`
|
||||
|
||||
ChrootDevice string `mapstructure:"chroot_device"`
|
||||
ChrootDisk bool `mapstructure:"chroot_disk"`
|
||||
ChrootDiskSize float32 `mapstructure:"chroot_disk_size"`
|
||||
ChrootDiskType string `mapstructure:"chroot_disk_type"`
|
||||
ChrootMountPath string `mapstructure:"chroot_mount_path"`
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts"`
|
||||
ChrootCopyFiles []string `mapstructure:"chroot_copy_files"`
|
||||
// How to run shell commands. This defaults to `{{.Command}}`. This may be
|
||||
// useful to set if you want to set environmental variables or perhaps run
|
||||
// it with sudo or so on. This is a configuration template where the
|
||||
// .Command variable is replaced with the command to be run. Defaults to
|
||||
// `{{.Command}}`.
|
||||
ChrootCommandWrapper string `mapstructure:"chroot_command_wrapper"`
|
||||
|
||||
MountOptions []string `mapstructure:"mount_options"`
|
||||
MountPartition string `mapstructure:"mount_partition"`
|
||||
// A series of commands to execute after attaching the root volume and
|
||||
// before mounting the chroot. This is not required unless using
|
||||
// from_scratch. If so, this should include any partitioning and filesystem
|
||||
// creation commands. The path to the device is provided by `{{.Device}}`.
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||
// As pre_mount_commands, but the commands are executed after mounting the
|
||||
// root device and before the extra mount and copy steps. The device and
|
||||
// mount path are provided by `{{.Device}}` and `{{.MountPath}}`.
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands"`
|
||||
// List of SSH keys by name or id to be added
|
||||
// to the server on launch.
|
||||
SSHKeys []string `mapstructure:"ssh_keys" required:"false"`
|
||||
// User data to launch with the server. Packer will not
|
||||
// automatically wait for a user script to finish before shutting down the
|
||||
// instance, this must be handled in a provisioner.
|
||||
UserData string `mapstructure:"user_data" required:"false"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
||||
|
||||
var md mapstructure.Metadata
|
||||
err := config.Decode(c, &config.DecodeOpts{
|
||||
Metadata: &md,
|
||||
Interpolate: true,
|
||||
InterpolateContext: &c.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"run_command",
|
||||
"chroot_command_wrapper",
|
||||
"post_mount_commands",
|
||||
"pre_mount_commands",
|
||||
"mount_path",
|
||||
},
|
||||
},
|
||||
}, raws...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cliConfig, err := loadCLIConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Defaults
|
||||
if c.Comm.SSHUsername == "" {
|
||||
c.Comm.SSHUsername = defaultUserName
|
||||
}
|
||||
|
||||
if c.Comm.SSHTimeout == 0 {
|
||||
c.Comm.SSHTimeout = 10 * time.Minute
|
||||
}
|
||||
|
||||
if c.APIURL == "" {
|
||||
c.APIURL = os.Getenv("HYPERONE_API_URL")
|
||||
}
|
||||
|
||||
if c.Token == "" {
|
||||
c.Token = os.Getenv(tokenEnv)
|
||||
|
||||
if c.Token == "" {
|
||||
c.Token = cliConfig.Profile.APIKey
|
||||
}
|
||||
|
||||
// Fetching token by SSH is available only for the default API endpoint
|
||||
if c.TokenLogin != "" && c.APIURL == "" {
|
||||
c.Token, err = fetchTokenBySSH(c.TokenLogin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Project == "" {
|
||||
c.Project = cliConfig.Profile.Project.ID
|
||||
}
|
||||
|
||||
if c.StateTimeout == 0 {
|
||||
c.StateTimeout = defaultStateTimeout
|
||||
}
|
||||
|
||||
if c.ImageName == "" {
|
||||
name, err := interpolate.Render("packer-{{timestamp}}", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.ImageName = name
|
||||
}
|
||||
|
||||
if c.ImageService == "" {
|
||||
c.ImageService = defaultImageService
|
||||
}
|
||||
|
||||
if c.VmName == "" {
|
||||
c.VmName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
||||
}
|
||||
|
||||
if c.DiskType == "" {
|
||||
c.DiskType = defaultDiskType
|
||||
}
|
||||
|
||||
if c.PublicNetAdpService == "" {
|
||||
c.PublicNetAdpService = "public"
|
||||
}
|
||||
|
||||
if c.ChrootCommandWrapper == "" {
|
||||
c.ChrootCommandWrapper = "{{.Command}}"
|
||||
}
|
||||
|
||||
if c.ChrootDiskSize == 0 {
|
||||
c.ChrootDiskSize = c.DiskSize
|
||||
}
|
||||
|
||||
if c.ChrootDiskType == "" {
|
||||
c.ChrootDiskType = c.DiskType
|
||||
}
|
||||
|
||||
if c.ChrootMountPath == "" {
|
||||
path, err := interpolate.Render("/mnt/packer-hyperone-volumes/{{timestamp}}", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.ChrootMountPath = path
|
||||
}
|
||||
|
||||
if c.ChrootMounts == nil {
|
||||
c.ChrootMounts = make([][]string, 0)
|
||||
}
|
||||
|
||||
if len(c.ChrootMounts) == 0 {
|
||||
c.ChrootMounts = [][]string{
|
||||
{"proc", "proc", "/proc"},
|
||||
{"sysfs", "sysfs", "/sys"},
|
||||
{"bind", "/dev", "/dev"},
|
||||
{"devpts", "devpts", "/dev/pts"},
|
||||
{"binfmt_misc", "binfmt_misc", "/proc/sys/fs/binfmt_misc"},
|
||||
}
|
||||
}
|
||||
|
||||
if c.ChrootCopyFiles == nil {
|
||||
c.ChrootCopyFiles = []string{"/etc/resolv.conf"}
|
||||
}
|
||||
|
||||
if c.MountPartition == "" {
|
||||
c.MountPartition = "1"
|
||||
}
|
||||
|
||||
// Validation
|
||||
var errs *packersdk.MultiError
|
||||
errs = packersdk.MultiErrorAppend(errs, c.ImageTag.CopyOn(&c.ImageTags)...)
|
||||
errs = packersdk.MultiErrorAppend(errs, c.VmTag.CopyOn(&c.VmTags)...)
|
||||
|
||||
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
|
||||
errs = packersdk.MultiErrorAppend(errs, es...)
|
||||
}
|
||||
|
||||
if c.Token == "" {
|
||||
errs = packersdk.MultiErrorAppend(errs, errors.New("token is required"))
|
||||
}
|
||||
|
||||
if c.VmType == "" {
|
||||
errs = packersdk.MultiErrorAppend(errs, errors.New("vm type is required"))
|
||||
}
|
||||
|
||||
if c.DiskSize == 0 {
|
||||
errs = packersdk.MultiErrorAppend(errs, errors.New("disk size is required"))
|
||||
}
|
||||
|
||||
if c.SourceImage == "" {
|
||||
errs = packersdk.MultiErrorAppend(errs, errors.New("source image is required"))
|
||||
}
|
||||
|
||||
if c.ChrootDisk {
|
||||
if len(c.PreMountCommands) == 0 {
|
||||
errs = packersdk.MultiErrorAppend(errs, errors.New("pre-mount commands are required for chroot disk"))
|
||||
}
|
||||
}
|
||||
|
||||
for _, mounts := range c.ChrootMounts {
|
||||
if len(mounts) != 3 {
|
||||
errs = packersdk.MultiErrorAppend(
|
||||
errs, errors.New("each chroot_mounts entry should have three elements"))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
packersdk.LogSecretFilter.Set(c.Token)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type cliConfig struct {
|
||||
Profile struct {
|
||||
APIKey string `json:"apiKey"`
|
||||
Project struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"project"`
|
||||
} `json:"profile"`
|
||||
}
|
||||
|
||||
func loadCLIConfig() (cliConfig, error) {
|
||||
path, err := homedir.Expand(configPath)
|
||||
if err != nil {
|
||||
return cliConfig{}, err
|
||||
}
|
||||
|
||||
_, err = os.Stat(path)
|
||||
if err != nil {
|
||||
// Config not found
|
||||
return cliConfig{}, nil
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return cliConfig{}, err
|
||||
}
|
||||
|
||||
var c cliConfig
|
||||
err = json.Unmarshal(content, &c)
|
||||
if err != nil {
|
||||
return cliConfig{}, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getPublicIP(state multistep.StateBag) (string, error) {
|
||||
return state.Get("public_ip").(string), nil
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||
|
||||
package hyperone
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatConfig is an auto-generated flat version of Config.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatConfig struct {
|
||||
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
|
||||
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
|
||||
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
|
||||
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
|
||||
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
|
||||
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
|
||||
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
|
||||
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
|
||||
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
|
||||
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
|
||||
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
|
||||
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
|
||||
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
|
||||
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
|
||||
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
|
||||
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
|
||||
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
|
||||
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
|
||||
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
|
||||
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
|
||||
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
|
||||
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
|
||||
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
|
||||
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
|
||||
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
|
||||
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
|
||||
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
|
||||
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
|
||||
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
|
||||
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
|
||||
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
|
||||
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
|
||||
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
|
||||
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
|
||||
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
|
||||
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
|
||||
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
|
||||
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
|
||||
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
|
||||
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
|
||||
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
|
||||
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
|
||||
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
|
||||
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
|
||||
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
|
||||
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
|
||||
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
|
||||
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
|
||||
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
|
||||
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
|
||||
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
|
||||
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
|
||||
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
|
||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||
APIURL *string `mapstructure:"api_url" required:"false" cty:"api_url" hcl:"api_url"`
|
||||
Token *string `mapstructure:"token" required:"true" cty:"token" hcl:"token"`
|
||||
Project *string `mapstructure:"project" required:"true" cty:"project" hcl:"project"`
|
||||
TokenLogin *string `mapstructure:"token_login" required:"false" cty:"token_login" hcl:"token_login"`
|
||||
StateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout" hcl:"state_timeout"`
|
||||
SourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||
ImageName *string `mapstructure:"image_name" required:"false" cty:"image_name" hcl:"image_name"`
|
||||
ImageDescription *string `mapstructure:"image_description" required:"false" cty:"image_description" hcl:"image_description"`
|
||||
ImageTags map[string]string `mapstructure:"image_tags" required:"false" cty:"image_tags" hcl:"image_tags"`
|
||||
ImageTag []config.FlatKeyValue `mapstructure:"image_tag" required:"false" cty:"image_tag" hcl:"image_tag"`
|
||||
ImageService *string `mapstructure:"image_service" required:"false" cty:"image_service" hcl:"image_service"`
|
||||
VmType *string `mapstructure:"vm_type" required:"true" cty:"vm_type" hcl:"vm_type"`
|
||||
VmName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"`
|
||||
VmTags map[string]string `mapstructure:"vm_tags" required:"false" cty:"vm_tags" hcl:"vm_tags"`
|
||||
VmTag []config.FlatNameValue `mapstructure:"vm_tag" required:"false" cty:"vm_tag" hcl:"vm_tag"`
|
||||
DiskName *string `mapstructure:"disk_name" required:"false" cty:"disk_name" hcl:"disk_name"`
|
||||
DiskType *string `mapstructure:"disk_type" required:"false" cty:"disk_type" hcl:"disk_type"`
|
||||
DiskSize *float32 `mapstructure:"disk_size" required:"true" cty:"disk_size" hcl:"disk_size"`
|
||||
Network *string `mapstructure:"network" required:"false" cty:"network" hcl:"network"`
|
||||
PrivateIP *string `mapstructure:"private_ip" required:"false" cty:"private_ip" hcl:"private_ip"`
|
||||
PublicIP *string `mapstructure:"public_ip" required:"false" cty:"public_ip" hcl:"public_ip"`
|
||||
PublicNetAdpService *string `mapstructure:"public_netadp_service" required:"false" cty:"public_netadp_service" hcl:"public_netadp_service"`
|
||||
ChrootDevice *string `mapstructure:"chroot_device" cty:"chroot_device" hcl:"chroot_device"`
|
||||
ChrootDisk *bool `mapstructure:"chroot_disk" cty:"chroot_disk" hcl:"chroot_disk"`
|
||||
ChrootDiskSize *float32 `mapstructure:"chroot_disk_size" cty:"chroot_disk_size" hcl:"chroot_disk_size"`
|
||||
ChrootDiskType *string `mapstructure:"chroot_disk_type" cty:"chroot_disk_type" hcl:"chroot_disk_type"`
|
||||
ChrootMountPath *string `mapstructure:"chroot_mount_path" cty:"chroot_mount_path" hcl:"chroot_mount_path"`
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts" cty:"chroot_mounts" hcl:"chroot_mounts"`
|
||||
ChrootCopyFiles []string `mapstructure:"chroot_copy_files" cty:"chroot_copy_files" hcl:"chroot_copy_files"`
|
||||
ChrootCommandWrapper *string `mapstructure:"chroot_command_wrapper" cty:"chroot_command_wrapper" hcl:"chroot_command_wrapper"`
|
||||
MountOptions []string `mapstructure:"mount_options" cty:"mount_options" hcl:"mount_options"`
|
||||
MountPartition *string `mapstructure:"mount_partition" cty:"mount_partition" hcl:"mount_partition"`
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands" cty:"pre_mount_commands" hcl:"pre_mount_commands"`
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands" cty:"post_mount_commands" hcl:"post_mount_commands"`
|
||||
SSHKeys []string `mapstructure:"ssh_keys" required:"false" cty:"ssh_keys" hcl:"ssh_keys"`
|
||||
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
// FlatConfig is an auto-generated flat version of Config.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a Config.
|
||||
// This spec is used by HCL to read the fields of Config.
|
||||
// The decoded values from this spec will then be applied to a FlatConfig.
|
||||
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
|
||||
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
|
||||
"packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false},
|
||||
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
|
||||
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
|
||||
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
|
||||
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
|
||||
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
|
||||
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
|
||||
"ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false},
|
||||
"ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false},
|
||||
"ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false},
|
||||
"ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false},
|
||||
"temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false},
|
||||
"temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false},
|
||||
"temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false},
|
||||
"ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false},
|
||||
"ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false},
|
||||
"ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false},
|
||||
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
|
||||
"ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false},
|
||||
"ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false},
|
||||
"ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false},
|
||||
"ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false},
|
||||
"ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false},
|
||||
"ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false},
|
||||
"ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false},
|
||||
"ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false},
|
||||
"ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false},
|
||||
"ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false},
|
||||
"ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false},
|
||||
"ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false},
|
||||
"ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false},
|
||||
"ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false},
|
||||
"ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false},
|
||||
"ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false},
|
||||
"ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false},
|
||||
"ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false},
|
||||
"ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false},
|
||||
"ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false},
|
||||
"ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false},
|
||||
"ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false},
|
||||
"ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false},
|
||||
"ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false},
|
||||
"ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false},
|
||||
"ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false},
|
||||
"winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false},
|
||||
"winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false},
|
||||
"winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false},
|
||||
"winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false},
|
||||
"winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false},
|
||||
"winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false},
|
||||
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
|
||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||
"api_url": &hcldec.AttrSpec{Name: "api_url", Type: cty.String, Required: false},
|
||||
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||
"project": &hcldec.AttrSpec{Name: "project", Type: cty.String, Required: false},
|
||||
"token_login": &hcldec.AttrSpec{Name: "token_login", Type: cty.String, Required: false},
|
||||
"state_timeout": &hcldec.AttrSpec{Name: "state_timeout", Type: cty.String, Required: false},
|
||||
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
|
||||
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
|
||||
"image_tags": &hcldec.AttrSpec{Name: "image_tags", Type: cty.Map(cty.String), Required: false},
|
||||
"image_tag": &hcldec.BlockListSpec{TypeName: "image_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
|
||||
"image_service": &hcldec.AttrSpec{Name: "image_service", Type: cty.String, Required: false},
|
||||
"vm_type": &hcldec.AttrSpec{Name: "vm_type", Type: cty.String, Required: false},
|
||||
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
|
||||
"vm_tags": &hcldec.AttrSpec{Name: "vm_tags", Type: cty.Map(cty.String), Required: false},
|
||||
"vm_tag": &hcldec.BlockListSpec{TypeName: "vm_tag", Nested: hcldec.ObjectSpec((*config.FlatNameValue)(nil).HCL2Spec())},
|
||||
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
|
||||
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
|
||||
"private_ip": &hcldec.AttrSpec{Name: "private_ip", Type: cty.String, Required: false},
|
||||
"public_ip": &hcldec.AttrSpec{Name: "public_ip", Type: cty.String, Required: false},
|
||||
"public_netadp_service": &hcldec.AttrSpec{Name: "public_netadp_service", Type: cty.String, Required: false},
|
||||
"chroot_device": &hcldec.AttrSpec{Name: "chroot_device", Type: cty.String, Required: false},
|
||||
"chroot_disk": &hcldec.AttrSpec{Name: "chroot_disk", Type: cty.Bool, Required: false},
|
||||
"chroot_disk_size": &hcldec.AttrSpec{Name: "chroot_disk_size", Type: cty.Number, Required: false},
|
||||
"chroot_disk_type": &hcldec.AttrSpec{Name: "chroot_disk_type", Type: cty.String, Required: false},
|
||||
"chroot_mount_path": &hcldec.AttrSpec{Name: "chroot_mount_path", Type: cty.String, Required: false},
|
||||
"chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false},
|
||||
"chroot_copy_files": &hcldec.AttrSpec{Name: "chroot_copy_files", Type: cty.List(cty.String), Required: false},
|
||||
"chroot_command_wrapper": &hcldec.AttrSpec{Name: "chroot_command_wrapper", Type: cty.String, Required: false},
|
||||
"mount_options": &hcldec.AttrSpec{Name: "mount_options", Type: cty.List(cty.String), Required: false},
|
||||
"mount_partition": &hcldec.AttrSpec{Name: "mount_partition", Type: cty.String, Required: false},
|
||||
"pre_mount_commands": &hcldec.AttrSpec{Name: "pre_mount_commands", Type: cty.List(cty.String), Required: false},
|
||||
"post_mount_commands": &hcldec.AttrSpec{Name: "post_mount_commands", Type: cty.List(cty.String), Required: false},
|
||||
"ssh_keys": &hcldec.AttrSpec{Name: "ssh_keys", Type: cty.List(cty.String), Required: false},
|
||||
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"variables": {
|
||||
"token": "{{ env `HYPERONE_TOKEN` }}",
|
||||
"project": "{{ env `HYPERONE_PROJECT` }}"
|
||||
},
|
||||
"builders": [
|
||||
{
|
||||
"token": "{{ user `token` }}",
|
||||
"project": "{{ user `project` }}",
|
||||
"type": "hyperone",
|
||||
"source_image": "ubuntu",
|
||||
"disk_size": 10,
|
||||
"vm_type": "a1.nano"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "shell",
|
||||
"inline": [
|
||||
"apt-get update",
|
||||
"apt-get upgrade -y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"variables": {
|
||||
"token": "{{ env `HYPERONE_TOKEN` }}",
|
||||
"project": "{{ env `HYPERONE_PROJECT` }}"
|
||||
},
|
||||
"builders": [
|
||||
{
|
||||
"token": "{{ user `token` }}",
|
||||
"project": "{{ user `project` }}",
|
||||
"type": "hyperone",
|
||||
"source_image": "ubuntu",
|
||||
"disk_size": 10,
|
||||
"vm_type": "a1.nano",
|
||||
|
||||
"chroot_disk": true,
|
||||
"chroot_command_wrapper": "sudo {{.Command}}",
|
||||
"pre_mount_commands": [
|
||||
"parted {{.Device}} mklabel msdos mkpart primary 1M 100% set 1 boot on print",
|
||||
"mkfs.ext4 {{.Device}}1"
|
||||
],
|
||||
"post_mount_commands": [
|
||||
"apt-get update",
|
||||
"apt-get install debootstrap",
|
||||
"debootstrap --arch amd64 bionic {{.MountPath}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"provisioners": []
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
variable "token" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "project" {
|
||||
type = string
|
||||
}
|
||||
|
||||
source "hyperone" "new-syntax" {
|
||||
token = var.token
|
||||
project = var.project
|
||||
source_image = "debian"
|
||||
disk_size = 10
|
||||
vm_type = "a1.nano"
|
||||
image_name = "packerbats-hcl-{{timestamp}}"
|
||||
image_tags = {
|
||||
key="value"
|
||||
}
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.hyperone.new-syntax"
|
||||
]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"apt-get update",
|
||||
"apt-get upgrade -y"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type stepChrootProvision struct{}
|
||||
|
||||
func (s *stepChrootProvision) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
||||
sshCommunicator := state.Get("communicator").(packersdk.Communicator)
|
||||
|
||||
comm := &ChrootCommunicator{
|
||||
Chroot: config.ChrootMountPath,
|
||||
CmdWrapper: wrappedCommand,
|
||||
Wrapped: sshCommunicator,
|
||||
}
|
||||
|
||||
stepProvision := commonsteps.StepProvision{Comm: comm}
|
||||
return stepProvision.Run(ctx, state)
|
||||
}
|
||||
|
||||
func (s *stepChrootProvision) Cleanup(multistep.StateBag) {}
|
|
@ -1,40 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type stepCopyFiles struct{}
|
||||
|
||||
func (s *stepCopyFiles) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
|
||||
if len(config.ChrootCopyFiles) == 0 {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
ui.Say("Copying files from host to chroot...")
|
||||
for _, path := range config.ChrootCopyFiles {
|
||||
chrootPath := filepath.Join(config.ChrootMountPath, path)
|
||||
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
||||
|
||||
command := fmt.Sprintf("cp --remove-destination %s %s", path, chrootPath)
|
||||
err := runCommands([]string{command}, config.ctx, state)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCopyFiles) Cleanup(state multistep.StateBag) {}
|
|
@ -1,65 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type stepCreateImage struct {
|
||||
imageID string
|
||||
}
|
||||
|
||||
func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
vmID := state.Get("vm_id").(string)
|
||||
|
||||
ui.Say("Creating image...")
|
||||
|
||||
image, _, err := client.ImageApi.ImageCreate(ctx, openapi.ImageCreate{
|
||||
Name: config.ImageName,
|
||||
Vm: vmID,
|
||||
Service: config.ImageService,
|
||||
Description: config.ImageDescription,
|
||||
Tag: config.ImageTags,
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating image: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.imageID = image.Id
|
||||
|
||||
state.Put("image_id", image.Id)
|
||||
state.Put("image_name", image.Name)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateImage) Cleanup(state multistep.StateBag) {
|
||||
if s.imageID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
if !cancelled && !halted {
|
||||
return
|
||||
}
|
||||
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
|
||||
_, err := client.ImageApi.ImageDelete(context.TODO(), s.imageID)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("error deleting image '%s' - consider deleting it manually: %s",
|
||||
s.imageID, formatOpenAPIError(err)))
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type stepCreateSSHKey struct {
|
||||
Debug bool
|
||||
DebugKeyPath string
|
||||
}
|
||||
|
||||
func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
c := state.Get("config").(*Config)
|
||||
ui.Say("Creating a temporary ssh key for the VM...")
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("error generating ssh key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
privDER := x509.MarshalPKCS1PrivateKey(priv)
|
||||
privBLK := pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Headers: nil,
|
||||
Bytes: privDER,
|
||||
}
|
||||
|
||||
c.Comm.SSHPrivateKey = pem.EncodeToMemory(&privBLK)
|
||||
|
||||
pub, err := ssh.NewPublicKey(&priv.PublicKey)
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("error getting public key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
pubSSHFormat := string(ssh.MarshalAuthorizedKey(pub))
|
||||
|
||||
// Remember public SSH key for future connections
|
||||
state.Put("ssh_public_key", pubSSHFormat)
|
||||
|
||||
// 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(&privBLK)); 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
|
||||
}
|
||||
|
||||
func (s *stepCreateSSHKey) Cleanup(state multistep.StateBag) {}
|
|
@ -1,203 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type stepCreateVM struct {
|
||||
vmID string
|
||||
}
|
||||
|
||||
const (
|
||||
chrootDiskName = "packer-chroot-disk"
|
||||
)
|
||||
|
||||
func (s *stepCreateVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
sshKey := state.Get("ssh_public_key").(string)
|
||||
|
||||
ui.Say("Creating VM...")
|
||||
|
||||
netAdapter := pickNetAdapter(config)
|
||||
|
||||
var sshKeys = []string{sshKey}
|
||||
sshKeys = append(sshKeys, config.SSHKeys...)
|
||||
|
||||
disks := []openapi.VmCreateDisk{
|
||||
{
|
||||
Service: config.DiskType,
|
||||
Size: config.DiskSize,
|
||||
},
|
||||
}
|
||||
|
||||
if config.ChrootDisk {
|
||||
disks = append(disks, openapi.VmCreateDisk{
|
||||
Service: config.ChrootDiskType,
|
||||
Size: config.ChrootDiskSize,
|
||||
Name: chrootDiskName,
|
||||
})
|
||||
}
|
||||
|
||||
options := openapi.VmCreate{
|
||||
Name: config.VmName,
|
||||
Image: config.SourceImage,
|
||||
Service: config.VmType,
|
||||
SshKeys: sshKeys,
|
||||
Disk: disks,
|
||||
Netadp: []openapi.VmCreateNetadp{netAdapter},
|
||||
UserMetadata: config.UserData,
|
||||
Tag: config.VmTags,
|
||||
Username: config.Comm.SSHUsername,
|
||||
}
|
||||
|
||||
vm, _, err := client.VmApi.VmCreate(ctx, options)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating VM: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.vmID = vm.Id
|
||||
state.Put("vm_id", vm.Id)
|
||||
// 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", vm.Id)
|
||||
|
||||
hdds, _, err := client.VmApi.VmListHdd(ctx, vm.Id)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error listing hdd: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
for _, hdd := range hdds {
|
||||
if hdd.Disk.Name == chrootDiskName {
|
||||
state.Put("chroot_disk_id", hdd.Disk.Id)
|
||||
controllerNumber := strings.ToLower(strings.Trim(hdd.ControllerNumber, "{}"))
|
||||
state.Put("chroot_controller_number", controllerNumber)
|
||||
state.Put("chroot_controller_location", int(hdd.ControllerLocation))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
netadp, _, err := client.VmApi.VmListNetadp(ctx, vm.Id)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error listing netadp: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(netadp) < 1 {
|
||||
err := fmt.Errorf("no network adapters found")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
publicIP, err := associatePublicIP(ctx, config, client, netadp[0])
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error associating IP: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("public_ip", publicIP)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func pickNetAdapter(config *Config) openapi.VmCreateNetadp {
|
||||
if config.Network == "" {
|
||||
if config.PublicIP != "" {
|
||||
return openapi.VmCreateNetadp{
|
||||
Service: config.PublicNetAdpService,
|
||||
Ip: []string{config.PublicIP},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var privateIPs []string
|
||||
|
||||
if config.PrivateIP == "" {
|
||||
privateIPs = nil
|
||||
} else {
|
||||
privateIPs = []string{config.PrivateIP}
|
||||
}
|
||||
|
||||
return openapi.VmCreateNetadp{
|
||||
Service: "private",
|
||||
Network: config.Network,
|
||||
Ip: privateIPs,
|
||||
}
|
||||
}
|
||||
|
||||
return openapi.VmCreateNetadp{
|
||||
Service: config.PublicNetAdpService,
|
||||
}
|
||||
}
|
||||
|
||||
func associatePublicIP(ctx context.Context, config *Config, client *openapi.APIClient, netadp openapi.Netadp) (string, error) {
|
||||
if config.Network == "" || config.PublicIP == "" {
|
||||
// Public IP belongs to attached net adapter
|
||||
return netadp.Ip[0].Address, nil
|
||||
}
|
||||
|
||||
var privateIP string
|
||||
if config.PrivateIP == "" {
|
||||
privateIP = netadp.Ip[0].Id
|
||||
} else {
|
||||
privateIP = config.PrivateIP
|
||||
}
|
||||
|
||||
ip, _, err := client.IpApi.IpActionAssociate(ctx, config.PublicIP, openapi.IpActionAssociate{Ip: privateIP})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ip.Address, nil
|
||||
}
|
||||
|
||||
func (s *stepCreateVM) Cleanup(state multistep.StateBag) {
|
||||
if s.vmID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
|
||||
ui.Say(fmt.Sprintf("Deleting VM %s...", s.vmID))
|
||||
err := deleteVMWithDisks(s.vmID, state)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func deleteVMWithDisks(vmID string, state multistep.StateBag) error {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
hdds, _, err := client.VmApi.VmListHdd(context.TODO(), vmID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing hdd: %s", formatOpenAPIError(err))
|
||||
}
|
||||
|
||||
deleteOptions := openapi.VmDelete{}
|
||||
for _, hdd := range hdds {
|
||||
deleteOptions.RemoveDisks = append(deleteOptions.RemoveDisks, hdd.Disk.Id)
|
||||
}
|
||||
|
||||
_, err = client.VmApi.VmDelete(context.TODO(), vmID, deleteOptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting server '%s' - please delete it manually: %s", vmID, formatOpenAPIError(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type stepCreateVMFromDisk struct {
|
||||
vmID string
|
||||
}
|
||||
|
||||
func (s *stepCreateVMFromDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
sshKey := state.Get("ssh_public_key").(string)
|
||||
chrootDiskID := state.Get("chroot_disk_id").(string)
|
||||
|
||||
ui.Say("Creating VM from disk...")
|
||||
|
||||
options := openapi.VmCreate{
|
||||
Name: config.VmName,
|
||||
Service: config.VmType,
|
||||
Disk: []openapi.VmCreateDisk{
|
||||
{
|
||||
Id: chrootDiskID,
|
||||
},
|
||||
},
|
||||
SshKeys: []string{sshKey},
|
||||
Boot: false,
|
||||
}
|
||||
|
||||
vm, _, err := client.VmApi.VmCreate(ctx, options)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating VM from disk: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.vmID = vm.Id
|
||||
state.Put("vm_id", vm.Id)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateVMFromDisk) Cleanup(state multistep.StateBag) {
|
||||
if s.vmID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
|
||||
ui.Say(fmt.Sprintf("Deleting VM %s (from chroot disk)...", s.vmID))
|
||||
err := deleteVMWithDisks(s.vmID, state)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPickNetAdapter(t *testing.T) {
|
||||
cases := []struct {
|
||||
Name string
|
||||
Config Config
|
||||
Expected openapi.VmCreateNetadp
|
||||
}{
|
||||
{
|
||||
Name: "no_network",
|
||||
Config: Config{
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "public",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "no_network_public_ip",
|
||||
Config: Config{
|
||||
PublicIP: "some-public-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "public",
|
||||
Ip: []string{"some-public-ip"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "no_network_private_ip",
|
||||
Config: Config{
|
||||
PrivateIP: "some-private-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "public",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "no_network_both_ip",
|
||||
Config: Config{
|
||||
PublicIP: "some-public-ip",
|
||||
PrivateIP: "some-private-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "public",
|
||||
Ip: []string{"some-public-ip"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "network_no_ip",
|
||||
Config: Config{
|
||||
Network: "some-network",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "private",
|
||||
Network: "some-network",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "network_public_ip",
|
||||
Config: Config{
|
||||
Network: "some-network",
|
||||
PublicIP: "some-public-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "private",
|
||||
Network: "some-network",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "network_private_ip",
|
||||
Config: Config{
|
||||
Network: "some-network",
|
||||
PrivateIP: "some-private-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "private",
|
||||
Network: "some-network",
|
||||
Ip: []string{"some-private-ip"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "network_both_ip",
|
||||
Config: Config{
|
||||
Network: "some-network",
|
||||
PublicIP: "some-public-ip",
|
||||
PrivateIP: "some-private-ip",
|
||||
PublicNetAdpService: "public",
|
||||
},
|
||||
Expected: openapi.VmCreateNetadp{
|
||||
Service: "private",
|
||||
Network: "some-network",
|
||||
Ip: []string{"some-private-ip"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.Name, func(t *testing.T) {
|
||||
result := pickNetAdapter(&c.Config)
|
||||
assert.Equal(t, c.Expected, result)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type stepDetachDisk struct {
|
||||
vmID string
|
||||
}
|
||||
|
||||
func (s *stepDetachDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
vmID := state.Get("vm_id").(string)
|
||||
chrootDiskID := state.Get("chroot_disk_id").(string)
|
||||
|
||||
ui.Say("Detaching chroot disk...")
|
||||
_, _, err := client.VmApi.VmDeleteHddDiskId(ctx, vmID, chrootDiskID)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error detaching disk: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepDetachDisk) Cleanup(state multistep.StateBag) {}
|
|
@ -1,51 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type stepMountChroot struct{}
|
||||
|
||||
func (s *stepMountChroot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
device := state.Get("device").(string)
|
||||
|
||||
log.Printf("Mount path: %s", config.ChrootMountPath)
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating mount directory: %s", config.ChrootMountPath))
|
||||
|
||||
opts := ""
|
||||
if len(config.MountOptions) > 0 {
|
||||
opts = "-o " + strings.Join(config.MountOptions, " -o ")
|
||||
}
|
||||
|
||||
deviceMount := device
|
||||
if config.MountPartition != "" {
|
||||
deviceMount = fmt.Sprintf("%s%s", device, config.MountPartition)
|
||||
}
|
||||
|
||||
commands := []string{
|
||||
fmt.Sprintf("mkdir -m 755 -p %s", config.ChrootMountPath),
|
||||
fmt.Sprintf("mount %s %s %s", opts, deviceMount, config.ChrootMountPath),
|
||||
}
|
||||
|
||||
err := runCommands(commands, config.ctx, state)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("mount_path", config.ChrootMountPath)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepMountChroot) Cleanup(state multistep.StateBag) {}
|
|
@ -1,45 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type stepMountExtra struct{}
|
||||
|
||||
func (s *stepMountExtra) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
mountPath := state.Get("mount_path").(string)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
|
||||
ui.Say("Mounting additional paths within the chroot...")
|
||||
for _, mountInfo := range config.ChrootMounts {
|
||||
innerPath := mountPath + mountInfo[2]
|
||||
|
||||
flags := "-t " + mountInfo[0]
|
||||
if mountInfo[0] == "bind" {
|
||||
flags = "--bind"
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2]))
|
||||
|
||||
commands := []string{
|
||||
fmt.Sprintf("mkdir -m 755 -p %s", innerPath),
|
||||
fmt.Sprintf("mount %s %s %s", flags, mountInfo[1], innerPath),
|
||||
}
|
||||
|
||||
err := runCommands(commands, config.ctx, state)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepMountExtra) Cleanup(state multistep.StateBag) {}
|
|
@ -1,37 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type postMountCommandsData struct {
|
||||
Device string
|
||||
MountPath string
|
||||
}
|
||||
|
||||
type stepPostMountCommands struct{}
|
||||
|
||||
func (s *stepPostMountCommands) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
device := state.Get("device").(string)
|
||||
|
||||
ictx := config.ctx
|
||||
ictx.Data = &postMountCommandsData{
|
||||
Device: device,
|
||||
MountPath: config.ChrootMountPath,
|
||||
}
|
||||
|
||||
ui.Say("Running post-mount commands...")
|
||||
if err := runCommands(config.PostMountCommands, ictx, state); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepPostMountCommands) Cleanup(state multistep.StateBag) {}
|
|
@ -1,37 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type preMountCommandsData struct {
|
||||
Device string
|
||||
MountPath string
|
||||
}
|
||||
|
||||
type stepPreMountCommands struct{}
|
||||
|
||||
func (s *stepPreMountCommands) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
device := state.Get("device").(string)
|
||||
|
||||
ictx := config.ctx
|
||||
ictx.Data = &preMountCommandsData{
|
||||
Device: device,
|
||||
MountPath: config.ChrootMountPath,
|
||||
}
|
||||
|
||||
ui.Say("Running pre-mount commands...")
|
||||
if err := runCommands(config.PreMountCommands, ictx, state); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepPreMountCommands) Cleanup(state multistep.StateBag) {}
|
|
@ -1,57 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
const (
|
||||
vmBusPath = "/sys/bus/vmbus/devices"
|
||||
)
|
||||
|
||||
type stepPrepareDevice struct{}
|
||||
|
||||
func (s *stepPrepareDevice) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
|
||||
if config.ChrootDevice != "" {
|
||||
state.Put("device", config.ChrootDevice)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
controllerNumber := state.Get("chroot_controller_number").(string)
|
||||
controllerLocation := state.Get("chroot_controller_location").(int)
|
||||
|
||||
log.Println("Searching for available device...")
|
||||
|
||||
cmd := fmt.Sprintf("find %s/%s/ -path *:%d/block -exec ls {} \\;",
|
||||
vmBusPath, controllerNumber, controllerLocation)
|
||||
|
||||
block, err := captureOutput(cmd, state)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error finding available device: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if block == "" {
|
||||
err := fmt.Errorf("device not found")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
device := fmt.Sprintf("/dev/%s", block)
|
||||
|
||||
ui.Say(fmt.Sprintf("Found device: %s", device))
|
||||
state.Put("device", device)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepPrepareDevice) Cleanup(state multistep.StateBag) {}
|
|
@ -1,32 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
type stepStopVM struct{}
|
||||
|
||||
func (s *stepStopVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*openapi.APIClient)
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
vmID := state.Get("vm_id").(string)
|
||||
|
||||
ui.Say("Stopping VM...")
|
||||
|
||||
_, _, err := client.VmApi.VmActionStop(ctx, vmID)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error stopping VM: %s", formatOpenAPIError(err))
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepStopVM) Cleanup(multistep.StateBag) {}
|
|
@ -1,89 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/json"
|
||||
)
|
||||
|
||||
const (
|
||||
sshAddress = "api.hyperone.com:22"
|
||||
sshSubsystem = "rbx-auth"
|
||||
hostKeyHash = "3e2aa423d42d7e8b14d50625512c8ac19db767ed"
|
||||
)
|
||||
|
||||
type sshData struct {
|
||||
ID string `json:"_id"`
|
||||
}
|
||||
|
||||
func sshAgent() ssh.AuthMethod {
|
||||
if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
|
||||
return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchTokenBySSH(user string) (string, error) {
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{
|
||||
sshAgent(),
|
||||
},
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
hash := sha1Sum(key)
|
||||
if hash != hostKeyHash {
|
||||
return fmt.Errorf("invalid host key hash: %s", hash)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
client, err := ssh.Dial("tcp", sshAddress, sshConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = session.RequestSubsystem(sshSubsystem)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
out, err := ioutil.ReadAll(stdout)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var data sshData
|
||||
err = json.Unmarshal(out, &data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return data.ID, nil
|
||||
}
|
||||
|
||||
func sha1Sum(pubKey ssh.PublicKey) string {
|
||||
sum := sha1.Sum(pubKey.Marshal())
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package hyperone
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
openapi "github.com/hyperonecom/h1-client-go"
|
||||
)
|
||||
|
||||
func formatOpenAPIError(err error) string {
|
||||
openAPIError, ok := err.(openapi.GenericOpenAPIError)
|
||||
if !ok {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (body: %s)", openAPIError.Error(), openAPIError.Body())
|
||||
}
|
||||
|
||||
func runCommands(commands []string, ictx interpolate.Context, state multistep.StateBag) error {
|
||||
ctx := context.TODO()
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
||||
comm := state.Get("communicator").(packersdk.Communicator)
|
||||
|
||||
for _, rawCmd := range commands {
|
||||
intCmd, err := interpolate.Render(rawCmd, &ictx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error interpolating: %s", err)
|
||||
}
|
||||
|
||||
command, err := wrappedCommand(intCmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error wrapping command: %s", err)
|
||||
}
|
||||
|
||||
remoteCmd := &packersdk.RemoteCmd{
|
||||
Command: command,
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
||||
|
||||
err = remoteCmd.RunWithUi(ctx, comm, ui)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error running remote cmd: %s", err)
|
||||
}
|
||||
|
||||
if remoteCmd.ExitStatus() != 0 {
|
||||
return fmt.Errorf(
|
||||
"received non-zero exit code %d from command: %s",
|
||||
remoteCmd.ExitStatus(),
|
||||
command)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func captureOutput(command string, state multistep.StateBag) (string, error) {
|
||||
ctx := context.TODO()
|
||||
comm := state.Get("communicator").(packersdk.Communicator)
|
||||
|
||||
var stdout bytes.Buffer
|
||||
remoteCmd := &packersdk.RemoteCmd{
|
||||
Command: command,
|
||||
Stdout: &stdout,
|
||||
}
|
||||
|
||||
log.Println(fmt.Sprintf("Executing command: %s", command))
|
||||
|
||||
err := comm.Start(ctx, remoteCmd)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error running remote cmd: %s", err)
|
||||
}
|
||||
|
||||
remoteCmd.Wait()
|
||||
if remoteCmd.ExitStatus() != 0 {
|
||||
return "", fmt.Errorf(
|
||||
"received non-zero exit code %d from command: %s",
|
||||
remoteCmd.ExitStatus(),
|
||||
command)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(stdout.String()), nil
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var HyperonePluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
HyperonePluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -19,7 +19,6 @@ import (
|
|||
digitaloceanbuilder "github.com/hashicorp/packer/builder/digitalocean"
|
||||
filebuilder "github.com/hashicorp/packer/builder/file"
|
||||
hcloudbuilder "github.com/hashicorp/packer/builder/hcloud"
|
||||
hyperonebuilder "github.com/hashicorp/packer/builder/hyperone"
|
||||
hypervisobuilder "github.com/hashicorp/packer/builder/hyperv/iso"
|
||||
hypervvmcxbuilder "github.com/hashicorp/packer/builder/hyperv/vmcx"
|
||||
jdcloudbuilder "github.com/hashicorp/packer/builder/jdcloud"
|
||||
|
@ -72,7 +71,6 @@ var Builders = map[string]packersdk.Builder{
|
|||
"digitalocean": new(digitaloceanbuilder.Builder),
|
||||
"file": new(filebuilder.Builder),
|
||||
"hcloud": new(hcloudbuilder.Builder),
|
||||
"hyperone": new(hyperonebuilder.Builder),
|
||||
"hyperv-iso": new(hypervisobuilder.Builder),
|
||||
"hyperv-vmcx": new(hypervvmcxbuilder.Builder),
|
||||
"jdcloud": new(jdcloudbuilder.Builder),
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
googlecomputebuilder "github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute"
|
||||
googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export"
|
||||
googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import"
|
||||
hyperonebuilder "github.com/hashicorp/packer-plugin-hyperone/builder/hyperone"
|
||||
ncloudbuilder "github.com/hashicorp/packer-plugin-ncloud/builder/ncloud"
|
||||
openstackbuilder "github.com/hashicorp/packer-plugin-openstack/builder/openstack"
|
||||
oscbsubuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu"
|
||||
|
@ -94,6 +95,7 @@ var VendoredBuilders = map[string]packersdk.Builder{
|
|||
"osc-bsusurrogate": new(oscbsusurrogatebuilder.Builder),
|
||||
"osc-bsuvolume": new(oscbsuvolumebuilder.Builder),
|
||||
"osc-chroot": new(oscchrootbuilder.Builder),
|
||||
"hyperone": new(hyperonebuilder.Builder),
|
||||
}
|
||||
|
||||
// VendoredProvisioners are provisioner components that were once bundled with the
|
||||
|
|
4
go.mod
4
go.mod
|
@ -44,6 +44,7 @@ require (
|
|||
github.com/hashicorp/packer-plugin-cloudstack v0.0.1
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1
|
||||
github.com/hashicorp/packer-plugin-hyperone v0.0.1
|
||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2
|
||||
github.com/hashicorp/packer-plugin-openstack v0.0.1
|
||||
github.com/hashicorp/packer-plugin-outscale v0.0.1
|
||||
|
@ -57,7 +58,6 @@ require (
|
|||
github.com/hashicorp/packer-plugin-vmware v0.0.1
|
||||
github.com/hashicorp/packer-plugin-vsphere v0.0.1
|
||||
github.com/hetznercloud/hcloud-go v1.15.1
|
||||
github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4
|
||||
github.com/jdcloud-api/jdcloud-sdk-go v1.9.1-0.20190605102154-3d81a50ca961
|
||||
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62
|
||||
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec
|
||||
|
@ -66,7 +66,7 @@ require (
|
|||
github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08
|
||||
github.com/mitchellh/cli v1.1.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.4.0
|
||||
github.com/mitchellh/mapstructure v1.4.1
|
||||
github.com/mitchellh/panicwrap v1.0.0
|
||||
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
|
||||
github.com/mitchellh/reflectwalk v1.0.0
|
||||
|
|
5
go.sum
5
go.sum
|
@ -476,6 +476,8 @@ github.com/hashicorp/packer-plugin-docker v0.0.7 h1:hMTrH7vrkFIjphtbbtpuzffTzSjM
|
|||
github.com/hashicorp/packer-plugin-docker v0.0.7/go.mod h1:IpeKlwOSy2kdgQcysqd3gCsoqjME9jtmpFoKxn7RRNI=
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1 h1:Shjio88MraB+ocj0VI5+M65r4UBKbYI4eCqLNyPXKEo=
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI=
|
||||
github.com/hashicorp/packer-plugin-hyperone v0.0.1 h1:Owp1B5cI0VgFgR3pCyeeQdyKPTWls36mVedv+WxZMOM=
|
||||
github.com/hashicorp/packer-plugin-hyperone v0.0.1/go.mod h1:9DglrxEBIig85Hr8r11YE+uMn3G0u+pt0AZHVP+wnAY=
|
||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2 h1:MGvGkOVfzeosqOSs5dteghLwv9VRcRxTuLoLX1ssUag=
|
||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2/go.mod h1:Hud2R1pkky96TQy3TPTTrr9Kej4b/4dqC/v+uEE0VDY=
|
||||
github.com/hashicorp/packer-plugin-openstack v0.0.1 h1:FUaNjKguAipPZZXQ4UiJK6c5+2nS89CRxJHjAsfVyIQ=
|
||||
|
@ -647,8 +649,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
|||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
|
||||
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE=
|
||||
github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA=
|
||||
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784 h1:+DAetXqxv/mSyCkE9KBIYOZs9b68y7SUaDCxQMRjA68=
|
||||
|
|
|
@ -1,284 +0,0 @@
|
|||
---
|
||||
description: |
|
||||
HyperOne Packer builder creates new images on the HyperOne platform.
|
||||
The builder takes a source image, runs any provisioning necessary on
|
||||
the image after launching it, then creates a reusable image.
|
||||
page_title: HyperOne - Builders
|
||||
---
|
||||
|
||||
# HyperOne Builder
|
||||
|
||||
Type: `hyperone`
|
||||
Artifact BuilderId: `hyperone.builder`
|
||||
|
||||
The `hyperone` Packer builder is able to create new images on the [HyperOne
|
||||
platform](http://www.hyperone.com/). The builder takes a source image, runs
|
||||
any provisioning necessary on the image after launching it, then creates a
|
||||
reusable image.
|
||||
|
||||
The builder does _not_ manage images. Once it creates an image, it is up to you
|
||||
to use it or delete it.
|
||||
|
||||
## Authentication
|
||||
|
||||
HyperOne supports several authentication methods, which are all supported by
|
||||
this builder.
|
||||
|
||||
### User session
|
||||
|
||||
If using user session, set the `token` field to your authentication token.
|
||||
The `project` field is required when using this method.
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "YOUR TOKEN",
|
||||
"project": "YOUR_PROJECT"
|
||||
}
|
||||
```
|
||||
|
||||
### User session by SSH key
|
||||
|
||||
If you've added an SSH key as a credential to your user account and the
|
||||
private key is added to the ssh-agent on your local machine, you can
|
||||
authenticate by setting just the platform login (your e-mail address):
|
||||
|
||||
```json
|
||||
{
|
||||
"token_login": "your.user@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### h1 CLI
|
||||
|
||||
If you're using [h1-cli](https://github.com/hyperonecom/h1-cli) on your local
|
||||
machine, HyperOne builder can use your credentials saved in a config file.
|
||||
|
||||
All you have to do is login within the tool:
|
||||
|
||||
```shell-session
|
||||
$ h1 login --username your.user@example.com
|
||||
```
|
||||
|
||||
You don't have to set `token` or `project` fields at all using this method.
|
||||
|
||||
### Service account
|
||||
|
||||
Using `h1`, you can create a new token associated with chosen project.
|
||||
|
||||
```shell-session
|
||||
$ h1 project token add --name packer-builder --project PROJECT_ID
|
||||
```
|
||||
|
||||
Set the `token` field to the generated token or save it in the `HYPERONE_TOKEN`
|
||||
environment variable. You don't have to set the `project` option using this
|
||||
method.
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "YOUR TOKEN"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
There are many configuration options available for the builder. They are
|
||||
segmented below into two categories: required and optional parameters. Within
|
||||
each category, the available configuration keys are alphabetized.
|
||||
|
||||
In addition to the options listed here, a
|
||||
[communicator](/docs/templates/legacy_json_templates/communicator) can be configured for this
|
||||
builder.
|
||||
|
||||
### Required:
|
||||
|
||||
- `disk_size` (float) - Size of the created disk, in GiB.
|
||||
|
||||
- `project` (string) - The id or name of the project. This field is required
|
||||
only if using session tokens. It should be skipped when using service
|
||||
account authentication.
|
||||
|
||||
- `source_image` (string) - ID or name of the image to launch server from.
|
||||
|
||||
- `token` (string) - The authentication token used to access your account.
|
||||
This can be either a session token or a service account token.
|
||||
If not defined, the builder will attempt to find it in the following order:
|
||||
|
||||
- In `HYPERONE_TOKEN` environment variable.
|
||||
- In `~/.h1-cli/conf.json` config file used by [h1-cli](https://github.com/hyperonecom/h1-cli).
|
||||
- By using SSH authentication if `token_login` variable has been set.
|
||||
|
||||
- `vm_type` (string) - ID or name of the type this server should be created with.
|
||||
|
||||
### Optional:
|
||||
|
||||
- `api_url` (string) - Custom API endpoint URL, compatible with HyperOne.
|
||||
It can also be specified via environment variable `HYPERONE_API_URL`.
|
||||
|
||||
- `disk_name` (string) - The name of the created disk.
|
||||
|
||||
- `disk_type` (string) - The type of the created disk. Defaults to `ssd`.
|
||||
|
||||
- `image_description` (string) - The description of the resulting image.
|
||||
|
||||
- `image_name` (string) - The name of the resulting image. Defaults to
|
||||
`packer-{{timestamp}}`
|
||||
(see [configuration templates](/docs/templates/legacy_json_templates/engine) for more info).
|
||||
|
||||
- `image_service` (string) - The service of the resulting image.
|
||||
|
||||
- `image_tags` (map of key/value strings) - Key/value pair tags to
|
||||
add to the created image.
|
||||
|
||||
- `network` (string) - The ID of the network to attach to the created server.
|
||||
|
||||
- `private_ip` (string) - The ID of the private IP within chosen `network`
|
||||
that should be assigned to the created server.
|
||||
|
||||
- `public_ip` (string) - The ID of the public IP that should be assigned to
|
||||
the created server. If `network` is chosen, the public IP will be associated
|
||||
with server's private IP.
|
||||
|
||||
- `public_netadp_service` (string) - Custom service of public network adapter.
|
||||
Can be useful when using custom `api_url`. Defaults to `public`.
|
||||
|
||||
- `ssh_keys` (array of strings) - List of SSH keys by name or id to be added
|
||||
to the server on launch.
|
||||
|
||||
- `state_timeout` (string) - Timeout for waiting on the API to complete
|
||||
a request. Defaults to 5m.
|
||||
|
||||
- `token_login` (string) - Login (an e-mail) on HyperOne platform. Set this
|
||||
if you want to fetch the token by SSH authentication.
|
||||
|
||||
- `user_data` (string) - User data to launch with the server. Packer will not
|
||||
automatically wait for a user script to finish before shutting down the
|
||||
instance, this must be handled in a provisioner.
|
||||
|
||||
- `vm_name` (string) - The name of the created server.
|
||||
|
||||
- `vm_tags` (map of key/value strings) - Key/value pair tags to
|
||||
add to the created server.
|
||||
|
||||
## Chroot disk
|
||||
|
||||
### Required:
|
||||
|
||||
- `chroot_disk` (bool) - Set to `true` to enable chroot disk build.
|
||||
|
||||
- `pre_mount_commands` (array of strings) - A series of commands to execute
|
||||
before mounting the chroot. This should include any partitioning and
|
||||
filesystem creation commands. The path to the device is provided by
|
||||
`{{.Device}}`.
|
||||
|
||||
### Optional:
|
||||
|
||||
- `chroot_command_wrapper` (string) - How to run shell commands. This defaults
|
||||
to `{{.Command}}`. This may be useful to set if you want to set
|
||||
environment variables or run commands with `sudo`.
|
||||
|
||||
- `chroot_copy_files` (array of strings) - Paths to files on the running VM
|
||||
that will be copied into the chroot environment before provisioning.
|
||||
Defaults to `/etc/resolv.conf` so that DNS lookups work.
|
||||
|
||||
- `chroot_device` (string) - The path of chroot device. Defaults an attempt is
|
||||
made to identify it based on the attach location.
|
||||
|
||||
- `chroot_disk_size` (float) - The size of the chroot disk in GiB. Defaults
|
||||
to `disk_size`.
|
||||
|
||||
- `chroot_disk_type` (string) - The type of the chroot disk. Defaults to
|
||||
`disk_type`.
|
||||
|
||||
- `chroot_mount_path` (string) - The path on which the device will be mounted.
|
||||
|
||||
- `chroot_mounts` (array of strings) - A list of devices to mount into the
|
||||
chroot environment. This is a list of 3-element tuples, in order:
|
||||
|
||||
- The filesystem type. If this is "bind", then Packer will properly bind the
|
||||
filesystem to another mount point.
|
||||
|
||||
- The source device.
|
||||
|
||||
- The mount directory.
|
||||
|
||||
- `mount_options` (array of tuples) - Options to supply the `mount` command
|
||||
when mounting devices. Each option will be prefixed with `-o` and supplied
|
||||
to the `mount` command.
|
||||
|
||||
- `mount_partition` (string) - The partition number containing the / partition.
|
||||
By default this is the first partition of the volume (for example, sdb1).
|
||||
|
||||
- `post_mount_commands` (array of strings) - As `pre_mount_commands`, but the
|
||||
commands are executed after mounting the root device and before the extra
|
||||
mount and copy steps. The device and mount path are provided by
|
||||
`{{.Device}}` and `{{.MountPath}}`.
|
||||
|
||||
## Basic Example
|
||||
|
||||
Here is a basic example. It is completely valid as soon as you enter your own
|
||||
token.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "hyperone",
|
||||
"token": "YOUR_AUTH_TOKEN",
|
||||
"source_image": "ubuntu-18.04",
|
||||
"vm_type": "a1.nano",
|
||||
"disk_size": 10
|
||||
}
|
||||
```
|
||||
|
||||
## Chroot Example
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "hyperone",
|
||||
"token": "YOUR_AUTH_TOKEN",
|
||||
"source_image": "ubuntu-18.04",
|
||||
"vm_type": "a1.nano",
|
||||
"disk_size": 10,
|
||||
"chroot_disk": true,
|
||||
"pre_mount_commands": [
|
||||
"apt-get update",
|
||||
"apt-get install debootstrap",
|
||||
"debootstrap --arch amd64 bionic {{.MountPath}}"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## HCL Example
|
||||
|
||||
```hcl
|
||||
variable "token" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "project" {
|
||||
type = string
|
||||
}
|
||||
|
||||
source "hyperone" "new-syntax" {
|
||||
token = var.token
|
||||
project = var.project
|
||||
source_image = "debian"
|
||||
disk_size = 10
|
||||
vm_type = "a1.nano"
|
||||
image_name = "packerbats-hcl-{{timestamp}}"
|
||||
image_tags = {
|
||||
key="value"
|
||||
}
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.hyperone.new-syntax"
|
||||
]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"apt-get update",
|
||||
"apt-get upgrade -y"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,92 +0,0 @@
|
|||
<!-- Code generated from the comments of the Config struct in builder/hyperone/config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `api_url` (string) - Custom API endpoint URL, compatible with HyperOne.
|
||||
It can also be specified via environment variable HYPERONE_API_URL.
|
||||
|
||||
- `token_login` (string) - Login (an e-mail) on HyperOne platform. Set this
|
||||
if you want to fetch the token by SSH authentication.
|
||||
|
||||
- `state_timeout` (duration string | ex: "1h5m2s") - Timeout for waiting on the API to complete
|
||||
a request. Defaults to 5m.
|
||||
|
||||
- `image_name` (string) - The name of the resulting image. Defaults to
|
||||
`packer-{{timestamp}}`
|
||||
(see configuration templates for more info).
|
||||
|
||||
- `image_description` (string) - The description of the resulting image.
|
||||
|
||||
- `image_tags` (map[string]string) - Key/value pair tags to add to the created image.
|
||||
|
||||
- `image_tag` ([]{key string, value string}) - Same as [`image_tags`](#image_tags) but defined as a singular repeatable
|
||||
block containing a `key` and a `value` field. In HCL2 mode the
|
||||
[`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `image_service` (string) - The service of the resulting image.
|
||||
|
||||
- `vm_name` (string) - The name of the created server.
|
||||
|
||||
- `vm_tags` (map[string]string) - Key/value pair tags to add to the created server.
|
||||
|
||||
- `vm_tag` ([]{name string, value string}) - Same as [`vm_tags`](#vm_tags) but defined as a singular repeatable block
|
||||
containing a `key` and a `value` field. In HCL2 mode the
|
||||
[`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `disk_name` (string) - The name of the created disk.
|
||||
|
||||
- `disk_type` (string) - The type of the created disk. Defaults to ssd.
|
||||
|
||||
- `network` (string) - The ID of the network to attach to the created server.
|
||||
|
||||
- `private_ip` (string) - The ID of the private IP within chosen network
|
||||
that should be assigned to the created server.
|
||||
|
||||
- `public_ip` (string) - The ID of the public IP that should be assigned to
|
||||
the created server. If network is chosen, the public IP will be associated
|
||||
with server's private IP.
|
||||
|
||||
- `public_netadp_service` (string) - Custom service of public network adapter.
|
||||
Can be useful when using custom api_url. Defaults to public.
|
||||
|
||||
- `chroot_device` (string) - Chroot Device
|
||||
|
||||
- `chroot_disk` (bool) - Chroot Disk
|
||||
|
||||
- `chroot_disk_size` (float32) - Chroot Disk Size
|
||||
|
||||
- `chroot_disk_type` (string) - Chroot Disk Type
|
||||
|
||||
- `chroot_mount_path` (string) - Chroot Mount Path
|
||||
|
||||
- `chroot_mounts` ([][]string) - Chroot Mounts
|
||||
|
||||
- `chroot_copy_files` ([]string) - Chroot Copy Files
|
||||
|
||||
- `chroot_command_wrapper` (string) - How to run shell commands. This defaults to `{{.Command}}`. This may be
|
||||
useful to set if you want to set environmental variables or perhaps run
|
||||
it with sudo or so on. This is a configuration template where the
|
||||
.Command variable is replaced with the command to be run. Defaults to
|
||||
`{{.Command}}`.
|
||||
|
||||
- `mount_options` ([]string) - Mount Options
|
||||
|
||||
- `mount_partition` (string) - Mount Partition
|
||||
|
||||
- `pre_mount_commands` ([]string) - A series of commands to execute after attaching the root volume and
|
||||
before mounting the chroot. This is not required unless using
|
||||
from_scratch. If so, this should include any partitioning and filesystem
|
||||
creation commands. The path to the device is provided by `{{.Device}}`.
|
||||
|
||||
- `post_mount_commands` ([]string) - As pre_mount_commands, but the commands are executed after mounting the
|
||||
root device and before the extra mount and copy steps. The device and
|
||||
mount path are provided by `{{.Device}}` and `{{.MountPath}}`.
|
||||
|
||||
- `ssh_keys` ([]string) - List of SSH keys by name or id to be added
|
||||
to the server on launch.
|
||||
|
||||
- `user_data` (string) - User data to launch with the server. Packer will not
|
||||
automatically wait for a user script to finish before shutting down the
|
||||
instance, this must be handled in a provisioner.
|
||||
|
||||
<!-- End of code generated from the comments of the Config struct in builder/hyperone/config.go; -->
|
|
@ -1,17 +0,0 @@
|
|||
<!-- Code generated from the comments of the Config struct in builder/hyperone/config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `token` (string) - The authentication token used to access your account.
|
||||
This can be either a session token or a service account token.
|
||||
If not defined, the builder will attempt to find it in the following order:
|
||||
|
||||
- `project` (string) - The id or name of the project. This field is required
|
||||
only if using session tokens. It should be skipped when using service
|
||||
account authentication.
|
||||
|
||||
- `source_image` (string) - ID or name of the image to launch server from.
|
||||
|
||||
- `vm_type` (string) - ID or name of the type this server should be created with.
|
||||
|
||||
- `disk_size` (float32) - Size of the created disk, in GiB.
|
||||
|
||||
<!-- End of code generated from the comments of the Config struct in builder/hyperone/config.go; -->
|
|
@ -708,10 +708,6 @@
|
|||
"title": "Hetzner Cloud",
|
||||
"path": "builders/hetzner-cloud"
|
||||
},
|
||||
{
|
||||
"title": "HyperOne",
|
||||
"path": "builders/hyperone"
|
||||
},
|
||||
{
|
||||
"title": "Hyper-V",
|
||||
"routes": [
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
"title": "Docker",
|
||||
"path": "docker",
|
||||
"repo": "hashicorp/packer-plugin-docker",
|
||||
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
|
@ -46,6 +45,13 @@
|
|||
"repo": "hashicorp/packer-plugin-googlecompute",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "HyperOne",
|
||||
"path": "hyperone",
|
||||
"repo": "hashicorp/packer-plugin-hyperone",
|
||||
"version": "latest",
|
||||
"pluginTier": "community"
|
||||
},
|
||||
{
|
||||
"title": "Naver Cloud",
|
||||
"path": "ncloud",
|
||||
|
@ -87,6 +93,12 @@
|
|||
"version": "latest",
|
||||
"pluginTier": "community"
|
||||
},
|
||||
{
|
||||
"title": "QEMU",
|
||||
"path": "qemu",
|
||||
"repo": "hashicorp/packer-plugin-qemu",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "Scaleway",
|
||||
"path": "scaleway",
|
||||
|
@ -111,11 +123,5 @@
|
|||
"path": "vmware",
|
||||
"repo": "hashicorp/packer-plugin-vmware",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "QEMU",
|
||||
"path": "qemu",
|
||||
"repo": "hashicorp/packer-plugin-qemu",
|
||||
"version": "latest"
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue