| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- package commands
- import (
- "context"
- "fmt"
- "os"
- "time"
- "github.com/briandowns/spinner"
- "github.com/fatih/color"
- api "github.com/porter-dev/porter/api/client"
- "github.com/porter-dev/porter/api/server/handlers/environment_groups"
- "github.com/porter-dev/porter/api/server/handlers/porter_app"
- "github.com/porter-dev/porter/api/types"
- "github.com/porter-dev/porter/cli/cmd/config"
- "github.com/spf13/cobra"
- )
- var (
- appName string
- envGroupName string
- envFilePath string
- )
- type envVariables struct {
- Variables map[string]string `json:"variables"`
- Secrets map[string]string `json:"secrets"`
- }
- type envVariableDeletions struct {
- Variables []string `json:"variables"`
- Secrets []string `json:"secrets"`
- }
- func registerCommand_Env(cliConf config.CLIConfig) *cobra.Command {
- envCmd := &cobra.Command{
- Use: "env",
- Args: cobra.MinimumNArgs(0),
- Short: "Manage environment variables for a project",
- PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
- if len(cmd.Commands()) == 1 {
- return nil
- }
- if appName == "" && envGroupName == "" {
- return fmt.Errorf("must specify either --app or --group")
- }
- if appName != "" && envGroupName != "" {
- return fmt.Errorf("only one of --app or --group can be specified")
- }
- return nil
- },
- RunE: func(cmd *cobra.Command, args []string) error {
- return cmd.Help()
- },
- }
- envCmd.PersistentFlags().StringVarP(&appName, "app", "a", "", "app name")
- envCmd.PersistentFlags().StringVarP(&envGroupName, "group", "g", "", "environment group name")
- envCmd.PersistentFlags().StringVarP(&deploymentTargetName, "target", "x", "", "the name of the deployment target for the app")
- pullCommand := &cobra.Command{
- Use: "pull",
- Short: "Pull environment variables for an app or environment group",
- Long: `Pull environment variables for an app or environment group.
- Optionally, specify a file to write the environment variables to. Otherwise the environment variables will be written to stdout.`,
- Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, args []string) error {
- return checkLoginAndRunWithConfig(cmd, cliConf, args, pullEnv)
- },
- }
- pullCommand.Flags().StringVarP(&envFilePath, "file", "f", "", "file to write environment variables to")
- setCommand := &cobra.Command{
- Use: "set",
- Short: "Set environment variables for an app or environment group",
- Long: `Set environment variables for an app or environment group.
- Both variables and secrets can be specified as key-value pairs.
- When updating an environment group, all apps linked to the environment group will be re-deployed, unless the --skip-redeploys flag is used.`,
- Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, args []string) error {
- return checkLoginAndRunWithConfig(cmd, cliConf, args, setEnv)
- },
- }
- setCommand.Flags().StringToStringP("variables", "v", nil, "variables to set")
- setCommand.Flags().StringToStringP("secrets", "s", nil, "secrets to set")
- setCommand.Flags().Bool("skip-redeploys", false, "skip re-deploying apps linked to the environment group")
- unsetCommand := &cobra.Command{
- Use: "unset",
- Short: "Unset environment variables for an app or environment group",
- Long: `Unset environment variables for an app or environment group.
- Both variables and secrets can be specified as keys.
- When updating an environment group, all apps linked to the environment group will be re-deployed, unless the --skip-redeploys flag is used.`,
- Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, args []string) error {
- return checkLoginAndRunWithConfig(cmd, cliConf, args, unsetEnv)
- },
- }
- unsetCommand.Flags().StringSliceP("variables", "v", nil, "variables to unset")
- unsetCommand.Flags().StringSliceP("secrets", "s", nil, "secrets to unset")
- unsetCommand.Flags().Bool("skip-redeploys", false, "skip re-deploying apps linked to the environment group")
- envCmd.AddCommand(pullCommand)
- envCmd.AddCommand(setCommand)
- envCmd.AddCommand(unsetCommand)
- return envCmd
- }
- func pullEnv(ctx context.Context, user *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
- var envVars envVariables
- if appName != "" {
- color.New(color.FgGreen).Printf("Pulling environment variables for app %s...\n", appName) // nolint:errcheck,gosec
- envVarsResp, err := client.GetAppEnvVariables(ctx, cliConf.Project, cliConf.Cluster, appName, deploymentTargetName)
- if err != nil {
- return fmt.Errorf("could not get app env variables: %w", err)
- }
- if envVarsResp == nil {
- return fmt.Errorf("could not get app env variables: response was nil")
- }
- envVars = envVariables{
- Variables: envVarsResp.EnvVariables.Variables,
- Secrets: envVarsResp.EnvVariables.Secrets,
- }
- }
- if envGroupName != "" {
- color.New(color.FgGreen).Printf("Pulling environment variables for environment group %s...\n", envGroupName) // nolint:errcheck,gosec
- envVarsResp, err := client.GetLatestEnvGroupVariables(ctx, cliConf.Project, cliConf.Cluster, envGroupName)
- if err != nil {
- return fmt.Errorf("could not get env group env variables: %w", err)
- }
- if envVarsResp == nil {
- return fmt.Errorf("could not get env group variables: response was nil")
- }
- envVars = envVariables{
- Variables: envVarsResp.Variables,
- Secrets: envVarsResp.Secrets,
- }
- }
- if envFilePath != "" {
- err := writeEnvFile(envFilePath, envVars)
- if err != nil {
- return fmt.Errorf("could not write env file: %w", err)
- }
- color.New(color.FgGreen).Printf("Wrote environment variables to %s\n", envFilePath) // nolint:errcheck,gosec
- }
- if envFilePath == "" {
- err := exportEnvVars(envVars)
- if err != nil {
- return fmt.Errorf("could not export env vars: %w", err)
- }
- }
- return nil
- }
- func setEnv(ctx context.Context, user *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
- var envVars envVariables
- variables, err := cmd.Flags().GetStringToString("variables")
- if err != nil {
- return fmt.Errorf("could not get variables: %w", err)
- }
- secrets, err := cmd.Flags().GetStringToString("secrets")
- if err != nil {
- return fmt.Errorf("could not get secrets: %w", err)
- }
- skipRedeploys, err := cmd.Flags().GetBool("skip-redeploys")
- if err != nil {
- return fmt.Errorf("could not get skip-redeploys: %w", err)
- }
- envVars = envVariables{
- Variables: variables,
- Secrets: secrets,
- }
- s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
- s.Color("cyan") // nolint:errcheck,gosec
- if appName != "" {
- s.Suffix = fmt.Sprintf(" Setting environment variables for app %s...", appName)
- s.Start()
- _, err := client.UpdateApp(ctx, api.UpdateAppInput{
- ProjectID: cliConf.Project,
- ClusterID: cliConf.Cluster,
- Name: appName,
- DeploymentTargetName: deploymentTargetName,
- Variables: envVars.Variables,
- Secrets: envVars.Secrets,
- })
- if err != nil {
- return fmt.Errorf("could not set app env variables: %w", err)
- }
- s.Stop()
- color.New(color.FgGreen).Printf("Updated environment variable keys in app %s:\n", appName) // nolint:errcheck,gosec
- }
- if envGroupName != "" {
- s.Suffix = fmt.Sprintf(" Setting environment variables for environment group %s...", envGroupName)
- s.Start()
- err := client.UpdateEnvGroup(ctx, api.UpdateEnvGroupInput{
- ProjectID: cliConf.Project,
- ClusterID: cliConf.Cluster,
- EnvGroupName: envGroupName,
- Variables: envVars.Variables,
- Secrets: envVars.Secrets,
- SkipRedeploys: skipRedeploys,
- })
- if err != nil {
- return fmt.Errorf("could not set env group env variables: %w", err)
- }
- s.Stop()
- color.New(color.FgGreen).Printf("Updated keys in environment group %s:\n", envGroupName) // nolint:errcheck,gosec
- }
- for k, v := range envVars.Variables {
- color.New(color.FgBlue).Printf("%s=%s\n", k, v) // nolint:errcheck,gosec
- }
- for k := range envVars.Secrets {
- color.New(color.FgBlue).Printf("%s=********\n", k) // nolint:errcheck,gosec
- }
- return nil
- }
- func unsetEnv(ctx context.Context, user *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
- var envVarDeletions envVariableDeletions
- variables, err := cmd.Flags().GetStringSlice("variables")
- if err != nil {
- return fmt.Errorf("could not get variables: %w", err)
- }
- secrets, err := cmd.Flags().GetStringSlice("secrets")
- if err != nil {
- return fmt.Errorf("could not get secrets: %w", err)
- }
- skipRedeploys, err := cmd.Flags().GetBool("skip-redeploys")
- if err != nil {
- return fmt.Errorf("could not get skip-redeploys: %w", err)
- }
- envVarDeletions = envVariableDeletions{
- Variables: variables,
- Secrets: secrets,
- }
- s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
- s.Color("cyan") // nolint:errcheck,gosec
- if appName != "" {
- s.Suffix = fmt.Sprintf(" Unsetting environment variables for app %s...", appName)
- s.Start()
- _, err := client.UpdateApp(ctx, api.UpdateAppInput{
- ProjectID: cliConf.Project,
- ClusterID: cliConf.Cluster,
- Name: appName,
- DeploymentTargetName: deploymentTargetName,
- Deletions: porter_app.Deletions{
- EnvVariableDeletions: porter_app.EnvVariableDeletions{
- Variables: envVarDeletions.Variables,
- Secrets: envVarDeletions.Secrets,
- },
- },
- })
- if err != nil {
- return fmt.Errorf("could not unset app env variables: %w", err)
- }
- s.Stop()
- color.New(color.FgGreen).Printf("Unset environment variable keys in app %s:\n", appName) // nolint:errcheck,gosec
- }
- if envGroupName != "" {
- s.Suffix = fmt.Sprintf(" Unsetting environment variables for environment group %s...", envGroupName)
- err := client.UpdateEnvGroup(ctx, api.UpdateEnvGroupInput{
- ProjectID: cliConf.Project,
- ClusterID: cliConf.Cluster,
- EnvGroupName: envGroupName,
- Deletions: environment_groups.EnvVariableDeletions{
- Variables: envVarDeletions.Variables,
- Secrets: envVarDeletions.Secrets,
- },
- SkipRedeploys: skipRedeploys,
- })
- if err != nil {
- return fmt.Errorf("could not unset env group env variables: %w", err)
- }
- color.New(color.FgGreen).Printf("Unset the keys in environment group %s:\n", envGroupName) // nolint:errcheck,gosec
- }
- for _, v := range envVarDeletions.Variables {
- color.New(color.FgBlue).Printf("%s\n", v) // nolint:errcheck,gosec
- }
- for _, v := range envVarDeletions.Secrets {
- color.New(color.FgBlue).Printf("%s\n", v) // nolint:errcheck,gosec
- }
- return nil
- }
- func writeEnvFile(envFilePath string, envVars envVariables) error {
- // open existing file or create new file: https://pkg.go.dev/os#example-OpenFile-Append
- envFile, err := os.OpenFile(envFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) // nolint:gosec
- if err != nil {
- return err
- }
- defer envFile.Close() // nolint:errcheck
- _, err = envFile.WriteString("# Generated by Porter CLI\n")
- if err != nil {
- return err
- }
- for k, v := range envVars.Variables {
- _, err := envFile.WriteString(fmt.Sprintf("%s=%s\n", k, v))
- if err != nil {
- return err
- }
- }
- for k, v := range envVars.Secrets {
- _, err := envFile.WriteString(fmt.Sprintf("%s=%s\n", k, v))
- if err != nil {
- return err
- }
- }
- return nil
- }
- func exportEnvVars(envVars envVariables) error {
- for k, v := range envVars.Variables {
- _, err := os.Stdout.WriteString(fmt.Sprintf("%s=%s\n", k, v))
- if err != nil {
- return err
- }
- }
- for k, v := range envVars.Secrets {
- _, err := os.Stdout.WriteString(fmt.Sprintf("%s=%s\n", k, v))
- if err != nil {
- return err
- }
- }
- return nil
- }
|