diff --git a/pkg/app/api/grpcapi/piped_api.go b/pkg/app/api/grpcapi/piped_api.go index b8593aca0a..c60488ed60 100644 --- a/pkg/app/api/grpcapi/piped_api.go +++ b/pkg/app/api/grpcapi/piped_api.go @@ -204,6 +204,36 @@ func (a *PipedAPI) ReportApplicationSyncState(ctx context.Context, req *pipedser return &pipedservice.ReportApplicationSyncStateResponse{}, nil } +// ReportApplicationDeployingStatus is used to report whether the specified application is deploying or not. +func (a *PipedAPI) ReportApplicationDeployingStatus(ctx context.Context, req *pipedservice.ReportApplicationDeployingStatusRequest) (*pipedservice.ReportApplicationDeployingStatusResponse, error) { + _, pipedID, _, err := rpcauth.ExtractPipedToken(ctx) + if err != nil { + return nil, err + } + if err := a.validateAppBelongsToPiped(ctx, req.ApplicationId, pipedID); err != nil { + return nil, err + } + + err = a.applicationStore.UpdateApplication(ctx, req.ApplicationId, func(app *model.Application) error { + app.Deploying = req.Deploying + return nil + }) + switch err { + case datastore.ErrNotFound: + return nil, status.Error(codes.InvalidArgument, "application is not found") + case datastore.ErrInvalidArgument: + return nil, status.Error(codes.InvalidArgument, "invalid value for update") + default: + a.logger.Error("failed to update deploying status of application", + zap.String("application-id", req.ApplicationId), + zap.Error(err), + ) + return nil, status.Error(codes.Internal, "failed to update deploying status of application") + } + + return &pipedservice.ReportApplicationDeployingStatusResponse{}, nil +} + // ReportApplicationMostRecentDeployment is used to update the basic information about // the most recent deployment of a specific application. func (a *PipedAPI) ReportApplicationMostRecentDeployment(ctx context.Context, req *pipedservice.ReportApplicationMostRecentDeploymentRequest) (*pipedservice.ReportApplicationMostRecentDeploymentResponse, error) { diff --git a/pkg/app/api/service/pipedservice/pipedclientfake/fakeclient.go b/pkg/app/api/service/pipedservice/pipedclientfake/fakeclient.go index 1ea5188082..c7baa2287e 100644 --- a/pkg/app/api/service/pipedservice/pipedclientfake/fakeclient.go +++ b/pkg/app/api/service/pipedservice/pipedclientfake/fakeclient.go @@ -158,6 +158,21 @@ func (c *fakeClient) ReportApplicationSyncState(ctx context.Context, req *pipeds return &pipedservice.ReportApplicationSyncStateResponse{}, nil } +// ReportApplicationDeployingStatus is used to report whether the specified application is deploying or not. +func (c *fakeClient) ReportApplicationDeployingStatus(_ context.Context, req *pipedservice.ReportApplicationDeployingStatusRequest, _ ...grpc.CallOption) (*pipedservice.ReportApplicationDeployingStatusResponse, error) { + c.logger.Info("fake client received ReportApplicationDeployingStatus rpc", zap.Any("request", req)) + c.mu.RLock() + defer c.mu.RUnlock() + + app, ok := c.applications[req.ApplicationId] + if !ok { + return nil, status.Error(codes.NotFound, "application was not found") + } + app.Deploying = req.Deploying + + return &pipedservice.ReportApplicationDeployingStatusResponse{}, nil +} + // ReportApplicationMostRecentDeployment is used to update the basic information about // the most recent deployment of a specific application. func (c *fakeClient) ReportApplicationMostRecentDeployment(ctx context.Context, req *pipedservice.ReportApplicationMostRecentDeploymentRequest, opts ...grpc.CallOption) (*pipedservice.ReportApplicationMostRecentDeploymentResponse, error) { diff --git a/pkg/app/api/service/pipedservice/service.proto b/pkg/app/api/service/pipedservice/service.proto index 54a9d4d7f7..9e5d056de9 100644 --- a/pkg/app/api/service/pipedservice/service.proto +++ b/pkg/app/api/service/pipedservice/service.proto @@ -51,6 +51,9 @@ service PipedService { // ReportApplicationSyncState is used to update the sync status of an application. rpc ReportApplicationSyncState(ReportApplicationSyncStateRequest) returns (ReportApplicationSyncStateResponse) {} + // ReportApplicationDeployingStatus is used to report whether the specified application is deploying or not. + rpc ReportApplicationDeployingStatus(ReportApplicationDeployingStatusRequest) returns (ReportApplicationDeployingStatusResponse) {} + // ReportApplicationMostRecentDeployment is used to update the basic information about // the most recent deployment of a specific application. rpc ReportApplicationMostRecentDeployment(ReportApplicationMostRecentDeploymentRequest) returns (ReportApplicationMostRecentDeploymentResponse) {} @@ -173,6 +176,14 @@ message ReportApplicationSyncStateRequest { message ReportApplicationSyncStateResponse { } +message ReportApplicationDeployingStatusRequest { + string application_id = 1 [(validate.rules).string.min_len = 1]; + bool deploying = 2; +} + +message ReportApplicationDeployingStatusResponse { +} + message ReportApplicationMostRecentDeploymentRequest { string application_id = 1 [(validate.rules).string.min_len = 1]; pipe.model.DeploymentStatus status = 2 [(validate.rules).enum.defined_only = true]; diff --git a/pkg/app/piped/controller/controller.go b/pkg/app/piped/controller/controller.go index 25740b3ae8..fafa88c40b 100644 --- a/pkg/app/piped/controller/controller.go +++ b/pkg/app/piped/controller/controller.go @@ -44,6 +44,7 @@ import ( type apiClient interface { GetApplicationMostRecentDeployment(ctx context.Context, req *pipedservice.GetApplicationMostRecentDeploymentRequest, opts ...grpc.CallOption) (*pipedservice.GetApplicationMostRecentDeploymentResponse, error) + ReportApplicationDeployingStatus(ctx context.Context, req *pipedservice.ReportApplicationDeployingStatusRequest, opts ...grpc.CallOption) (*pipedservice.ReportApplicationDeployingStatusResponse, error) ReportDeploymentPlanned(ctx context.Context, req *pipedservice.ReportDeploymentPlannedRequest, opts ...grpc.CallOption) (*pipedservice.ReportDeploymentPlannedResponse, error) ReportDeploymentStatusChanged(ctx context.Context, req *pipedservice.ReportDeploymentStatusChangedRequest, opts ...grpc.CallOption) (*pipedservice.ReportDeploymentStatusChangedResponse, error) ReportDeploymentCompleted(ctx context.Context, req *pipedservice.ReportDeploymentCompletedRequest, opts ...grpc.CallOption) (*pipedservice.ReportDeploymentCompletedResponse, error) @@ -192,7 +193,7 @@ func (c *controller) Run(ctx context.Context) error { c.logger.Info("start running controller") // Make sure the existence of the workspace directory. - // Each planner/scheduler will have an working directory inside this workspace. + // Each planner/scheduler will have a working directory inside this workspace. dir, err := ioutil.TempDir("", "workspace") if err != nil { c.logger.Error("failed to create workspace directory", zap.Error(err)) @@ -589,6 +590,25 @@ func (c *controller) getMostRecentlySuccessfulDeployment(ctx context.Context, ap return nil, err } +func (c *controller) reportApplicationDeployingStatus(ctx context.Context, appID string, deploying bool) error { + var ( + err error + retry = pipedservice.NewRetry(10) + req = &pipedservice.ReportApplicationDeployingStatusRequest{ + ApplicationId: appID, + Deploying: deploying, + } + ) + + for retry.WaitNext(ctx) { + if _, err = c.apiClient.ReportApplicationDeployingStatus(ctx, req); err == nil { + return nil + } + err = fmt.Errorf("failed to report application deploying status to control-plane: %w", err) + } + return err +} + type appLiveResourceLister struct { lister liveResourceLister cloudProvider string