-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Issue 71] Adds convert_to_template option to proxmox builders #72
Changes from all commits
cdd14b5
2dfa394
fc68e7d
fc876b4
3ca1ef1
fcb4b79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -47,29 +47,31 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook, | |||||
|
||||||
comm := &b.config.Comm | ||||||
|
||||||
// Build the steps | ||||||
coreSteps := []multistep.Step{ | ||||||
&stepStartVM{ | ||||||
vmCreator: b.vmCreator, | ||||||
}, | ||||||
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), | ||||||
&stepTypeBootCommand{ | ||||||
BootConfig: b.config.BootConfig, | ||||||
Ctx: b.config.Ctx, | ||||||
}, | ||||||
&communicator.StepConnect{ | ||||||
Config: comm, | ||||||
Host: commHost((*comm).Host()), | ||||||
SSHConfig: (*comm).SSHConfigFunc(), | ||||||
}, | ||||||
&commonsteps.StepProvision{}, | ||||||
&commonsteps.StepCleanupTempKeys{ | ||||||
Comm: &b.config.Comm, | ||||||
}, | ||||||
&stepConvertToTemplate{}, | ||||||
&stepFinalizeTemplateConfig{}, | ||||||
&stepSuccess{}, | ||||||
} | ||||||
// Build the steps (Order matters) | ||||||
coreSteps := []multistep.Step{} | ||||||
|
||||||
coreSteps = append(coreSteps, &stepStartVM{vmCreator: b.vmCreator}) | ||||||
coreSteps = append(coreSteps, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig)) | ||||||
coreSteps = append(coreSteps, &stepTypeBootCommand{ | ||||||
BootConfig: b.config.BootConfig, | ||||||
Ctx: b.config.Ctx, | ||||||
}) | ||||||
coreSteps = append(coreSteps, &communicator.StepConnect{ | ||||||
Config: comm, | ||||||
Host: commHost((*comm).Host()), | ||||||
SSHConfig: (*comm).SSHConfigFunc(), | ||||||
}) | ||||||
coreSteps = append(coreSteps, &commonsteps.StepProvision{}) | ||||||
coreSteps = append(coreSteps, &commonsteps.StepCleanupTempKeys{ | ||||||
Comm: &b.config.Comm, | ||||||
}) | ||||||
coreSteps = append(coreSteps, &stepStopVM{}) | ||||||
|
||||||
coreSteps = append(coreSteps, &stepConvertToTemplate{}) | ||||||
|
||||||
coreSteps = append(coreSteps, &stepFinalizeVMConfig{}) | ||||||
coreSteps = append(coreSteps, &stepSuccess{}) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason for this change? This might be me only but I don't find this more readable than the original way of defining the steps, and it complexifies the diff so I would consider leaving this change out of the current patchset. |
||||||
|
||||||
preSteps := b.preSteps | ||||||
for idx := range b.config.AdditionalISOFiles { | ||||||
preSteps = append(preSteps, &commonsteps.StepDownload{ | ||||||
|
@@ -97,15 +99,16 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook, | |||||
return nil, errors.New("build was cancelled") | ||||||
} | ||||||
|
||||||
// Verify that the template_id was set properly, otherwise we didn't progress through the last step | ||||||
tplID, ok := state.Get("template_id").(int) | ||||||
// Get vmRef for vmid in artifact storage | ||||||
vmRef, ok := state.Get("vmRef").(*proxmox.VmRef) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be sure, if the artifact is a template, do we still get the appropriate ID from the vmRef in state? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: yes we do, the current way this is implemented is by writing |
||||||
if !ok { | ||||||
return nil, fmt.Errorf("template ID could not be determined") | ||||||
return nil, fmt.Errorf("vmRef could not be determined") | ||||||
} | ||||||
|
||||||
artifact := &Artifact{ | ||||||
builderID: b.id, | ||||||
templateID: tplID, | ||||||
vmID: vmRef.VmId(), | ||||||
isTemplate: !b.config.SkipConvertToTemplate.True(), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we decide to keep it as a Trilean, this could be changed to
Suggested change
|
||||||
proxmoxClient: b.proxmoxClient, | ||||||
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,8 +62,9 @@ type Config struct { | |
Onboot bool `mapstructure:"onboot"` | ||
DisableKVM bool `mapstructure:"disable_kvm"` | ||
|
||
TemplateName string `mapstructure:"template_name"` | ||
TemplateDescription string `mapstructure:"template_description"` | ||
TemplateName string `mapstructure:"template_name"` | ||
TemplateDescription string `mapstructure:"template_description"` | ||
SkipConvertToTemplate config.Trilean `mapstructure:"skip_convert_to_template"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there a reason why this is a Trilean? If the intent is that this is |
||
|
||
CloudInit bool `mapstructure:"cloud_init"` | ||
CloudInitStoragePool string `mapstructure:"cloud_init_storage_pool"` | ||
|
@@ -109,6 +110,7 @@ type vgaConfig struct { | |
func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []string, error) { | ||
// Do not add a cloud-init cdrom by default | ||
c.CloudInit = false | ||
|
||
var md mapstructure.Metadata | ||
err := config.Decode(upper, &config.DecodeOpts{ | ||
Metadata: &md, | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,21 +3,17 @@ package proxmox | |||||||||||
import ( | ||||||||||||
"context" | ||||||||||||
"fmt" | ||||||||||||
"log" | ||||||||||||
|
||||||||||||
"github.com/Telmate/proxmox-api-go/proxmox" | ||||||||||||
"github.com/hashicorp/packer-plugin-sdk/multistep" | ||||||||||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" | ||||||||||||
) | ||||||||||||
|
||||||||||||
// stepConvertToTemplate takes the running VM configured in earlier steps, stops it, and | ||||||||||||
// converts it into a Proxmox template. | ||||||||||||
// | ||||||||||||
// It sets the template_id state which is used for Artifact lookup. | ||||||||||||
// stepConvertToTemplate takes the stopped VM configured in earlier steps, | ||||||||||||
// and converts it into a Proxmox VM template. | ||||||||||||
type stepConvertToTemplate struct{} | ||||||||||||
|
||||||||||||
type templateConverter interface { | ||||||||||||
ShutdownVm(*proxmox.VmRef) (string, error) | ||||||||||||
CreateTemplate(*proxmox.VmRef) error | ||||||||||||
} | ||||||||||||
|
||||||||||||
|
@@ -27,26 +23,22 @@ func (s *stepConvertToTemplate) Run(ctx context.Context, state multistep.StateBa | |||||||||||
ui := state.Get("ui").(packersdk.Ui) | ||||||||||||
client := state.Get("proxmoxClient").(templateConverter) | ||||||||||||
vmRef := state.Get("vmRef").(*proxmox.VmRef) | ||||||||||||
c := state.Get("config").(*Config) | ||||||||||||
|
||||||||||||
ui.Say("Stopping VM") | ||||||||||||
_, err := client.ShutdownVm(vmRef) | ||||||||||||
if err != nil { | ||||||||||||
err := fmt.Errorf("Error converting VM to template, could not stop: %s", err) | ||||||||||||
state.Put("error", err) | ||||||||||||
ui.Error(err.Error()) | ||||||||||||
return multistep.ActionHalt | ||||||||||||
} | ||||||||||||
if !c.SkipConvertToTemplate.True() { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this can be inverted here since this is the last step here
Suggested change
The rest of the code can be left unchanged if we do it this way |
||||||||||||
|
||||||||||||
ui.Say("Converting VM to template") | ||||||||||||
var err = client.CreateTemplate(vmRef) | ||||||||||||
if err != nil { | ||||||||||||
err := fmt.Errorf("error converting VM to template: %s", err) | ||||||||||||
state.Put("error", err) | ||||||||||||
ui.Error(err.Error()) | ||||||||||||
return multistep.ActionHalt | ||||||||||||
} | ||||||||||||
|
||||||||||||
ui.Say("Converting VM to template") | ||||||||||||
err = client.CreateTemplate(vmRef) | ||||||||||||
if err != nil { | ||||||||||||
err := fmt.Errorf("Error converting VM to template: %s", err) | ||||||||||||
state.Put("error", err) | ||||||||||||
ui.Error(err.Error()) | ||||||||||||
return multistep.ActionHalt | ||||||||||||
} else { | ||||||||||||
ui.Say("Skipping VM template conversion") | ||||||||||||
} | ||||||||||||
log.Printf("template_id: %d", vmRef.VmId()) | ||||||||||||
state.Put("template_id", vmRef.VmId()) | ||||||||||||
|
||||||||||||
return multistep.ActionContinue | ||||||||||||
} | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,10 +10,10 @@ import ( | |
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" | ||
) | ||
|
||
// stepFinalizeTemplateConfig does any required modifications to the configuration _after_ | ||
// stepFinalizeVMConfig does any required modifications to the configuration _after_ | ||
// the VM has been converted into a template, such as updating name and description, or | ||
// unmounting the installation ISO. | ||
type stepFinalizeTemplateConfig struct{} | ||
type stepFinalizeVMConfig struct{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we can either produce a template or a VM, might I suggest renaming this step as |
||
|
||
type templateFinalizer interface { | ||
GetVmConfig(*proxmox.VmRef) (map[string]interface{}, error) | ||
|
@@ -22,7 +22,7 @@ type templateFinalizer interface { | |
|
||
var _ templateFinalizer = &proxmox.Client{} | ||
|
||
func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { | ||
func (s *stepFinalizeVMConfig) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { | ||
ui := state.Get("ui").(packersdk.Ui) | ||
client := state.Get("proxmoxClient").(templateFinalizer) | ||
c := state.Get("config").(*Config) | ||
|
@@ -118,4 +118,4 @@ func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.St | |
return multistep.ActionContinue | ||
} | ||
|
||
func (s *stepFinalizeTemplateConfig) Cleanup(state multistep.StateBag) {} | ||
func (s *stepFinalizeVMConfig) Cleanup(state multistep.StateBag) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I don't think there's other possible types than VM and template, I would maybe suggest changing this to a string, and have an enumeration to the side.
Something like
Doing it this way also makes it possible to inject this in the
String()
andDestroy()
methods without needing conditionals.