Skip to content
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
47 changes: 45 additions & 2 deletions pkg/app/api/grpcapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,51 @@ func (a *API) AddApplication(ctx context.Context, req *apiservice.AddApplication
}, nil
}

func (a *API) SyncApplication(ctx context.Context, _ *apiservice.SyncApplicationRequest) (*apiservice.SyncApplicationResponse, error) {
_, err := requireAPIKey(ctx, model.APIKey_READ_WRITE, a.logger)
func (a *API) SyncApplication(ctx context.Context, req *apiservice.SyncApplicationRequest) (*apiservice.SyncApplicationResponse, error) {
key, err := requireAPIKey(ctx, model.APIKey_READ_WRITE, a.logger)
if err != nil {
return nil, err
}

app, err := getApplication(ctx, a.applicationStore, req.ApplicationId, a.logger)
if err != nil {
return nil, err
}

if key.ProjectId != app.ProjectId {
return nil, status.Error(codes.InvalidArgument, "Requested application does not belong to your project")
}

cmd := model.Command{
Id: uuid.New().String(),
PipedId: app.PipedId,
ApplicationId: app.Id,
Type: model.Command_SYNC_APPLICATION,
Commander: key.Id,
SyncApplication: &model.Command_SyncApplication{
ApplicationId: app.Id,
},
}
if err := addCommand(ctx, a.commandStore, &cmd, a.logger); err != nil {
return nil, err
}

return &apiservice.SyncApplicationResponse{
CommandId: cmd.Id,
}, nil
}

func (a *API) GetDeployment(ctx context.Context, _ *apiservice.GetDeploymentRequest) (*apiservice.GetDeploymentResponse, error) {
_, err := requireAPIKey(ctx, model.APIKey_READ_ONLY, a.logger)
if err != nil {
return nil, err
}

return nil, status.Error(codes.Unimplemented, "")
}

func (a *API) GetCommand(ctx context.Context, _ *apiservice.GetCommandRequest) (*apiservice.GetCommandResponse, error) {
_, err := requireAPIKey(ctx, model.APIKey_READ_ONLY, a.logger)
if err != nil {
return nil, err
}
Expand Down
22 changes: 22 additions & 0 deletions pkg/app/api/grpcapi/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/pipe-cd/pipe/pkg/app/api/commandstore"
"github.com/pipe-cd/pipe/pkg/datastore"
"github.com/pipe-cd/pipe/pkg/git"
"github.com/pipe-cd/pipe/pkg/model"
Expand All @@ -40,6 +41,27 @@ func getPiped(ctx context.Context, store datastore.PipedStore, id string, logger
return piped, nil
}

func getApplication(ctx context.Context, store datastore.ApplicationStore, id string, logger *zap.Logger) (*model.Application, error) {
app, err := store.GetApplication(ctx, id)
if errors.Is(err, datastore.ErrNotFound) {
return nil, status.Error(codes.NotFound, "Application is not found")
}
if err != nil {
logger.Error("failed to get application", zap.Error(err))
return nil, status.Error(codes.Internal, "Failed to get application")
}

return app, nil
}

func addCommand(ctx context.Context, store commandstore.Store, cmd *model.Command, logger *zap.Logger) error {
if err := store.AddCommand(ctx, cmd); err != nil {
logger.Error("failed to create command", zap.Error(err))
return status.Error(codes.Internal, "Failed to create command")
}
return nil
}

// makeGitPath returns an ApplicationGitPath by adding Repository info and GitPath URL to given args.
func makeGitPath(repoID, path, cfgFilename string, piped *model.Piped, logger *zap.Logger) (*model.ApplicationGitPath, error) {
var repo *model.ApplicationGitRepository
Expand Down
30 changes: 12 additions & 18 deletions pkg/app/api/grpcapi/web_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,41 +526,34 @@ func (a *WebAPI) SyncApplication(ctx context.Context, req *webservice.SyncApplic
return nil, err
}

app, err := a.getApplication(ctx, req.ApplicationId)
app, err := getApplication(ctx, a.applicationStore, req.ApplicationId, a.logger)
if err != nil {
return nil, err
}
if err := a.validateAppBelongsToProject(ctx, req.ApplicationId, claims.Role.ProjectId); err != nil {
return nil, err

if claims.Role.ProjectId != app.ProjectId {
return nil, status.Error(codes.InvalidArgument, "Requested application does not belong to your project")
}

commandID := uuid.New().String()
cmd := model.Command{
Id: commandID,
Id: uuid.New().String(),
PipedId: app.PipedId,
ApplicationId: app.Id,
Type: model.Command_SYNC_APPLICATION,
Commander: claims.Subject,
SyncApplication: &model.Command_SyncApplication{
ApplicationId: req.ApplicationId,
ApplicationId: app.Id,
},
}
if err := a.addCommand(ctx, &cmd); err != nil {
if err := addCommand(ctx, a.commandStore, &cmd, a.logger); err != nil {
return nil, err
}

return &webservice.SyncApplicationResponse{
CommandId: commandID,
CommandId: cmd.Id,
}, nil
}

func (a *WebAPI) addCommand(ctx context.Context, cmd *model.Command) error {
if err := a.commandStore.AddCommand(ctx, cmd); err != nil {
a.logger.Error("failed to create command", zap.Error(err))
return status.Error(codes.Internal, "Failed to create command")
}
return nil
}

func (a *WebAPI) GetApplication(ctx context.Context, req *webservice.GetApplicationRequest) (*webservice.GetApplicationResponse, error) {
claims, err := rpcauth.ExtractClaims(ctx)
if err != nil {
Expand Down Expand Up @@ -849,7 +842,7 @@ func (a *WebAPI) CancelDeployment(ctx context.Context, req *webservice.CancelDep
ForceNoRollback: req.ForceNoRollback,
},
}
if err := a.addCommand(ctx, &cmd); err != nil {
if err := addCommand(ctx, a.commandStore, &cmd, a.logger); err != nil {
return nil, err
}
return &webservice.CancelDeploymentResponse{
Expand Down Expand Up @@ -893,9 +886,10 @@ func (a *WebAPI) ApproveStage(ctx context.Context, req *webservice.ApproveStageR
StageId: req.StageId,
},
}
if err := a.addCommand(ctx, &cmd); err != nil {
if err := addCommand(ctx, a.commandStore, &cmd, a.logger); err != nil {
return nil, err
}

return &webservice.ApproveStageResponse{
CommandId: commandID,
}, nil
Expand Down
22 changes: 22 additions & 0 deletions pkg/app/api/service/apiservice/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ option go_package = "github.com/pipe-cd/pipe/pkg/app/api/service/apiservice";
import "validate/validate.proto";
import "pkg/model/common.proto";
import "pkg/model/application.proto";
import "pkg/model/deployment.proto";
import "pkg/model/command.proto";

// APIService contains all RPC definitions for external service, pipectl.
// All of these RPCs are authenticated by using API key.
service APIService {
rpc AddApplication(AddApplicationRequest) returns (AddApplicationResponse) {}
rpc SyncApplication(SyncApplicationRequest) returns (SyncApplicationResponse) {}

rpc GetDeployment(GetDeploymentRequest) returns (GetDeploymentResponse) {}

rpc GetCommand(GetCommandRequest) returns (GetCommandResponse) {}
}

message AddApplicationRequest {
Expand All @@ -48,3 +54,19 @@ message SyncApplicationRequest {
message SyncApplicationResponse {
string command_id = 1;
}

message GetDeploymentRequest {
string deployment_id = 1;
}

message GetDeploymentResponse {
pipe.model.Deployment deployment = 1;
}

message GetCommandRequest {
string command_id = 1 [(validate.rules).string.min_len = 1];
}

message GetCommandResponse {
pipe.model.Command command = 1;
}