File: step_keypair.go

package info (click to toggle)
packer 1.6.6%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 33,156 kB
  • sloc: sh: 1,154; python: 619; makefile: 251; ruby: 205; xml: 97
file content (139 lines) | stat: -rw-r--r-- 3,863 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package cloudstack

import (
	"context"
	"fmt"
	"os"
	"runtime"

	"github.com/hashicorp/packer/packer-plugin-sdk/communicator"
	"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
	packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
	"github.com/xanzy/go-cloudstack/cloudstack"
)

type stepKeypair struct {
	Debug        bool
	Comm         *communicator.Config
	DebugKeyPath string
}

func (s *stepKeypair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
	ui := state.Get("ui").(packersdk.Ui)

	if s.Comm.SSHPrivateKeyFile != "" {
		ui.Say("Using existing SSH private key")
		privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
		if err != nil {
			state.Put("error", err)
			return multistep.ActionHalt
		}

		s.Comm.SSHPrivateKey = privateKeyBytes

		return multistep.ActionContinue
	}

	if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName == "" {
		ui.Say("Using SSH Agent with keypair in Source image")
		return multistep.ActionContinue
	}

	if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName != "" {
		ui.Say(fmt.Sprintf("Using SSH Agent for existing keypair %s", s.Comm.SSHKeyPairName))
		return multistep.ActionContinue
	}

	if s.Comm.SSHTemporaryKeyPairName == "" {
		ui.Say("Not using a keypair")
		s.Comm.SSHKeyPairName = ""
		return multistep.ActionContinue
	}

	client := state.Get("client").(*cloudstack.CloudStackClient)

	ui.Say(fmt.Sprintf("Creating temporary keypair: %s ...", s.Comm.SSHTemporaryKeyPairName))

	p := client.SSH.NewCreateSSHKeyPairParams(s.Comm.SSHTemporaryKeyPairName)

	cfg := state.Get("config").(*Config)
	if cfg.Project != "" {
		p.SetProjectid(cfg.Project)
	}

	keypair, err := client.SSH.CreateSSHKeyPair(p)
	if err != nil {
		err := fmt.Errorf("Error creating temporary keypair: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	if keypair.Privatekey == "" {
		err := fmt.Errorf("The temporary keypair returned was blank")
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	ui.Say(fmt.Sprintf("Created temporary keypair: %s", s.Comm.SSHTemporaryKeyPairName))

	// 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([]byte(keypair.Privatekey)); err != nil {
			err := fmt.Errorf("Error saving debug key: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}

		// Chmod it so that it is SSH ready
		if runtime.GOOS != "windows" {
			if err := f.Chmod(0600); err != nil {
				err := fmt.Errorf("Error setting permissions of debug key: %s", err)
				state.Put("error", err)
				ui.Error(err.Error())
				return multistep.ActionHalt
			}
		}
	}

	// Set some data for use in future steps
	s.Comm.SSHKeyPairName = s.Comm.SSHTemporaryKeyPairName
	s.Comm.SSHPrivateKey = []byte(keypair.Privatekey)

	return multistep.ActionContinue
}

func (s *stepKeypair) Cleanup(state multistep.StateBag) {
	if s.Comm.SSHTemporaryKeyPairName == "" {
		return
	}

	ui := state.Get("ui").(packersdk.Ui)
	client := state.Get("client").(*cloudstack.CloudStackClient)
	cfg := state.Get("config").(*Config)

	p := client.SSH.NewDeleteSSHKeyPairParams(s.Comm.SSHTemporaryKeyPairName)
	if cfg.Project != "" {
		p.SetProjectid(cfg.Project)
	}

	ui.Say(fmt.Sprintf("Deleting temporary keypair: %s ...", s.Comm.SSHTemporaryKeyPairName))

	_, err := client.SSH.DeleteSSHKeyPair(p)
	if err != nil {
		ui.Error(err.Error())
		ui.Error(fmt.Sprintf(
			"Error cleaning up keypair. Please delete the key manually: %s", s.Comm.SSHTemporaryKeyPairName))
	}
}