Skip to content
This repository has been archived by the owner on Oct 4, 2021. It is now read-only.

Commit

Permalink
Added ability to provide ssh keys
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfrei committed Feb 18, 2021
1 parent 67fc8fc commit 9bc4c46
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 25 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ This section describes the available configuration options for the builder. Plea
* `state_timeout_duration` (string) The amount of time to wait for resource state changes. Defaults to `5m`.
* `template_prefix` (string) The prefix to use for the generated template title. Defaults to an empty string, meaning the prefix will be the storage title. You can use this option to easily differentiate between different templates.
* `clone_zones` ([]string) The array of extra zones (locations) where created templates should be cloned. Note that default `state_timeout_duration` is not enough for cloning, better to increase a value depending on storage size.
* `ssh_private_key_path` (string) Path to SSH Private Key that will be used for provisioning and stored in the template.
* `ssh_public_key_path` (string) Path to SSH Public Key that will be used for provisioning.
* `network_interfaces` (array) The array of network interfaces to request during the creation of the server for building the packer image. Example:

```json
Expand Down
23 changes: 23 additions & 0 deletions builder/upcloud/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package upcloud

import (
"errors"
"fmt"
"io/ioutil"
"os"
"time"

Expand Down Expand Up @@ -55,6 +57,11 @@ type Config struct {
RawNetworking []internal.NetworkInterface `mapstructure:"network_interfaces"`
Networking []request.CreateServerInterface

SSHPrivateKeyPath string `mapstructure:"ssh_private_key_path"`
SSHPublicKeyPath string `mapstructure:"ssh_public_key_path"`
SSHPrivateKey []byte
SSHPublicKey []byte

ctx interpolate.Context
}

Expand Down Expand Up @@ -123,6 +130,22 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
)
}

if c.SSHPrivateKeyPath != "" {
c.SSHPrivateKey, err = ioutil.ReadFile(c.SSHPrivateKeyPath)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Failed to read private key: %s", err))
}
}

if c.SSHPublicKeyPath != "" {
c.SSHPublicKey, err = ioutil.ReadFile(c.SSHPublicKeyPath)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Failed to read public key: %s", err))
}
}

if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
Expand Down
4 changes: 4 additions & 0 deletions builder/upcloud/config.hcl2spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ type FlatConfig struct {
StorageSize *int `mapstructure:"storage_size" cty:"storage_size"`
Timeout *string `mapstructure:"state_timeout_duration" cty:"state_timeout_duration"`
CloneZones []string `mapstructure:"clone_zones" cty:"clone_zones"`
SSHPrivateKeyPath *string `mapstructure:"ssh_private_key_path" cty:"ssh_private_key_path"`
SSHPublicKeyPath *string `mapstructure:"ssh_public_key_path" cty:"ssh_public_key_path"`
}

// FlatMapstructure returns a new FlatConfig.
Expand Down Expand Up @@ -154,6 +156,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"storage_size": &hcldec.AttrSpec{Name: "storage_size", Type: cty.Number, Required: false},
"state_timeout_duration": &hcldec.AttrSpec{Name: "state_timeout_duration", Type: cty.String, Required: false},
"clone_zones": &hcldec.AttrSpec{Name: "clone_zones", Type: cty.List(cty.String), Required: false},
"ssh_private_key_path": &hcldec.AttrSpec{Name: "ssh_private_key_path", Type: cty.String, Required: false},
"ssh_public_key_path": &hcldec.AttrSpec{Name: "ssh_public_key_path", Type: cty.String, Required: false},
}
return s
}
18 changes: 9 additions & 9 deletions builder/upcloud/step_create_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type StepCreateServer struct {
}

// Run runs the actual step
func (s *StepCreateServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
func (s *StepCreateServer) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
driver := state.Get("driver").(internal.Driver)

Expand All @@ -36,14 +36,14 @@ func (s *StepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu

ui.Say(fmt.Sprintf("Creating server based on storage %q...", storage.Title))

response, err := driver.CreateServer(
storage.UUID,
s.Config.Zone,
s.Config.TemplatePrefix,
sshKeyPublic,
s.Config.StorageSize,
s.Config.Networking,
)
response, err := driver.CreateServer(&internal.ServerOpts{
StorageUuid: storage.UUID,
StorageSize: s.Config.StorageSize,
Zone: s.Config.Zone,
TemplatePrefix: s.Config.TemplatePrefix,
SshPublicKey: sshKeyPublic,
Networking: s.Config.Networking,
})
if err != nil {
return internal.StepHaltWithError(state, err)
}
Expand Down
11 changes: 11 additions & 0 deletions builder/upcloud/step_create_ssh_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/pem"
"fmt"
"io/ioutil"
"strings"

internal "github.com/UpCloudLtd/upcloud-packer/internal"
"github.com/hashicorp/packer-plugin-sdk/multistep"
Expand All @@ -26,6 +27,16 @@ func (s *StepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
ui := state.Get("ui").(packersdk.Ui)
config := state.Get("config").(*Config)

if len(config.SSHPrivateKey) != 0 && len(config.SSHPublicKey) != 0 {
ui.Say("Using provided SSH keys...")

config.Comm.SSHPrivateKey = config.SSHPrivateKey
config.Comm.SSHPublicKey = config.SSHPublicKey

state.Put("ssh_key_public", strings.Trim(string(config.SSHPublicKey), "\n"))
return multistep.ActionContinue
}

ui.Say("Creating temporary ssh key...")

priv, err := rsa.GenerateKey(rand.Reader, 2048)
Expand Down
2 changes: 1 addition & 1 deletion builder/upcloud/step_create_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type StepCreateTemplate struct {
}

// Run runs the actual step
func (s *StepCreateTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
func (s *StepCreateTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
serverUuid := state.Get("server_uuid").(string)

ui := state.Get("ui").(packer.Ui)
Expand Down
2 changes: 1 addition & 1 deletion builder/upcloud/step_teardown_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
type StepTeardownServer struct{}

// Run runs the actual step
func (s *StepTeardownServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
func (s *StepTeardownServer) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
// Extract server details
serverUuid := state.Get("server_uuid").(string)
serverTitle := state.Get("server_title").(string)
Expand Down
35 changes: 21 additions & 14 deletions internal/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (

type (
Driver interface {
CreateServer(string, string, string, string, int, []request.CreateServerInterface) (*upcloud.ServerDetails, error)
CreateServer(*ServerOpts) (*upcloud.ServerDetails, error)
DeleteServer(string) error
StopServer(string) error
GetStorage(string, string) (*upcloud.Storage, error)
Expand All @@ -38,6 +38,15 @@ type (
Timeout time.Duration
SSHUsername string
}

ServerOpts struct {
StorageUuid string
StorageSize int
Zone string
TemplatePrefix string
SshPublicKey string
Networking []request.CreateServerInterface
}
)

func NewDriver(c *DriverConfig) Driver {
Expand All @@ -49,9 +58,9 @@ func NewDriver(c *DriverConfig) Driver {
}
}

func (d *driver) CreateServer(storageUuid, zone, prefix, sshKeyPublic string, storageSize int, networking []request.CreateServerInterface) (*upcloud.ServerDetails, error) {
func (d *driver) CreateServer(opts *ServerOpts) (*upcloud.ServerDetails, error) {
// Create server
request := d.prepareCreateRequest(storageUuid, zone, prefix, sshKeyPublic, storageSize, networking)
request := d.prepareCreateRequest(opts)
response, err := d.svc.CreateServer(request)
if err != nil {
return nil, fmt.Errorf("Error creating server: %s", err)
Expand Down Expand Up @@ -259,36 +268,34 @@ func (d *driver) GetServerStorage(serverUuid string) (*upcloud.ServerStorageDevi
return &storage, nil
}

func (d *driver) prepareCreateRequest(storageUuid, zone, prefix, sshKeyPublic string, storageSize int, networking []request.CreateServerInterface) *request.CreateServerRequest {
title := fmt.Sprintf("packer-%s-%s", prefix, GetNowString())
hostname := prefix
func (d *driver) prepareCreateRequest(opts *ServerOpts) *request.CreateServerRequest {
title := fmt.Sprintf("packer-%s-%s", opts.TemplatePrefix, GetNowString())
hostname := opts.TemplatePrefix
titleDisk := fmt.Sprintf("%s-disk1", title)

request := request.CreateServerRequest{
Title: title,
Hostname: hostname,
Zone: zone,
Zone: opts.Zone,
PasswordDelivery: request.PasswordDeliveryNone,
Plan: DefaultPlan,
StorageDevices: []request.CreateServerStorageDevice{
{
Action: request.CreateServerStorageDeviceActionClone,
Storage: storageUuid,
Storage: opts.StorageUuid,
Title: titleDisk,
Size: storageSize,
Size: opts.StorageSize,
Tier: upcloud.StorageTierMaxIOPS,
},
},
Networking: &request.CreateServerNetworking{
Interfaces: networking,
Interfaces: opts.Networking,
},
LoginUser: &request.LoginUser{
CreatePassword: "no",
Username: d.config.SSHUsername,
SSHKeys: []string{opts.SshPublicKey},
},
}
if sshKeyPublic != "" {
request.LoginUser.Username = d.config.SSHUsername
request.LoginUser.SSHKeys = []string{sshKeyPublic}
}
return &request
}

0 comments on commit 9bc4c46

Please sign in to comment.