Commit dc74ec56 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: remove Environment

parent ba359394
......@@ -3,7 +3,6 @@ package command
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"log"
"os"
......@@ -17,28 +16,22 @@ type FixCommand struct {
}
func (c *FixCommand) Run(args []string) int {
env, err := c.Meta.Environment()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing environment: %s", err))
return 1
}
cmdFlags := flag.NewFlagSet("fix", flag.ContinueOnError)
cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
flags := c.Meta.FlagSet("fix", FlagSetNone)
flags.Usage = func() { c.Ui.Say(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
args = cmdFlags.Args()
args = flags.Args()
if len(args) != 1 {
cmdFlags.Usage()
flags.Usage()
return 1
}
// Read the file for decoding
tplF, err := os.Open(args[0])
if err != nil {
env.Ui().Error(fmt.Sprintf("Error opening template: %s", err))
c.Ui.Error(fmt.Sprintf("Error opening template: %s", err))
return 1
}
defer tplF.Close()
......@@ -47,7 +40,7 @@ func (c *FixCommand) Run(args []string) int {
var templateData map[string]interface{}
decoder := json.NewDecoder(tplF)
if err := decoder.Decode(&templateData); err != nil {
env.Ui().Error(fmt.Sprintf("Error parsing template: %s", err))
c.Ui.Error(fmt.Sprintf("Error parsing template: %s", err))
return 1
}
......@@ -65,7 +58,7 @@ func (c *FixCommand) Run(args []string) int {
log.Printf("Running fixer: %s", name)
input, err = fixer.Fix(input)
if err != nil {
env.Ui().Error(fmt.Sprintf("Error fixing: %s", err))
c.Ui.Error(fmt.Sprintf("Error fixing: %s", err))
return 1
}
}
......@@ -73,20 +66,20 @@ func (c *FixCommand) Run(args []string) int {
var output bytes.Buffer
encoder := json.NewEncoder(&output)
if err := encoder.Encode(input); err != nil {
env.Ui().Error(fmt.Sprintf("Error encoding: %s", err))
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
return 1
}
var indented bytes.Buffer
if err := json.Indent(&indented, output.Bytes(), "", " "); err != nil {
env.Ui().Error(fmt.Sprintf("Error encoding: %s", err))
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
return 1
}
result := indented.String()
result = strings.Replace(result, `\u003c`, "<", -1)
result = strings.Replace(result, `\u003e`, ">", -1)
env.Ui().Say(result)
c.Ui.Say(result)
return 0
}
......
package command
import (
"flag"
"fmt"
"github.com/mitchellh/packer/packer"
"log"
......@@ -9,19 +8,13 @@ import (
"strings"
)
type InspectCommand struct{
type InspectCommand struct {
Meta
}
func (c *InspectCommand) Run(args []string) int {
env, err := c.Meta.Environment()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing environment: %s", err))
return 1
}
flags := flag.NewFlagSet("inspect", flag.ContinueOnError)
flags.Usage = func() { env.Ui().Say(c.Help()) }
flags := c.Meta.FlagSet("build", FlagSetNone)
flags.Usage = func() { c.Ui.Say(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
......@@ -36,12 +29,12 @@ func (c *InspectCommand) Run(args []string) int {
log.Printf("Reading template: %#v", args[0])
tpl, err := packer.ParseTemplateFile(args[0], nil)
if err != nil {
env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
return 1
}
// Convenience...
ui := env.Ui()
ui := c.Ui
// Description
if tpl.Description != "" {
......
......@@ -26,7 +26,6 @@ const (
// Packer command inherits.
type Meta struct {
CoreConfig *packer.CoreConfig
EnvConfig *packer.EnvironmentConfig
Ui packer.Ui
// These are set by command-line flags
......@@ -148,7 +147,3 @@ func (m *Meta) ValidateFlags() error {
// TODO
return nil
}
func (m *Meta) Environment() (packer.Environment, error) {
return packer.NewEnvironment(m.EnvConfig)
}
package command
import (
"flag"
"fmt"
cmdcommon "github.com/mitchellh/packer/common/command"
"github.com/mitchellh/packer/packer"
"log"
"strings"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template"
)
type ValidateCommand struct {
......@@ -15,72 +15,54 @@ type ValidateCommand struct {
func (c *ValidateCommand) Run(args []string) int {
var cfgSyntaxOnly bool
buildOptions := new(cmdcommon.BuildOptions)
env, err := c.Meta.Environment()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing environment: %s", err))
flags := c.Meta.FlagSet("validate", FlagSetBuildFilter|FlagSetVars)
flags.Usage = func() { c.Ui.Say(c.Help()) }
flags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only")
if err := flags.Parse(args); err != nil {
return 1
}
cmdFlags := flag.NewFlagSet("validate", flag.ContinueOnError)
cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
cmdFlags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only")
cmdcommon.BuildOptionFlags(cmdFlags, buildOptions)
if err := cmdFlags.Parse(args); err != nil {
return 1
}
args = cmdFlags.Args()
args = flags.Args()
if len(args) != 1 {
cmdFlags.Usage()
flags.Usage()
return 1
}
if err := buildOptions.Validate(); err != nil {
env.Ui().Error(err.Error())
env.Ui().Error("")
env.Ui().Error(c.Help())
// Parse the template
tpl, err := template.ParseFile(args[0])
if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
return 1
}
userVars, err := buildOptions.AllUserVars()
if err != nil {
env.Ui().Error(fmt.Sprintf("Error compiling user variables: %s", err))
env.Ui().Error("")
env.Ui().Error(c.Help())
return 1
// If we're only checking syntax, then we're done already
if cfgSyntaxOnly {
c.Ui.Say("Syntax-only check passed. Everything looks okay.")
return 0
}
// Parse the template into a machine-usable format
log.Printf("Reading template: %s", args[0])
tpl, err := packer.ParseTemplateFile(args[0], userVars)
// Get the core
core, err := c.Meta.Core(tpl)
if err != nil {
env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
c.Ui.Error(err.Error())
return 1
}
if cfgSyntaxOnly {
env.Ui().Say("Syntax-only check passed. Everything looks okay.")
return 0
}
errs := make([]error, 0)
warnings := make(map[string][]string)
// The component finder for our builds
components := &packer.ComponentFinder{
Builder: env.Builder,
Hook: env.Hook,
PostProcessor: env.PostProcessor,
Provisioner: env.Provisioner,
}
// Get the builds we care about
buildNames := c.Meta.BuildNames(core)
builds := make([]packer.Build, 0, len(buildNames))
for _, n := range buildNames {
b, err := core.Build(n)
if err != nil {
c.Ui.Error(fmt.Sprintf(
"Failed to initialize build '%s': %s",
n, err))
}
// Otherwise, get all the builds
builds, err := buildOptions.Builds(tpl, components)
if err != nil {
env.Ui().Error(err.Error())
return 1
builds = append(builds, b)
}
// Check the configuration of all builds
......@@ -96,12 +78,12 @@ func (c *ValidateCommand) Run(args []string) int {
}
if len(errs) > 0 {
env.Ui().Error("Template validation failed. Errors are shown below.\n")
c.Ui.Error("Template validation failed. Errors are shown below.\n")
for i, err := range errs {
env.Ui().Error(err.Error())
c.Ui.Error(err.Error())
if (i + 1) < len(errs) {
env.Ui().Error("")
c.Ui.Error("")
}
}
......@@ -109,21 +91,21 @@ func (c *ValidateCommand) Run(args []string) int {
}
if len(warnings) > 0 {
env.Ui().Say("Template validation succeeded, but there were some warnings.")
env.Ui().Say("These are ONLY WARNINGS, and Packer will attempt to build the")
env.Ui().Say("template despite them, but they should be paid attention to.\n")
c.Ui.Say("Template validation succeeded, but there were some warnings.")
c.Ui.Say("These are ONLY WARNINGS, and Packer will attempt to build the")
c.Ui.Say("template despite them, but they should be paid attention to.\n")
for build, warns := range warnings {
env.Ui().Say(fmt.Sprintf("Warnings for build '%s':\n", build))
c.Ui.Say(fmt.Sprintf("Warnings for build '%s':\n", build))
for _, warning := range warns {
env.Ui().Say(fmt.Sprintf("* %s", warning))
c.Ui.Say(fmt.Sprintf("* %s", warning))
}
}
return 0
}
env.Ui().Say("Template validated successfully.")
c.Ui.Say("Template validated successfully.")
return 0
}
......
......@@ -33,15 +33,9 @@ func (c *VersionCommand) Help() string {
}
func (c *VersionCommand) Run(args []string) int {
env, err := c.Meta.Environment()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing environment: %s", err))
return 1
}
env.Ui().Machine("version", c.Version)
env.Ui().Machine("version-prelease", c.VersionPrerelease)
env.Ui().Machine("version-commit", c.Revision)
c.Ui.Machine("version", c.Version)
c.Ui.Machine("version-prelease", c.VersionPrerelease)
c.Ui.Machine("version-commit", c.Revision)
var versionString bytes.Buffer
fmt.Fprintf(&versionString, "Packer v%s", c.Version)
......
......@@ -21,7 +21,6 @@ const OutputPrefix = "o:"
func init() {
meta := command.Meta{
CoreConfig: &CoreConfig,
EnvConfig: &EnvConfig,
Ui: &packer.BasicUi{
Reader: os.Stdin,
Writer: os.Stdout,
......
......@@ -16,9 +16,6 @@ import (
// CoreConfig is the global CoreConfig we use to initialize the CLI.
var CoreConfig packer.CoreConfig
// EnvConfig is the global EnvironmentConfig we use to initialize the CLI.
var EnvConfig packer.EnvironmentConfig
type config struct {
DisableCheckpoint bool `json:"disable_checkpoint"`
DisableCheckpointSignature bool `json:"disable_checkpoint_signature"`
......
......@@ -140,14 +140,13 @@ func wrappedMain() int {
defer plugin.CleanupClients()
// Create the environment configuration
EnvConfig = *packer.DefaultEnvironmentConfig()
EnvConfig.Cache = cache
EnvConfig.Components.Builder = config.LoadBuilder
EnvConfig.Components.Hook = config.LoadHook
EnvConfig.Components.PostProcessor = config.LoadPostProcessor
EnvConfig.Components.Provisioner = config.LoadProvisioner
CoreConfig.Cache = cache
CoreConfig.Components.Builder = config.LoadBuilder
CoreConfig.Components.Hook = config.LoadHook
CoreConfig.Components.PostProcessor = config.LoadPostProcessor
CoreConfig.Components.Provisioner = config.LoadProvisioner
if machineReadable {
EnvConfig.Ui = &packer.MachineReadableUi{
CoreConfig.Ui = &packer.MachineReadableUi{
Writer: os.Stdout,
}
......@@ -159,13 +158,6 @@ func wrappedMain() int {
}
}
// Create the core configuration
CoreConfig = packer.CoreConfig{
Cache: EnvConfig.Cache,
Components: EnvConfig.Components,
Ui: EnvConfig.Ui,
}
//setupSignalHandlers(env)
cli := &cli.CLI{
......
......@@ -31,6 +31,28 @@ type CoreConfig struct {
Variables map[string]string
}
// The function type used to lookup Builder implementations.
type BuilderFunc func(name string) (Builder, error)
// The function type used to lookup Hook implementations.
type HookFunc func(name string) (Hook, error)
// The function type used to lookup PostProcessor implementations.
type PostProcessorFunc func(name string) (PostProcessor, error)
// The function type used to lookup Provisioner implementations.
type ProvisionerFunc func(name string) (Provisioner, error)
// ComponentFinder is a struct that contains the various function
// pointers necessary to look up components of Packer such as builders,
// commands, etc.
type ComponentFinder struct {
Builder BuilderFunc
Hook HookFunc
PostProcessor PostProcessorFunc
Provisioner ProvisionerFunc
}
// NewCore creates a new Core.
func NewCore(c *CoreConfig) (*Core, error) {
if c.Ui == nil {
......
......@@ -99,3 +99,14 @@ func TestCoreValidate(t *testing.T) {
}
}
}
func testComponentFinder() *ComponentFinder {
builderFactory := func(n string) (Builder, error) { return new(MockBuilder), nil }
ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil }
provFactory := func(n string) (Provisioner, error) { return new(MockProvisioner), nil }
return &ComponentFinder{
Builder: builderFactory,
PostProcessor: ppFactory,
Provisioner: provFactory,
}
}
// The packer package contains the core components of Packer.
package packer
import (
"errors"
"fmt"
"os"
)
// The function type used to lookup Builder implementations.
type BuilderFunc func(name string) (Builder, error)
// The function type used to lookup Hook implementations.
type HookFunc func(name string) (Hook, error)
// The function type used to lookup PostProcessor implementations.
type PostProcessorFunc func(name string) (PostProcessor, error)
// The function type used to lookup Provisioner implementations.
type ProvisionerFunc func(name string) (Provisioner, error)
// ComponentFinder is a struct that contains the various function
// pointers necessary to look up components of Packer such as builders,
// commands, etc.
type ComponentFinder struct {
Builder BuilderFunc
Hook HookFunc
PostProcessor PostProcessorFunc
Provisioner ProvisionerFunc
}
// The environment interface provides access to the configuration and
// state of a single Packer run.
//
// It allows for things such as executing CLI commands, getting the
// list of available builders, and more.
type Environment interface {
Builder(string) (Builder, error)
Cache() Cache
Hook(string) (Hook, error)
PostProcessor(string) (PostProcessor, error)
Provisioner(string) (Provisioner, error)
Ui() Ui
}
// An implementation of an Environment that represents the Packer core
// environment.
type coreEnvironment struct {
cache Cache
components ComponentFinder
ui Ui
}
// This struct configures new environments.
type EnvironmentConfig struct {
Cache Cache
Components ComponentFinder
Ui Ui
}
// DefaultEnvironmentConfig returns a default EnvironmentConfig that can
// be used to create a new enviroment with NewEnvironment with sane defaults.
func DefaultEnvironmentConfig() *EnvironmentConfig {
config := &EnvironmentConfig{}
config.Ui = &BasicUi{
Reader: os.Stdin,
Writer: os.Stdout,
ErrorWriter: os.Stdout,
}
return config
}
// This creates a new environment
func NewEnvironment(config *EnvironmentConfig) (resultEnv Environment, err error) {
if config == nil {
err = errors.New("config must be given to initialize environment")
return
}
env := &coreEnvironment{}
env.cache = config.Cache
env.components = config.Components
env.ui = config.Ui
// We want to make sure the components have valid function pointers.
// If a function pointer was not given, we assume that the function
// will just return a nil component.
if env.components.Builder == nil {
env.components.Builder = func(string) (Builder, error) { return nil, nil }
}
if env.components.Hook == nil {
env.components.Hook = func(string) (Hook, error) { return nil, nil }
}
if env.components.PostProcessor == nil {
env.components.PostProcessor = func(string) (PostProcessor, error) { return nil, nil }
}
if env.components.Provisioner == nil {
env.components.Provisioner = func(string) (Provisioner, error) { return nil, nil }
}
// The default cache is just the system temporary directory
if env.cache == nil {
env.cache = &FileCache{CacheDir: os.TempDir()}
}
resultEnv = env
return
}
// Returns a builder of the given name that is registered with this
// environment.
func (e *coreEnvironment) Builder(name string) (b Builder, err error) {
b, err = e.components.Builder(name)
if err != nil {
return
}
if b == nil {
err = fmt.Errorf("No builder returned for name: %s", name)
}
return
}
// Returns the cache for this environment
func (e *coreEnvironment) Cache() Cache {
return e.cache
}
// Returns a hook of the given name that is registered with this
// environment.
func (e *coreEnvironment) Hook(name string) (h Hook, err error) {
h, err = e.components.Hook(name)
if err != nil {
return
}
if h == nil {
err = fmt.Errorf("No hook returned for name: %s", name)
}
return
}
// Returns a PostProcessor for the given name that is registered with this
// environment.
func (e *coreEnvironment) PostProcessor(name string) (p PostProcessor, err error) {
p, err = e.components.PostProcessor(name)
if err != nil {
return
}
if p == nil {
err = fmt.Errorf("No post processor found for name: %s", name)
}
return
}
// Returns a provisioner for the given name that is registered with this
// environment.
func (e *coreEnvironment) Provisioner(name string) (p Provisioner, err error) {
p, err = e.components.Provisioner(name)
if err != nil {
return
}
if p == nil {
err = fmt.Errorf("No provisioner returned for name: %s", name)
}
return
}
// Returns the UI for the environment. The UI is the interface that should
// be used for all communication with the outside world.
func (e *coreEnvironment) Ui() Ui {
return e.ui
}
package packer
import (
"bytes"
"errors"
"io/ioutil"
"log"
"os"
"testing"
)
func init() {
// Disable log output for tests
log.SetOutput(ioutil.Discard)
}
func testComponentFinder() *ComponentFinder {
builderFactory := func(n string) (Builder, error) { return new(MockBuilder), nil }
ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil }
provFactory := func(n string) (Provisioner, error) { return new(MockProvisioner), nil }
return &ComponentFinder{
Builder: builderFactory,
PostProcessor: ppFactory,
Provisioner: provFactory,
}
}
func testEnvironment() Environment {
config := DefaultEnvironmentConfig()
config.Ui = &BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
ErrorWriter: new(bytes.Buffer),
}
env, err := NewEnvironment(config)
if err != nil {
panic(err)
}
return env
}
func TestEnvironment_DefaultConfig_Ui(t *testing.T) {
config := DefaultEnvironmentConfig()
if config.Ui == nil {
t.Fatal("config.Ui should not be nil")
}
rwUi, ok := config.Ui.(*BasicUi)
if !ok {
t.Fatal("default UI should be BasicUi")
}
if rwUi.Writer != os.Stdout {
t.Fatal("default UI should go to stdout")
}
if rwUi.Reader != os.Stdin {
t.Fatal("default UI reader should go to stdin")
}
}
func TestNewEnvironment_NoConfig(t *testing.T) {
env, err := NewEnvironment(nil)
if env != nil {
t.Fatal("env should be nil")
}
if err == nil {
t.Fatal("should have error")
}
}
func TestEnvironment_NilComponents(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components = *new(ComponentFinder)
env, err := NewEnvironment(config)
if err != nil {
t.Fatalf("err: %s", err)
}
// All of these should not cause panics... so we don't assert
// anything but if there is a panic in the test then yeah, something
// went wrong.
env.Builder("foo")
env.Hook("foo")
env.PostProcessor("foo")
env.Provisioner("foo")
}
func TestEnvironment_Builder(t *testing.T) {
builder := &MockBuilder{}
builders := make(map[string]Builder)
builders["foo"] = builder
config := DefaultEnvironmentConfig()
config.Components.Builder = func(n string) (Builder, error) { return builders[n], nil }
env, _ := NewEnvironment(config)
returnedBuilder, err := env.Builder("foo")
if err != nil {
t.Fatalf("err: %s", err)
}
if returnedBuilder != builder {
t.Fatalf("bad: %#v", returnedBuilder)
}
}
func TestEnvironment_Builder_NilError(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Builder = func(n string) (Builder, error) { return nil, nil }
env, _ := NewEnvironment(config)
returnedBuilder, err := env.Builder("foo")
if err == nil {
t.Fatal("should have error")
}
if returnedBuilder != nil {
t.Fatalf("bad: %#v", returnedBuilder)
}
}
func TestEnvironment_Builder_Error(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Builder = func(n string) (Builder, error) { return nil, errors.New("foo") }
env, _ := NewEnvironment(config)
returnedBuilder, err := env.Builder("foo")
if err == nil {
t.Fatal("should have error")
}
if err.Error() != "foo" {
t.Fatalf("bad err: %s", err)
}
if returnedBuilder != nil {
t.Fatalf("should be nil: %#v", returnedBuilder)
}
}
func TestEnvironment_Cache(t *testing.T) {
config := DefaultEnvironmentConfig()
env, _ := NewEnvironment(config)
if env.Cache() == nil {
t.Fatal("cache should not be nil")
}
}
func TestEnvironment_Hook(t *testing.T) {
hook := &MockHook{}
hooks := make(map[string]Hook)
hooks["foo"] = hook
config := DefaultEnvironmentConfig()
config.Components.Hook = func(n string) (Hook, error) { return hooks[n], nil }
env, _ := NewEnvironment(config)
returned, err := env.Hook("foo")
if err != nil {
t.Fatalf("err: %s", err)
}
if returned != hook {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_Hook_NilError(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Hook = func(n string) (Hook, error) { return nil, nil }
env, _ := NewEnvironment(config)
returned, err := env.Hook("foo")
if err == nil {
t.Fatal("should have error")
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_Hook_Error(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Hook = func(n string) (Hook, error) { return nil, errors.New("foo") }
env, _ := NewEnvironment(config)
returned, err := env.Hook("foo")
if err == nil {
t.Fatal("should have error")
}
if err.Error() != "foo" {
t.Fatalf("err: %s", err)
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_PostProcessor(t *testing.T) {
pp := &TestPostProcessor{}
pps := make(map[string]PostProcessor)
pps["foo"] = pp
config := DefaultEnvironmentConfig()
config.Components.PostProcessor = func(n string) (PostProcessor, error) { return pps[n], nil }
env, _ := NewEnvironment(config)
returned, err := env.PostProcessor("foo")
if err != nil {
t.Fatalf("err: %s", err)
}
if returned != pp {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_PostProcessor_NilError(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.PostProcessor = func(n string) (PostProcessor, error) { return nil, nil }
env, _ := NewEnvironment(config)
returned, err := env.PostProcessor("foo")
if err == nil {
t.Fatal("should have error")
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_PostProcessor_Error(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.PostProcessor = func(n string) (PostProcessor, error) { return nil, errors.New("foo") }
env, _ := NewEnvironment(config)
returned, err := env.PostProcessor("foo")
if err == nil {
t.Fatal("should be an error")
}
if err.Error() != "foo" {
t.Fatalf("bad err: %s", err)
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironmentProvisioner(t *testing.T) {
p := &MockProvisioner{}
ps := make(map[string]Provisioner)
ps["foo"] = p
config := DefaultEnvironmentConfig()
config.Components.Provisioner = func(n string) (Provisioner, error) { return ps[n], nil }
env, _ := NewEnvironment(config)
returned, err := env.Provisioner("foo")
if err != nil {
t.Fatalf("err: %s", err)
}
if returned != p {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironmentProvisioner_NilError(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Provisioner = func(n string) (Provisioner, error) { return nil, nil }
env, _ := NewEnvironment(config)
returned, err := env.Provisioner("foo")
if err == nil {
t.Fatal("should have error")
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironmentProvisioner_Error(t *testing.T) {
config := DefaultEnvironmentConfig()
config.Components.Provisioner = func(n string) (Provisioner, error) {
return nil, errors.New("foo")
}
env, _ := NewEnvironment(config)
returned, err := env.Provisioner("foo")
if err == nil {
t.Fatal("should have error")
}
if err.Error() != "foo" {
t.Fatalf("err: %s", err)
}
if returned != nil {
t.Fatalf("bad: %#v", returned)
}
}
func TestEnvironment_SettingUi(t *testing.T) {
ui := &BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
}
config := &EnvironmentConfig{}
config.Ui = ui
env, _ := NewEnvironment(config)
if env.Ui() != ui {
t.Fatalf("UI should be equal: %#v", env.Ui())
}
}
......@@ -100,13 +100,6 @@ func (c *Client) Communicator() packer.Communicator {
}
}
func (c *Client) Environment() packer.Environment {
return &Environment{
client: c.client,
mux: c.mux,
}
}
func (c *Client) Hook() packer.Hook {
return &hook{
client: c.client,
......
package rpc
import (
"github.com/mitchellh/packer/packer"
"log"
"net/rpc"
)
// A Environment is an implementation of the packer.Environment interface
// where the actual environment is executed over an RPC connection.
type Environment struct {
client *rpc.Client
mux *muxBroker
}
// A EnvironmentServer wraps a packer.Environment and makes it exportable
// as part of a Golang RPC server.
type EnvironmentServer struct {
env packer.Environment
mux *muxBroker
}
func (e *Environment) Builder(name string) (b packer.Builder, err error) {
var streamId uint32
err = e.client.Call("Environment.Builder", name, &streamId)
if err != nil {
return
}
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
return nil, err
}
b = client.Builder()
return
}
func (e *Environment) Cache() packer.Cache {
var streamId uint32
if err := e.client.Call("Environment.Cache", new(interface{}), &streamId); err != nil {
panic(err)
}
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
log.Printf("[ERR] Error getting cache client: %s", err)
return nil
}
return client.Cache()
}
func (e *Environment) Hook(name string) (h packer.Hook, err error) {
var streamId uint32
err = e.client.Call("Environment.Hook", name, &streamId)
if err != nil {
return
}
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
return nil, err
}
return client.Hook(), nil
}
func (e *Environment) PostProcessor(name string) (p packer.PostProcessor, err error) {
var streamId uint32
err = e.client.Call("Environment.PostProcessor", name, &streamId)
if err != nil {
return
}
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
return nil, err
}
p = client.PostProcessor()
return
}
func (e *Environment) Provisioner(name string) (p packer.Provisioner, err error) {
var streamId uint32
err = e.client.Call("Environment.Provisioner", name, &streamId)
if err != nil {
return
}
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
return nil, err
}
p = client.Provisioner()
return
}
func (e *Environment) Ui() packer.Ui {
var streamId uint32
e.client.Call("Environment.Ui", new(interface{}), &streamId)
client, err := newClientWithMux(e.mux, streamId)
if err != nil {
log.Printf("[ERR] Error connecting to Ui: %s", err)
return nil
}
return client.Ui()
}
func (e *EnvironmentServer) Builder(name string, reply *uint32) error {
builder, err := e.env.Builder(name)
if err != nil {
return NewBasicError(err)
}
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterBuilder(builder)
go server.Serve()
return nil
}
func (e *EnvironmentServer) Cache(args *interface{}, reply *uint32) error {
cache := e.env.Cache()
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterCache(cache)
go server.Serve()
return nil
}
func (e *EnvironmentServer) Hook(name string, reply *uint32) error {
hook, err := e.env.Hook(name)
if err != nil {
return NewBasicError(err)
}
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterHook(hook)
go server.Serve()
return nil
}
func (e *EnvironmentServer) PostProcessor(name string, reply *uint32) error {
pp, err := e.env.PostProcessor(name)
if err != nil {
return NewBasicError(err)
}
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterPostProcessor(pp)
go server.Serve()
return nil
}
func (e *EnvironmentServer) Provisioner(name string, reply *uint32) error {
prov, err := e.env.Provisioner(name)
if err != nil {
return NewBasicError(err)
}
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterProvisioner(prov)
go server.Serve()
return nil
}
func (e *EnvironmentServer) Ui(args *interface{}, reply *uint32) error {
ui := e.env.Ui()
*reply = e.mux.NextId()
server := newServerWithMux(e.mux, *reply)
server.RegisterUi(ui)
go server.Serve()
return nil
}
package rpc
import (
"github.com/mitchellh/packer/packer"
"testing"
)
var testEnvBuilder = &packer.MockBuilder{}
var testEnvCache = &testCache{}
var testEnvUi = &testUi{}
type testEnvironment struct {
builderCalled bool
builderName string
cliCalled bool
cliArgs []string
hookCalled bool
hookName string
ppCalled bool
ppName string
provCalled bool
provName string
uiCalled bool
}
func (e *testEnvironment) Builder(name string) (packer.Builder, error) {
e.builderCalled = true
e.builderName = name
return testEnvBuilder, nil
}
func (e *testEnvironment) Cache() packer.Cache {
return testEnvCache
}
func (e *testEnvironment) Cli(args []string) (int, error) {
e.cliCalled = true
e.cliArgs = args
return 42, nil
}
func (e *testEnvironment) Hook(name string) (packer.Hook, error) {
e.hookCalled = true
e.hookName = name
return nil, nil
}
func (e *testEnvironment) PostProcessor(name string) (packer.PostProcessor, error) {
e.ppCalled = true
e.ppName = name
return nil, nil
}
func (e *testEnvironment) Provisioner(name string) (packer.Provisioner, error) {
e.provCalled = true
e.provName = name
return nil, nil
}
func (e *testEnvironment) Ui() packer.Ui {
e.uiCalled = true
return testEnvUi
}
func TestEnvironmentRPC(t *testing.T) {
// Create the interface to test
e := &testEnvironment{}
// Start the server
client, server := testClientServer(t)
defer client.Close()
defer server.Close()
server.RegisterEnvironment(e)
eClient := client.Environment()
// Test Builder
builder, _ := eClient.Builder("foo")
if !e.builderCalled {
t.Fatal("builder should be called")
}
if e.builderName != "foo" {
t.Fatalf("bad: %#v", e.builderName)
}
builder.Prepare(nil)
if !testEnvBuilder.PrepareCalled {
t.Fatal("should be called")
}
// Test Cache
cache := eClient.Cache()
cache.Lock("foo")
if !testEnvCache.lockCalled {
t.Fatal("should be called")
}
// Test Provisioner
_, _ = eClient.Provisioner("foo")
if !e.provCalled {
t.Fatal("should be called")
}
if e.provName != "foo" {
t.Fatalf("bad: %s", e.provName)
}
// Test Ui
ui := eClient.Ui()
if !e.uiCalled {
t.Fatal("should be called")
}
// Test calls on the Ui
ui.Say("format")
if !testEnvUi.sayCalled {
t.Fatal("should be called")
}
if testEnvUi.sayMessage != "format" {
t.Fatalf("bad: %#v", testEnvUi.sayMessage)
}
}
func TestEnvironment_ImplementsEnvironment(t *testing.T) {
var _ packer.Environment = new(Environment)
}
......@@ -19,7 +19,6 @@ const (
DefaultCacheEndpoint = "Cache"
DefaultCommandEndpoint = "Command"
DefaultCommunicatorEndpoint = "Communicator"
DefaultEnvironmentEndpoint = "Environment"
DefaultHookEndpoint = "Hook"
DefaultPostProcessorEndpoint = "PostProcessor"
DefaultProvisionerEndpoint = "Provisioner"
......@@ -95,13 +94,6 @@ func (s *Server) RegisterCommunicator(c packer.Communicator) {
})
}
func (s *Server) RegisterEnvironment(b packer.Environment) {
s.server.RegisterName(DefaultEnvironmentEndpoint, &EnvironmentServer{
env: b,
mux: s.mux,
})
}
func (s *Server) RegisterHook(h packer.Hook) {
s.server.RegisterName(DefaultHookEndpoint, &HookServer{
hook: h,
......
......@@ -10,7 +10,7 @@ import (
// Prepares the signal handlers so that we handle interrupts properly.
// The signal handler exists in a goroutine.
func setupSignalHandlers(env packer.Environment) {
func setupSignalHandlers(ui packer.Ui) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
......@@ -20,13 +20,13 @@ func setupSignalHandlers(env packer.Environment) {
<-ch
log.Println("First interrupt. Ignoring to allow plugins to clean up.")
env.Ui().Error("Interrupt signal received. Cleaning up...")
ui.Error("Interrupt signal received. Cleaning up...")
// Second interrupt. Go down hard.
<-ch
log.Println("Second interrupt. Exiting now.")
env.Ui().Error("Interrupt signal received twice. Forcefully exiting now.")
ui.Error("Interrupt signal received twice. Forcefully exiting now.")
// Force kill all the plugins, but mark that we're killing them
// first so that we don't get panics everywhere.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment