Exemple #1
0
// getDeveloper retrieves the local dev and updates if out of date, or no
// dev exists.
func getDeveloper() (*db.Developer, error) {
	dev, err := db.GetDeveloper()
	if err != nil && err != errors.ErrNoDeveloper {
		return dev, err
	}

	ok := false
	if err != nil {
		log.Println("yellow", "Oops! You must be logged in.")
	} else {
		ok, err = devUpToDate(dev)
		if err != nil {
			return dev, err
		}

		if !ok {
			log.Println("yellow", "Oops! Your login information is out of date.")
		}
	}

	if err != nil || !ok {
		err = getToken(dev)
		if err != nil {
			return dev, err
		}
	}

	return dev, updateDeveloper(dev)
}
Exemple #2
0
func logoutRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	dev, err := db.GetDeveloper()
	if err != nil && err != errors.ErrNoDeveloper {
		rollbar.Report(err)
		return 1
	}

	if err == nil {
		log.Println("", "Logging you out",
			strings.Split(dev.Developer.Name, " ")[0]+".")
	} else {
		log.Println("yellow", "No user logged in.")
	}

	dev.Token = ""
	dev.Developer = nil
	err = dev.Save()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	keen.AddEvent("bowery logout", map[string]*db.Developer{"user": dev})

	return 0
}
Exemple #3
0
func removeRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	force := Cmds["remove"].Force

	if len(args) <= 0 {
		fmt.Fprintln(os.Stderr,
			"Usage: bowery "+Cmds["remove"].Usage, "\n\n"+Cmds["remove"].Short)
		return 2 // --help uses 2.
	}

	services, err := db.GetServices()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	for _, name := range args {
		_, ok := services.Data[name]
		if !ok {
			log.Println("yellow", "Service", name, "doesn't exist, skipping.")
			continue
		}

		if !force {
			ok, err = prompt.Ask("Are you sure you want to remove " + name)
			if err != nil {
				rollbar.Report(err)
				return 1
			}
			if !ok {
				log.Println("yellow", "Skipping", name)
				continue
			}
		}

		delete(services.Data, name)
		log.Println("", "Removed service", name)
	}

	err = services.Save()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	keen.AddEvent("bowery remove", map[string]interface{}{
		"toRemove": args,
		"existing": services.Data,
	})
	return 0
}
Exemple #4
0
func loginRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	dev, err := db.GetDeveloper()
	if err != nil && err != errors.ErrNoDeveloper {
		rollbar.Report(err)
		return 1
	}

	// If dev was found then check if token is up to date.
	if err == nil {
		ok, err := devUpToDate(dev)
		if err != nil {
			rollbar.Report(err)
			return 1
		}

		if ok {
			log.Println("", "You're logged in as",
				strings.Split(dev.Developer.Name, " ")[0]+".")
			return 0
		} else {
			log.Println("yellow", "Oops! Your login information is out of date.")
		}
	}

	err = getToken(dev)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	err = updateDeveloper(dev)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	keen.AddEvent("bowery login", map[string]*db.Developer{"user": dev})

	log.Println("magenta", "Hey there", strings.Split(dev.Developer.Name, " ")[0],
		"you're logged in now.")
	return 0
}
Exemple #5
0
// getToken gets the login information for a developer and gets a new token.
func getToken(dev *db.Developer) error {
	var err error
	i := 0
	token := ""

	// Get email and password up to 5 times, then report the error.
	for token == "" && i < 5 {
		validEmail := false
		email := ""
		pass := ""

		for !validEmail {
			email, err = prompt.Basic("Email", true)
			if err != nil {
				return err
			}

			_, err = mail.ParseAddress(email)
			if err == nil {
				validEmail = true
			} else {
				log.Println("yellow", "Try again! Valid email address required.")
			}
		}

		pass, err = prompt.Password("Password")
		if err != nil {
			return err
		}
		log.Debug("Collected email", email, "pass", pass)

		token, err = broome.GetTokenByLogin(email, pass)
		if err != nil {
			if i < 4 {
				log.Fprintln(os.Stderr, "red", errors.Newf(errors.ErrLoginRetryTmpl, err))
			}
			i++
		}
	}

	if err != nil {
		if err == errors.ErrInvalidLogin {
			err = errors.ErrTooManyLogins
		}

		return err
	}

	log.Debug("Got token", token)
	dev.Token = token
	return dev.Save()
}
Exemple #6
0
func saveRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	if len(args) <= 0 {
		fmt.Fprintln(os.Stderr,
			"Usage: bowery "+Cmds["save"].Usage, "\n\n"+Cmds["save"].Short)
		return 2
	}

	dev, err := getDeveloper()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	state, err := db.GetState()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	// Create slices of service names, and find the requested service.
	var service *schemas.Service
	services := make([]string, len(state.App.Services))
	for i, v := range state.App.Services {
		services[i] = v.Name
		if args[0] == v.Name {
			service = v
			break
		}
	}

	// Handle no service found.
	if service == nil {
		log.Fprintln(os.Stderr, "red", errors.ErrInvalidService, args[0])
		log.Println("yellow", "Valid services:", strings.Join(services, ", "))
		return 1
	}
	log.Debug("Found service", service.Name, "public addr:", service.PublicAddr)

	// Get image name
	log.Println("yellow", "What would you like to call this image?")
	imageName, err := prompt.Basic("Image Name", true)
	if err != nil {
		rollbar.Report(err)
		return 1
	}
	log.Debug("Collected Image Name", imageName)

	imageDesc, err := prompt.Basic("Description", true)
	if err != nil {
		rollbar.Report(err)
		return 1
	}
	log.Debug("Collected Description", imageDesc)

	log.Println("yellow", "A new image is being created and saved to our registry...")
	log.Println("yellow", "This may take a couple minutes.")

	err = api.SaveService(state, dev, service.Name, service.PublicAddr, imageName, imageDesc)
	if err != nil {
		errmsg := err.Error()
		if errmsg == imageName+" is an invalid service name" ||
			errmsg == "Image already exists" {
			log.Println("yellow", err)
		} else {
			rollbar.Report(err)
		}

		return 1
	}

	log.Println("yellow", imageName+" successfully created.")

	keen.AddEvent("bowery save", map[string]string{
		"serviceName": service.Name,
		"imageName":   imageName,
		"appId":       state.App.ID,
	})
	return 0
}
Exemple #7
0
// Shell opens a shell connection on the servives ssh address.
func Shell(app *schemas.Application, service *schemas.Service) error {
	// Make sure we're in raw mode.
	termState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
	if err != nil {
		if prompt.IsNotTerminal(err) {
			return errors.ErrIORedirection
		}

		return errors.NewStackError(err)
	}
	defer terminal.Restore(int(os.Stdin.Fd()), termState)

	// Get terminal size.
	cols, rows, err := terminal.GetSize(int(os.Stdout.Fd()))
	if err != nil {
		if prompt.IsNotTerminal(err) {
			return errors.ErrIORedirection
		}

		return errors.NewStackError(err)
	}

	// Open an SSH connection to the address.
	config := &ssh.ClientConfig{User: "******", Auth: []ssh.AuthMethod{
		ssh.Password("password"),
	}}
	client, err := ssh.Dial("tcp", service.SSHAddr, config)
	if err != nil {
		return errors.NewStackError(err)
	}
	defer client.Close()

	// Start a session on the client.
	session, err := client.NewSession()
	if err != nil {
		return errors.NewStackError(err)
	}
	defer session.Close()
	session.Stdout = prompt.NewAnsiWriter(os.Stdout)
	session.Stderr = prompt.NewAnsiWriter(os.Stderr)

	// Create a stdin pipe copying os.Stdin to it.
	stdin, err := session.StdinPipe()
	if err != nil {
		return errors.NewStackError(err)
	}
	defer stdin.Close()

	go func() {
		io.Copy(stdin, prompt.NewAnsiReader(os.Stdin))
	}()

	log.Println("magenta", "Welcome to Bowery Services.")
	log.Println("magenta", "---------------------------------------------")
	log.Println("magenta", "Name:", service.Name)
	log.Println("magenta", "Application:", app.ID)
	log.Println("magenta", "Time:", time.Now())
	log.Println("magenta", "---------------------------------------------")

	// Start a shell session.
	termModes := ssh.TerminalModes{
		ssh.ECHO:          1,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}
	err = session.RequestPty("xterm", rows, cols, termModes)
	if err == nil {
		err = session.Shell()
	}
	if err != nil {
		return errors.NewStackError(err)
	}

	// Wait for the session.
	err = session.Wait()
	if err != nil && err != io.EOF {
		// Ignore the error if it's an ExitError with an empty message,
		// this occurs when you do CTRL+c and then run exit cmd which isn't an
		// actual error.
		waitMsg, ok := err.(*ssh.ExitError)
		if ok && waitMsg.Msg() == "" {
			return nil
		}

		return errors.NewStackError(err)
	}

	return nil
}
Exemple #8
0
func updateRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	keen.AddEvent("cli update", map[string]string{"installed": version.Version})

	ver, err := api.GetVersion()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	if ver == version.Version {
		log.Println("", "Bowery is up to date.")
		return 0
	}
	log.Println("yellow", "Bowery is out of date. Updating to", ver, "now...")

	newVer, releaseNotes, err := api.DownloadNewVersion(ver)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	exec, err := osext.Executable()
	if err != nil {
		rollbar.Report(errors.NewStackError(err))
		return 1
	}
	tempExec := filepath.Join(filepath.Dir(exec), ".old_bowery"+filepath.Ext(exec))

	// Open exec, should fail if execing somewhere else.
	file, err := os.Open(exec)
	if err != nil {
		rollbar.Report(errors.ErrUpdatePerm)
		return 1
	}
	file.Close()

	// Create the temp exec file to test io permissions.
	file, err = os.Create(tempExec)
	if err != nil {
		rollbar.Report(errors.ErrUpdatePerm)
		return 1
	}
	file.Close()

	// Remove it which also removes any previous executables.
	err = os.RemoveAll(tempExec)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	// Move the exec to a temp file so we can write the new one.
	err = os.Rename(exec, tempExec)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	file, err = os.OpenFile(exec, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
	if err != nil {
		rollbar.Report(err)
		return 1
	}
	defer file.Close()

	_, err = io.Copy(file, newVer)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	log.Println("magenta", "Updated bowery to version", ver+".")

	if notes, err := ioutil.ReadAll(releaseNotes); err != nil {
		log.Println("", string(notes))
		return 0
	} else {
		rollbar.Report(err)
		return 1
	}

	return 0
}
Exemple #9
0
func restartRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int {
	if len(args) <= 0 {
		fmt.Fprintln(os.Stderr,
			"Usage: bowery "+Cmds["restart"].Usage, "\n\n"+Cmds["restart"].Short)
		return 2
	}

	dev, err := getDeveloper()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	state, err := db.GetState()
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	// Create slices of service names, and find the requested service.
	var service *schemas.Service
	services := make([]string, len(state.App.Services))
	serviceIdx := -1
	for i, v := range state.App.Services {
		services[i] = v.Name
		if args[0] == v.Name {
			service = v
			serviceIdx = i
			break
		}
	}

	// Handle no service found.
	if service == nil {
		log.Fprintln(os.Stderr, "red", errors.ErrInvalidService, args[0])
		log.Println("yellow", "Valid services:", strings.Join(services, ", "))
		return 1
	}
	log.Debug("Found service", service.Name)

	newService, err := api.RestartService(service.DockerID, dev.Token)
	if err != nil {
		rollbar.Report(err)
		return 1
	}

	if newService != nil {
		state.App.Services[serviceIdx] = newService
		service = newService

		err = state.Save()
		if err != nil {
			rollbar.Report(err)
			return 1
		}
	}

	keen.AddEvent("bowery restart", map[string]string{
		"name":  service.Name,
		"appId": state.App.ID,
	})
	return 0
}