Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for token auth #8

Merged
merged 1 commit into from
Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
issues:
exclude:
SA1019
32 changes: 26 additions & 6 deletions cmd/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,34 @@ func DBUsage() string {

// ExecuteDB launches several different subcommands and as of today is the main entry point
// into automation of Astra
func ExecuteDB(args []string, confFile string, verbose bool) error {
clientInfo, err := pkg.ReadLogin(confFile)
func ExecuteDB(args []string, confFile pkg.ConfFiles, verbose bool) error {
hasToken, err := confFile.HasToken()
if err != nil {
return fmt.Errorf("%v", err)
return fmt.Errorf("unable to read conf file %v with error %v", confFile.TokenPath, err)
}
client, err := astraops.Authenticate(clientInfo, verbose)
if err != nil {
return fmt.Errorf("authenticate failed with error %v", err)
var client *astraops.AuthenticatedClient
if hasToken {
token, err := pkg.ReadToken(confFile.TokenPath)
if err != nil {
return fmt.Errorf("found token at %v but unable to read it with error %v", confFile.TokenPath, err)
}
client = astraops.AuthenticateToken(token, verbose)
} else {
hasSa, err := confFile.HasServiceAccount()
if err != nil {
return fmt.Errorf("unable to read conf file %v with error %v", confFile.SaPath, err)
}
if !hasSa {
return fmt.Errorf("unable to access any configuration, run astra-cli login first")
}
clientInfo, err := pkg.ReadLogin(confFile.SaPath)
if err != nil {
return fmt.Errorf("%v", err)
}
client, err = astraops.Authenticate(clientInfo, verbose)
if err != nil {
return fmt.Errorf("authenticate failed with error %v", err)
}
}
if len(args) == 0 {
return &pkg.ParseError{
Expand Down
6 changes: 4 additions & 2 deletions cmd/db/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,22 @@ func ExecuteCreate(args []string, client *astraops.AuthenticatedClient) error {
Err: err,
}
}
capacity := int32(*createDbCapacityUnitFlag)
createDb := astraops.CreateDb{
Name: *createDbNameFlag,
Keyspace: *createDbKeyspaceFlag,
CapacityUnits: *createDbCapacityUnitFlag,
CapacityUnits: capacity,
Region: *createDbRegionFlag,
User: *createDbUserFlag,
Password: *createDbPasswordFlag,
Tier: *createDbTierFlag,
CloudProvider: *createDbCloudProviderFlag,
}
id, _, err := client.CreateDb(createDb)
db, err := client.CreateDb(createDb)
if err != nil {
return fmt.Errorf("unable to create '%v' with error %v", createDb, err)
}
id := db.ID
fmt.Printf("database %v created\n", id)
return nil
}
4 changes: 2 additions & 2 deletions cmd/db/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func ExecuteGet(args []string, client *astraops.AuthenticatedClient) error {
}
}
id := args[0]
var db astraops.DataBase
var db astraops.Database
var err error
if db, err = client.FindDb(id); err != nil {
return fmt.Errorf("unable to get '%s' with error %v\n", id, err)
Expand All @@ -59,7 +59,7 @@ func ExecuteGet(args []string, client *astraops.AuthenticatedClient) error {
case "text":
var rows [][]string
rows = append(rows, []string{"name", "id", "status"})
rows = append(rows, []string{db.Info.Name, db.ID, db.Status})
rows = append(rows, []string{db.Info.Name, db.ID, string(db.Status)})
for _, row := range pkg.PadColumns(rows) {
fmt.Println(strings.Join(row, " "))
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/db/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func ExecuteList(args []string, client *astraops.AuthenticatedClient) error {
Err: err,
}
}
var dbs []astraops.DataBase
var dbs []astraops.Database
var err error
if dbs, err = client.ListDb(*includeFlag, *providerFlag, *startingAfterFlag, int32(*limitFlag)); err != nil {
return fmt.Errorf("unable to get list of dbs with error %v", err)
Expand All @@ -56,7 +56,7 @@ func ExecuteList(args []string, client *astraops.AuthenticatedClient) error {
var rows [][]string
rows = append(rows, []string{"name", "id", "status"})
for _, db := range dbs {
rows = append(rows, []string{db.Info.Name, db.ID, db.Status})
rows = append(rows, []string{db.Info.Name, db.ID, string(db.Status)})
}
for _, row := range pkg.PadColumns(rows) {
fmt.Println(strings.Join(row, " "))
Expand Down
2 changes: 1 addition & 1 deletion cmd/db/tiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func ExecuteTiers(args []string, client *astraops.AuthenticatedClient) error {
rows = append(rows, []string{
tier.Tier,
tier.CloudProvider,
tier.RegionDisplay,
tier.Region,
fmt.Sprintf("%v/%v", tier.DatabaseCountUsed, tier.DatabaseCountLimit),
fmt.Sprintf("%v/%v", tier.CapacityUnitsUsed, tier.CapacityUnitsLimit),
fmt.Sprintf("$%.2f", costMonth),
Expand Down
2 changes: 1 addition & 1 deletion cmd/db/unpark.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func ExecuteUnpark(args []string, client *astraops.AuthenticatedClient) error {
}
id := args[0]
fmt.Printf("starting to unpark database %v\n", id)
if err := client.UnPark(id); err != nil {
if err := client.Unpark(id); err != nil {
return fmt.Errorf("unable to unpark '%s' with error %v\n", id, err)
}
fmt.Printf("database %v unparked\n", id)
Expand Down
15 changes: 11 additions & 4 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,25 @@ var loginCmd = flag.NewFlagSet("login", flag.ExitOnError)
var clientIDFlag = loginCmd.String("id", "", "clientId from service account. Ignored if -json flag is used.")
var clientNameFlag = loginCmd.String("name", "", "clientName from service account. Ignored if -json flag is used.")
var clientSecretFlag = loginCmd.String("secret", "", "clientSecret from service account. Ignored if -json flag is used.")
var clientJSONFlag = loginCmd.String("json", "", "copy the json for service account from the Astra page")
var clientJSONFlag = loginCmd.String("json", "", "copy the json for service account from the Astra site")
var authTokenFlag = loginCmd.String("token", "", "authtoken generated with enough rights to perform the devops actions. Generated from the Astra site")

//LoginUsage returns the usage text for login
func LoginUsage() string {
return pkg.PrintFlags(loginCmd, "astra-cli login", "stores off login credentials for astra devops api")
}

//ExecuteLogin logs into Astra
func ExecuteLogin(args []string, confDir string, confFile string) error {
func ExecuteLogin(args []string, confDir string, confFiles pkg.ConfFiles) error {
if err := loginCmd.Parse(args); err != nil {
return &pkg.ParseError{
Args: args,
Err: fmt.Errorf("incorrect options with error %v", err),
}
}
if authTokenFlag != nil {
return makeConf(confDir, confFiles.TokenPath, *authTokenFlag)
}
var clientJSON string
if clientJSONFlag != nil {
clientJSON = *clientJSONFlag
Expand Down Expand Up @@ -71,13 +75,16 @@ func ExecuteLogin(args []string, confDir string, confFile string) error {
Err: fmt.Errorf("clientSecret missing"),
}
}

} else {
clientID := *clientIDFlag
clientName := *clientNameFlag
clientSecret := *clientSecretFlag
clientJSON = fmt.Sprintf("{\"clientId\":\"%v\",\"clientName\":\"%v\",\"clientSecret\":\"%v:\"}", clientID, clientName, clientSecret)
}
return makeConf(confDir, confFiles.SaPath, clientJSON)
}

func makeConf(confDir, confFile, content string) error {
if err := os.MkdirAll(confDir, 0700); err != nil {
return fmt.Errorf("unable to get make config directory with error %s", err)
}
Expand All @@ -92,7 +99,7 @@ func ExecuteLogin(args []string, confDir string, confFile string) error {
}()
writer := bufio.NewWriter(f)
//safe to write after validation
_, err = writer.Write([]byte(clientJSON))
_, err = writer.Write([]byte(content))
if err != nil {
return fmt.Errorf("error writing file")
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ module github.com/rsds143/astra-cli

go 1.16

require github.com/rsds143/astra-devops-sdk-go v0.2.0
require github.com/rsds143/astra-devops-sdk-go v0.3.0
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/rsds143/astra-devops-sdk-go v0.2.0 h1:Oq5fWejjQ7pr3D7IeFrEO7hybvGHa++MdTMtvA+VEIU=
github.com/rsds143/astra-devops-sdk-go v0.2.0/go.mod h1:LQaUwm75Ydy/z71nl466Xv0yw8ib5b9L6laTFXbvtHU=
github.com/rsds143/astra-devops-sdk-go v0.3.0 h1:ymkYLcf5AfM1zYbyEmiETHzR34HcItp4n9b4GKGVj+Q=
github.com/rsds143/astra-devops-sdk-go v0.3.0/go.mod h1:LQaUwm75Ydy/z71nl466Xv0yw8ib5b9L6laTFXbvtHU=
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func usage() {
}
func main() {
flag.Parse()
confDir, confFile, err := pkg.GetHome()
confDir, confFiles, err := pkg.GetHome()
if err != nil {
fmt.Printf("%v\n", err)
os.Exit(3)
Expand All @@ -46,9 +46,9 @@ func main() {
}
switch flag.Arg(0) {
case "login":
err = cmd.ExecuteLogin(flag.Args()[1:], confDir, confFile)
err = cmd.ExecuteLogin(flag.Args()[1:], confDir, confFiles)
case "db":
err = cmd.ExecuteDB(flag.Args()[1:], confFile, *verbose)
err = cmd.ExecuteDB(flag.Args()[1:], confFiles, *verbose)
default:
fmt.Printf("%q is not valid command.\n", flag.Arg(1))
os.Exit(1)
Expand Down
67 changes: 63 additions & 4 deletions pkg/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,78 @@ import (
"io"
"os"
"path"
"strings"
)

//ConfFiles supports both formats of credentials and will say if the token one is present
type ConfFiles struct {
TokenPath string
SaPath string
}

//HasServiceAccount returns true if there is a service account file present and accessible
func (c ConfFiles) HasServiceAccount() (bool, error) {
if _, err := os.Stat(c.SaPath); err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, fmt.Errorf("warning error of %v is unexpected", err)
}
return true, nil
}

//Hastoken returns true if there is a token file present and accessible
func (c ConfFiles) HasToken() (bool, error) {
if _, err := os.Stat(c.TokenPath); err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, fmt.Errorf("warning error of %v is unexpected", err)
}
return true, nil
}

// GetHome returns the configuration directory and file
// error will return if there is no user home folder
func GetHome() (confDir string, confFile string, err error) {
func GetHome() (confDir string, confFiles ConfFiles, err error) {
var home string
home, err = os.UserHomeDir()
if err != nil {
return "", "", fmt.Errorf("unable to get user home directory with error %s", err)
return "", ConfFiles{}, fmt.Errorf("unable to get user home directory with error %s", err)
}
confDir = path.Join(home, ".config", "astra")
confFile = path.Join(confDir, "sa.json")
return confDir, confFile, nil

tokenFile := path.Join(confDir, "token")
saFile := path.Join(confDir, "sa.json")
return confDir, ConfFiles{
TokenPath: tokenFile,
SaPath: saFile,
}, nil
}

// ReadToken retrieves the login from the specified json file
func ReadToken(tokenFile string) (string, error) {
f, err := os.Open(tokenFile)
if err != nil {
return "", &FileNotFoundError{
Path: tokenFile,
Err: fmt.Errorf("unable to read login file with error %w", err),
}
}
defer func() {
if err := f.Close(); err != nil {
fmt.Printf("warning unable to close %v with error %v", tokenFile, err)
}
}()
b, err := io.ReadAll(f)
if err != nil {
return "", fmt.Errorf("unable to read login file %s with error %w", tokenFile, err)
}
token := strings.Trim(string(b), "\n")
if !strings.HasPrefix(token, "AstraCS") {
return "", fmt.Errorf("invalid token in login file %s with error %s", tokenFile, err)
}
return token, nil
}

// ReadLogin retrieves the login from the specified json file
Expand Down