Пример #1
0
// setGivenEnv takes the given env name and finds it in the env list
// in the given settings object. It then populates the EnvironmentID and
// ServiceID on the settings object with appropriate values.
func setGivenEnv(envName string, settings *models.Settings) {
	for eName, e := range settings.Environments {
		if eName == envName {
			settings.EnvironmentID = e.EnvironmentID
			settings.ServiceID = e.ServiceID
			settings.EnvironmentName = envName
		}
	}
}
Пример #2
0
// setFirstAssociatedEnv is the last line of defense. If no other environments
// were found locally or from the default flag, then the first one in the list
// of environments in the given settings object is used to populate
// EnvironmentID and ServiceID with appropriate values.
func setFirstAssociatedEnv(required bool, promptForEnv bool, settings *models.Settings) {
	for envName, e := range settings.Environments {
		settings.EnvironmentID = e.EnvironmentID
		settings.ServiceID = e.ServiceID
		settings.EnvironmentName = e.Name
		if promptForEnv {
			defaultEnvPrompt(envName)
		}
		break
	}
}
Пример #3
0
func promptForCredentials(settings *models.Settings) {
	var username string
	fmt.Print("Username: "******"Password: "******"windows" {
		stdIn, _, _ := term.StdStreams()
		fd, _ = term.GetFdInfo(stdIn)
	}
	bytes, _ := terminal.ReadPassword(int(fd))
	fmt.Println("")
	settings.Password = string(bytes)
}
Пример #4
0
// verify tests whether or not the given session token is still valid
func verify(settings *models.Settings) bool {
	resp := httpclient.Get(fmt.Sprintf("%s/v2/auth/verify", settings.BaasHost), false, settings)
	m := make(map[string]string)
	json.Unmarshal(resp, &m)
	// the verify route returns userId and not usersId like everything else...
	if m["userId"] != "" {
		settings.UsersID = m["userId"]
	}
	return m["userId"] != ""
}
Пример #5
0
// GetSettings returns a Settings object for the current context
func GetSettings(required bool, promptForEnv bool, envName string, baasHost string, paasHost string, username string, password string) *models.Settings {
	HomeDir, err := homedir.Dir()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	file, err := os.Open(filepath.Join(HomeDir, SettingsFile))
	if os.IsNotExist(err) {
		file, err = os.Create(filepath.Join(HomeDir, SettingsFile))
	}
	defer file.Close()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
	var settings models.Settings
	json.NewDecoder(file).Decode(&settings)
	// would be best to default this to an initialized map rather than nil
	if settings.Environments == nil {
		settings.Environments = make(map[string]models.AssociatedEnv)
	}

	// try and set the given env first, if it exists
	if envName != "" {
		setGivenEnv(envName, &settings)
		if settings.EnvironmentID == "" || settings.ServiceID == "" {
			fmt.Printf("No environment named \"%s\" has been associated. Run \"catalyze associated\" to see what environments have been associated or run \"catalyze associate\" from a local git repo to create a new association\n", envName)
			os.Exit(1)
		}
	}

	// if no env name was given, try and fetch the local env
	if settings.EnvironmentID == "" || settings.ServiceID == "" {
		setLocalEnv(required, &settings)
	}

	// if its not there, fetch the default
	if settings.EnvironmentID == "" || settings.ServiceID == "" {
		setDefaultEnv(&settings)
	}

	// if no default, fetch the first associated env and print warning
	if settings.EnvironmentID == "" || settings.ServiceID == "" {
		// warn and ask
		setFirstAssociatedEnv(required, promptForEnv, &settings)
	}

	// if no env found, warn and quit
	if required && (settings.EnvironmentID == "" || settings.ServiceID == "") {
		fmt.Println("No Catalyze environment has been associated. Run \"catalyze associate\" from a local git repo first")
		os.Exit(1)
	}

	settings.BaasHost = baasHost
	settings.PaasHost = paasHost
	settings.Username = username
	settings.Password = password
	return &settings
}
Пример #6
0
// DeleteBreadcrumb removes the config file at LocalSettingsPath
func DeleteBreadcrumb(alias string, settings *models.Settings) {
	env := settings.Environments[alias]
	dir := env.Directory
	dir = filepath.Join(dir, ".git", LocalSettingsFile)
	defer os.Remove(dir)

	delete(settings.Environments, alias)
	if settings.Default == alias {
		settings.Default = ""
	}
	os.Remove(dir)
	SaveSettings(settings)
}
Пример #7
0
// SignIn signs in the user and retrieves a session. The passed in Settings
// object is updated with the most up to date credentials
func SignIn(settings *models.Settings) {
	// if we're already signed in with a valid session, don't sign in again
	if verify(settings) {
		return
	}
	if settings.Username == "" || settings.Password == "" {
		promptForCredentials(settings)
	}
	login := models.Login{
		Username: settings.Username,
		Password: settings.Password,
	}
	b, err := json.Marshal(login)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
	resp := httpclient.Post(b, fmt.Sprintf("%s/v2/auth/signin", settings.BaasHost), true, settings)
	var user models.User
	json.Unmarshal(resp, &user)
	settings.SessionToken = user.SessionToken
	settings.UsersID = user.UsersID
	config.SaveSettings(settings)
}
Пример #8
0
// SetDefault sets the default environment. This environment must already be
// associated. Any commands run outside of a git directory will use the default
// environment for context.
func SetDefault(alias string, settings *models.Settings) {
	var found bool
	for name := range settings.Environments {
		if name == alias {
			found = true
			break
		}
	}
	if !found {
		fmt.Printf("No environment with an alias of \"%s\" has been associated. Please run \"catalyze associate\" first\n", alias)
		os.Exit(1)
	}
	settings.Default = alias
	config.SaveSettings(settings)
	fmt.Printf("%s is now the default environment\n", alias)
}
Пример #9
0
// Metrics prints out metrics for a given service or if the service is not
// specified, metrics for the entire environment are printed.
func Metrics(serviceLabel string, jsonFlag bool, csvFlag bool, sparkFlag bool, streamFlag bool, mins int, settings *models.Settings) {
	if streamFlag && (jsonFlag || csvFlag || mins != 1) {
		fmt.Println("--stream cannot be used with a custom format and multiple records")
		os.Exit(1)
	}
	var singleRetriever func(mins int, settings *models.Settings) *models.Metrics
	if serviceLabel != "" {
		service := helpers.RetrieveServiceByLabel(serviceLabel, settings)
		if service == nil {
			fmt.Printf("Could not find a service with the label \"%s\"\n", serviceLabel)
			os.Exit(1)
		}
		settings.ServiceID = service.ID
		singleRetriever = helpers.RetrieveServiceMetrics
	}
	var transformer Transformer
	redraw := make(chan bool)
	if jsonFlag {
		transformer = Transformer{
			SingleRetriever: singleRetriever,
			DataTransformer: &JSONTransformer{},
		}
	} else if csvFlag {
		buffer := &bytes.Buffer{}
		transformer = Transformer{
			SingleRetriever: singleRetriever,
			DataTransformer: &CSVTransformer{
				HeadersWritten: false,
				GroupMode:      serviceLabel == "",
				Buffer:         buffer,
				Writer:         csv.NewWriter(buffer),
			},
		}
	} else if sparkFlag {
		// the spark lines interface stays up until closed by the user, so
		// we might as well keep updating it as long as it is there
		streamFlag = true
		mins = 60
		err := ui.Init()
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		defer ui.Close()
		ui.UseTheme("helloworld")

		p := ui.NewPar("PRESS q TO QUIT")
		p.HasBorder = false
		p.TextFgColor = ui.Theme().SparklineTitle
		ui.Body.AddRows(
			ui.NewRow(ui.NewCol(12, 0, p)),
		)

		transformer = Transformer{
			SingleRetriever: singleRetriever,
			DataTransformer: &SparkTransformer{
				Redraw:     redraw,
				SparkLines: make(map[string]*ui.Sparklines),
			},
		}
	} else {
		transformer = Transformer{
			SingleRetriever: singleRetriever,
			DataTransformer: &TextTransformer{},
		}
	}
	transformer.GroupRetriever = helpers.RetrieveEnvironmentMetrics
	transformer.Stream = streamFlag
	transformer.GroupMode = serviceLabel == ""
	transformer.Mins = mins
	transformer.settings = settings

	helpers.SignIn(settings)

	if sparkFlag {
		go transformer.process()

		ui.Body.Align()
		ui.Render(ui.Body)

		quit := make(chan bool)
		go maintainSparkLines(redraw, quit)
		<-quit
	} else {
		transformer.process()
	}
}
Пример #10
0
// Logs is a way to stream logs from Kibana to your local terminal. This is
// useful because Kibana is hard to look at because it splits every single
// log statement into a separate block that spans multiple lines so it's
// not very cohesive. This is intended to be similar to the `heroku logs`
// command.
func Logs(queryString string, tail bool, hours int, minutes int, seconds int, settings *models.Settings) {
	if settings.Username == "" || settings.Password == "" {
		// sometimes this will be filled in from env variables
		// if it is, just use that and don't prompt them
		settings.Username = ""
		settings.Password = ""
		fmt.Println("Please enter your logging dashboard credentials")
	}
	// if we remove the session token, the CLI will prompt for the
	// username/password normally. It will also set the username/password
	// on the settings object.
	sessionToken := settings.SessionToken
	settings.SessionToken = ""

	helpers.SignIn(settings)

	env := helpers.RetrieveEnvironment("pod", settings)
	var domain = env.Data.DNSName
	if domain == "" {
		domain = fmt.Sprintf("%s.catalyze.io", env.Data.Namespace)
	}

	urlString := fmt.Sprintf("https://%s/__es", domain)

	offset := time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second
	timestamp := time.Now().In(time.UTC).Add(-1 * offset)

	from := 0
	query := &models.LogQuery{
		Fields: []string{"@timestamp", "message"},
		Query: &models.Query{
			Wildcard: map[string]string{
				"message": queryString,
			},
		},
		Filter: &models.FilterRange{
			Range: &models.RangeTimestamp{
				Timestamp: map[string]string{
					"gt": fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", timestamp.Year(), timestamp.Month(), timestamp.Day(), timestamp.Hour(), timestamp.Minute(), timestamp.Second()),
				},
			},
		},
		Sort: &models.LogSort{
			Timestamp: map[string]string{
				"order": "asc",
			},
			Message: map[string]string{
				"order": "asc",
			},
		},
		From: from,
		Size: 50,
	}

	var tr = &http.Transport{
		TLSClientConfig: &tls.Config{
			MinVersion: tls.VersionTLS12,
		},
	}

	client := &http.Client{
		Transport: tr,
	}

	settings.SessionToken = sessionToken
	config.SaveSettings(settings)

	fmt.Println("        @timestamp       -        message")
	for {
		query.From = from
		b, err := json.Marshal(*query)
		if err != nil {
			panic(err)
		}
		reader := bytes.NewReader(b)

		req, _ := http.NewRequest("GET", fmt.Sprintf("%s/_search", urlString), reader)
		req.SetBasicAuth(settings.Username, settings.Password)

		resp, err := client.Do(req)
		if err != nil {
			fmt.Println(err.Error())
		}
		respBody, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if resp.StatusCode < 200 || resp.StatusCode >= 300 {
			fmt.Println(fmt.Errorf("%d %s", resp.StatusCode, string(respBody)).Error())
			os.Exit(1)
		}
		var logs models.Logs
		json.Unmarshal(respBody, &logs)
		for _, lh := range *logs.Hits.Hits {
			fmt.Printf("%s - %s\n", lh.Fields["@timestamp"][0], lh.Fields["message"][0])
		}
		if !tail {
			break
		}
		time.Sleep(2 * time.Second)
		from += len(*logs.Hits.Hits)
	}
}
Пример #11
0
// Logout clears the stored user information from the local machine. This does
// not remove environment data.
func Logout(settings *models.Settings) {
	settings.SessionToken = ""
	settings.UsersID = ""
	config.SaveSettings(settings)
}
Пример #12
0
// Associate an environment so that commands can be run against it. This command
// no longer adds a git remote. See commands.AddRemote().
func Associate(envLabel string, serviceLabel string, alias string, remote string, defaultEnv bool, settings *models.Settings) {
	if _, err := os.Stat(".git"); os.IsNotExist(err) {
		fmt.Println("Not git repo found in the current directory")
		os.Exit(1)
	}
	helpers.SignIn(settings)
	envs := helpers.ListEnvironments("pod", settings)
	for _, env := range *envs {
		if env.Data.Name == envLabel {
			if env.State == "defined" {
				fmt.Printf("Your environment is not yet provisioned. Please visit https://dashboard.catalyze.io/environments/update/%s to finish provisioning your environment\n", env.ID)
				return
			}
			// would be nice to have some sort of global filter() function
			var chosenService models.Service
			if serviceLabel != "" {
				labels := []string{}
				for _, service := range *env.Data.Services {
					if service.Type == "code" {
						labels = append(labels, service.Label)
						if service.Label == serviceLabel {
							chosenService = service
							break
						}
					}
				}
				if chosenService.Type == "" {
					fmt.Printf("No code service found with name '%s'. Code services found: %s\n", serviceLabel, strings.Join(labels, ", "))
					os.Exit(1)
				}
			} else {
				for _, service := range *env.Data.Services {
					if service.Type == "code" {
						chosenService = service
						break
					}
				}
				if chosenService.Type == "" {
					fmt.Printf("No code service found for \"%s\" environment (ID = %s)\n", envLabel, settings.EnvironmentID)
					os.Exit(1)
				}
			}
			for _, r := range helpers.ListGitRemote() {
				if r == remote {
					helpers.RemoveGitRemote(remote)
					break
				}
			}
			helpers.AddGitRemote(remote, chosenService.Source)
			fmt.Printf("\"%s\" remote added.\n", remote)
			dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
			if err != nil {
				panic(err)
			}
			name := alias
			if name == "" {
				name = envLabel
			}
			settings.Environments[name] = models.AssociatedEnv{
				EnvironmentID: env.ID,
				ServiceID:     chosenService.ID,
				Directory:     dir,
				Name:          envLabel,
			}
			if defaultEnv {
				settings.Default = name
			}
			config.DropBreadcrumb(name, settings)
			config.SaveSettings(settings)
			if len(settings.Environments) > 1 && settings.Default == "" {
				fmt.Printf("You now have %d environments associated. Consider running \"catalyze default ENV_NAME\" to set a default\n", len(settings.Environments))
			}
			return
		}
	}
	fmt.Printf("No environment with label \"%s\" found\n", envLabel)
	os.Exit(1)
}