Exemple #1
0
// ResetPassword sends request to broome to send password reset email
func ResetPassword(email string) error {
	res, err := http.Get(Host + strings.Replace(ResetPasswordPath, "{email}", email, -1))

	if err != nil {
		return errors.NewStackError(err)
	}
	defer res.Body.Close()

	resetRes := new(responses.Res)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(resetRes)
	if err != nil {
		return errors.NewStackError(err)
	}

	if resetRes.Status == "success" {
		return nil
	}

	if strings.Contains(resetRes.Error(), "not found") {
		return errors.ErrInvalidEmail
	}

	return errors.NewStackError(errors.ErrResetRequest)
}
Exemple #2
0
// Download retrieves the contents of a service.
func Download(url string) (io.Reader, error) {
	var buf bytes.Buffer
	res, err := http.Get("http://" + url)
	if err != nil {
		return nil, errors.NewStackError(err)
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		downloadRes := new(responses.Res)
		decoder := json.NewDecoder(res.Body)
		err = decoder.Decode(downloadRes)
		if err != nil {
			return nil, errors.NewStackError(err)
		}

		return nil, errors.NewStackError(downloadRes)
	}

	_, err = io.Copy(&buf, res.Body)
	if err != nil {
		return nil, errors.NewStackError(err)
	}

	return &buf, nil
}
Exemple #3
0
// GetDeveloper retrieves the developer for the given token.
func GetDeveloper(token string) (*schemas.Developer, error) {
	res, err := http.Get(Host + strings.Replace(MePath, "{token}", token, -1))
	if err != nil {
		return nil, errors.NewStackError(err)
	}
	defer res.Body.Close()

	// Decode json response.
	devRes := new(responses.DeveloperRes)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(devRes)
	if err != nil {
		return nil, errors.NewStackError(err)
	}

	// Found so return the developer.
	if devRes.Status == "found" {
		return devRes.Developer, nil
	}

	if strings.Contains(devRes.Error(), "Invalid Token") {
		return nil, errors.ErrInvalidToken
	}

	// Non "found" status indicates error.
	return nil, errors.NewStackError(devRes)
}
Exemple #4
0
// Close disables the terminals raw input.
func (term *Terminal) Close() error {
	if term.isTerm {
		ret, _, err := setConsoleMode.Call(term.In.Fd(), uintptr(term.origMode))
		if ret == 0 {
			return errors.NewStackError(err)
		}
	}

	return nil
}
Exemple #5
0
// CreateDeveloper creates a new developer.
func CreateDeveloper(name, email, password string) (*schemas.Developer, error) {
	var body bytes.Buffer
	bodyReq := &LoginReq{Name: name, Email: email, Password: password}

	encoder := json.NewEncoder(&body)
	err := encoder.Encode(bodyReq)
	if err != nil {
		return nil, errors.NewStackError(err)
	}

	res, err := http.Post(Host+CreateDeveloperPath, "application/json", &body)
	if err != nil {
		return nil, errors.NewStackError(err)
	}
	defer res.Body.Close()

	// Decode json response.
	createRes := new(responses.DeveloperRes)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(createRes)
	if err != nil {
		return nil, errors.NewStackError(err)
	}

	// Created, just return token.
	if createRes.Status == "created" {
		return createRes.Developer, nil
	}

	// If the error is about developer existing, don't create stack error.
	if strings.Contains(createRes.Error(), "email already exists") {
		return nil, errors.ErrDeveloperExists
	}

	// Check for license issues.
	if strings.Contains(createRes.Error(), "License expired.") ||
		strings.Contains(createRes.Error(), "License user limit reached.") {
		return nil, createRes
	}

	// Non "created" status indicates error, just return invalid.
	return nil, errors.NewStackError(createRes)
}
Exemple #6
0
// DevPing checks to see if the api is up and running and updates
// the developers lastActive field.
func DevPing(token string) error {
	endpoint := Host + strings.Replace(CheckPath, "{token}", token, -1)
	res, err := http.Get(endpoint)
	if err != nil {
		return errors.NewStackError(err)
	}
	defer res.Body.Close()

	return nil
}
Exemple #7
0
// simplePrompt is a fallback prompt without line editing support.
func (term *Terminal) simplePrompt(prefix string) (string, error) {
	term.Out.Write([]byte(prefix))
	line, err := inReader.ReadString('\n')
	line = strings.TrimRight(line, "\r\n ")
	line = strings.TrimLeft(line, " ")
	if err != nil {
		err = errors.NewStackError(err)
	}

	return line, err
}
Exemple #8
0
// TerminalSize retrieves the cols/rows for the terminal connected to out.
func TerminalSize(out *os.File) (int, int, error) {
	csbi := new(consoleScreenBufferInfo)
	ret, _, err := getConsoleScreenBufferInfo.Call(out.Fd(),
		uintptr(unsafe.Pointer(csbi)))
	if ret == 0 {
		return 0, 0, errors.NewStackError(err)
	}

	// Results are always off by one.
	cols := csbi.window.right - csbi.window.left + 1
	rows := csbi.window.bottom - csbi.window.top + 1
	return int(cols), int(rows), nil
}
Exemple #9
0
// GetTokenByLogin creates a token for the given devs email.
func GetTokenByLogin(email, password string) (string, error) {
	var body bytes.Buffer
	bodyReq := &LoginReq{Email: email, Password: password}

	encoder := json.NewEncoder(&body)
	err := encoder.Encode(bodyReq)
	if err != nil {
		return "", errors.NewStackError(err)
	}

	res, err := http.Post(Host+CreateTokenPath, "application/json", &body)
	if err != nil {
		return "", errors.NewStackError(err)
	}
	defer res.Body.Close()

	// Decode json response.
	createRes := new(responses.CreateTokenRes)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(createRes)
	if err != nil {
		return "", errors.NewStackError(err)
	}

	// Created, just return token.
	if createRes.Status == "created" {
		return createRes.Token, nil
	}

	// Check for license issues.
	if strings.Contains(createRes.Error(), "License expired.") ||
		strings.Contains(createRes.Error(), "License user limit reached.") {
		return "", createRes
	}

	// Non "created" status indicates error, just return invalid.
	return "", errors.ErrInvalidLogin
}
Exemple #10
0
// NewTerminal creates a terminal and sets it to raw input mode.
func NewTerminal() (*Terminal, error) {
	if inReader == nil {
		inReader = bufio.NewReader(os.Stdin)
	}
	term := &Terminal{In: os.Stdin, Out: os.Stdout}

	err := syscall.GetConsoleMode(syscall.Handle(term.In.Fd()), &term.origMode)
	if err != nil {
		return term, nil
	}
	mode := term.origMode
	term.isTerm = true

	// Set new mode flags.
	mode &^= (echoInputFlag | insertModeFlag | lineInputFlag | mouseInputFlag |
		processedInputFlag | windowInputFlag)

	ret, _, err := setConsoleMode.Call(term.In.Fd(), uintptr(mode))
	if ret == 0 {
		return nil, errors.NewStackError(err)
	}

	return term, nil
}
Exemple #11
0
// prompt reads from in and parses ansi escapes writing to buf.
func (term *Terminal) prompt(buf *Buffer, in io.Reader) (string, error) {
	cols, _, err := TerminalSize(buf.Out)
	if err != nil {
		return "", err
	}
	buf.Cols = cols
	input := bufio.NewReader(in)

	err = buf.Refresh()
	if err != nil {
		return "", errors.NewStackError(err)
	}

	for {
		char, _, err := input.ReadRune()
		if err != nil {
			return buf.String(), errors.NewStackError(err)
		}

		switch char {
		default:
			// Insert characters in the buffer.
			err = buf.Insert(char)
			if err != nil {
				return buf.String(), errors.NewStackError(err)
			}
		case tabKey, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlH, ctrlJ, ctrlK, ctrlN,
			ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX,
			ctrlY, ctrlZ:
			// Skip.
			continue
		case returnKey, ctrlD:
			// Finished, return the buffer contents.
			err = buf.EndLine()
			if err != nil {
				err = errors.NewStackError(err)
			}

			return buf.String(), err
		case ctrlC:
			// Finished, return CTRL+C error.
			err = buf.EndLine()
			if err != nil {
				err = errors.NewStackError(err)
			} else {
				err = errors.ErrCTRLC
			}

			return buf.String(), err
		case backKey:
			// Backspace.
			err = buf.DelLeft()
			if err != nil {
				return buf.String(), errors.NewStackError(err)
			}
		case ctrlL:
			// Clear screen.
			err = buf.ClsScreen()
			if err != nil {
				return buf.String(), errors.NewStackError(err)
			}
		case escKey:
			// Functions like arrows, home, etc.
			esc := make([]byte, 2)
			_, err = input.Read(esc)
			if err != nil {
				return buf.String(), errors.NewStackError(err)
			}

			// Home, end.
			if esc[0] == 'O' {
				switch esc[1] {
				case 'H':
					// Home.
					err = buf.Start()
					if err != nil {
						return buf.String(), errors.NewStackError(err)
					}
				case 'F':
					// End.
					err = buf.End()
					if err != nil {
						return buf.String(), errors.NewStackError(err)
					}
				}

				continue
			}

			// Arrows, delete, pgup, pgdown, insert.
			if esc[0] == '[' {
				switch esc[1] {
				case 'A', 'B':
					// Up, down.
					continue
				case 'C':
					// Right.
					err = buf.Right()
					if err != nil {
						return buf.String(), errors.NewStackError(err)
					}
				case 'D':
					// Left.
					err = buf.Left()
					if err != nil {
						return buf.String(), errors.NewStackError(err)
					}
				}

				// Delete, pgup, pgdown, insert.
				if esc[1] > '0' && esc[1] < '7' {
					extEsc := make([]byte, 3)
					_, err = input.Read(extEsc)
					if err != nil {
						return buf.String(), errors.NewStackError(err)
					}

					if extEsc[0] == '~' {
						switch esc[1] {
						case '2', '5', '6':
							// Insert, pgup, pgdown.
							continue
						case '3':
							// Delete.
							err = buf.Del()
							if err != nil {
								return buf.String(), errors.NewStackError(err)
							}
						}
					}
				}
			}
		}
	}
}
Exemple #12
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 #13
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 #14
0
// Upload sends an upload request to a satellite endpoint, including
// a tar upload file if given.
func Upload(url, serviceName string, file *os.File) error {
	var body bytes.Buffer
	writer := multipart.NewWriter(&body)

	// Write file to multipart body if given.
	if file != nil {
		part, err := writer.CreateFormFile("file", "upload")
		if err != nil {
			return errors.NewStackError(err)
		}

		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}

	// Get current app and add fields for init, build, test, and start.
	state, err := db.GetState()
	if err != nil {
		return err
	}

	service := state.Config[serviceName]
	if service != nil {
		err = writer.WriteField("init", service.Init)
		if err == nil {
			err = writer.WriteField("build", service.Build)
		}
		if err == nil {
			err = writer.WriteField("test", service.Test)
		}
		if err == nil {
			err = writer.WriteField("start", service.Start)
		}
		if err == nil {
			err = writer.WriteField("path", service.Path)
		}
		if err == nil && service.Env != nil {
			envData, err := json.Marshal(service.Env)
			if err != nil {
				return err
			}
			err = writer.WriteField("env", string(envData))
		}
	}
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		return err
	}

	res, err := http.Post("http://"+url, writer.FormDataContentType(), &body)
	if err != nil {
		if responses.IsRefusedConn(err) {
			err = errors.ErrSyncFailed
		}

		return errors.NewStackError(err)
	}
	defer res.Body.Close()

	// Decode json response.
	uploadRes := new(responses.Res)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(uploadRes)
	if err != nil {
		return errors.NewStackError(err)
	}

	// Created, so no error.
	if uploadRes.Status == "created" {
		return nil
	}

	return errors.NewStackError(uploadRes)
}
Exemple #15
0
// Update updates the given name with the status and path.
func Update(url, serviceName, fullPath, name, status string) error {
	var body bytes.Buffer

	// Create writer, and write form fields.
	writer := multipart.NewWriter(&body)
	err := writer.WriteField("type", status)
	if err == nil {
		err = writer.WriteField("path", path.Join(strings.Split(name, string(filepath.Separator))...))
	}
	if err != nil {
		return errors.NewStackError(err)
	}

	// Attach file if update or create.
	if status == "update" || status == "create" {
		file, err := os.Open(fullPath)
		if err != nil {
			return err
		}
		defer file.Close()

		stat, err := file.Stat()
		if err != nil {
			return err
		}

		// Add file mode to write with.
		err = writer.WriteField("mode", strconv.FormatUint(uint64(stat.Mode().Perm()), 10))
		if err != nil {
			return errors.NewStackError(err)
		}

		part, err := writer.CreateFormFile("file", "upload")
		if err != nil {
			return errors.NewStackError(err)
		}

		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}

	// Get current app and add fields for init, build, test, and start.
	state, err := db.GetState()
	if err != nil {
		return err
	}

	if service := state.Config[serviceName]; service != nil {
		writer.WriteField("init", service.Init)
		writer.WriteField("build", service.Build)
		writer.WriteField("test", service.Test)
		writer.WriteField("start", service.Start)

		if service.Env != nil {
			envData, err := json.Marshal(service.Env)
			if err != nil {
				return err
			}
			err = writer.WriteField("env", string(envData))
		}
	}

	if err = writer.Close(); err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", "http://"+url, &body)
	if err != nil {
		return errors.NewStackError(err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		if responses.IsRefusedConn(err) {
			err = errors.ErrSyncFailed
		}

		return errors.NewStackError(err)
	}
	defer res.Body.Close()

	// Decode json response.
	uploadRes := new(responses.Res)
	decoder := json.NewDecoder(res.Body)
	err = decoder.Decode(uploadRes)
	if err != nil {
		return errors.NewStackError(err)
	}

	// Created, so no error.
	if uploadRes.Status == "updated" {
		return nil
	}

	return errors.NewStackError(uploadRes)
}