Beispiel #1
0
// GetOverlay fetches an overlay from nanobox.io and untars it into dst
func GetOverlay(overlay, dst string) {

	// extract a user and archive (desired engine)
	user, archive := ExtractArchive(overlay)

	// extract an engine and version from the archive
	engine, version := ExtractEngine(archive)

	//
	res, err := GetEngine(user, engine, version)
	if err != nil {
		config.Fatal("[util/engine/engine] http.Get() failed", err.Error())
	}
	defer res.Body.Close()

	//
	switch res.StatusCode / 100 {
	case 2, 3:
		break
	case 4, 5:
		os.Stderr.WriteString(stylish.ErrBullet("Unable to fetch '%v' overlay, exiting...", engine))
		os.Exit(1)
	}

	//
	if err := fileutil.Untar(dst, res.Body); err != nil {
		config.Fatal("[util/engine/engine] file.Untar() failed", err.Error())
	}
}
Beispiel #2
0
// RemoveDomain
func RemoveDomain() {

	var contents string

	// open hosts file
	f, err := os.OpenFile("/etc/hosts", os.O_RDWR, 0644)
	if err != nil {
		config.Fatal("[util/file/hosts] os.OpenFile() failed", err.Error())
	}
	defer f.Close()

	// remove entry from /etc/hosts
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {

		// if the line contain the entry skip it
		if strings.HasPrefix(scanner.Text(), config.Nanofile.IP) {
			continue
		}

		// add each line back into the file
		contents += fmt.Sprintf("%s\n", scanner.Text())
	}

	// trim the contents to avoid any extra newlines
	contents = strings.TrimSpace(contents)

	// write back the contents of the hosts file minus the removed entry
	if err := ioutil.WriteFile("/etc/hosts", []byte(contents), 0644); err != nil {
		config.Fatal("[util/file/hosts] ioutil.WriteFile failed", err.Error())
	}
}
Beispiel #3
0
// Status returns the current status of the VM; this command needs to be run
// in a way independant of a Vagrantfile to ensure that the status will always
// be available
func Status() (status string) {

	// default status of the VM
	status = "not created"

	// attempt to get the uuid; don't handle the error here because there are some
	// other conditions we want lumped together
	b, _ := ioutil.ReadFile(fmt.Sprintf("%v/.vagrant/machines/%v/%v/index_uuid", config.AppDir, config.Nanofile.Name, config.Nanofile.Provider))

	// set uuid (this will be "" if the above returned an error)
	uuid := string(b)

	// attempt to get the machine data
	b, err = ioutil.ReadFile(config.Home + "/.vagrant.d/data/machine-index/index")

	// an error here (os.PathError) means that the files was not found, causing
	// meaning no VMs have been created. Returning here will indicate a VM needs
	// to be created due to the default status above
	if uuid == "" || err != nil {
		return
	}

	// get the initial data
	machineIndex := make(map[string]json.RawMessage)
	if err := json.Unmarshal(b, &machineIndex); err != nil {
		config.Fatal("[util/vagrant/status] json.Unmarshal() machineIndex failed", err.Error())
	}

	// read the machines from machineIndex
	machines := make(map[string]json.RawMessage)
	if err := json.Unmarshal(machineIndex["machines"], &machines); err != nil {
		config.Fatal("[util/vagrant/status] json.Unmarshal() machines failed", err.Error())
	}

	// attempt to pull the machine based on the uuid
	machine := struct {
		Name        string `json:"name"`
		Provider    string `json:"provider"`
		State       string `json:"state"`
		Vagrantfile string `json:"vagrantfile_path"`
	}{}
	if m, ok := machines[uuid]; ok {
		if err := json.Unmarshal(m, &machine); err != nil {
			config.Fatal("[util/vagrant/status] json.Unmarshal() machine failed", err.Error())
		}
	}

	//
	if machine.State != "" {
		status = machine.State
	}

	return
}
Beispiel #4
0
// AddDomain
func AddDomain() {

	// open hosts file
	f, err := os.OpenFile("/etc/hosts", os.O_RDWR|os.O_APPEND, 0644)
	if err != nil {
		config.Fatal("[util/file/hosts] os.OpenFile() failed", err.Error())
	}
	defer f.Close()

	// write the entry to the file
	entry := fmt.Sprintf("\n%-15v   %s # '%v' private network (added by nanobox)", config.Nanofile.IP, config.Nanofile.Domain, config.Nanofile.Name)
	if _, err := f.WriteString(entry); err != nil {
		config.Fatal("[util/file/hosts] file.WriteString() failed", err.Error())
	}
}
Beispiel #5
0
// destroy
func destroy(ccmd *cobra.Command, args []string) {

	// PreRun: runnable

	// if the command is being run with --remove-entry, it means an entry needs
	// to be removed from the hosts file and execution yielded back to the parent
	if removeEntry {
		hosts.RemoveDomain()
		os.Exit(0) // this exits the sudoed (child) destroy, not the parent proccess
	}

	// destroy the vm; this needs to happen before cleaning up the app to ensure
	// there is a Vagrantfile to run the command with (otherwise it will just get
	// re-created)
	fmt.Printf(stylish.Bullet("Destroying nanobox..."))
	fmt.Printf(stylish.Bullet("Nanobox may require admin privileges to modify your /etc/hosts and /etc/exports files."))
	if err := vagrant.Destroy(); err != nil {

		// dont care if the project no longer exists... thats what we're doing anyway
		if err != err.(*os.PathError) {
			vagrant.Fatal("[commands/destroy] vagrant.Destroy() failed", err.Error())
		}
	}

	// remove app; this needs to happen after the VM is destroyed so that the app
	// isn't just created again upon running the vagrant command
	fmt.Printf(stylish.Bullet("Deleting nanobox files (%s)", config.AppDir))
	if err := os.RemoveAll(config.AppDir); err != nil {
		config.Fatal("[commands/destroy] os.RemoveAll() failed", err.Error())
	}

	// attempt to remove the entry regardless of whether its there or not
	util.PrivilegeExec("dev destroy --remove-entry", fmt.Sprintf("Removing %s domain from /etc/hosts", config.Nanofile.Domain))
}
Beispiel #6
0
// Listen connects a to mist, subscribes tags, and listens for 'model' updates
func Listen(tags []string, handle func(string) error) error {

	// only subscribe if a subscription doesn't already exist
	if _, ok := subscriptions[strings.Join(tags, "")]; ok {
		return nil
	}

	// connect
	client := connect()
	defer client.Close()

	// subscribe
	subscribe(client, tags)
	defer delete(subscriptions, strings.Join(tags, ""))

	// add tags to list of subscriptions
	subscriptions[strings.Join(tags, "")] = struct{}{}

	//
	model := Model{}
	for msg := range client.Messages() {

		// unmarshal the incoming Message
		if err := json.Unmarshal([]byte(msg.Data), &model); err != nil {
			config.Fatal("[util/server/mist/mist] json.Unmarshal() failed - ", err.Error())
		}

		// handle the status; when the handler returns false, it's time to break the
		// stream
		return handle(model.Document.Status)
	}

	return nil
}
Beispiel #7
0
// initialize
func initialize(ccmd *cobra.Command, args []string) {

	// PreRun: runnable

	// check to see if a box needs to be installed
	box.Install(nil, args)

	// creates a project folder at ~/.nanobox/apps/<name> where the Vagrantfile and
	// .vagrant dir will live for each app
	if err := os.MkdirAll(config.AppDir, 0755); err != nil {
		config.Fatal("[commands/init] os.Mkdir() failed", err.Error())
	}

	// set up a dedicated vagrant logger
	vagrant.NewLogger(config.AppDir + "/vagrant.log")

	// set up a dedicated server logger
	server.NewLogger(config.AppDir + "/server.log")

	// 'parse' the .vmfile (either creating one, or parsing it)
	config.VMfile = config.ParseVMfile()

	//
	// generate a Vagrantfile at ~/.nanobox/apps/<app-name>/Vagrantfile
	// only if one doesn't already exist (unless forced)
	if !config.Force {
		if _, err := os.Stat(config.AppDir + "/Vagrantfile"); err == nil {
			return
		}
	}

	vagrant.Init()
}
Beispiel #8
0
// uninstall
func uninstall(ccmd *cobra.Command, args []string) {

	//
	switch printutil.Prompt("Are you sure you want to uninstall nanobox (y/N)? ") {

	// don't uninstall by default
	default:
		fmt.Println("Nanobox has not been uninstalled!")
		return

	// if yes continue to uninstall
	case "Yes", "yes", "Y", "y":
		break
	}

	fmt.Println("Uninstalling nanobox... ")

	// do we need to do more here than just this?
	// - shutdown/destroy all vms?
	// - remove virtualbox/vagrant?
	// - probably need to remove nanobox binary

	//
	if err := os.RemoveAll(config.Root); err != nil {
		config.Fatal("[install] os.Remove() failed", err.Error())
	}

	fmt.Println("Nanobox has been successfully uninstalled!")
}
Beispiel #9
0
// updateImages
func updateImages(ccmd *cobra.Command, args []string) {

	// PreRun: boot

	fmt.Printf(stylish.Bullet("Updating nanobox docker images..."))

	// stream update output
	go Mist.Stream([]string{"log", "deploy"}, Mist.PrintLogStream)

	// listen for status updates
	errch := make(chan error)
	go func() {
		errch <- Mist.Listen([]string{"job", "imageupdate"}, Mist.ImageUpdates)
	}()

	// run an image update
	if err := Server.Update(""); err != nil {
		config.Fatal("[commands/update-images] server.Update() failed - ", err.Error())
	}

	// wait for a status update (blocking)
	err := <-errch

	//
	if err != nil {
		fmt.Printf(err.Error())
		return
	}

	// PostRun: halt
}
Beispiel #10
0
// getIgnoreDirs
func getIgnoreDirs() {
	res, err := http.Get(fmt.Sprintf("%s/libdirs", config.ServerURL))
	if err != nil {
		config.Fatal("[util/notify/notify] htto.Get() failed - ", err.Error())
	}
	defer res.Body.Close()

	//
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		config.Fatal("[util/notify/notify] ioutil.ReadAll() failed - ", err.Error())
	}

	if err := json.Unmarshal(b, &ignoreDirs); err != nil {
		config.Fatal("[util/notify/notify] json.Unmarshal() failed - ", err.Error())
	}
}
Beispiel #11
0
// connect connects 'mist' to the server running on the guest machine
func connect() mistClient.Client {
	mistClient, err := mistClient.NewRemoteClient(config.MistURI)
	if err != nil {
		config.Fatal("[util/server/mist/mist] mist.NewRemoteClient() failed - ", err.Error())
	}

	return mistClient
}
Beispiel #12
0
// Exists ensure vagrant is installed
func Exists() (exists bool) {
	var err error

	// check if vagrant is installed
	if _, err = exec.LookPath("vagrant"); err == nil {

		// initilize Vagrant incase it hasn't been; there is a chance that Vagrant has
		// never been used meaning there won't be a .vagrant.d folder, so we initialize
		// vagrant just to ensure it's ready to be used with nanobox by running any
		// vagrant command (in this case "vagrant -v").
		if b, err := exec.Command("vagrant", "-v").CombinedOutput(); err != nil {
			config.Fatal("[util/vagrant/vagrant] exec.Command() failed", string(b))
		}

		// read setup_version to determine if the version of vagrant is too old
		// (< 1.5.0) and needs to be migrated
		b, err := ioutil.ReadFile(filepath.Join(config.Home, ".vagrant.d", "setup_version"))
		if err != nil {
			config.Fatal("[util/vagrant/vagrant] ioutil.ReadFile() failed", err.Error())
		}

		// convert the []byte value from the file into a float 'version'
		version, err := strconv.ParseFloat(string(b), 64)
		if err != nil {
			config.Fatal("[util/vagrant/vagrant] strconv.ParseFloat() failed", err.Error())
		}

		// if the current version of vagrant is less than a 'working version' (1.5)
		// give instructions on how to update
		if version < 1.5 {
			fmt.Println(`
Nanobox has detected that you are using an old version of Vagrant (<1.5). Before
you can continue you'll need to run "vagrant update" and follow the instructions
to update Vagrant.
			`)

			// exit here to allow for upgrade
			os.Exit(0)
		}

		// if all checks pass
		exists = true
	}

	return
}
Beispiel #13
0
// Stream connects to mist, subscribes tags, and logs Messages
func Stream(tags []string, handle func(Log)) {

	// add log level to tags
	tags = append(tags, config.LogLevel)

	// if this subscription already exists, exit; this prevents double subscriptions
	if _, ok := subscriptions[strings.Join(tags, "")]; ok {
		return
	}

	// connect to mist
	client, err := mistClient.NewRemoteClient(config.MistURI)
	if err != nil {
		config.Fatal("[util/server/mist/mist] mist.NewRemoteClient() failed - ", err.Error())
	}
	defer client.Close()

	// this is a bandaid to fix a race condition in mist when immediatly subscribing
	// after connecting a client; once this is fixed in mist this can be removed
	<-time.After(time.Second * 1)

	// subscribe
	if err := client.Subscribe(tags); err != nil {
		config.Fatal("[util/server/mist/mist] client.Subscribe() failed - ", err.Error())
	}
	defer delete(subscriptions, strings.Join(tags, ""))

	// add tags to list of subscriptions
	subscriptions[strings.Join(tags, "")] = struct{}{}

	//
	for msg := range client.Messages() {

		//
		log := Log{}

		// unmarshal the incoming Message
		if err := json.Unmarshal([]byte(msg.Data), &log); err != nil {
			config.Fatal("[util/server/mist/mist] json.Unmarshal() failed - ", err.Error())
		}

		//
		handle(log)
	}
}
Beispiel #14
0
// NewLogger sets the vagrant logger to the given path
func NewLogger(path string) {

	var err error

	// create a file logger
	if Log, err = lumber.NewAppendLogger(path); err != nil {
		config.Fatal("[util/server/log] lumber.NewAppendLogger() failed", err.Error())
	}
}
Beispiel #15
0
// Listen connects a to mist, subscribes tags, and listens for 'model' updates
func Listen(tags []string, handle func(string) error) error {

	// only subscribe if a subscription doesn't already exist
	if _, ok := subscriptions[strings.Join(tags, "")]; ok {
		return nil
	}

	// connect to mist
	client, err := mistClient.NewRemoteClient(config.MistURI)
	if err != nil {
		config.Fatal("[util/server/mist/mist] mist.NewRemoteClient() failed - ", err.Error())
	}
	defer client.Close()

	// this is a bandaid to fix a race condition in mist when immediatly subscribing
	// after connecting a client; once this is fixed in mist this can be removed
	<-time.After(time.Second * 1)

	// subscribe
	if err := client.Subscribe(tags); err != nil {
		config.Fatal("[util/server/mist/mist] client.Subscribe() failed - ", err.Error())
	}
	defer delete(subscriptions, strings.Join(tags, ""))

	// add tags to list of subscriptions
	subscriptions[strings.Join(tags, "")] = struct{}{}

	//
	model := Model{}
	for msg := range client.Messages() {

		// unmarshal the incoming Message
		if err := json.Unmarshal([]byte(msg.Data), &model); err != nil {
			config.Fatal("[util/server/mist/mist] json.Unmarshal() failed - ", err.Error())
		}

		// handle the status; when the handler returns false, it's time to break the
		// stream
		return handle(model.Document.Status)
	}

	return nil
}
Beispiel #16
0
// halt
func halt(ccmd *cobra.Command, args []string) {

	//
	server.Unlock()

	//

	if err := server.Suspend(); err != nil {
		config.Fatal("[commands/halt] server.Suspend() failed", err.Error())
	}

	//
	if err := vagrant.Suspend(); err != nil {
		config.Fatal("[commands/halt] vagrant.Suspend() failed", err.Error())
	}

	//
	// os.Exit(0)
}
Beispiel #17
0
// GetTTYSize
func GetTTYSize(fd uintptr) (int, int) {

	ws, err := term.GetWinsize(fd)
	if err != nil {
		config.Fatal("[util/server/exec] term.GetWinsize() failed", err.Error())
	}

	//
	return int(ws.Width), int(ws.Height)
}
Beispiel #18
0
// Lock opens a 'lock' with the server; this is done so that nanobox can know how
// many clients are currenctly connected to the server
func Lock() {
	conn, err := net.Dial("tcp", config.ServerURI)
	if err != nil {
		config.Fatal("[util/server/locks] net.Dial() failed", err.Error())
	}

	conn.Write([]byte(fmt.Sprintf("PUT /lock? HTTP/1.1\r\n\r\n")))

	//
	lock = conn
}
Beispiel #19
0
// NewLogger sets the vagrant logger to the given path
func NewLogger(path string) {

	var err error

	// create a file logger (append if already exists)
	if Log, err = lumber.NewAppendLogger(path); err != nil {
		config.Fatal("[util/vagrant/log] lumber.NewAppendLogger() failed", err.Error())
	}

	logFile = path
}
Beispiel #20
0
// Prompt will prompt for input from the shell and return a trimmed response
func Prompt(p string, v ...interface{}) string {
	reader := bufio.NewReader(os.Stdin)

	//
	fmt.Print(colorstring.Color(fmt.Sprintf(p, v...)))

	input, err := reader.ReadString('\n')
	if err != nil {
		config.Fatal("[util/print] reader.ReadString() failed - ", err.Error())
	}

	return strings.TrimSpace(input)
}
Beispiel #21
0
// NewLogger sets the vagrant logger to the given path
func NewLogger(path string) {

	var err error

	// create a file logger (append if already exists)
	if Log, err = lumber.NewAppendLogger(path); err != nil {
		config.Fatal("[util/server/log] lumber.NewAppendLogger() failed", err.Error())
	}

	logFile = path

	fmt.Printf(stylish.Bullet("Created %s", path))
}
Beispiel #22
0
// PrivilegeExec runs a command as sudo
func PrivilegeExec(command, msg string) {
	fmt.Printf(stylish.Bullet(msg))

	//
	cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("sudo %v %v", os.Args[0], command))

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// run command
	if err := cmd.Run(); err != nil {
		config.Fatal("[util/util_unix]", err.Error())
	}
}
Beispiel #23
0
// PrivilegeExec runs a command, but assumes your already running as adminsitrator
func PrivilegeExec(command, msg string) {
	fmt.Printf(stylish.Bullet(msg))

	//
	cmd := exec.Command(os.Args[0], strings.Split(command, " ")...)

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// run command
	if err := cmd.Run(); err != nil {
		config.Fatal("[commands/commands_windows]", err.Error())
	}
}
Beispiel #24
0
// Download downloads a file
func Download(path string, w io.Writer) error {
	res, err := http.Get(path)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		config.Fatal("[util/file/file] ioutil.ReadAll() failed", err.Error())
	}

	w.Write(b)

	return nil
}
Beispiel #25
0
// watchDir gets run as a walk func, searching for directories to add watchers to
func watchDir(path string, fi os.FileInfo, err error) error {

	// don't walk any directory that is an ignore dir
	if isIgnoreDir(fi.Name()) {
		return filepath.SkipDir
	}

	// recursively add watchers to directores only (fsnotify will watch all files
	// in an added directory). Also, dont watch any files/dirs on the ignore list
	if fi.Mode().IsDir() {
		if err = watcher.Add(path); err != nil {
			config.Fatal("[util/notify/notify] watcher.Add() failed - ", err.Error())
		}
	}

	return nil
}
Beispiel #26
0
// init
func init() {

	// check for a ~/.nanobox/.auth file and create one if it's not found
	authfile = filepath.Clean(config.Root + "/.auth")
	if _, err := os.Stat(authfile); err != nil {
		f, err := os.Create(authfile)
		if err != nil {
			config.Fatal("[auth/auth] os.Create() failed", err.Error())
		}
		defer f.Close()
	}

	creds = &credentials{}

	//
	if err := config.ParseConfig(authfile, creds); err != nil {
		fmt.Printf("Nanobox failed to parse the .auth file.\n")
		os.Exit(1)
	}
}
Beispiel #27
0
// HasDomain
func HasDomain() (has bool) {

	// open the /etc/hosts file for scanning...
	f, err := os.Open("/etc/hosts")
	if err != nil {
		config.Fatal("[util/file/hosts] os.Open() failed", err.Error())
	}
	defer f.Close()

	// scan hosts file looking for an entry corresponding to this app...
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {

		// if an entry with the IP is detected, indicate that it's not needed
		if strings.HasPrefix(scanner.Text(), config.Nanofile.IP) {
			has = true
		}
	}

	return
}
Beispiel #28
0
// isContainer
func isContainer(args []string) bool {

	// fetch services to see if the command is trying to run on a specific container
	var services []server.Service
	if _, err := server.Get("/services", &services); err != nil {
		config.Fatal("[commands/exec] server.Get() failed", err.Error())
	}

	// make an exception for build1, as it wont show up on the list, but will always exist
	if args[0] == "build1" {
		return true
	}

	// look for a match
	for _, service := range services {
		if args[0] == service.Name {
			return true
		}
	}
	return false
}
Beispiel #29
0
// authenticate
func authenticate(Userslug, password string) (string, string) {

	fmt.Printf("\nAttempting login for %v... ", Userslug)

	// get auth_token
	user, err := api.GetAuthToken(Userslug, password)
	if err != nil {
		printutil.Color("[red]failure![reset]")
		fmt.Println("Unable to login... please verify your username and password are correct.")
		os.Exit(1)
	}

	//
	if err := saveCredentials(user.ID, user.AuthenticationToken); err != nil {
		config.Fatal("[auth/auth] saveCredentials failed", err.Error())
	}

	//
	printutil.Color("[green]success![reset]")

	return user.ID, user.AuthenticationToken
}
Beispiel #30
0
// update
func update(ccmd *cobra.Command, args []string) {

	update, err := updatable()
	if err != nil {
		config.Error("Unable to determing if updates are available", err.Error())
		return
	}

	// if the md5s don't match or it's been forced, update
	switch {
	case update, config.Force:
		if err := runUpdate(); err != nil {
			if _, ok := err.(*os.LinkError); ok {
				fmt.Println(`Nanobox was unable to update, try again with admin privilege (ex. "sudo nanobox update")`)
			} else {
				config.Fatal("[commands/update] runUpdate() failed", err.Error())
			}
		}
	default:
		fmt.Printf(stylish.SubBullet("[√] Nanobox is up-to-date"))
	}
}