diff --git a/internal/services/gateway/action/secret.go b/internal/services/gateway/action/secret.go new file mode 100644 index 0000000..1f25610 --- /dev/null +++ b/internal/services/gateway/action/secret.go @@ -0,0 +1,119 @@ +// Copyright 2019 Sorint.lab +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied +// See the License for the specific language governing permissions and +// limitations under the License. + +package action + +import ( + "context" + "net/http" + + csapi "github.com/sorintlab/agola/internal/services/configstore/api" + "github.com/sorintlab/agola/internal/services/types" + "github.com/sorintlab/agola/internal/util" + "go.uber.org/zap" + + "github.com/pkg/errors" +) + +type GetSecretsRequest struct { + ParentType types.ConfigType + ParentRef string + + Tree bool +} + +func (h *ActionHandler) GetSecrets(ctx context.Context, req *GetSecretsRequest) ([]*csapi.Secret, error) { + var cssecrets []*csapi.Secret + var resp *http.Response + var err error + switch req.ParentType { + case types.ConfigTypeProjectGroup: + cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, req.Tree) + case types.ConfigTypeProject: + cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, req.Tree) + } + if err != nil { + return nil, ErrFromRemote(resp, err) + } + + return cssecrets, nil +} + +type CreateSecretRequest struct { + Name string + + ParentType types.ConfigType + ParentRef string + + Type types.SecretType + + // internal secret + Data map[string]string + + // external secret + SecretProviderID string + Path string +} + +type CreateSecretHandler struct { + log *zap.SugaredLogger + configstoreClient *csapi.Client +} + +func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretRequest) (*csapi.Secret, error) { + if !util.ValidateName(req.Name) { + return nil, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name)) + } + + s := &types.Secret{ + Name: req.Name, + Type: req.Type, + Data: req.Data, + } + + var resp *http.Response + var rs *csapi.Secret + var err error + switch req.ParentType { + case types.ConfigTypeProjectGroup: + h.log.Infof("creating project group secret") + rs, resp, err = h.configstoreClient.CreateProjectGroupSecret(ctx, req.ParentRef, s) + case types.ConfigTypeProject: + h.log.Infof("creating project secret") + rs, resp, err = h.configstoreClient.CreateProjectSecret(ctx, req.ParentRef, s) + } + if err != nil { + return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to create secret")) + } + h.log.Infof("secret %s created, ID: %s", rs.Name, rs.ID) + + return rs, nil +} + +func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.ConfigType, parentRef, name string) error { + var resp *http.Response + var err error + switch parentType { + case types.ConfigTypeProjectGroup: + h.log.Infof("deleting project group secret") + resp, err = h.configstoreClient.DeleteProjectGroupSecret(ctx, parentRef, name) + case types.ConfigTypeProject: + h.log.Infof("deleting project secret") + resp, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, name) + } + if err != nil { + return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete secret")) + } + return nil +} diff --git a/internal/services/gateway/api/secret.go b/internal/services/gateway/api/secret.go index 665f68c..5e78cf9 100644 --- a/internal/services/gateway/api/secret.go +++ b/internal/services/gateway/api/secret.go @@ -19,12 +19,12 @@ import ( "net/http" csapi "github.com/sorintlab/agola/internal/services/configstore/api" + "github.com/sorintlab/agola/internal/services/gateway/action" "github.com/sorintlab/agola/internal/services/types" "github.com/sorintlab/agola/internal/util" "go.uber.org/zap" "github.com/gorilla/mux" - "github.com/pkg/errors" ) type SecretResponse struct { @@ -42,12 +42,12 @@ func createSecretResponse(s *csapi.Secret) *SecretResponse { } type SecretHandler struct { - log *zap.SugaredLogger - configstoreClient *csapi.Client + log *zap.SugaredLogger + ah *action.ActionHandler } -func NewSecretHandler(logger *zap.Logger, configstoreClient *csapi.Client) *SecretHandler { - return &SecretHandler{log: logger.Sugar(), configstoreClient: configstoreClient} +func NewSecretHandler(logger *zap.Logger, ah *action.ActionHandler) *SecretHandler { + return &SecretHandler{log: logger.Sugar(), ah: ah} } func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -61,15 +61,13 @@ func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - var cssecrets []*csapi.Secret - var resp *http.Response - switch parentType { - case types.ConfigTypeProjectGroup: - cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, parentRef, tree) - case types.ConfigTypeProject: - cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, parentRef, tree) + areq := &action.GetSecretsRequest{ + ParentType: parentType, + ParentRef: parentRef, + Tree: tree, } - if httpErrorFromRemote(w, resp, err) { + cssecrets, err := h.ah.GetSecrets(ctx, areq) + if httpError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -98,12 +96,12 @@ type CreateSecretRequest struct { } type CreateSecretHandler struct { - log *zap.SugaredLogger - configstoreClient *csapi.Client + log *zap.SugaredLogger + ah *action.ActionHandler } -func NewCreateSecretHandler(logger *zap.Logger, configstoreClient *csapi.Client) *CreateSecretHandler { - return &CreateSecretHandler{log: logger.Sugar(), configstoreClient: configstoreClient} +func NewCreateSecretHandler(logger *zap.Logger, ah *action.ActionHandler) *CreateSecretHandler { + return &CreateSecretHandler{log: logger.Sugar(), ah: ah} } func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -120,46 +118,34 @@ func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) return } - if !util.ValidateName(req.Name) { - httpError(w, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name))) - return + areq := &action.CreateSecretRequest{ + Name: req.Name, + ParentType: parentType, + ParentRef: parentRef, + Type: req.Type, + Data: req.Data, + SecretProviderID: req.SecretProviderID, + Path: req.Path, } - - s := &types.Secret{ - Name: req.Name, - Type: req.Type, - Data: req.Data, - } - - var resp *http.Response - var rs *csapi.Secret - switch parentType { - case types.ConfigTypeProjectGroup: - h.log.Infof("creating project group secret") - rs, resp, err = h.configstoreClient.CreateProjectGroupSecret(ctx, parentRef, s) - case types.ConfigTypeProject: - h.log.Infof("creating project secret") - rs, resp, err = h.configstoreClient.CreateProjectSecret(ctx, parentRef, s) - } - if httpErrorFromRemote(w, resp, err) { + cssecret, err := h.ah.CreateSecret(ctx, areq) + if httpError(w, err) { h.log.Errorf("err: %+v", err) return } - h.log.Infof("secret %s created, ID: %s", rs.Name, rs.ID) - res := createSecretResponse(rs) + res := createSecretResponse(cssecret) if err := httpResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } type DeleteSecretHandler struct { - log *zap.SugaredLogger - configstoreClient *csapi.Client + log *zap.SugaredLogger + ah *action.ActionHandler } -func NewDeleteSecretHandler(logger *zap.Logger, configstoreClient *csapi.Client) *DeleteSecretHandler { - return &DeleteSecretHandler{log: logger.Sugar(), configstoreClient: configstoreClient} +func NewDeleteSecretHandler(logger *zap.Logger, ah *action.ActionHandler) *DeleteSecretHandler { + return &DeleteSecretHandler{log: logger.Sugar(), ah: ah} } func (h *DeleteSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -172,16 +158,8 @@ func (h *DeleteSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) return } - var resp *http.Response - switch parentType { - case types.ConfigTypeProjectGroup: - h.log.Infof("deleting project group secret") - resp, err = h.configstoreClient.DeleteProjectGroupSecret(ctx, parentRef, secretName) - case types.ConfigTypeProject: - h.log.Infof("deleting project secret") - resp, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, secretName) - } - if httpErrorFromRemote(w, resp, err) { + err = h.ah.DeleteSecret(ctx, parentType, parentRef, secretName) + if httpError(w, err) { h.log.Errorf("err: %+v", err) return } diff --git a/internal/services/gateway/gateway.go b/internal/services/gateway/gateway.go index 49afc1f..2a886f7 100644 --- a/internal/services/gateway/gateway.go +++ b/internal/services/gateway/gateway.go @@ -158,9 +158,9 @@ func (g *Gateway) Run(ctx context.Context) error { deleteProjectHandler := api.NewDeleteProjectHandler(logger, g.configstoreClient) projectReconfigHandler := api.NewProjectReconfigHandler(logger, g.ah, g.configstoreClient, g.c.APIExposedURL) - secretHandler := api.NewSecretHandler(logger, g.configstoreClient) - createSecretHandler := api.NewCreateSecretHandler(logger, g.configstoreClient) - deleteSecretHandler := api.NewDeleteSecretHandler(logger, g.configstoreClient) + secretHandler := api.NewSecretHandler(logger, g.ah) + createSecretHandler := api.NewCreateSecretHandler(logger, g.ah) + deleteSecretHandler := api.NewDeleteSecretHandler(logger, g.ah) variableHandler := api.NewVariableHandler(logger, g.ah) createVariableHandler := api.NewCreateVariableHandler(logger, g.ah)