Breakout hcloud (#10966)

* Delete hetzner-cloud.mdx

* delete hcloud builder

* use hcloud plugin

* up mods

* use github.com/hashicorp/packer-plugin-hcloud v0.0.1
This commit is contained in:
Adrien Delorme 2021-04-22 14:52:07 +02:00 committed by GitHub
parent 972497589e
commit ef612c0eb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 14 additions and 1194 deletions

View File

@ -1,51 +0,0 @@
package hcloud
import (
"context"
"fmt"
"log"
"strconv"
"github.com/hetznercloud/hcloud-go/hcloud"
)
type Artifact struct {
// The name of the snapshot
snapshotName string
// The ID of the image
snapshotId int
// The hcloudClient for making API calls
hcloudClient *hcloud.Client
// StateData should store data such as GeneratedData
// to be shared with post-processors
StateData map[string]interface{}
}
func (*Artifact) BuilderId() string {
return BuilderId
}
func (*Artifact) Files() []string {
return nil
}
func (a *Artifact) Id() string {
return strconv.Itoa(a.snapshotId)
}
func (a *Artifact) String() string {
return fmt.Sprintf("A snapshot was created: '%v' (ID: %v)", a.snapshotName, a.snapshotId)
}
func (a *Artifact) State(name string) interface{} {
return a.StateData[name]
}
func (a *Artifact) Destroy() error {
log.Printf("Destroying image: %d (%s)", a.snapshotId, a.snapshotName)
_, err := a.hcloudClient.Image.Delete(context.TODO(), &hcloud.Image{ID: a.snapshotId})
return err
}

View File

@ -1,57 +0,0 @@
package hcloud
import (
"testing"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)
func TestArtifact_Impl(t *testing.T) {
var _ packersdk.Artifact = (*Artifact)(nil)
}
func TestArtifactId(t *testing.T) {
generatedData := make(map[string]interface{})
a := &Artifact{"packer-foobar", 42, nil, generatedData}
expected := "42"
if a.Id() != expected {
t.Fatalf("artifact ID should match: %v", expected)
}
}
func TestArtifactString(t *testing.T) {
generatedData := make(map[string]interface{})
a := &Artifact{"packer-foobar", 42, nil, generatedData}
expected := "A snapshot was created: 'packer-foobar' (ID: 42)"
if a.String() != expected {
t.Fatalf("artifact string should match: %v", expected)
}
}
func TestArtifactState_StateData(t *testing.T) {
expectedData := "this is the data"
artifact := &Artifact{
StateData: map[string]interface{}{"state_data": expectedData},
}
// Valid state
result := artifact.State("state_data")
if result != expectedData {
t.Fatalf("Bad: State data was %s instead of %s", result, expectedData)
}
// Invalid state
result = artifact.State("invalid_key")
if result != nil {
t.Fatalf("Bad: State should be nil for invalid state data name")
}
// Nil StateData should not fail and should return nil
artifact = &Artifact{}
result = artifact.State("key")
if result != nil {
t.Fatalf("Bad: State should be nil for nil StateData")
}
}

View File

@ -1,91 +0,0 @@
package hcloud
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/hetznercloud/hcloud-go/hcloud"
)
// The unique id for the builder
const BuilderId = "hcloud.builder"
type Builder struct {
config Config
runner multistep.Runner
hcloudClient *hcloud.Client
}
var pluginVersion = "1.0.0"
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
}
return nil, nil, nil
}
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
opts := []hcloud.ClientOption{
hcloud.WithToken(b.config.HCloudToken),
hcloud.WithEndpoint(b.config.Endpoint),
hcloud.WithPollInterval(b.config.PollInterval),
hcloud.WithApplication("hcloud-packer", pluginVersion),
}
b.hcloudClient = hcloud.NewClient(opts...)
// Set up the state
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("hcloudClient", b.hcloudClient)
state.Put("hook", hook)
state.Put("ui", ui)
// Build the steps
steps := []multistep.Step{
&stepCreateSSHKey{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("ssh_key_%s.pem", b.config.PackerBuildName),
},
&stepCreateServer{},
&communicator.StepConnect{
Config: &b.config.Comm,
Host: getServerIP,
SSHConfig: b.config.Comm.SSHConfigFunc(),
},
&commonsteps.StepProvision{},
&commonsteps.StepCleanupTempKeys{
Comm: &b.config.Comm,
},
&stepShutdownServer{},
&stepCreateSnapshot{},
}
// Run the steps
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)
// If there was an error, return that
if rawErr, ok := state.GetOk("error"); ok {
return nil, rawErr.(error)
}
if _, ok := state.GetOk("snapshot_name"); !ok {
return nil, nil
}
artifact := &Artifact{
snapshotName: state.Get("snapshot_name").(string),
snapshotId: state.Get("snapshot_id").(int),
hcloudClient: b.hcloudClient,
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
}
return artifact, nil
}

View File

@ -1,35 +0,0 @@
package hcloud
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 testAccPreCheck(t *testing.T) {
if v := os.Getenv("HCLOUD_TOKEN"); v == "" {
t.Fatal("HCLOUD_TOKEN must be set for acceptance tests")
}
}
const testBuilderAccBasic = `
{
"builders": [{
"type": "test",
"location": "nbg1",
"server_type": "cx11",
"image": "ubuntu-18.04",
"user_data": "",
"user_data_file": ""
}]
}
`

View File

@ -1,152 +0,0 @@
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,imageFilter
package hcloud
import (
"errors"
"fmt"
"os"
"time"
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/communicator"
"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/hetznercloud/hcloud-go/hcloud"
"github.com/mitchellh/mapstructure"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"`
HCloudToken string `mapstructure:"token"`
Endpoint string `mapstructure:"endpoint"`
PollInterval time.Duration `mapstructure:"poll_interval"`
ServerName string `mapstructure:"server_name"`
Location string `mapstructure:"location"`
ServerType string `mapstructure:"server_type"`
Image string `mapstructure:"image"`
ImageFilter *imageFilter `mapstructure:"image_filter"`
SnapshotName string `mapstructure:"snapshot_name"`
SnapshotLabels map[string]string `mapstructure:"snapshot_labels"`
UserData string `mapstructure:"user_data"`
UserDataFile string `mapstructure:"user_data_file"`
SSHKeys []string `mapstructure:"ssh_keys"`
RescueMode string `mapstructure:"rescue"`
ctx interpolate.Context
}
type imageFilter struct {
WithSelector []string `mapstructure:"with_selector"`
MostRecent bool `mapstructure:"most_recent"`
}
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",
},
},
}, raws...)
if err != nil {
return nil, err
}
// Defaults
if c.HCloudToken == "" {
c.HCloudToken = os.Getenv("HCLOUD_TOKEN")
}
if c.Endpoint == "" {
if os.Getenv("HCLOUD_ENDPOINT") != "" {
c.Endpoint = os.Getenv("HCLOUD_ENDPOINT")
} else {
c.Endpoint = hcloud.Endpoint
}
}
if c.PollInterval == 0 {
c.PollInterval = 500 * time.Millisecond
}
if c.SnapshotName == "" {
def, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
panic(err)
}
// Default to packer-{{ unix timestamp (utc) }}
c.SnapshotName = def
}
if c.ServerName == "" {
// Default to packer-[time-ordered-uuid]
c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
var errs *packersdk.MultiError
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packersdk.MultiErrorAppend(errs, es...)
}
if c.HCloudToken == "" {
// Required configurations that will display errors if not set
errs = packersdk.MultiErrorAppend(
errs, errors.New("token for auth must be specified"))
}
if c.Location == "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("location is required"))
}
if c.ServerType == "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("server type is required"))
}
if c.Image == "" && c.ImageFilter == nil {
errs = packersdk.MultiErrorAppend(
errs, errors.New("image or image_filter is required"))
}
if c.ImageFilter != nil {
if len(c.ImageFilter.WithSelector) == 0 {
errs = packersdk.MultiErrorAppend(
errs, errors.New("image_filter.with_selector is required when specifying filter"))
} else if c.Image != "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("only one of image or image_filter can be specified"))
}
}
if c.UserData != "" && c.UserDataFile != "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("only one of user_data or user_data_file can be specified"))
} else if c.UserDataFile != "" {
if _, err := os.Stat(c.UserDataFile); err != nil {
errs = packersdk.MultiErrorAppend(
errs, errors.New(fmt.Sprintf("user_data_file not found: %s", c.UserDataFile)))
}
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
packersdk.LogSecretFilter.Set(c.HCloudToken)
return nil, nil
}
func getServerIP(state multistep.StateBag) (string, error) {
return state.Get("server_ip").(string), nil
}

View File

@ -1,196 +0,0 @@
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
package hcloud
import (
"github.com/hashicorp/hcl/v2/hcldec"
"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"`
HCloudToken *string `mapstructure:"token" cty:"token" hcl:"token"`
Endpoint *string `mapstructure:"endpoint" cty:"endpoint" hcl:"endpoint"`
PollInterval *string `mapstructure:"poll_interval" cty:"poll_interval" hcl:"poll_interval"`
ServerName *string `mapstructure:"server_name" cty:"server_name" hcl:"server_name"`
Location *string `mapstructure:"location" cty:"location" hcl:"location"`
ServerType *string `mapstructure:"server_type" cty:"server_type" hcl:"server_type"`
Image *string `mapstructure:"image" cty:"image" hcl:"image"`
ImageFilter *FlatimageFilter `mapstructure:"image_filter" cty:"image_filter" hcl:"image_filter"`
SnapshotName *string `mapstructure:"snapshot_name" cty:"snapshot_name" hcl:"snapshot_name"`
SnapshotLabels map[string]string `mapstructure:"snapshot_labels" cty:"snapshot_labels" hcl:"snapshot_labels"`
UserData *string `mapstructure:"user_data" cty:"user_data" hcl:"user_data"`
UserDataFile *string `mapstructure:"user_data_file" cty:"user_data_file" hcl:"user_data_file"`
SSHKeys []string `mapstructure:"ssh_keys" cty:"ssh_keys" hcl:"ssh_keys"`
RescueMode *string `mapstructure:"rescue" cty:"rescue" hcl:"rescue"`
}
// 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},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"endpoint": &hcldec.AttrSpec{Name: "endpoint", Type: cty.String, Required: false},
"poll_interval": &hcldec.AttrSpec{Name: "poll_interval", Type: cty.String, Required: false},
"server_name": &hcldec.AttrSpec{Name: "server_name", Type: cty.String, Required: false},
"location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false},
"server_type": &hcldec.AttrSpec{Name: "server_type", Type: cty.String, Required: false},
"image": &hcldec.AttrSpec{Name: "image", Type: cty.String, Required: false},
"image_filter": &hcldec.BlockSpec{TypeName: "image_filter", Nested: hcldec.ObjectSpec((*FlatimageFilter)(nil).HCL2Spec())},
"snapshot_name": &hcldec.AttrSpec{Name: "snapshot_name", Type: cty.String, Required: false},
"snapshot_labels": &hcldec.AttrSpec{Name: "snapshot_labels", Type: cty.Map(cty.String), Required: false},
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
"ssh_keys": &hcldec.AttrSpec{Name: "ssh_keys", Type: cty.List(cty.String), Required: false},
"rescue": &hcldec.AttrSpec{Name: "rescue", Type: cty.String, Required: false},
}
return s
}
// FlatimageFilter is an auto-generated flat version of imageFilter.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatimageFilter struct {
WithSelector []string `mapstructure:"with_selector" cty:"with_selector" hcl:"with_selector"`
MostRecent *bool `mapstructure:"most_recent" cty:"most_recent" hcl:"most_recent"`
}
// FlatMapstructure returns a new FlatimageFilter.
// FlatimageFilter is an auto-generated flat version of imageFilter.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*imageFilter) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatimageFilter)
}
// HCL2Spec returns the hcl spec of a imageFilter.
// This spec is used by HCL to read the fields of imageFilter.
// The decoded values from this spec will then be applied to a FlatimageFilter.
func (*FlatimageFilter) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"with_selector": &hcldec.AttrSpec{Name: "with_selector", Type: cty.List(cty.String), Required: false},
"most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false},
}
return s
}

View File

@ -1,234 +0,0 @@
package hcloud
import (
"context"
"fmt"
"io/ioutil"
"sort"
"strings"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hetznercloud/hcloud-go/hcloud"
)
type stepCreateServer struct {
serverId int
}
func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
c := state.Get("config").(*Config)
sshKeyId := state.Get("ssh_key_id").(int)
// Create the server based on configuration
ui.Say("Creating server...")
userData := c.UserData
if c.UserDataFile != "" {
contents, err := ioutil.ReadFile(c.UserDataFile)
if err != nil {
state.Put("error", fmt.Errorf("Problem reading user data file: %s", err))
return multistep.ActionHalt
}
userData = string(contents)
}
sshKeys := []*hcloud.SSHKey{{ID: sshKeyId}}
for _, k := range c.SSHKeys {
sshKey, _, err := client.SSHKey.Get(ctx, k)
if err != nil {
ui.Error(err.Error())
state.Put("error", fmt.Errorf("Error fetching SSH key: %s", err))
return multistep.ActionHalt
}
if sshKey == nil {
state.Put("error", fmt.Errorf("Could not find key: %s", k))
return multistep.ActionHalt
}
sshKeys = append(sshKeys, sshKey)
}
var image *hcloud.Image
if c.Image != "" {
image = &hcloud.Image{Name: c.Image}
} else {
var err error
image, err = getImageWithSelectors(ctx, client, c)
if err != nil {
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Using image %s with ID %d", image.Description, image.ID))
}
serverCreateResult, _, err := client.Server.Create(ctx, hcloud.ServerCreateOpts{
Name: c.ServerName,
ServerType: &hcloud.ServerType{Name: c.ServerType},
Image: image,
SSHKeys: sshKeys,
Location: &hcloud.Location{Name: c.Location},
UserData: userData,
})
if err != nil {
err := fmt.Errorf("Error creating server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
state.Put("server_ip", serverCreateResult.Server.PublicNet.IPv4.IP.String())
// We use this in cleanup
s.serverId = serverCreateResult.Server.ID
// Store the server id for later
state.Put("server_id", serverCreateResult.Server.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", serverCreateResult.Server.ID)
if err := waitForAction(ctx, client, serverCreateResult.Action); err != nil {
err := fmt.Errorf("Error creating server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
for _, nextAction := range serverCreateResult.NextActions {
if err := waitForAction(ctx, client, nextAction); err != nil {
err := fmt.Errorf("Error creating server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
if c.RescueMode != "" {
ui.Say("Enabling Rescue Mode...")
rootPassword, err := setRescue(ctx, client, serverCreateResult.Server, c.RescueMode, sshKeys)
if err != nil {
err := fmt.Errorf("Error enabling rescue mode: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say("Reboot server...")
action, _, err := client.Server.Reset(ctx, serverCreateResult.Server)
if err != nil {
err := fmt.Errorf("Error rebooting server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if err := waitForAction(ctx, client, action); err != nil {
err := fmt.Errorf("Error rebooting server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if c.RescueMode == "freebsd64" {
// We will set this only on freebsd
ui.Say("Using Root Password instead of SSH Keys...")
c.Comm.SSHPassword = rootPassword
}
}
return multistep.ActionContinue
}
func (s *stepCreateServer) Cleanup(state multistep.StateBag) {
// If the serverID isn't there, we probably never created it
if s.serverId == 0 {
return
}
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
// Destroy the server we just created
ui.Say("Destroying server...")
_, err := client.Server.Delete(context.TODO(), &hcloud.Server{ID: s.serverId})
if err != nil {
ui.Error(fmt.Sprintf(
"Error destroying server. Please destroy it manually: %s", err))
}
}
func setRescue(ctx context.Context, client *hcloud.Client, server *hcloud.Server, rescue string, sshKeys []*hcloud.SSHKey) (string, error) {
rescueChanged := false
if server.RescueEnabled {
rescueChanged = true
action, _, err := client.Server.DisableRescue(ctx, server)
if err != nil {
return "", err
}
if err := waitForAction(ctx, client, action); err != nil {
return "", err
}
}
if rescue != "" {
rescueChanged = true
if rescue == "freebsd64" {
sshKeys = nil // freebsd64 doesn't allow ssh keys so we will remove them here
}
res, _, err := client.Server.EnableRescue(ctx, server, hcloud.ServerEnableRescueOpts{
Type: hcloud.ServerRescueType(rescue),
SSHKeys: sshKeys,
})
if err != nil {
return "", err
}
if err := waitForAction(ctx, client, res.Action); err != nil {
return "", err
}
return res.RootPassword, nil
}
if rescueChanged {
action, _, err := client.Server.Reset(ctx, server)
if err != nil {
return "", err
}
if err := waitForAction(ctx, client, action); err != nil {
return "", err
}
}
return "", nil
}
func waitForAction(ctx context.Context, client *hcloud.Client, action *hcloud.Action) error {
_, errCh := client.Action.WatchProgress(ctx, action)
if err := <-errCh; err != nil {
return err
}
return nil
}
func getImageWithSelectors(ctx context.Context, client *hcloud.Client, c *Config) (*hcloud.Image, error) {
var allImages []*hcloud.Image
var selector = strings.Join(c.ImageFilter.WithSelector, ",")
opts := hcloud.ImageListOpts{
ListOpts: hcloud.ListOpts{LabelSelector: selector},
Status: []hcloud.ImageStatus{hcloud.ImageStatusAvailable},
}
allImages, err := client.Image.AllWithOpts(ctx, opts)
if err != nil {
return nil, err
}
if len(allImages) == 0 {
return nil, fmt.Errorf("no image found for selector %q", selector)
}
if len(allImages) > 1 {
if !c.ImageFilter.MostRecent {
return nil, fmt.Errorf("more than one image found for selector %q", selector)
}
sort.Slice(allImages, func(i, j int) bool {
return allImages[i].Created.After(allImages[j].Created)
})
}
return allImages[0], nil
}

View File

@ -1,54 +0,0 @@
package hcloud
import (
"context"
"fmt"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hetznercloud/hcloud-go/hcloud"
)
type stepCreateSnapshot struct{}
func (s *stepCreateSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
c := state.Get("config").(*Config)
serverID := state.Get("server_id").(int)
ui.Say("Creating snapshot ...")
ui.Say("This can take some time")
result, _, err := client.Server.CreateImage(ctx, &hcloud.Server{ID: serverID}, &hcloud.ServerCreateImageOpts{
Type: hcloud.ImageTypeSnapshot,
Labels: c.SnapshotLabels,
Description: hcloud.String(c.SnapshotName),
})
if err != nil {
err := fmt.Errorf("Error creating snapshot: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
state.Put("snapshot_id", result.Image.ID)
state.Put("snapshot_name", c.SnapshotName)
_, errCh := client.Action.WatchProgress(ctx, result.Action)
for {
select {
case err1 := <-errCh:
if err1 == nil {
return multistep.ActionContinue
} else {
err := fmt.Errorf("Error creating snapshot: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
}
func (s *stepCreateSnapshot) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -1,127 +0,0 @@
package hcloud
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
"runtime"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/uuid"
"github.com/hetznercloud/hcloud-go/hcloud"
"golang.org/x/crypto/ssh"
)
type stepCreateSSHKey struct {
Debug bool
DebugKeyPath string
keyId int
}
func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
c := state.Get("config").(*Config)
ui.Say("Creating temporary ssh key for server...")
priv, err := rsa.GenerateKey(rand.Reader, 2014)
if err != nil {
state.Put("error", fmt.Errorf("Error generating RSA key: %s", err))
ui.Error(err.Error())
return multistep.ActionHalt
}
// ASN.1 DER encoded form
privDER := x509.MarshalPKCS1PrivateKey(priv)
privBLK := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}
// Set the private key in the config for later
c.Comm.SSHPrivateKey = pem.EncodeToMemory(&privBLK)
// Marshal the public key into SSH compatible format
pub, err := ssh.NewPublicKey(&priv.PublicKey)
if err != nil {
state.Put("error", fmt.Errorf("Error generating public key: %s", err))
ui.Error(err.Error())
return multistep.ActionHalt
}
pubSSHFormat := string(ssh.MarshalAuthorizedKey(pub))
// The name of the public key on the Hetzner Cloud
name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
// Create the key!
key, _, err := client.SSHKey.Create(ctx, hcloud.SSHKeyCreateOpts{
Name: name,
PublicKey: pubSSHFormat,
})
if err != nil {
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// We use this to check cleanup
s.keyId = key.ID
log.Printf("temporary ssh key name: %s", name)
// Remember some state for the future
state.Put("ssh_key_id", key.ID)
// If we're in debug mode, output the private key to the working directory.
if s.Debug {
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
f, err := os.Create(s.DebugKeyPath)
if err != nil {
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
return multistep.ActionHalt
}
defer f.Close()
// Write the key out
if _, err := f.Write(pem.EncodeToMemory(&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) {
// If no key id is set, then we never created it, so just return
if s.keyId == 0 {
return
}
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
ui.Say("Deleting temporary ssh key...")
_, err := client.SSHKey.Delete(context.TODO(), &hcloud.SSHKey{ID: s.keyId})
if err != nil {
log.Printf("Error cleaning up ssh key: %s", err)
ui.Error(fmt.Sprintf(
"Error cleaning up ssh key. Please delete the key manually: %s", err))
}
}

View File

@ -1,49 +0,0 @@
package hcloud
import (
"context"
"fmt"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hetznercloud/hcloud-go/hcloud"
)
type stepShutdownServer struct{}
func (s *stepShutdownServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("hcloudClient").(*hcloud.Client)
ui := state.Get("ui").(packersdk.Ui)
serverID := state.Get("server_id").(int)
ui.Say("Shutting down server...")
action, _, err := client.Server.Shutdown(ctx, &hcloud.Server{ID: serverID})
if err != nil {
err := fmt.Errorf("Error stopping server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
_, errCh := client.Action.WatchProgress(ctx, action)
for {
select {
case err1 := <-errCh:
if err1 == nil {
return multistep.ActionContinue
} else {
err := fmt.Errorf("Error stopping server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
}
func (s *stepShutdownServer) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -1,13 +0,0 @@
package version
import (
"github.com/hashicorp/packer-plugin-sdk/version"
packerVersion "github.com/hashicorp/packer/version"
)
var HcloudPluginVersion *version.PluginVersion
func init() {
HcloudPluginVersion = version.InitializePluginVersion(
packerVersion.Version, packerVersion.VersionPrerelease)
}

View File

@ -17,7 +17,6 @@ import (
azurechrootbuilder "github.com/hashicorp/packer/builder/azure/chroot" azurechrootbuilder "github.com/hashicorp/packer/builder/azure/chroot"
azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl" azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl"
filebuilder "github.com/hashicorp/packer/builder/file" filebuilder "github.com/hashicorp/packer/builder/file"
hcloudbuilder "github.com/hashicorp/packer/builder/hcloud"
nullbuilder "github.com/hashicorp/packer/builder/null" nullbuilder "github.com/hashicorp/packer/builder/null"
oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone"
profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks" profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks"
@ -52,7 +51,6 @@ var Builders = map[string]packersdk.Builder{
"azure-chroot": new(azurechrootbuilder.Builder), "azure-chroot": new(azurechrootbuilder.Builder),
"azure-dtl": new(azuredtlbuilder.Builder), "azure-dtl": new(azuredtlbuilder.Builder),
"file": new(filebuilder.Builder), "file": new(filebuilder.Builder),
"hcloud": new(hcloudbuilder.Builder),
"null": new(nullbuilder.Builder), "null": new(nullbuilder.Builder),
"oneandone": new(oneandonebuilder.Builder), "oneandone": new(oneandonebuilder.Builder),
"profitbricks": new(profitbricksbuilder.Builder), "profitbricks": new(profitbricksbuilder.Builder),

View File

@ -33,6 +33,7 @@ import (
googlecomputebuilder "github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute" googlecomputebuilder "github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute"
googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export" googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export"
googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import" googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import"
hcloudbuilder "github.com/hashicorp/packer-plugin-hcloud/builder/hcloud"
hyperonebuilder "github.com/hashicorp/packer-plugin-hyperone/builder/hyperone" hyperonebuilder "github.com/hashicorp/packer-plugin-hyperone/builder/hyperone"
hypervisobuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/iso" hypervisobuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/iso"
hypervvmcxbuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/vmcx" hypervvmcxbuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/vmcx"
@ -93,6 +94,7 @@ var VendoredBuilders = map[string]packersdk.Builder{
"digitalocean": new(digitaloceanbuilder.Builder), "digitalocean": new(digitaloceanbuilder.Builder),
"docker": new(dockerbuilder.Builder), "docker": new(dockerbuilder.Builder),
"googlecompute": new(googlecomputebuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder),
"hcloud": new(hcloudbuilder.Builder),
"hyperv-iso": new(hypervisobuilder.Builder), "hyperv-iso": new(hypervisobuilder.Builder),
"hyperv-vmcx": new(hypervvmcxbuilder.Builder), "hyperv-vmcx": new(hypervvmcxbuilder.Builder),
"hyperone": new(hyperonebuilder.Builder), "hyperone": new(hyperonebuilder.Builder),

2
go.mod
View File

@ -41,6 +41,7 @@ require (
github.com/hashicorp/packer-plugin-digitalocean v0.0.1 github.com/hashicorp/packer-plugin-digitalocean v0.0.1
github.com/hashicorp/packer-plugin-docker v0.0.7 github.com/hashicorp/packer-plugin-docker v0.0.7
github.com/hashicorp/packer-plugin-googlecompute v0.0.1 github.com/hashicorp/packer-plugin-googlecompute v0.0.1
github.com/hashicorp/packer-plugin-hcloud v0.0.1
github.com/hashicorp/packer-plugin-hyperone v0.0.1 github.com/hashicorp/packer-plugin-hyperone v0.0.1
github.com/hashicorp/packer-plugin-hyperv v0.0.1 github.com/hashicorp/packer-plugin-hyperv v0.0.1
github.com/hashicorp/packer-plugin-jdcloud v0.0.1 github.com/hashicorp/packer-plugin-jdcloud v0.0.1
@ -63,7 +64,6 @@ require (
github.com/hashicorp/packer-plugin-virtualbox v0.0.1 github.com/hashicorp/packer-plugin-virtualbox v0.0.1
github.com/hashicorp/packer-plugin-vmware v0.0.1 github.com/hashicorp/packer-plugin-vmware v0.0.1
github.com/hashicorp/packer-plugin-vsphere v0.0.1 github.com/hashicorp/packer-plugin-vsphere v0.0.1
github.com/hetznercloud/hcloud-go v1.15.1
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec
github.com/masterzen/winrm v0.0.0-20201030141608-56ca5c5f2380 github.com/masterzen/winrm v0.0.0-20201030141608-56ca5c5f2380
github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08 github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08

5
go.sum
View File

@ -536,6 +536,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-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 h1:Shjio88MraB+ocj0VI5+M65r4UBKbYI4eCqLNyPXKEo=
github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI= github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI=
github.com/hashicorp/packer-plugin-hcloud v0.0.1 h1:KM4fxnIpBBCe0SHoK9FHLFlGDWoW8uvMLUdtcNRzla0=
github.com/hashicorp/packer-plugin-hcloud v0.0.1/go.mod h1:H+LpMPP8V+VqFqBHBD2qVSYWE5woFWQRVdtB7S6LMT0=
github.com/hashicorp/packer-plugin-hyperone v0.0.1 h1:Owp1B5cI0VgFgR3pCyeeQdyKPTWls36mVedv+WxZMOM= 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-hyperone v0.0.1/go.mod h1:9DglrxEBIig85Hr8r11YE+uMn3G0u+pt0AZHVP+wnAY=
github.com/hashicorp/packer-plugin-hyperv v0.0.1 h1:ZdsJw4X+4zSgRYPzVQbJrx8Az73AkneSWLnmfpojl0k= github.com/hashicorp/packer-plugin-hyperv v0.0.1 h1:ZdsJw4X+4zSgRYPzVQbJrx8Az73AkneSWLnmfpojl0k=
@ -604,8 +606,9 @@ github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvh
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hetznercloud/hcloud-go v1.15.1 h1:G8Q+xyAqQ5IUY7yq4HKZgkabFa0S/VXJXq3TGCeT8JM=
github.com/hetznercloud/hcloud-go v1.15.1/go.mod h1:8lR3yHBHZWy2uGcUi9Ibt4UOoop2wrVdERJgCtxsF3Q= github.com/hetznercloud/hcloud-go v1.15.1/go.mod h1:8lR3yHBHZWy2uGcUi9Ibt4UOoop2wrVdERJgCtxsF3Q=
github.com/hetznercloud/hcloud-go v1.25.0 h1:QAaFKtGKWRxjwjKJWBGMxGYUxVEQmIkb35j/WXrsazY=
github.com/hetznercloud/hcloud-go v1.25.0/go.mod h1:2C5uMtBiMoFr3m7lBFPf7wXTdh33CevmZpQIIDPGYJI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4 h1:mSmyzhwBeQt2TlHbsXYLona9pwjWAvYGwQJ2Cq/k3VE= github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4 h1:mSmyzhwBeQt2TlHbsXYLona9pwjWAvYGwQJ2Cq/k3VE=
github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4/go.mod h1:yNUVHSleURKSaYUKq4Wx0i/vjCen2aq7CvPyHd/Vj2Q= github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4/go.mod h1:yNUVHSleURKSaYUKq4Wx0i/vjCen2aq7CvPyHd/Vj2Q=

View File

@ -1,127 +0,0 @@
---
description: |
The Hetzner Cloud Packer builder is able to create new images for use with the
Hetzner Cloud. The builder takes a source image, runs any provisioning
necessary on the image after launching it, then snapshots it into a reusable
image. This reusable image can then be used as the foundation of new servers
that are launched within the Hetzner Cloud.
page_title: Hetzner Cloud - Builders
---
# Hetzner Cloud Builder
Type: `hcloud`
Artifact BuilderId: `hcloud.builder`
The `hcloud` Packer builder is able to create new images for use with [Hetzner
Cloud](https://www.hetzner.cloud). The builder takes a source image, runs any
provisioning necessary on the image after launching it, then snapshots it into
a reusable image. This reusable image can then be used as the foundation of new
servers that are launched within the Hetzner Cloud.
The builder does _not_ manage images. Once it creates an image, it is up to you
to use it or delete it.
## 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 Builder Configuration options:
- `token` (string) - The client TOKEN to use to access your account. It can
also be specified via environment variable `HCLOUD_TOKEN`, if set.
- `image` (string) - ID or name of image to launch server from. Alternatively
you can use `image_filter`.
- `location` (string) - The name of the location to launch the server in.
- `server_type` (string) - ID or name of the server type this server should
be created with.
### Optional:
- `endpoint` (string) - Non standard api endpoint URL. Set this if you are
using a Hetzner Cloud API compatible service. It can also be specified via
environment variable `HCLOUD_ENDPOINT`.
- `image_filter` (object) - Filters used to populate the `filter`
field. Example:
```json
{
"image_filter": {
"with_selector": ["name==my-image"],
"most_recent": true
}
}
```
This selects the most recent image with the label `name==my-image`. NOTE:
This will fail unless _exactly_ one AMI is returned. In the above example,
`most_recent` will cause this to succeed by selecting the newest image.
- `with_selector` (list of strings) - label selectors used to select an
`image`. NOTE: This will fail unless _exactly_ one image is returned.
Check the official hcloud docs on
[Label Selectors](https://docs.hetzner.cloud/#overview-label-selector)
for more info.
- `most_recent` (boolean) - Selects the newest created image when true.
This is most useful if you base your image on another Packer build image.
You may set this in place of `image`, but not both.
- `server_name` (string) - The name assigned to the server. The Hetzner Cloud
sets the hostname of the machine to this value.
- `snapshot_name` (string) - The name of the resulting snapshot that will
appear in your account as image description. Defaults to `packer-{{timestamp}}` (see
[configuration templates](/docs/templates/legacy_json_templates/engine) for more info). If you want to reference the image as a sample in your terraform configuration please use the image id or the `snapshot_labels`.
- `snapshot_labels` (map of key/value strings) - Key/value pair labels to
apply to the created image.
- `poll_interval` (string) - Configures the interval in which actions are
polled by the client. Default `500ms`. Increase this interval if you run
into rate limiting errors.
- `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.
- `user_data_file` (string) - Path to a file that will be used for the user
data when launching the server.
- `ssh_keys` (array of strings) - List of SSH keys by name or id to be added
to image on launch.
- `rescue` (string) - Enable and boot in to the specified rescue system. This
enables simple installation of custom operating systems. `linux64`
`linux32` or `freebsd64`
## Basic Example
Here is a basic example. It is completely valid as soon as you enter your own
access tokens:
```json
{
"builders": [
{
"type": "hcloud",
"token": "YOUR API KEY",
"image": "ubuntu-18.04",
"location": "nbg1",
"server_type": "cx11",
"ssh_username": "root"
}
]
}
```

View File

@ -700,10 +700,6 @@
"title": "File", "title": "File",
"path": "builders/file" "path": "builders/file"
}, },
{
"title": "Hetzner Cloud",
"path": "builders/hetzner-cloud"
},
{ {
"title": "Null", "title": "Null",
"path": "builders/null" "path": "builders/null"

View File

@ -58,6 +58,13 @@
"repo": "hashicorp/packer-plugin-googlecompute", "repo": "hashicorp/packer-plugin-googlecompute",
"version": "latest" "version": "latest"
}, },
{
"title": "hcloud",
"path": "hetzner-cloud",
"repo": "hashicorp/packer-plugin-hcloud",
"version": "latest",
"pluginTier": "community"
},
{ {
"title": "HyperOne", "title": "HyperOne",
"path": "hyperone", "path": "hyperone",