This repository has been archived by the owner on Dec 26, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into 89-cmd-to-select-current-context
- Loading branch information
Showing
30 changed files
with
944 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package cli | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func init() { | ||
rootCmd.AddCommand(cloudCmd) | ||
} | ||
|
||
var cloudCmd = &cobra.Command{ | ||
Use: "cloud", | ||
Short: "Modify layerform cloud entities", | ||
Long: `Modify layerform cloud entities using subcomands like "layerform cloud create-user" | ||
This command only works if the current context is of type "cloud"`, | ||
Example: `# Create a new cloud user | ||
layerform cloud create-user --name "John Doe" --email [email protected]`, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package cli | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-hclog" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/ergomake/layerform/internal/lfconfig" | ||
"github.com/ergomake/layerform/internal/validation" | ||
) | ||
|
||
func init() { | ||
cloudCreateUserCmd.Flags().StringP("name", "n", "", "name of the new user") | ||
cloudCreateUserCmd.Flags().StringP("email", "e", "", "email of the new user") | ||
cloudCreateUserCmd.MarkFlagRequired("email") | ||
|
||
cloudCmd.AddCommand(cloudCreateUserCmd) | ||
} | ||
|
||
var cloudCreateUserCmd = &cobra.Command{ | ||
Use: "create-user", | ||
Short: "Creates a new user in layerform cloud", | ||
Long: `Creates a new user in layerform cloud. | ||
The password will be printed to stdout, e-mail must be unique.`, | ||
Example: `# Set a context of type local named local-example | ||
layerform cloud create-user --name "John Doe" --email "[email protected]"`, | ||
Run: func(cmd *cobra.Command, _ []string) { | ||
logger := hclog.Default() | ||
logLevel := hclog.LevelFromString(os.Getenv("LF_LOG")) | ||
if logLevel != hclog.NoLevel { | ||
logger.SetLevel(logLevel) | ||
} | ||
ctx := hclog.WithContext(context.Background(), logger) | ||
|
||
cfg, err := lfconfig.Load("") | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to load config")) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
currentCfgCtx := cfg.GetCurrent() | ||
if currentCfgCtx.Type != "cloud" { | ||
fmt.Fprintf( | ||
os.Stderr, | ||
"This command only works if the current context is of type \"cloud\" but current has type \"%s\".\n", | ||
currentCfgCtx.Type, | ||
) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
name, err := cmd.Flags().GetString("name") | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to get --name flag, this is a bug in layerform")) | ||
os.Exit(1) | ||
return | ||
} | ||
name = strings.TrimSpace(name) | ||
|
||
email, err := cmd.Flags().GetString("email") | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to get --email flag, this is a bug in layerform")) | ||
os.Exit(1) | ||
return | ||
} | ||
email = strings.TrimSpace(email) | ||
|
||
if !validation.IsValidEmail(email) { | ||
fmt.Fprintf(os.Stderr, "Invalid email \"%s\"\n", email) | ||
os.Exit(1) | ||
return | ||
|
||
} | ||
|
||
cloudClient, err := cfg.GetCloudClient(ctx) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to get cloud client")) | ||
os.Exit(1) | ||
} | ||
|
||
payload, err := json.Marshal(map[string]string{"name": name, "email": email}) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail marshal create user payload to json")) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
req, err := cloudClient.NewRequest(ctx, "POST", "/v1/users", bytes.NewReader(payload)) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to marshal create user payload to json")) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
res, err := cloudClient.Do(req) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to perform http request to cloud backend")) | ||
os.Exit(1) | ||
return | ||
} | ||
defer res.Body.Close() | ||
|
||
if res.StatusCode == http.StatusConflict { | ||
fmt.Fprintf(os.Stderr, "User with email %s already exists.\n", email) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
var body struct { | ||
Password string `json:"password"` | ||
} | ||
err = json.NewDecoder(res.Body).Decode(&body) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail decode create user JSON response")) | ||
os.Exit(1) | ||
return | ||
|
||
} | ||
|
||
identifier := name | ||
if identifier == "" { | ||
identifier = email | ||
} | ||
fmt.Fprintf(os.Stdout, "User %s created successfully.\nPassword: %s\n", identifier, body.Password) | ||
}, | ||
SilenceErrors: true, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
"text/tabwriter" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/ergomake/layerform/internal/lfconfig" | ||
) | ||
|
||
func init() { | ||
configCmd.AddCommand(configGetContextsCmd) | ||
} | ||
|
||
var configGetContextsCmd = &cobra.Command{ | ||
Use: "get-contexts", | ||
Short: "Display contexts from layerform config file", | ||
Long: `Display contexts from layerform config file`, | ||
Run: func(_ *cobra.Command, _ []string) { | ||
cfg, err := lfconfig.Load("") | ||
if err != nil && !errors.Is(err, os.ErrNotExist) { | ||
fmt.Fprintln(os.Stdout, "No contexts configure, configure contexts using the set-context command.") | ||
return | ||
} | ||
|
||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) | ||
fmt.Fprintln(w, "CURRENT\tNAME\tTYPE\tLOCATION") | ||
for name, ctx := range cfg.Contexts { | ||
isCurrent := name == cfg.CurrentContext | ||
current := "" | ||
if isCurrent { | ||
current = "*" | ||
} | ||
|
||
fmt.Fprintln(w, strings.Join([]string{current, name, ctx.Type, ctx.Location()}, "\t")) | ||
} | ||
err = w.Flush() | ||
|
||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to print output")) | ||
os.Exit(1) | ||
} | ||
|
||
}, | ||
SilenceErrors: true, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package cli | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/hashicorp/go-hclog" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/ergomake/layerform/internal/lfconfig" | ||
"github.com/ergomake/layerform/pkg/data" | ||
) | ||
|
||
func init() { | ||
rootCmd.AddCommand(setEnvCmd) | ||
} | ||
|
||
var setEnvCmd = &cobra.Command{ | ||
Use: "set-env <VAR_NAME> <value>", | ||
Short: "set an environment variable to be used when spawning a layer", | ||
Long: `The set-env command sets an environment variable to be used when spawning layers. | ||
These are often used for configuring the providers, for instance, you can use this command to set AWS credentials. | ||
Environment variables can also be used to set values for the variables in your layers. The environment variables must be in the format TF_VAR_name.`, | ||
Example: `# Set value for a variable in your layer | ||
layerform set-env TF_VAR_foo bar`, | ||
Args: cobra.MinimumNArgs(2), | ||
Run: func(_ *cobra.Command, args []string) { | ||
logger := hclog.Default() | ||
logLevel := hclog.LevelFromString(os.Getenv("LF_LOG")) | ||
if logLevel != hclog.NoLevel { | ||
logger.SetLevel(logLevel) | ||
} | ||
ctx := hclog.WithContext(context.Background(), logger) | ||
|
||
cfg, err := lfconfig.Load("") | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to load config")) | ||
os.Exit(1) | ||
return | ||
} | ||
|
||
varName := args[0] | ||
varValue := args[1] | ||
|
||
envvarsBackend, err := cfg.GetEnvVarsBackend(ctx) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to get environment variables backend")) | ||
os.Exit(1) | ||
} | ||
|
||
err = envvarsBackend.SaveVariable(ctx, &data.EnvVar{Name: varName, Value: varValue}) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, "fail to save environment variable")) | ||
os.Exit(1) | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.