diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 9711e78..df8d6fb 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -5,6 +5,8 @@ import ( "fmt" "os" + "github.com/spf13/pflag" + "github.com/integr8ly/smtp-service/version" "github.com/integr8ly/smtp-service/pkg/smtpdetails" @@ -16,11 +18,23 @@ import ( const ( defaultOutputSecretName = "rhmi-smtp" + exitCodeErrKnown = 1 + exitCodeErrUnknown = 2 +) + +var ( + flagDebug string ) +func init() { + pflag.StringVarP(&flagDebug, "debug", "d", "error", "--debug=[info|verbose|error]") +} + func main() { + pflag.Parse() + logrus.SetFormatter(&logrus.TextFormatter{}) - logrus.SetLevel(logrus.ErrorLevel) + logrus.SetLevel(getDebugLevelFromString(flagDebug)) logrus.SetOutput(os.Stderr) logger := logrus.WithField("service", "rhmi_sendgrid_cli") smtpdetailsClient, err := sendgrid.NewDefaultClient(logger) @@ -41,15 +55,18 @@ func main() { Run: func(cmd *cobra.Command, args []string) { smtpDetails, err := smtpdetailsClient.Create(args[0]) if err != nil { - logger.Fatal("failed to create api key", err) + if smtpdetails.IsAlreadyExistsError(err) { + exitError(fmt.Sprintf("api key for cluster %s already exists", args[0]), exitCodeErrKnown) + } + exitError(fmt.Sprintf("unknown error: %v", err), exitCodeErrUnknown) } logger.Debug("smtp details created successfully, converting to secret") smtpSecret := smtpdetails.ConvertSMTPDetailsToSecret(smtpDetails, defaultOutputSecretName) smtpJSON, err := json.MarshalIndent(smtpSecret, "", " ") if err != nil { - logger.Fatal("failed to convert smtp secret to json", err) + exitError(fmt.Sprintf("error converting details to secret: %v", err), exitCodeErrUnknown) } - fmt.Print(string(smtpJSON)) + exitSuccess(string(smtpJSON)) }, } @@ -60,9 +77,12 @@ func main() { Run: func(cmd *cobra.Command, args []string) { smtpDetails, err := smtpdetailsClient.Get(args[0]) if err != nil { - logger.Fatal("failed to get api key details", err) + if smtpdetails.IsNotExistError(err) { + exitError(fmt.Sprintf("api key for cluster %s not found", args[0]), exitCodeErrKnown) + } + exitError(fmt.Sprintf("unknown error: %v", err), exitCodeErrUnknown) } - fmt.Print(smtpDetails.ID) + exitSuccess(smtpDetails.ID) }, } @@ -72,8 +92,12 @@ func main() { Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { if err := smtpdetailsClient.Delete(args[0]); err != nil { - logger.Fatal("failed to delete api key", err) + if smtpdetails.IsNotExistError(err) { + exitError(fmt.Sprintf("api key for cluster %s does not exist", args[0]), exitCodeErrKnown) + } + exitError(fmt.Sprintf("failed to delete api key %v", err), exitCodeErrUnknown) } + exitSuccess("api key deleted") }, } @@ -90,3 +114,25 @@ func main() { panic(err) } } + +func exitSuccess(message string) { + fmt.Fprintf(os.Stdout, message) + os.Exit(0) +} + +func exitError(message string, code int) { + fmt.Fprintf(os.Stderr, message) + os.Exit(code) +} + +func getDebugLevelFromString(levelStr string) logrus.Level { + debugMap := map[string]logrus.Level{ + "verbose": logrus.DebugLevel, + "info": logrus.InfoLevel, + } + level := debugMap[levelStr] + if level == 0 { + return logrus.ErrorLevel + } + return level +} diff --git a/go.mod b/go.mod index 64a82e2..80af5aa 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/sethvargo/go-password v0.1.3 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 + github.com/spf13/pflag v1.0.5 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect k8s.io/api v0.17.2 k8s.io/apimachinery v0.17.2 diff --git a/pkg/sendgrid/errors.go b/pkg/sendgrid/errors.go new file mode 100644 index 0000000..929f7cd --- /dev/null +++ b/pkg/sendgrid/errors.go @@ -0,0 +1,33 @@ +package sendgrid + +//AlreadyExistsError Error to indicate an API key already exists +type AlreadyExistsError struct { + Message string +} + +//Error String representation of error +func (e *AlreadyExistsError) Error() string { + return e.Message +} + +//IsAlreadyExistsError Compare check for AlreadyExistsError +func IsAlreadyExistsError(err error) bool { + _, ok := err.(*AlreadyExistsError) + return ok +} + +//NotExistError Error to indicate an API key does not exist +type NotExistError struct { + Message string +} + +//Error String representation of error +func (e *NotExistError) Error() string { + return e.Message +} + +//IsNotExistError Compare check for NotExistError +func IsNotExistError(err error) bool { + _, ok := err.(*NotExistError) + return ok +} diff --git a/pkg/sendgrid/sendgrid.go b/pkg/sendgrid/sendgrid.go index 4665e17..4ca0d45 100644 --- a/pkg/sendgrid/sendgrid.go +++ b/pkg/sendgrid/sendgrid.go @@ -16,7 +16,7 @@ var ( DefaultAPIKeyScopes = []string{"mail.send"} ) -var _ smtpdetails.Client = Client{} +var _ smtpdetails.Client = &Client{} //Client Client used to generate new API keys for OpenShift clusters, abstracting sub user creation type Client struct { @@ -57,11 +57,11 @@ func NewClient(sendgridClient APIClient, apiKeyScopes []string, passGen smtpdeta } //Create Generate new SendGrid sub user and API key for a cluster with it's ID -func (c Client) Create(id string) (*smtpdetails.SMTPDetails, error) { +func (c *Client) Create(id string) (*smtpdetails.SMTPDetails, error) { // check if sub user exists c.logger.Infof("checking if sub user %s exists", id) subuser, err := c.sendgridClient.GetSubUserByUsername(id) - if err != nil && !smtpdetails.IsNotExistError(err) { + if err != nil && !IsNotExistError(err) { return nil, errors.Wrapf(err, "failed to check if sub user already exists") } // sub user doesn't exist, create it @@ -121,9 +121,12 @@ func (c Client) Create(id string) (*smtpdetails.SMTPDetails, error) { } //Get Retrieve the name of the SendGrid API key associated with an OpenShift cluster by it's ID -func (c Client) Get(id string) (*smtpdetails.SMTPDetails, error) { +func (c *Client) Get(id string) (*smtpdetails.SMTPDetails, error) { subuser, err := c.sendgridClient.GetSubUserByUsername(id) if err != nil { + if IsNotExistError(err) { + return nil, &smtpdetails.NotExistError{Message: err.Error()} + } return nil, errors.Wrapf(err, "failed to get user by username, %s", id) } c.logger.Debugf("found user with username %s, id=%d email=%s disabled=%t", subuser.Username, subuser.ID, subuser.Email, subuser.Disabled) @@ -148,10 +151,13 @@ func (c Client) Get(id string) (*smtpdetails.SMTPDetails, error) { } //Delete Delete the SendGrid sub user associated with a cluster by the cluster ID -func (c Client) Delete(id string) error { +func (c *Client) Delete(id string) error { c.logger.Debugf("checking if sub user %s exists", id) subuser, err := c.sendgridClient.GetSubUserByUsername(id) if err != nil { + if IsNotExistError(err) { + return &smtpdetails.NotExistError{Message: err.Error()} + } return errors.Wrapf(err, "failed to check if sub user exists") } if subuser.Username != id { diff --git a/pkg/sendgrid/sendgrid_test.go b/pkg/sendgrid/sendgrid_test.go index 05d85f6..b04f4b6 100644 --- a/pkg/sendgrid/sendgrid_test.go +++ b/pkg/sendgrid/sendgrid_test.go @@ -399,7 +399,7 @@ func TestClient_Create(t *testing.T) { fields: fields{ sendgridClient: newMockAPIClient(func(c *APIClientMock) { c.GetSubUserByUsernameFunc = func(username string) (user *SubUser, e error) { - return nil, &smtpdetails.NotExistError{Message: ""} + return nil, &NotExistError{Message: ""} } c.GetAPIKeysForSubUserFunc = func(username string) (keys []*APIKey, e error) { return []*APIKey{}, nil diff --git a/pkg/sendgrid/sendgridapi.go b/pkg/sendgrid/sendgridapi.go index 5fb87df..cd577e2 100644 --- a/pkg/sendgrid/sendgridapi.go +++ b/pkg/sendgrid/sendgridapi.go @@ -4,8 +4,6 @@ import ( "encoding/json" "fmt" - "github.com/integr8ly/smtp-service/pkg/smtpdetails" - "github.com/pkg/errors" "github.com/sendgrid/rest" "github.com/sirupsen/logrus" @@ -69,7 +67,7 @@ func (c *BackendAPIClient) GetAPIKeysForSubUser(username string) ([]*APIKey, err if err != nil { return nil, errors.Wrapf(err, "failed to list api keys for user %s", username) } - var apiKeysResp apiKeysListResponse + var apiKeysResp *apiKeysListResponse if err := json.Unmarshal([]byte(listResp.Body), &apiKeysResp); err != nil { return nil, errors.Wrapf(err, "failed to unmarshal api keys response, content=%s", listResp.Body) } @@ -166,7 +164,7 @@ func (c *BackendAPIClient) GetSubUserByUsername(username string) (*SubUser, erro return nil, errors.Wrapf(err, "failed to list sub users with username %s", username) } if len(subusers) != 1 { - return nil, &smtpdetails.NotExistError{Message: fmt.Sprintf("should be exactly one sub user with username %s, found %d", username, len(subusers))} + return nil, &NotExistError{Message: fmt.Sprintf("should be exactly one sub user with username %s, found %d", username, len(subusers))} } return subusers[0], nil }