From ef612c0eb15fb85b018baf7acc94cda79f77bb2c Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 22 Apr 2021 14:52:07 +0200 Subject: [PATCH] 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 --- builder/hcloud/artifact.go | 51 ---- builder/hcloud/artifact_test.go | 57 ----- builder/hcloud/builder.go | 91 ------- builder/hcloud/builder_acc_test.go | 35 --- builder/hcloud/config.go | 152 ------------ builder/hcloud/config.hcl2spec.go | 196 --------------- builder/hcloud/step_create_server.go | 234 ------------------ builder/hcloud/step_create_snapshot.go | 54 ---- builder/hcloud/step_create_sshkey.go | 127 ---------- builder/hcloud/step_shutdown_server.go | 49 ---- builder/hcloud/version/version.go | 13 - command/plugin.go | 2 - command/vendored_plugins.go | 2 + go.mod | 2 +- go.sum | 5 +- .../content/docs/builders/hetzner-cloud.mdx | 127 ---------- website/data/docs-nav-data.json | 4 - website/data/docs-remote-plugins.json | 7 + 18 files changed, 14 insertions(+), 1194 deletions(-) delete mode 100644 builder/hcloud/artifact.go delete mode 100644 builder/hcloud/artifact_test.go delete mode 100644 builder/hcloud/builder.go delete mode 100644 builder/hcloud/builder_acc_test.go delete mode 100644 builder/hcloud/config.go delete mode 100644 builder/hcloud/config.hcl2spec.go delete mode 100644 builder/hcloud/step_create_server.go delete mode 100644 builder/hcloud/step_create_snapshot.go delete mode 100644 builder/hcloud/step_create_sshkey.go delete mode 100644 builder/hcloud/step_shutdown_server.go delete mode 100644 builder/hcloud/version/version.go delete mode 100644 website/content/docs/builders/hetzner-cloud.mdx diff --git a/builder/hcloud/artifact.go b/builder/hcloud/artifact.go deleted file mode 100644 index 4bc9f4bf5..000000000 --- a/builder/hcloud/artifact.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/artifact_test.go b/builder/hcloud/artifact_test.go deleted file mode 100644 index 06de9b081..000000000 --- a/builder/hcloud/artifact_test.go +++ /dev/null @@ -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") - } -} diff --git a/builder/hcloud/builder.go b/builder/hcloud/builder.go deleted file mode 100644 index 3a5a47b3a..000000000 --- a/builder/hcloud/builder.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/builder_acc_test.go b/builder/hcloud/builder_acc_test.go deleted file mode 100644 index d9900944a..000000000 --- a/builder/hcloud/builder_acc_test.go +++ /dev/null @@ -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": "" - }] -} -` diff --git a/builder/hcloud/config.go b/builder/hcloud/config.go deleted file mode 100644 index d86272a1e..000000000 --- a/builder/hcloud/config.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/config.hcl2spec.go b/builder/hcloud/config.hcl2spec.go deleted file mode 100644 index e926704a5..000000000 --- a/builder/hcloud/config.hcl2spec.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/step_create_server.go b/builder/hcloud/step_create_server.go deleted file mode 100644 index 7f764563f..000000000 --- a/builder/hcloud/step_create_server.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/step_create_snapshot.go b/builder/hcloud/step_create_snapshot.go deleted file mode 100644 index a8f8b8536..000000000 --- a/builder/hcloud/step_create_snapshot.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/step_create_sshkey.go b/builder/hcloud/step_create_sshkey.go deleted file mode 100644 index b57d953f6..000000000 --- a/builder/hcloud/step_create_sshkey.go +++ /dev/null @@ -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)) - } -} diff --git a/builder/hcloud/step_shutdown_server.go b/builder/hcloud/step_shutdown_server.go deleted file mode 100644 index ad38c869b..000000000 --- a/builder/hcloud/step_shutdown_server.go +++ /dev/null @@ -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 -} diff --git a/builder/hcloud/version/version.go b/builder/hcloud/version/version.go deleted file mode 100644 index 7a0c24545..000000000 --- a/builder/hcloud/version/version.go +++ /dev/null @@ -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) -} diff --git a/command/plugin.go b/command/plugin.go index 09365d693..a31cf391b 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -17,7 +17,6 @@ import ( azurechrootbuilder "github.com/hashicorp/packer/builder/azure/chroot" azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl" filebuilder "github.com/hashicorp/packer/builder/file" - hcloudbuilder "github.com/hashicorp/packer/builder/hcloud" nullbuilder "github.com/hashicorp/packer/builder/null" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks" @@ -52,7 +51,6 @@ var Builders = map[string]packersdk.Builder{ "azure-chroot": new(azurechrootbuilder.Builder), "azure-dtl": new(azuredtlbuilder.Builder), "file": new(filebuilder.Builder), - "hcloud": new(hcloudbuilder.Builder), "null": new(nullbuilder.Builder), "oneandone": new(oneandonebuilder.Builder), "profitbricks": new(profitbricksbuilder.Builder), diff --git a/command/vendored_plugins.go b/command/vendored_plugins.go index 526e557c2..09f1b9a61 100644 --- a/command/vendored_plugins.go +++ b/command/vendored_plugins.go @@ -33,6 +33,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" + hcloudbuilder "github.com/hashicorp/packer-plugin-hcloud/builder/hcloud" hyperonebuilder "github.com/hashicorp/packer-plugin-hyperone/builder/hyperone" hypervisobuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/iso" hypervvmcxbuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/vmcx" @@ -93,6 +94,7 @@ var VendoredBuilders = map[string]packersdk.Builder{ "digitalocean": new(digitaloceanbuilder.Builder), "docker": new(dockerbuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder), + "hcloud": new(hcloudbuilder.Builder), "hyperv-iso": new(hypervisobuilder.Builder), "hyperv-vmcx": new(hypervvmcxbuilder.Builder), "hyperone": new(hyperonebuilder.Builder), diff --git a/go.mod b/go.mod index c52435d7b..e1ce0fb35 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/hashicorp/packer-plugin-digitalocean 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-hcloud 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-jdcloud v0.0.1 @@ -63,7 +64,6 @@ require ( github.com/hashicorp/packer-plugin-virtualbox v0.0.1 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/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec github.com/masterzen/winrm v0.0.0-20201030141608-56ca5c5f2380 github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08 diff --git a/go.sum b/go.sum index 366d35312..df1b6c8c9 100644 --- a/go.sum +++ b/go.sum @@ -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-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-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/go.mod h1:9DglrxEBIig85Hr8r11YE+uMn3G0u+pt0AZHVP+wnAY= 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-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= 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.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/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= diff --git a/website/content/docs/builders/hetzner-cloud.mdx b/website/content/docs/builders/hetzner-cloud.mdx deleted file mode 100644 index c33b7b8a2..000000000 --- a/website/content/docs/builders/hetzner-cloud.mdx +++ /dev/null @@ -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" - } - ] -} -``` diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 3fe567188..212c611d1 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -700,10 +700,6 @@ "title": "File", "path": "builders/file" }, - { - "title": "Hetzner Cloud", - "path": "builders/hetzner-cloud" - }, { "title": "Null", "path": "builders/null" diff --git a/website/data/docs-remote-plugins.json b/website/data/docs-remote-plugins.json index 7a3452033..3e5d9fcab 100644 --- a/website/data/docs-remote-plugins.json +++ b/website/data/docs-remote-plugins.json @@ -58,6 +58,13 @@ "repo": "hashicorp/packer-plugin-googlecompute", "version": "latest" }, + { + "title": "hcloud", + "path": "hetzner-cloud", + "repo": "hashicorp/packer-plugin-hcloud", + "version": "latest", + "pluginTier": "community" + }, { "title": "HyperOne", "path": "hyperone",