Пример #1
0
// Discover discovers plugins.
//
// This looks in the directory of the executable and the CWD, in that
// order for priority.
func (c *Config) Discover() error {
	// Look in the cwd.
	if err := c.discover("."); err != nil {
		return err
	}

	// Look in the plugins directory. This will override any found
	// in the current directory.
	dir, err := ConfigDir()
	if err != nil {
		log.Printf("[ERR] Error loading config directory: %s", err)
	} else {
		if err := c.discover(filepath.Join(dir, "plugins")); err != nil {
			return err
		}
	}

	// Next, look in the same directory as the executable. Any conflicts
	// will overwrite those found in our current directory.
	exePath, err := osext.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := c.discover(filepath.Dir(exePath)); err != nil {
			return err
		}
	}

	return nil
}
Пример #2
0
func (c *config) pluginClient(path string) *plugin.Client {
	originalPath := path

	// First attempt to find the executable by consulting the PATH.
	path, err := exec.LookPath(path)
	if err != nil {
		// If that doesn't work, look for it in the same directory
		// as the `packer` executable (us).
		log.Printf("Plugin could not be found. Checking same directory as executable.")
		exePath, err := osext.Executable()
		if err != nil {
			log.Printf("Couldn't get current exe path: %s", err)
		} else {
			log.Printf("Current exe path: %s", exePath)
			path = filepath.Join(filepath.Dir(exePath), filepath.Base(originalPath))
		}
	}

	// If everything failed, just use the original path and let the error
	// bubble through.
	if path == "" {
		path = originalPath
	}

	log.Printf("Creating plugin client for path: %s", path)
	var config plugin.ClientConfig
	config.Cmd = exec.Command(path)
	config.Managed = true
	config.MinPort = c.PluginMinPort
	config.MaxPort = c.PluginMaxPort
	return plugin.NewClient(&config)
}
Пример #3
0
// Discover discovers plugins.
//
// Search the directory of the executable, then the plugins directory, and
// finally the CWD, in that order. Any conflicts will overwrite previously
// found plugins, in that order.
// Hence, the priority order is the reverse of the search order - i.e., the
// CWD has the highest priority.
func (c *config) Discover() error {
	// First, look in the same directory as the executable.
	exePath, err := osext.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := c.discover(filepath.Dir(exePath)); err != nil {
			return err
		}
	}

	// Next, look in the plugins directory.
	dir, err := ConfigDir()
	if err != nil {
		log.Printf("[ERR] Error loading config directory: %s", err)
	} else {
		if err := c.discover(filepath.Join(dir, "plugins")); err != nil {
			return err
		}
	}

	// Last, look in the CWD.
	if err := c.discover("."); err != nil {
		return err
	}

	return nil
}
Пример #4
0
func pluginCmd(path string) *exec.Cmd {
	cmdPath := ""

	// If the path doesn't contain a separator, look in the same
	// directory as the Terraform executable first.
	if !strings.ContainsRune(path, os.PathSeparator) {
		exePath, err := osext.Executable()
		if err == nil {
			temp := filepath.Join(
				filepath.Dir(exePath),
				filepath.Base(path))

			if _, err := os.Stat(temp); err == nil {
				cmdPath = temp
			}
		}

		// If we still haven't found the executable, look for it
		// in the PATH.
		if v, err := exec.LookPath(path); err == nil {
			cmdPath = v
		}
	}

	// If we still don't have a path, then just set it to the original
	// given path.
	if cmdPath == "" {
		cmdPath = path
	}

	// Build the command to execute the plugin
	return exec.Command(cmdPath)
}
Пример #5
0
func pluginCmd(path string) *exec.Cmd {
	originalPath := path

	// First look for the provider on the PATH.
	path, err := exec.LookPath(path)
	if err != nil {
		// If that doesn't work, look for it in the same directory
		// as the executable that is running.
		exePath, err := osext.Executable()
		if err == nil {
			path = filepath.Join(
				filepath.Dir(exePath),
				filepath.Base(originalPath))
		}
	}

	// If we still don't have a path set, then set it to the
	// original path and let any errors that happen bubble out.
	if path == "" {
		path = originalPath
	}

	// Build the command to execute the plugin
	return exec.Command(path)
}
Пример #6
0
func realMain() int {
	flag.Parse()

	// If we have a token set, then we're in token handler mode. Do it!
	if *token != "" {
		return mainToken(*token, flag.Args())
	}

	// Set our own path for later
	var err error
	selfPath, err = osext.Executable()
	if err != nil {
		log.Printf("[FATAL] Error getting executable path:%s", err)
		return 1
	}

	http.HandleFunc("/", handleRoot)
	http.HandleFunc("/socket", handleWebSocket)

	log.Println("[INFO] Starting server...")
	log.Printf("[INFO] Executable (selfPath) = %s", selfPath)
	if err := http.ListenAndServe(*addr, nil); err != nil {
		log.Printf("[FATAL] error starting: %s", err)
		return 1
	}

	return 0
}
Пример #7
0
// Discover discovers plugins.
//
// Search the directory of the executable, then the plugins directory, and
// finally the CWD, in that order. Any conflicts will overwrite previously
// found plugins, in that order.
// Hence, the priority order is the reverse of the search order - i.e., the
// CWD has the highest priority.
func (c *config) Discover() error {
	// First, look in the same directory as the executable.
	exePath, err := osext.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := c.discover(filepath.Dir(exePath)); err != nil {
			return err
		}
	}

	// Next, look in the plugins directory.
	dir, err := ConfigDir()
	if err != nil {
		log.Printf("[ERR] Error loading config directory: %s", err)
	} else {
		if err := c.discover(filepath.Join(dir, "plugins")); err != nil {
			return err
		}
	}

	// Next, look in the CWD.
	if err := c.discover("."); err != nil {
		return err
	}

	// Finally, try to use an internal plugin. Note that this will not override
	// any previously-loaded plugins.
	if err := c.discoverInternal(); err != nil {
		return err
	}

	return nil
}
Пример #8
0
func TestPanicHandler(t *testing.T) {
	startTestServer()

	exePath, err := osext.Executable()
	if err != nil {
		t.Fatal(err)
	}

	// Use the same trick as panicwrap() to re-run ourselves.
	// In the init() block below, we will then panic.
	cmd := exec.Command(exePath, os.Args[1:]...)
	cmd.Env = append(os.Environ(), "BUGSNAG_API_KEY="+testAPIKey, "BUGSNAG_ENDPOINT="+testEndpoint)

	for i := range cmd.Env {
		if cmd.Env[i] == "bugsnag_wrapped=bugsnag_wrapped" {
			cmd.Env[i] = "please_panic=please_panic"
		}
	}

	if err = cmd.Start(); err != nil {
		t.Fatal(err)
	}

	if err = cmd.Wait(); err.Error() != "exit status 2" {
		t.Fatal(err)
	}

	json, err := simplejson.NewJson(<-postedJSON)
	if err != nil {
		t.Fatal(err)
	}

	event := json.Get("events").GetIndex(0)

	if event.Get("severity").MustString() != "error" {
		t.Errorf("severity should be error")
	}
	exception := event.Get("exceptions").GetIndex(0)

	if exception.Get("message").MustString() != "ruh roh" {
		t.Errorf("caught wrong panic")
	}

	if exception.Get("errorClass").MustString() != "panic" {
		t.Errorf("caught wrong panic")
	}

	frame := exception.Get("stacktrace").GetIndex(1)

	// Yeah, we just caught a panic from the init() function below and sent it to the server running above (mindblown)
	if frame.Get("inProject").MustBool() != true ||
		frame.Get("file").MustString() != "panicwrap_test.go" ||
		frame.Get("method").MustString() != "panick" ||
		frame.Get("lineNumber").MustInt() == 0 {
		t.Errorf("stack trace seemed wrong")
	}
}
Пример #9
0
func DiscoverPlugins() (*Plugins, error) {
	plugins := &Plugins{}

	// Look in the cwd.
	if err := discoverPluginsInDir(".", plugins); err != nil {
		return nil, err
	}

	// Next, look in the same directory as the executable. Any conflicts
	// will overwrite those found in our current directory.
	exePath, err := osext.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := discoverPluginsInDir(filepath.Dir(exePath), plugins); err != nil {
			return nil, err
		}
	}

	return plugins, nil
}
Пример #10
0
func (c *config) discoverInternal() error {
	// Get the packer binary path
	packerPath, err := osext.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
		return err
	}

	for builder := range command.Builders {
		_, found := (c.Builders)[builder]
		if !found {
			log.Printf("Using internal plugin for %s", builder)
			(c.Builders)[builder] = fmt.Sprintf("%s%splugin%spacker-builder-%s",
				packerPath, PACKERSPACE, PACKERSPACE, builder)
		}
	}

	for provisioner := range command.Provisioners {
		_, found := (c.Provisioners)[provisioner]
		if !found {
			log.Printf("Using internal plugin for %s", provisioner)
			(c.Provisioners)[provisioner] = fmt.Sprintf(
				"%s%splugin%spacker-provisioner-%s",
				packerPath, PACKERSPACE, PACKERSPACE, provisioner)
		}
	}

	for postProcessor := range command.PostProcessors {
		_, found := (c.PostProcessors)[postProcessor]
		if !found {
			log.Printf("Using internal plugin for %s", postProcessor)
			(c.PostProcessors)[postProcessor] = fmt.Sprintf(
				"%s%splugin%spacker-post-processor-%s",
				packerPath, PACKERSPACE, PACKERSPACE, postProcessor)
		}
	}

	return nil
}
Пример #11
0
func main() {
	debug := os.Getenv("VAGRANT_DEBUG_LAUNCHER") != ""

	// Get the path to the executable. This path doesn't resolve symlinks
	// so we have to do that afterwards to find the real binary.
	path, err := osext.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: path = %s", path)
	}
	for {
		fi, err := os.Lstat(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to stat executable: %s\n", err)
			os.Exit(1)
		}
		if fi.Mode()&os.ModeSymlink == 0 {
			break
		}

		// The executable is a symlink, so resolve it
		path, err = os.Readlink(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
			os.Exit(1)
		}
		if debug {
			log.Printf("launcher: resolved symlink = %s", path)
		}
	}

	// Determine some basic directories that we use throughout
	path = filepath.Dir(filepath.Clean(path))
	installerDir := filepath.Dir(path)
	embeddedDir := filepath.Join(installerDir, "embedded")
	if debug {
		log.Printf("launcher: installerDir = %s", installerDir)
		log.Printf("launcher: embeddedDir = %s", embeddedDir)
	}

	// Find the Vagrant gem
	gemPaths, err := filepath.Glob(
		filepath.Join(embeddedDir, "gems", "gems", "vagrant-*"))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: gemPaths (initial) = %#v", gemPaths)
	}
	for i := 0; i < len(gemPaths); i++ {
		fullPath := filepath.Join(gemPaths[i], "lib", "vagrant", "pre-rubygems.rb")
		if _, err := os.Stat(fullPath); err != nil {
			if debug {
				log.Printf("launcher: bad gemPath += %s", fullPath)
			}

			gemPaths = append(gemPaths[:i], gemPaths[i+1:]...)
			i--
		}
	}
	if len(gemPaths) == 0 {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant!\n")
		os.Exit(1)
	}
	gemPath := gemPaths[len(gemPaths)-1]
	vagrantExecutable := filepath.Join(gemPath, "bin", "vagrant")
	if debug {
		log.Printf("launcher: gemPaths (final) = %#v", gemPaths)
		log.Printf("launcher: gemPath = %s", gemPath)
	}

	// Setup the CPP/LDFLAGS so that native extensions can be
	// properly compiled into the Vagrant environment.
	cppflags := "-I" + filepath.Join(embeddedDir, "include")
	ldflags := "-L" + filepath.Join(embeddedDir, "lib")
	if original := os.Getenv("CPPFLAGS"); original != "" {
		cppflags = original + " " + cppflags
	}
	if original := os.Getenv("LDFLAGS"); original != "" {
		ldflags = original + " " + ldflags
	}

	// Set the PATH to include the proper paths into our embedded dir
	path = os.Getenv("PATH")
	if runtime.GOOS == "windows" {
		path = fmt.Sprintf(
			"%s;%s;%s",
			filepath.Join(embeddedDir, "bin"),
			filepath.Join(embeddedDir, "gnuwin32", "bin"),
			path)
	} else {
		path = fmt.Sprintf("%s:%s",
			filepath.Join(embeddedDir, "bin"), path)
	}

	// Allow users to specify a custom SSL cert
	sslCertFile := os.Getenv("SSL_CERT_FILE")
	if sslCertFile == "" {
		sslCertFile = filepath.Join(embeddedDir, "cacert.pem")
	}

	newEnv := map[string]string{
		// Setup the environment to prefer our embedded dir over
		// anything the user might have setup on his/her system.
		"CPPFLAGS":      cppflags,
		"GEM_HOME":      filepath.Join(embeddedDir, "gems"),
		"GEM_PATH":      filepath.Join(embeddedDir, "gems"),
		"GEMRC":         filepath.Join(embeddedDir, "etc", "gemrc"),
		"LDFLAGS":       ldflags,
		"PATH":          path,
		"SSL_CERT_FILE": sslCertFile,

		// Environmental variables used by Vagrant itself
		"VAGRANT_EXECUTABLE":             vagrantExecutable,
		"VAGRANT_INSTALLER_ENV":          "1",
		"VAGRANT_INSTALLER_EMBEDDED_DIR": embeddedDir,
		"VAGRANT_INSTALLER_VERSION":      "2",
	}

	// Unset any RUBYOPT, we don't want this bleeding into our runtime
	newEnv["RUBYOPT"] = ""
	// Unset any RUBYLIB, we don't want this bleeding into our runtime
	newEnv["RUBYLIB"] = ""

	// Store the "current" environment so Vagrant can restore it when shelling
	// out.
	for _, value := range os.Environ() {
		idx := strings.IndexRune(value, '=')
		key := fmt.Sprintf("%s_%s", envPrefix, value[:idx])
		newEnv[key] = value[idx+1:]
	}
	if debug {
		keys := make([]string, 0, len(newEnv))
		for k, _ := range newEnv {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, k := range keys {
			log.Printf("launcher: env %q = %q", k, newEnv[k])
		}
	}

	// Set all the environmental variables
	for k, v := range newEnv {
		if err := os.Setenv(k, v); err != nil {
			fmt.Fprintf(os.Stderr, "Error setting env var %s: %s\n", k, err)
			os.Exit(1)
		}
	}

	// Determine the path to Ruby and then start the Vagrant process
	rubyPath := filepath.Join(embeddedDir, "bin", "ruby")
	if runtime.GOOS == "windows" {
		rubyPath += ".exe"
	}

	// Prior to starting the command, we ignore interrupts. Vagrant itself
	// handles these, so the launcher should just wait until that exits.
	signal.Ignore(os.Interrupt)

	cmd := exec.Command(rubyPath)
	cmd.Args = make([]string, len(os.Args)+1)
	cmd.Args[0] = "ruby"
	cmd.Args[1] = filepath.Join(gemPath, "lib", "vagrant", "pre-rubygems.rb")
	copy(cmd.Args[2:], os.Args[1:])
	if debug {
		log.Printf("launcher: rubyPath = %s", rubyPath)
		log.Printf("launcher: args = %#v", cmd.Args)
	}

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "Exec error: %s\n", err)
		os.Exit(1)
	}

	exitCode := 0
	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			// This works on both Unix and Windows. Although package
			// syscall is generally platform dependent, WaitStatus is
			// defined for both Unix and Windows and in both cases has
			// an ExitStatus() method with the same signature.
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				exitCode = status.ExitStatus()
			}
		}
	}

	os.Exit(exitCode)
}
Пример #12
0
// Wrap wraps the current executable in a handler to catch panics. It
// returns an error if there was an error during the wrapping process.
// If the error is nil, then the int result indicates the exit status of the
// child process. If the exit status is -1, then this is the child process,
// and execution should continue as normal. Otherwise, this is the parent
// process and the child successfully ran already, and you should exit the
// process with the returned exit status.
//
// This function should be called very very early in your program's execution.
// Ideally, this runs as the first line of code of main.
//
// Once this is called, the given WrapConfig shouldn't be modified or used
// any further.
func Wrap(c *WrapConfig) (int, error) {
	if c.Handler == nil {
		return -1, errors.New("Handler must be set")
	}

	if c.CookieKey == "" {
		c.CookieKey = DEFAULT_COOKIE_KEY
	}

	if c.CookieValue == "" {
		c.CookieValue = DEFAULT_COOKIE_VAL
	}

	if c.DetectDuration == 0 {
		c.DetectDuration = 300 * time.Millisecond
	}

	if c.Writer == nil {
		c.Writer = os.Stderr
	}

	// If the cookie key/value match our environment, then we are the
	// child, so just exit now and tell the caller that we're the child
	if os.Getenv(c.CookieKey) == c.CookieValue {
		return -1, nil
	}

	// Get the path to our current executable
	exePath, err := osext.Executable()
	if err != nil {
		return -1, err
	}

	// Pipe the stderr so we can read all the data as we look for panics
	stderr_r, stderr_w := io.Pipe()

	// doneCh is closed when we're done, signaling any other goroutines
	// to end immediately.
	doneCh := make(chan struct{})

	// panicCh is the channel on which the panic text will actually be
	// sent.
	panicCh := make(chan string)

	// On close, make sure to finish off the copying of data to stderr
	defer func() {
		defer close(doneCh)
		stderr_w.Close()
		<-panicCh
	}()

	// Start the goroutine that will watch stderr for any panics
	go trackPanic(stderr_r, c.Writer, c.DetectDuration, panicCh)

	// Build a subcommand to re-execute ourselves. We make sure to
	// set the environmental variable to include our cookie. We also
	// set stdin/stdout to match the config. Finally, we pipe stderr
	// through ourselves in order to watch for panics.
	cmd := exec.Command(exePath, os.Args[1:]...)
	cmd.Env = append(os.Environ(), c.CookieKey+"="+c.CookieValue)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = stderr_w
	if err := cmd.Start(); err != nil {
		return 1, err
	}

	// Listen to signals and capture them forever. We allow the child
	// process to handle them in some way.
	sigCh := make(chan os.Signal)
	signal.Notify(sigCh, os.Interrupt)
	go func() {
		defer signal.Stop(sigCh)
		for {
			select {
			case <-doneCh:
				return
			case <-sigCh:
			}
		}
	}()

	if err := cmd.Wait(); err != nil {
		exitErr, ok := err.(*exec.ExitError)
		if !ok {
			// This is some other kind of subprocessing error.
			return 1, err
		}

		exitStatus := 1
		if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
			exitStatus = status.ExitStatus()
		}

		// Close the writer end so that the tracker goroutine ends at some point
		stderr_w.Close()

		// Wait on the panic data
		panicTxt := <-panicCh
		if panicTxt != "" {
			if !c.HidePanic {
				c.Writer.Write([]byte(panicTxt))
			}

			c.Handler(panicTxt)
		}

		return exitStatus, nil
	}

	return 0, nil
}