Add a snapshot (#22)
This commit is contained in:
parent
e394b27a21
commit
fbe2065ec2
|
@ -51,7 +51,8 @@ $ packer build template.json
|
||||||
* `dc_name` (source datacenter)
|
* `dc_name` (source datacenter)
|
||||||
* Post-processing:
|
* Post-processing:
|
||||||
* `linked_clone`
|
* `linked_clone`
|
||||||
* `to_template`
|
* `create_snapshot`
|
||||||
|
* `convert_to_template`
|
||||||
|
|
||||||
See an example below:
|
See an example below:
|
||||||
```json
|
```json
|
||||||
|
@ -71,7 +72,8 @@ See an example below:
|
||||||
"vm_name": "clone_name",
|
"vm_name": "clone_name",
|
||||||
"host": "172.16.0.1",
|
"host": "172.16.0.1",
|
||||||
"linked_clone": true,
|
"linked_clone": true,
|
||||||
"to_template": true,
|
"create_snapshot": true,
|
||||||
|
"convert_to_template": true,
|
||||||
|
|
||||||
"RAM": "1024",
|
"RAM": "1024",
|
||||||
"cpus": "2",
|
"cpus": "2",
|
||||||
|
|
10
builder.go
10
builder.go
|
@ -35,6 +35,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
|
|
||||||
// Build the steps.
|
// Build the steps.
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
|
&StepSetup{
|
||||||
|
config: b.config,
|
||||||
|
},
|
||||||
&StepCloneVM{
|
&StepCloneVM{
|
||||||
config: b.config,
|
config: b.config,
|
||||||
},
|
},
|
||||||
|
@ -65,8 +68,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Command: b.config.ShutdownCommand,
|
Command: b.config.ShutdownCommand,
|
||||||
ShutdownTimeout: b.config.ShutdownTimeout,
|
ShutdownTimeout: b.config.ShutdownTimeout,
|
||||||
},
|
},
|
||||||
&StepPostProcess{
|
&StepCreateSnapshot{
|
||||||
ToTemplate: b.config.ToTemplate,
|
createSnapshot: b.config.CreateSnapshot,
|
||||||
|
},
|
||||||
|
&StepConvertToTemplate{
|
||||||
|
ConvertToTemplate: b.config.ConvertToTemplate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,16 @@ type Config struct {
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
LinkedClone bool `mapstructure:"linked_clone"`
|
LinkedClone bool `mapstructure:"linked_clone"`
|
||||||
ToTemplate bool `mapstructure:"to_template"`
|
ConvertToTemplate bool `mapstructure:"convert_to_template"`
|
||||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||||
ShutdownTimeout time.Duration ``
|
ShutdownTimeout time.Duration ``
|
||||||
|
|
||||||
// Hardware
|
// Customization
|
||||||
Cpus string `mapstructure:"cpus"`
|
Cpus string `mapstructure:"cpus"`
|
||||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||||
Ram string `mapstructure:"RAM"`
|
Ram string `mapstructure:"RAM"`
|
||||||
|
CreateSnapshot bool `mapstructure:"create_snapshot"`
|
||||||
|
|
||||||
|
|
||||||
ctx interpolate.Context
|
ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/vmware/govmomi/find"
|
"github.com/vmware/govmomi/find"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"github.com/vmware/govmomi/vim25/mo"
|
"github.com/vmware/govmomi/vim25/mo"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
@ -31,25 +30,15 @@ type StepCloneVM struct{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
|
func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
client := state.Get("client").(*govmomi.Client)
|
||||||
|
ctx := state.Get("ctx").(context.Context)
|
||||||
|
finder := state.Get("finder").(*find.Finder)
|
||||||
|
dc := state.Get("dc").(*object.Datacenter)
|
||||||
|
vmSrc := state.Get("vmSrc").(*object.VirtualMachine)
|
||||||
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
ui.Say("start cloning...")
|
ui.Say("start cloning...")
|
||||||
|
|
||||||
// Prepare entities: client (authentification), finder, folder, virtual machine
|
|
||||||
client, ctx, err := createClient(s.config.Url, s.config.Username, s.config.Password)
|
|
||||||
if err != nil {
|
|
||||||
state.Put("error", err)
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up finder
|
|
||||||
finder := find.NewFinder(client.Client, false)
|
|
||||||
dc, err := finder.DatacenterOrDefault(ctx, s.config.DCName)
|
|
||||||
if err != nil {
|
|
||||||
state.Put("error", err)
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
finder.SetDatacenter(dc)
|
|
||||||
|
|
||||||
// Get folder
|
// Get folder
|
||||||
folder, err := finder.FolderOrDefault(ctx, s.config.FolderName)
|
folder, err := finder.FolderOrDefault(ctx, s.config.FolderName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -74,13 +63,6 @@ func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source VM
|
|
||||||
vmSrc, err := finder.VirtualMachine(ctx, s.config.Template)
|
|
||||||
if err != nil {
|
|
||||||
state.Put("error", err)
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
vm, err := cloneVM(&CloneParameters{
|
vm, err := cloneVM(&CloneParameters{
|
||||||
client: client,
|
client: client,
|
||||||
folder: folder,
|
folder: folder,
|
||||||
|
@ -179,24 +161,3 @@ func cloneVM(params *CloneParameters) (vm *object.VirtualMachine, err error) {
|
||||||
vm = object.NewVirtualMachine(params.client.Client, info.Result.(types.ManagedObjectReference))
|
vm = object.NewVirtualMachine(params.client.Client, info.Result.(types.ManagedObjectReference))
|
||||||
return vm, nil
|
return vm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createClient(URL, username, password string) (*govmomi.Client, context.Context, error) {
|
|
||||||
// create context
|
|
||||||
ctx := context.TODO() // an empty, default context (for those, who is unsure)
|
|
||||||
|
|
||||||
// create a client
|
|
||||||
// (connected to the specified URL,
|
|
||||||
// logged in with the username-password)
|
|
||||||
u, err := url.Parse(URL) // create a URL object from string
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
u.User = url.UserPassword(username, password) // set username and password for automatical authentification
|
|
||||||
fmt.Println(u.String())
|
|
||||||
client, err := govmomi.NewClient(ctx, u,true) // creating a client (logs in with given uname&pswd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, ctx, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"context"
|
||||||
|
"github.com/vmware/govmomi/object"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepCreateSnapshot struct{
|
||||||
|
createSnapshot bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepCreateSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
vm := state.Get("vm").(*object.VirtualMachine)
|
||||||
|
ctx := state.Get("ctx").(context.Context)
|
||||||
|
|
||||||
|
if s.createSnapshot {
|
||||||
|
ui.Say("creating snapshot...")
|
||||||
|
|
||||||
|
_, err := vm.CreateSnapshot(ctx, "packer_snapshot", "", true, true)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
ui.Say("done")
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepCreateSnapshot) Cleanup(state multistep.StateBag) {}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/vmware/govmomi/find"
|
||||||
|
"fmt"
|
||||||
|
"github.com/vmware/govmomi"
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepSetup struct{
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSetup) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
ui.Say("setup...")
|
||||||
|
|
||||||
|
// Prepare entities: client (authentification), finder, folder, virtual machine
|
||||||
|
client, ctx, err := createClient(s.config.Url, s.config.Username, s.config.Password)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up finder
|
||||||
|
finder := find.NewFinder(client.Client, false)
|
||||||
|
dc, err := finder.DatacenterOrDefault(ctx, s.config.DCName)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
finder.SetDatacenter(dc)
|
||||||
|
|
||||||
|
// Get source VM
|
||||||
|
vmSrc, err := finder.VirtualMachine(ctx, s.config.Template)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("client", client)
|
||||||
|
state.Put("ctx", ctx)
|
||||||
|
state.Put("finder", finder)
|
||||||
|
state.Put("dc", dc)
|
||||||
|
state.Put("vmSrc", vmSrc)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSetup) Cleanup(state multistep.StateBag) {}
|
||||||
|
|
||||||
|
func createClient(URL, username, password string) (*govmomi.Client, context.Context, error) {
|
||||||
|
// create context
|
||||||
|
ctx := context.TODO() // an empty, default context (for those, who is unsure)
|
||||||
|
|
||||||
|
// create a client
|
||||||
|
// (connected to the specified URL,
|
||||||
|
// logged in with the username-password)
|
||||||
|
u, err := url.Parse(URL) // create a URL object from string
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u.User = url.UserPassword(username, password) // set username and password for automatical authentification
|
||||||
|
fmt.Println(u.String())
|
||||||
|
client, err := govmomi.NewClient(ctx, u,true) // creating a client (logs in with given uname&pswd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, ctx, nil
|
||||||
|
}
|
|
@ -7,17 +7,17 @@ import (
|
||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StepPostProcess struct{
|
type StepConvertToTemplate struct{
|
||||||
ToTemplate bool
|
ConvertToTemplate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepPostProcess) Run(state multistep.StateBag) multistep.StepAction {
|
func (s *StepConvertToTemplate) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
vm := state.Get("vm").(*object.VirtualMachine)
|
vm := state.Get("vm").(*object.VirtualMachine)
|
||||||
ctx := state.Get("ctx").(context.Context)
|
ctx := state.Get("ctx").(context.Context)
|
||||||
|
|
||||||
// Turning into template if needed
|
// Turning into template if needed
|
||||||
if s.ToTemplate {
|
if s.ConvertToTemplate {
|
||||||
ui.Say("turning into template...")
|
ui.Say("turning into template...")
|
||||||
err := vm.MarkAsTemplate(ctx)
|
err := vm.MarkAsTemplate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,4 +30,4 @@ func (s *StepPostProcess) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepPostProcess) Cleanup(state multistep.StateBag) {}
|
func (s *StepConvertToTemplate) Cleanup(state multistep.StateBag) {}
|
Loading…
Reference in New Issue