From 49a33649325a7a12d7050e9d64cc97c357cc275b Mon Sep 17 00:00:00 2001 From: codybuell Date: Tue, 30 Jul 2024 09:19:17 -0400 Subject: [PATCH] Rough out initial alias support for stak and run Adds alias support via flags to the --stak and --run commands. Cache entries will be made with car + alias for the keys causing possible duplicate entries if there is a car + acc number cache entry for the same account + car combo. We can either leave this minor inefficiency or add another api call to translate between the two (alias <-> number) and create the appropriate cache entries. Feels like it's better to accept the minor occasional inefficiency instead of making an additional api call every time. --- README.md | 11 +++++-- lib/kion/car.go | 20 ++++++++++++- main.go | 76 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 91 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4203fcf..2a3628a 100644 --- a/README.md +++ b/README.md @@ -221,8 +221,12 @@ OPTIONS --account val, --acc val, -a val Target account number, used to bypass prompts, must be passed with --car. + --alias val, --aka val, -l val Target account alias, used to bypass + prompts, must be passed with --car. + --car val, --cloud-access-role val, Target cloud access role, used to bypass - -c val prompts, must be passed with --account. + -c val prompts, must be passed with --account + or --alias. --region val, -r val Specify which region to target. @@ -273,8 +277,11 @@ OPTIONS --account val, -acc val, -a val Specify which account to target, must be passed with --car. + --alias val, --aka val, -l val Target account alias, used to bypass + prompts, must be passed with --car. + --car val, -c val Specify which Cloud Access Role to use, - must be passed with --account. + must be passed with --account or --alias. --region val, -r val Specify which region to target. diff --git a/lib/kion/car.go b/lib/kion/car.go index dbf4039..7d51264 100644 --- a/lib/kion/car.go +++ b/lib/kion/car.go @@ -25,6 +25,7 @@ type CAR struct { AccountType string `json:"account_type"` AccountTypeID uint `json:"account_type_id"` AccountName string `json:"account_name"` + AccountAlias string `json:"account_alias"` ApplyToAllAccounts bool `json:"apply_to_all_accounts"` AwsIamPath string `json:"aws_iam_path"` AwsIamRoleName string `json:"aws_iam_role_name"` @@ -153,7 +154,24 @@ func GetCARByNameAndAccount(host string, token string, carName string, accountNu } } - return CAR{}, fmt.Errorf("unable to find car %v", carName) + return CAR{}, fmt.Errorf("unable to find car %v with account number %v", carName, accountNumber) +} + +// GetCARByNameAndAlias returns a car that matches by name and account alias. +func GetCARByNameAndAlias(host string, token string, carName string, accountAlias string) (CAR, error) { + allCars, err := GetCARS(host, token) + if err != nil { + return CAR{}, err + } + + // find our match + for _, car := range allCars { + if car.Name == carName && car.AccountAlias == accountAlias { + return car, nil + } + } + + return CAR{}, fmt.Errorf("unable to find car %v with account alias %v", carName, accountAlias) } // GetAllCARsByName returns a slice of cars that matches a given name. diff --git a/main.go b/main.go index 995f0cc..afe3a9e 100644 --- a/main.go +++ b/main.go @@ -447,12 +447,20 @@ func genStaks(cCtx *cli.Context) error { var stak kion.STAK // set vars for easier access + var cacheKey string endpoint := config.Kion.Url carName := cCtx.String("car") - account := cCtx.String("account") - cacheKey := fmt.Sprintf("%s-%s", carName, account) + accNum := cCtx.String("account") + accAlias := cCtx.String("alias") region := cCtx.String("region") + // fail fast if we have a bad combo of flags + if (accNum != "" || accAlias != "") && carName == "" { + return errors.New("must specify --car parameter when using --account or --alias") + } else if carName != "" && accNum == "" && accAlias == "" { + return errors.New("must specify --account OR --alias parameter when using --car") + } + // grab the command usage [stak, s, setenv, savecreds, etc] cmdUsed := cCtx.Lineage()[1].Args().Slice()[0] @@ -474,7 +482,14 @@ func genStaks(cCtx *cli.Context) error { } // if we have what we need go look stuff up without prompts do it - if account != "" && carName != "" { + if (accNum != "" || accAlias != "") && carName != "" { + // set the cache key based on what was passed + if accNum != "" { + cacheKey = fmt.Sprintf("%s-%s", carName, accNum) + } else { + cacheKey = fmt.Sprintf("%s-%s", carName, accAlias) + } + // determine if we have a valid cached entry cachedSTAK, found, err := c.GetStak(cacheKey) if err != nil { @@ -484,7 +499,8 @@ func genStaks(cCtx *cli.Context) error { if found && cachedSTAK.Expiration.After(time.Now().Add(-buffer*time.Second)) { // cached stak found and is still valid stak = cachedSTAK - if action != "subshell" { + if action != "subshell" && action != "save" { + // skip getting the car for everything but subshell and save getCar = false } } @@ -497,9 +513,16 @@ func genStaks(cCtx *cli.Context) error { return err } - car, err = kion.GetCARByNameAndAccount(endpoint, config.Kion.ApiKey, carName, account) - if err != nil { - return err + if accNum != "" { + car, err = kion.GetCARByNameAndAccount(endpoint, config.Kion.ApiKey, carName, accNum) + if err != nil { + return err + } + } else { + car, err = kion.GetCARByNameAndAlias(endpoint, config.Kion.ApiKey, carName, accAlias) + if err != nil { + return err + } } } } else { @@ -727,26 +750,28 @@ func listFavorites(cCtx *cli.Context) error { // provided command with said credentials set. func runCommand(cCtx *cli.Context) error { // set vars for easier access + var cacheKey string endpoint := config.Kion.Url favName := cCtx.String("favorite") accNum := cCtx.String("account") + accAlias := cCtx.String("alias") carName := cCtx.String("car") region := cCtx.String("region") // fail fast if we don't have what we need - if favName == "" && (accNum == "" || carName == "") { - return errors.New("must specify either --fav OR --account and --car parameters") + if favName == "" && ((accNum == "" && accAlias == "") || carName == "") { + return errors.New("must specify either --fav OR --account and --car OR --alias and --car parameters") } // placeholder for our stak var stak kion.STAK - // prefer favorites if specified, else use account and car + // prefer favorites if specified, else use account/alias and car if favName != "" { // map our favorites for ease of use _, fMap := helper.MapFavs(config.Favorites) - // if arg passed is a valid favorite use it else prompt + // if arg passed is a valid favorite use it else error out var fav string var err error if fMap[favName] != (structs.Favorite{}) { @@ -759,7 +784,7 @@ func runCommand(cCtx *cli.Context) error { favorite := fMap[fav] // check if we have a valid cached stak else grab a new one - cacheKey := fmt.Sprintf("%s-%s", favorite.CAR, favorite.Account) + cacheKey = fmt.Sprintf("%s-%s", favorite.CAR, favorite.Account) cachedSTAK, found, err := c.GetStak(cacheKey) if err != nil { return err @@ -798,8 +823,14 @@ func runCommand(cCtx *cli.Context) error { return err } } else { + // set the cache key based on what was passed + if accNum != "" { + cacheKey = fmt.Sprintf("%s-%s", carName, accNum) + } else { + cacheKey = fmt.Sprintf("%s-%s", carName, accAlias) + } + // check if we have a valid cached stak else grab a new one - cacheKey := fmt.Sprintf("%s-%s", carName, accNum) cachedSTAK, found, err := c.GetStak(cacheKey) if err != nil { return err @@ -813,6 +844,15 @@ func runCommand(cCtx *cli.Context) error { return err } + // grab car if alias used since we need the account number to run GenSTAK + if accAlias != "" { + car, err := kion.GetCARByNameAndAlias(endpoint, config.Kion.ApiKey, carName, accAlias) + if err != nil { + return err + } + accNum = car.AccountNumber + } + // grab a new stak stak, err = kion.GetSTAK(endpoint, config.Kion.ApiKey, carName, accNum) if err != nil { @@ -1009,6 +1049,11 @@ func main() { Aliases: []string{"acc", "a"}, Usage: "target account number, must be passed with car", }, + &cli.StringFlag{ + Name: "alias", + Aliases: []string{"aka", "l"}, + Usage: "account alias", + }, &cli.StringFlag{ Name: "car", Aliases: []string{"cloud-access-role", "c"}, @@ -1095,6 +1140,11 @@ func main() { Aliases: []string{"acc", "a"}, Usage: "account number", }, + &cli.StringFlag{ + Name: "alias", + Aliases: []string{"aka", "l"}, + Usage: "account alias", + }, &cli.StringFlag{ Name: "car", Aliases: []string{"c"},