Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bugbuilder committed Jul 9, 2017
0 parents commit 79f5da4
Show file tree
Hide file tree
Showing 275 changed files with 167,104 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin/
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Freezer is a Packer Postprocessor for VMWare vSphere

It allows you to create a template for the [vmware-iso builder](https://www.packer.io/docs/builders/vmware-iso.html).

- At the moment **keep_registered** option is **required** to be set as **true**

Go ahead and download a pre-built Freezer binary for your operating system from [Releases page](https://github.com/bennu/packer-post-processor-freezer/releases)
Then you need choose one folder for the magic to begins:

1. The directory where packer is, or the executable directory.

2. ~/.packer.d/plugins on Unix systems or %APPDATA%/packer.d/plugins on Windows.

3. The current working directory.

For more details check the [install plugins page](https://www.packer.io/docs/extending/plugins.html#installing-plugins)

## Basic Example

```json
{
"type":"freezer",
"host":"{{user `host`}}",
"username":"{{user `username`}}",
"password":"{{user `password`}}",
"vm_name":"{{user `vm_name`}}"
}
```

## Configuration Reference

Optional parameters:
* `folder` - Where the template is created.
* `datacenter` - If you have more than one, you will need to specified one.

## Full Example

```json
{
"type":"freezer",
"host":"vcenter.local",
"username":"root",
"password":"sssh_is_a_secret",
"datacenter":"murlock",
"vm_name":"centos-7.3",
"folder":"/packer-templates/os/centos-7"
}
```

### Todos

- Eliminate keep_registered dependency
- Fix/Review the waiting time for VMWare vSphere
37 changes: 37 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash
#
# build for multiple platforms.
set -e

OS=(linux windows darwin)
command_exists() {
command -v "$@" > /dev/null 2>&1
}

bin() {
printf ' Building freezer for %s...\n' $1

mkdir -p bin/$1

if [[ $1 == "windows" ]]; then
suffix='.exe'
fi

docker run --rm -v $(pwd):/go/src/github.com/bennu/post-processor-freezer \
-w /go/src/github.com/bennu/post-processor-freezer \
-e GOARCH=amd64 -e GOOS=$1 -e CGO_ENABLED=0 golang:1.8-alpine \
go build -o bin/$1/packer-post-processor-freezer$suffix
}

if command_exists docker; then
if [ $# -gt 0 ]; then
bin $1
else
for os in "${OS[@]}"; do
bin $os &
done
fi
wait
else
printf ' Error: you need to have Docker installed.'
fi
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"github.com/hashicorp/packer/packer/plugin"
)

func main() {
server, err := plugin.Server()
if err != nil {
panic(err)
}
server.RegisterPostProcessor(&PostProcessor{})
server.Serve()
}
115 changes: 115 additions & 0 deletions post-processor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package main

import (
"fmt"
"net/url"
"time"

"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/multistep"
)

type Config struct {
common.PackerConfig `mapstructure:",squash"`
Host string `mapstructure:"host"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Datacenter string `mapstructure:"datacenter"`
VMName string `mapstructure:"vm_name"`
Folder string `mapstructure:"folder"`

ctx interpolate.Context
}

type PostProcessor struct {
config Config
url *url.URL
}

func (p *PostProcessor) Configure(raws ...interface{}) error {
err := config.Decode(&p.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &p.config.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{},
},
}, raws...)

if err != nil {
return err
}

errs := new(packer.MultiError)
templates := map[string]*string{
"host": &p.config.Host,
"username": &p.config.Username,
"password": &p.config.Password,
}

for key, ptr := range templates {
if *ptr == "" {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("%s must be set", key))
}
}

if err := p.configureURL(); err != nil {
errs = packer.MultiErrorAppend(
errs, err)
}

if len(errs.Errors) > 0 {
return errs
}
return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
state := new(multistep.BasicStateBag)
state.Put("ui", ui)

//FIXME I've trash environment, so I need to wait :(
ui.Message("Waiting 10s for VMWare vSphere to start")
time.Sleep(10 * time.Second)

steps := []multistep.Step{
&StepVSphereClient{
Datacenter: p.config.Datacenter,
VMName: p.config.VMName,
Url: p.url,
},
&StepFetchVm{
VMName: p.config.VMName,
},
&StepCreateFolder{
Folder: p.config.Folder,
},
&StepMarkAsTemplate{},
&StepMoveTemplate{
Folder: p.config.Folder,
},
}

runner := &multistep.BasicRunner{Steps: steps}
runner.Run(state)

if rawErr, ok := state.GetOk("error"); ok {
return artifact, true, rawErr.(error)
}
return artifact, true, nil
}

func (p *PostProcessor) configureURL() error {
sdk, err := url.Parse("https://" + p.config.Host + "/sdk")

if err != nil {
return nil
}

sdk.User = url.UserPassword(p.config.Username, p.config.Password)
p.url = sdk
return nil
}
74 changes: 74 additions & 0 deletions step_create_folder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package main

import (
"context"
"fmt"
"path/filepath"
"strings"

"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/vmware/govmomi/find"
)

type StepCreateFolder struct {
Folder string
}

func (s *StepCreateFolder) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ctx := state.Get("context").(context.Context)
f := state.Get("finder").(*find.Finder)
d := state.Get("datacenter").(string)

if s.Folder != "" {
ui.Say("Creating or checking destination folders...")

if !strings.HasPrefix(s.Folder, "/") {
s.Folder = filepath.Join("/", s.Folder)
}

path := s.Folder
base := filepath.Join("/", d, "vm")
var folders []string
var folder, root string

for {
_, err := f.Folder(ctx, filepath.ToSlash(filepath.Join(base, path)))

if err != nil {

root, folder = filepath.Split(path)
folders = append(folders, folder)
if i := strings.LastIndex(path, "/"); i == 0 {
break
} else {
path = path[:i]
}
} else {
break
}
}

for i := len(folders) - 1; i >= 0; i-- {
folder, err := f.Folder(ctx, filepath.ToSlash(filepath.Join(base, "/", root)))

if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Creating folder: %v", folders[i]))

if _, err = folder.CreateFolder(ctx, folders[i]); err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
root = filepath.Join(root, folders[i], "/")
}
}
return multistep.ActionContinue
}

func (s *StepCreateFolder) Cleanup(multistep.StateBag) {}
34 changes: 34 additions & 0 deletions step_fetch_vm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"context"

"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/vmware/govmomi/find"
)

type StepFetchVm struct {
VMName string
}

func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ctx := state.Get("context").(context.Context)
f := state.Get("finder").(*find.Finder)

ui.Say("Fetching VM...")

vm, err := f.VirtualMachine(ctx, s.VMName)

if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}

state.Put("vm", vm)
return multistep.ActionContinue
}

func (s *StepFetchVm) Cleanup(multistep.StateBag) {}
30 changes: 30 additions & 0 deletions step_mark_as_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"context"

"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/vmware/govmomi/object"
)

type StepMarkAsTemplate struct {
Folder string
}

func (s *StepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ctx := state.Get("context").(context.Context)
vm := state.Get("vm").(*object.VirtualMachine)

ui.Say("Marking as a template...")

if err := vm.MarkAsTemplate(ctx); err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}

func (s *StepMarkAsTemplate) Cleanup(multistep.StateBag) {}
Loading

0 comments on commit 79f5da4

Please sign in to comment.