From 0deeca7d68c7fb64ecdf146d007f6fd3b5907af3 Mon Sep 17 00:00:00 2001 From: "Chang, Hui-Tang" Date: Thu, 30 Nov 2023 14:39:53 +0800 Subject: [PATCH] feat(organization): add organization API endpoints (#308) --- go.mod | 2 +- go.sum | 4 +- pkg/handler/connector.go | 1357 ++++++++ pkg/handler/connector_definition.go | 100 + .../{handle.go => formdata_handler.go} | 0 pkg/handler/handler.go | 90 + pkg/handler/operation.go | 25 + pkg/handler/operator_definition.go | 159 + pkg/handler/pipeline.go | 1788 +++++++++++ pkg/handler/privateHandler.go | 304 -- pkg/handler/publicHandler.go | 2800 ----------------- pkg/repository/repository.go | 154 +- pkg/service/convert.go | 28 +- pkg/service/mock_user_grpc_test.go | 20 - pkg/service/service.go | 412 +-- 15 files changed, 3827 insertions(+), 3416 deletions(-) create mode 100644 pkg/handler/connector.go create mode 100644 pkg/handler/connector_definition.go rename pkg/handler/{handle.go => formdata_handler.go} (100%) create mode 100644 pkg/handler/handler.go create mode 100644 pkg/handler/operation.go create mode 100644 pkg/handler/operator_definition.go create mode 100644 pkg/handler/pipeline.go delete mode 100644 pkg/handler/privateHandler.go delete mode 100644 pkg/handler/publicHandler.go diff --git a/go.mod b/go.mod index aeb15fcfe..cee079610 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/instill-ai/component v0.7.0-alpha.0.20231123142642-cdd8e3280413 github.com/instill-ai/connector v0.7.0-alpha.0.20231129072816-73792d943bf2 github.com/instill-ai/operator v0.5.0-alpha.0.20231129072812-3235831ef5e3 - github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231122080750-7a3598994bf3 + github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231129095217-f8d4e5951d35 github.com/instill-ai/usage-client v0.2.4-alpha.0.20231019203021-70410a0a8061 github.com/instill-ai/x v0.3.0-alpha.0.20231124062833-3236165f5782 github.com/knadh/koanf v1.5.0 diff --git a/go.sum b/go.sum index 403e8249a..33ea79941 100644 --- a/go.sum +++ b/go.sum @@ -1189,8 +1189,8 @@ github.com/instill-ai/connector v0.7.0-alpha.0.20231129072816-73792d943bf2 h1:cG github.com/instill-ai/connector v0.7.0-alpha.0.20231129072816-73792d943bf2/go.mod h1:x4aaGR/lbmESJ241m0Ctv947HkoJD+lB+SDTIkjdrQM= github.com/instill-ai/operator v0.5.0-alpha.0.20231129072812-3235831ef5e3 h1:tfpFWDniHvJtfsoFsOcOvJDaADuiJHrV8xERv8p2flw= github.com/instill-ai/operator v0.5.0-alpha.0.20231129072812-3235831ef5e3/go.mod h1:5a9GkE3uPV6ttR9zykdNwnaiH0Jzedazul0Y63ZQ9D4= -github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231122080750-7a3598994bf3 h1:xr4Igd5mfdO+ks3mze4haoIW1QPpka69X38XvudukVQ= -github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231122080750-7a3598994bf3/go.mod h1:q/YL5TZXD9nvmJ7Rih4gY3/B2HT2+GiFdxeZp9D+yE4= +github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231129095217-f8d4e5951d35 h1:25AKxLuDZmVJOnh+gx4tqsfS5y/woQHzh8j1J5wN0ec= +github.com/instill-ai/protogen-go v0.3.3-alpha.0.20231129095217-f8d4e5951d35/go.mod h1:q/YL5TZXD9nvmJ7Rih4gY3/B2HT2+GiFdxeZp9D+yE4= github.com/instill-ai/usage-client v0.2.4-alpha.0.20231019203021-70410a0a8061 h1:lOp2fORCj76/gfPuLqB3TEN2cvFRJHUQOxwFSl4qxEw= github.com/instill-ai/usage-client v0.2.4-alpha.0.20231019203021-70410a0a8061/go.mod h1:dxsx9oHibg/+FrFLxAMurvbheeVUrMdFTbVHsfANTCU= github.com/instill-ai/x v0.3.0-alpha.0.20231124062833-3236165f5782 h1:ErsJ1IkjD6Rtif0YI898fv/qllW5x9vb2fdt69EYwug= diff --git a/pkg/handler/connector.go b/pkg/handler/connector.go new file mode 100644 index 000000000..c7e44ce5c --- /dev/null +++ b/pkg/handler/connector.go @@ -0,0 +1,1357 @@ +package handler + +import ( + "context" + "fmt" + "net/http" + "strings" + + "strconv" + "time" + + "github.com/gofrs/uuid" + "github.com/iancoleman/strcase" + "go.einride.tech/aip/filtering" + "go.opentelemetry.io/otel/trace" + "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/fieldmaskpb" + "google.golang.org/protobuf/types/known/structpb" + + fieldmask_utils "github.com/mennanov/fieldmask-utils" + + "github.com/instill-ai/pipeline-backend/internal/resource" + "github.com/instill-ai/pipeline-backend/pkg/logger" + + "github.com/instill-ai/pipeline-backend/pkg/service" + "github.com/instill-ai/pipeline-backend/pkg/utils" + "github.com/instill-ai/x/checkfield" + "github.com/instill-ai/x/sterr" + + custom_otel "github.com/instill-ai/pipeline-backend/pkg/logger/otel" + mgmtPB "github.com/instill-ai/protogen-go/core/mgmt/v1alpha" + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +func (h *PrivateHandler) ListConnectorsAdmin(ctx context.Context, req *pipelinePB.ListConnectorsAdminRequest) (resp *pipelinePB.ListConnectorsAdminResponse, err error) { + + var pageSize int32 + var pageToken string + + resp = &pipelinePB.ListConnectorsAdminResponse{} + pageSize = req.GetPageSize() + pageToken = req.GetPageToken() + + var connType pipelinePB.ConnectorType + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareEnumIdent("connector_type", connType.Type()), + }...) + if err != nil { + return nil, err + } + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + return nil, err + } + + connectors, totalSize, nextPageToken, err := h.service.ListConnectorsAdmin(ctx, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + return nil, err + } + + resp.Connectors = connectors + resp.NextPageToken = nextPageToken + resp.TotalSize = int32(totalSize) + + return resp, nil + +} + +func (h *PrivateHandler) LookUpConnectorAdmin(ctx context.Context, req *pipelinePB.LookUpConnectorAdminRequest) (resp *pipelinePB.LookUpConnectorAdminResponse, err error) { + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.LookUpConnectorAdminResponse{} + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(req, lookUpConnectorRequiredFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] lookup connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + return nil, st.Err() + } + + connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) + if err != nil { + return nil, err + } + + connector, err := h.service.GetConnectorByUIDAdmin(ctx, connUID, parseView(int32(*req.GetView().Enum()))) + if err != nil { + return nil, err + } + + resp.Connector = connector + + return resp, nil +} + +func (h *PrivateHandler) CheckConnector(ctx context.Context, req *pipelinePB.CheckConnectorRequest) (resp *pipelinePB.CheckConnectorResponse, err error) { + + resp = &pipelinePB.CheckConnectorResponse{} + connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) + if err != nil { + return resp, err + } + + connector, err := h.service.GetConnectorByUIDAdmin(ctx, connUID, service.VIEW_BASIC) + if err != nil { + return nil, err + } + + if err != nil { + return nil, err + } + + if connector.Tombstone { + resp.State = pipelinePB.Connector_STATE_ERROR + return resp, nil + } + + if connector.State == pipelinePB.Connector_STATE_CONNECTED { + state, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) + if err != nil { + return resp, err + } + + resp.State = *state + return resp, nil + + } else { + resp.State = pipelinePB.Connector_STATE_DISCONNECTED + return resp, nil + } + +} + +func (h *PublicHandler) ListConnectors(ctx context.Context, req *pipelinePB.ListConnectorsRequest) (resp *pipelinePB.ListConnectorsResponse, err error) { + + eventName := "ListConnectors" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var pageSize int32 + var pageToken string + + resp = &pipelinePB.ListConnectorsResponse{} + pageSize = req.GetPageSize() + pageToken = req.GetPageToken() + + var connType pipelinePB.ConnectorType + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareEnumIdent("connector_type", connType.Type()), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + connectors, totalSize, nextPageToken, err := h.service.ListConnectors(ctx, userUid, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + + resp.Connectors = connectors + resp.NextPageToken = nextPageToken + resp.TotalSize = int32(totalSize) + + return resp, nil + +} + +func (h *PublicHandler) LookUpConnector(ctx context.Context, req *pipelinePB.LookUpConnectorRequest) (resp *pipelinePB.LookUpConnectorResponse, err error) { + + eventName := "LookUpConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.LookUpConnectorResponse{} + + connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) + if err != nil { + return nil, err + } + + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(req, lookUpConnectorRequiredFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] lookup connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return resp, st.Err() + } + + connector, err := h.service.GetConnectorByUID(ctx, userUid, connUID, parseView(int32(*req.GetView().Enum())), true) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + resp.Connector = connector + + return resp, nil +} + +type CreateNamespaceConnectorRequestInterface interface { + GetParent() string +} + +func (h *PublicHandler) CreateUserConnector(ctx context.Context, req *pipelinePB.CreateUserConnectorRequest) (resp *pipelinePB.CreateUserConnectorResponse, err error) { + resp = &pipelinePB.CreateUserConnectorResponse{} + resp.Connector, err = h.createNamespaceConnector(ctx, req.Connector, req) + return resp, err +} + +func (h *PublicHandler) CreateOrganizationConnector(ctx context.Context, req *pipelinePB.CreateOrganizationConnectorRequest) (resp *pipelinePB.CreateOrganizationConnectorResponse, err error) { + resp = &pipelinePB.CreateOrganizationConnectorResponse{} + resp.Connector, err = h.createNamespaceConnector(ctx, req.Connector, req) + return resp, err +} + +func (h *PublicHandler) createNamespaceConnector(ctx context.Context, connector *pipelinePB.Connector, req CreateNamespaceConnectorRequestInterface) (connectorCreated *pipelinePB.Connector, err error) { + + eventName := "CreateNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + ns, _, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + // TODO: ACL + if ns.NsType == resource.User && ns.String() != resource.UserUidToUserPermalink(userUid) { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Description: "can not create in other user's namespace", + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + // Set all OUTPUT_ONLY fields to zero value on the requested payload + if err := checkfield.CheckCreateOutputOnlyFields(connector, outputOnlyConnectorFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "OUTPUT_ONLY fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(connector, append(createConnectorRequiredFields, immutableConnectorFields...)); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + connID = connector.GetId() + if len(connID) > 8 && connID[:8] == "instill-" { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "connector", + Description: "the id can not start with instill-", + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + // Return error if resource ID does not follow RFC-1034 + if err := checkfield.CheckResourceID(connID); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "id", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + if strings.HasPrefix(req.GetParent(), "users") { + connector.Owner = &pipelinePB.Connector_User{User: req.GetParent()} + } else { + connector.Owner = &pipelinePB.Connector_Organization{Organization: req.GetParent()} + } + + connectorCreated, err = h.service.CreateNamespaceConnector(ctx, ns, userUid, connector) + + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { + return nil, err + } + + return connectorCreated, nil +} + +type ListNamespaceConnectorsRequestInterface interface { + GetPageSize() int32 + GetPageToken() string + GetView() pipelinePB.Connector_View + GetFilter() string + GetParent() string + GetShowDeleted() bool +} + +func (h *PublicHandler) ListUserConnectors(ctx context.Context, req *pipelinePB.ListUserConnectorsRequest) (resp *pipelinePB.ListUserConnectorsResponse, err error) { + resp = &pipelinePB.ListUserConnectorsResponse{} + resp.Connectors, resp.NextPageToken, resp.TotalSize, err = h.listNamespaceConnectors(ctx, req) + return resp, err +} + +func (h *PublicHandler) ListOrganizationConnectors(ctx context.Context, req *pipelinePB.ListOrganizationConnectorsRequest) (resp *pipelinePB.ListOrganizationConnectorsResponse, err error) { + resp = &pipelinePB.ListOrganizationConnectorsResponse{} + resp.Connectors, resp.NextPageToken, resp.TotalSize, err = h.listNamespaceConnectors(ctx, req) + return resp, err +} + +func (h *PublicHandler) listNamespaceConnectors(ctx context.Context, req ListNamespaceConnectorsRequestInterface) (connectors []*pipelinePB.Connector, nextPageToken string, totalSize int32, err error) { + + eventName := "ListNamespaceConnectors" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + logger, _ := logger.GetZapLogger(ctx) + pageSize := req.GetPageSize() + pageToken := req.GetPageToken() + + var connType pipelinePB.ConnectorType + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareEnumIdent("connector_type", connType.Type()), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + ns, _, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + connectors, totalSize, nextPageToken, err = h.service.ListNamespaceConnectors(ctx, ns, userUid, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + + return connectors, nextPageToken, int32(totalSize), nil + +} + +type GetNamespaceConnectorRequestInterface interface { + GetName() string + GetView() pipelinePB.Connector_View +} + +func (h *PublicHandler) GetUserConnector(ctx context.Context, req *pipelinePB.GetUserConnectorRequest) (resp *pipelinePB.GetUserConnectorResponse, err error) { + resp = &pipelinePB.GetUserConnectorResponse{} + resp.Connector, err = h.getNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) GetOrganizationConnector(ctx context.Context, req *pipelinePB.GetOrganizationConnectorRequest) (resp *pipelinePB.GetOrganizationConnectorResponse, err error) { + resp = &pipelinePB.GetOrganizationConnectorResponse{} + resp.Connector, err = h.getNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) getNamespaceConnector(ctx context.Context, req GetNamespaceConnectorRequestInterface) (connector *pipelinePB.Connector, err error) { + eventName := "GetNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + connector, err = h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, parseView(int32(*req.GetView().Enum())), true) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + return connector, nil +} + +type UpdateNamespaceConnectorRequestInterface interface { + GetConnector() *pipelinePB.Connector + GetUpdateMask() *fieldmaskpb.FieldMask +} + +func (h *PublicHandler) UpdateUserConnector(ctx context.Context, req *pipelinePB.UpdateUserConnectorRequest) (resp *pipelinePB.UpdateUserConnectorResponse, err error) { + resp = &pipelinePB.UpdateUserConnectorResponse{} + resp.Connector, err = h.updateNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) UpdateOrganizationConnector(ctx context.Context, req *pipelinePB.UpdateOrganizationConnectorRequest) (resp *pipelinePB.UpdateOrganizationConnectorResponse, err error) { + resp = &pipelinePB.UpdateOrganizationConnectorResponse{} + resp.Connector, err = h.updateNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) updateNamespaceConnector(ctx context.Context, req UpdateNamespaceConnectorRequestInterface) (connector *pipelinePB.Connector, err error) { + + eventName := "UpdateNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var mask fieldmask_utils.Mask + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetConnector().Name) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbConnectorReq := req.GetConnector() + pbUpdateMask := req.GetUpdateMask() + + // configuration filed is type google.protobuf.Struct, which needs to be updated as a whole + for idx, path := range pbUpdateMask.Paths { + if strings.Contains(path, "configuration") { + pbUpdateMask.Paths[idx] = "configuration" + } + } + + if !pbUpdateMask.IsValid(req.GetConnector()) { + st, err := sterr.CreateErrorBadRequest( + "[handler] update connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "update_mask", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + // Remove all OUTPUT_ONLY fields in the requested payload + pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, outputOnlyConnectorFields) + if err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] update connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "OUTPUT_ONLY fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + existedConnector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, false) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + // Return error if IMMUTABLE fields are intentionally changed + if err := checkfield.CheckUpdateImmutableFields(req.GetConnector(), existedConnector, immutableConnectorFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] update connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "IMMUTABLE fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + mask, err = fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) + if err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] update connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "update_mask", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + if mask.IsEmpty() { + existedConnector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, true) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + return existedConnector, nil + } + + pbConnectorToUpdate := existedConnector + if pbConnectorToUpdate.State == pipelinePB.Connector_STATE_CONNECTED { + st, err := sterr.CreateErrorPreconditionFailure( + "[service] update connector", + []*errdetails.PreconditionFailure_Violation{ + { + Type: "UPDATE", + Subject: fmt.Sprintf("id %s", req.GetConnector().Id), + Description: fmt.Sprintf("Cannot update a connected %s connector", req.GetConnector().Id), + }, + }) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + dbConnDefID, err := resource.GetRscNameID(existedConnector.GetConnectorDefinitionName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + configuration := &structpb.Struct{} + h.service.KeepCredentialFieldsWithMaskString(dbConnDefID, pbConnectorToUpdate.Configuration) + proto.Merge(configuration, pbConnectorToUpdate.Configuration) + + // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact + err = fieldmask_utils.StructToStruct(mask, pbConnectorReq, pbConnectorToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + h.service.RemoveCredentialFieldsWithMaskString(dbConnDefID, req.GetConnector().Configuration) + proto.Merge(configuration, req.GetConnector().Configuration) + pbConnectorToUpdate.Configuration = configuration + + connector, err = h.service.UpdateNamespaceConnectorByID(ctx, ns, userUid, connID, pbConnectorToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + return connector, nil +} + +type DeleteNamespaceConnectorRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) DeleteUserConnector(ctx context.Context, req *pipelinePB.DeleteUserConnectorRequest) (resp *pipelinePB.DeleteUserConnectorResponse, err error) { + resp = &pipelinePB.DeleteUserConnectorResponse{} + err = h.deleteNamespaceConnector(ctx, req) + return resp, err +} +func (h *PublicHandler) DeleteOrganizationConnector(ctx context.Context, req *pipelinePB.DeleteOrganizationConnectorRequest) (resp *pipelinePB.DeleteOrganizationConnectorResponse, err error) { + resp = &pipelinePB.DeleteOrganizationConnectorResponse{} + err = h.deleteNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) deleteNamespaceConnector(ctx context.Context, req DeleteNamespaceConnectorRequestInterface) (err error) { + + eventName := "DeleteNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + + dbConnector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + + if err := h.service.DeleteNamespaceConnectorByID(ctx, ns, userUid, connID); err != nil { + span.SetStatus(1, err.Error()) + return err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(dbConnector), + ))) + + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { + return err + } + return nil +} + +type ConnectNamespaceConnectorRequest interface { + GetName() string +} + +func (h *PublicHandler) ConnectUserConnector(ctx context.Context, req *pipelinePB.ConnectUserConnectorRequest) (resp *pipelinePB.ConnectUserConnectorResponse, err error) { + resp = &pipelinePB.ConnectUserConnectorResponse{} + resp.Connector, err = h.connectNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) ConnectOrganizationConnector(ctx context.Context, req *pipelinePB.ConnectOrganizationConnectorRequest) (resp *pipelinePB.ConnectOrganizationConnectorResponse, err error) { + resp = &pipelinePB.ConnectOrganizationConnectorResponse{} + resp.Connector, err = h.connectNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) connectNamespaceConnector(ctx context.Context, req ConnectNamespaceConnectorRequest) (connector *pipelinePB.Connector, err error) { + + eventName := "ConnectNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(req, connectConnectorRequiredFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] connect connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + connector, err = h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + state, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) + + if err != nil { + st, _ := sterr.CreateErrorBadRequest( + fmt.Sprintf("[handler] connect connector error %v", err), + []*errdetails.BadRequest_FieldViolation{}, + ) + span.SetStatus(1, fmt.Sprintf("connect connector error %v", err)) + return nil, st.Err() + } + if *state != pipelinePB.Connector_STATE_CONNECTED { + st, _ := sterr.CreateErrorBadRequest( + "[handler] connect connector error not Connector_STATE_CONNECTED", + []*errdetails.BadRequest_FieldViolation{}, + ) + span.SetStatus(1, "connect connector error not Connector_STATE_CONNECTED") + return nil, st.Err() + } + + connector, err = h.service.UpdateNamespaceConnectorStateByID(ctx, ns, userUid, connID, *state) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + return connector, nil +} + +type DisconnectNamespaceConnectorRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) DisconnectUserConnector(ctx context.Context, req *pipelinePB.DisconnectUserConnectorRequest) (resp *pipelinePB.DisconnectUserConnectorResponse, err error) { + resp = &pipelinePB.DisconnectUserConnectorResponse{} + resp.Connector, err = h.disconnectNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) DisconnectOrganizationConnector(ctx context.Context, req *pipelinePB.DisconnectOrganizationConnectorRequest) (resp *pipelinePB.DisconnectOrganizationConnectorResponse, err error) { + resp = &pipelinePB.DisconnectOrganizationConnectorResponse{} + resp.Connector, err = h.disconnectNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) disconnectNamespaceConnector(ctx context.Context, req DisconnectNamespaceConnectorRequestInterface) (connector *pipelinePB.Connector, err error) { + + eventName := "DisconnectNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(req, disconnectConnectorRequiredFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] disconnect connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + connector, err = h.service.UpdateNamespaceConnectorStateByID(ctx, ns, userUid, connID, pipelinePB.Connector_STATE_DISCONNECTED) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + return connector, nil +} + +type RenameNamespaceConnectorRequestInterface interface { + GetName() string + GetNewConnectorId() string +} + +func (h *PublicHandler) RenameUserConnector(ctx context.Context, req *pipelinePB.RenameUserConnectorRequest) (resp *pipelinePB.RenameUserConnectorResponse, err error) { + resp = &pipelinePB.RenameUserConnectorResponse{} + resp.Connector, err = h.renameNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) RenameOrganizationConnector(ctx context.Context, req *pipelinePB.RenameOrganizationConnectorRequest) (resp *pipelinePB.RenameOrganizationConnectorResponse, err error) { + resp = &pipelinePB.RenameOrganizationConnectorResponse{} + resp.Connector, err = h.renameNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) renameNamespaceConnector(ctx context.Context, req RenameNamespaceConnectorRequestInterface) (connector *pipelinePB.Connector, err error) { + + eventName := "RenameNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + var connNewID string + + // Return error if REQUIRED fields are not provided in the requested payload + if err := checkfield.CheckRequiredFields(req, renameConnectorRequiredFields); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] rename connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "REQUIRED fields", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + connNewID = req.GetNewConnectorId() + if len(connNewID) > 8 && connNewID[:8] == "instill-" { + st, err := sterr.CreateErrorBadRequest( + "[handler] create connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "connector", + Description: "the id can not start with instill-", + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + // Return error if resource ID does not follow RFC-1034 + if err := checkfield.CheckResourceID(connNewID); err != nil { + st, err := sterr.CreateErrorBadRequest( + "[handler] rename connector error", + []*errdetails.BadRequest_FieldViolation{ + { + Field: "id", + Description: err.Error(), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + span.SetStatus(1, st.Err().Error()) + return nil, st.Err() + } + + connector, err = h.service.UpdateNamespaceConnectorIDByID(ctx, ns, userUid, connID, connNewID) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + return connector, nil +} + +type WatchNamespaceConnectorRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) WatchUserConnector(ctx context.Context, req *pipelinePB.WatchUserConnectorRequest) (resp *pipelinePB.WatchUserConnectorResponse, err error) { + resp = &pipelinePB.WatchUserConnectorResponse{} + resp.State, err = h.watchNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) WatchOrganizationConnector(ctx context.Context, req *pipelinePB.WatchOrganizationConnectorRequest) (resp *pipelinePB.WatchOrganizationConnectorResponse, err error) { + resp = &pipelinePB.WatchOrganizationConnectorResponse{} + resp.State, err = h.watchNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) watchNamespaceConnector(ctx context.Context, req WatchNamespaceConnectorRequestInterface) (state pipelinePB.Connector_State, err error) { + + eventName := "WatchNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + + connector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) + if err != nil { + span.SetStatus(1, err.Error()) + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetErrorMessage(err.Error()), + ))) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + + statePtr, err := h.service.GetConnectorState(uuid.FromStringOrNil(connector.Uid)) + + if err != nil { + span.SetStatus(1, err.Error()) + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetErrorMessage(err.Error()), + custom_otel.SetEventResource(connector), + ))) + return pipelinePB.Connector_STATE_ERROR, nil + } + + return *statePtr, nil +} + +type TestNamespaceConnectorRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) TestUserConnector(ctx context.Context, req *pipelinePB.TestUserConnectorRequest) (resp *pipelinePB.TestUserConnectorResponse, err error) { + resp = &pipelinePB.TestUserConnectorResponse{} + resp.State, err = h.testNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) TestOrganizationConnector(ctx context.Context, req *pipelinePB.TestOrganizationConnectorRequest) (resp *pipelinePB.TestOrganizationConnectorResponse, err error) { + resp = &pipelinePB.TestOrganizationConnectorResponse{} + resp.State, err = h.testNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) testNamespaceConnector(ctx context.Context, req TestNamespaceConnectorRequestInterface) (state pipelinePB.Connector_State, err error) { + + eventName := "TestNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + var connID string + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + + connector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + + statePtr, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) + + if err != nil { + span.SetStatus(1, err.Error()) + return pipelinePB.Connector_STATE_UNSPECIFIED, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(connector), + ))) + + return *statePtr, nil +} + +type ExecuteNamespaceConnectorRequestInterface interface { + GetName() string + GetInputs() []*structpb.Struct + GetTask() string +} + +func (h *PublicHandler) ExecuteUserConnector(ctx context.Context, req *pipelinePB.ExecuteUserConnectorRequest) (resp *pipelinePB.ExecuteUserConnectorResponse, err error) { + resp = &pipelinePB.ExecuteUserConnectorResponse{} + resp.Outputs, err = h.executeNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) ExecuteOrganizationConnector(ctx context.Context, req *pipelinePB.ExecuteOrganizationConnectorRequest) (resp *pipelinePB.ExecuteOrganizationConnectorResponse, err error) { + resp = &pipelinePB.ExecuteOrganizationConnectorResponse{} + resp.Outputs, err = h.executeNamespaceConnector(ctx, req) + return resp, err +} + +func (h *PublicHandler) executeNamespaceConnector(ctx context.Context, req ExecuteNamespaceConnectorRequestInterface) (outputs []*structpb.Struct, err error) { + + startTime := time.Now() + eventName := "ExecuteNamespaceConnector" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, connID, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + connector, err := h.service.GetNamespaceConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, true) + if err != nil { + return nil, err + } + if connector.Tombstone { + st, _ := sterr.CreateErrorPreconditionFailure( + "ExecuteConnector", + []*errdetails.PreconditionFailure_Violation{ + { + Type: "STATE", + Subject: fmt.Sprintf("id %s", connID), + Description: "the connector definition is deprecated, you can not use it anymore", + }, + }) + return nil, st.Err() + } + + dataPoint := utils.ConnectorUsageMetricData{ + OwnerUID: userUid.String(), + ConnectorID: connector.Id, + ConnectorUID: connector.Uid, + ConnectorExecuteUID: logUUID.String(), + ConnectorDefinitionUid: connector.ConnectorDefinition.Uid, + ExecuteTime: startTime.Format(time.RFC3339Nano), + } + + md, _ := metadata.FromIncomingContext(ctx) + + pipelineVal := &structpb.Value{} + if len(md.Get("id")) > 0 && + len(md.Get("uid")) > 0 && + len(md.Get("release_id")) > 0 && + len(md.Get("release_uid")) > 0 && + len(md.Get("owner")) > 0 && + len(md.Get("trigger_id")) > 0 { + pipelineVal, _ = structpb.NewValue(map[string]interface{}{ + "id": md.Get("id")[0], + "uid": md.Get("uid")[0], + "release_id": md.Get("release_id")[0], + "release_uid": md.Get("release_uid")[0], + "owner": md.Get("owner")[0], + "trigger_id": md.Get("trigger_id")[0], + }) + } + + if outputs, err = h.service.Execute(ctx, ns, userUid, connID, req.GetTask(), req.GetInputs()); err != nil { + span.SetStatus(1, err.Error()) + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_ERRORED + _ = h.service.WriteNewConnectorDataPoint(ctx, dataPoint, pipelineVal) + return nil, err + } else { + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED + if err := h.service.WriteNewConnectorDataPoint(ctx, dataPoint, pipelineVal); err != nil { + logger.Warn("usage and metric data write fail") + } + } + return outputs, nil + +} diff --git a/pkg/handler/connector_definition.go b/pkg/handler/connector_definition.go new file mode 100644 index 000000000..0f8023a49 --- /dev/null +++ b/pkg/handler/connector_definition.go @@ -0,0 +1,100 @@ +package handler + +import ( + "context" + + "go.einride.tech/aip/filtering" + "go.opentelemetry.io/otel/trace" + + "github.com/instill-ai/pipeline-backend/internal/resource" + "github.com/instill-ai/pipeline-backend/pkg/logger" + + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +func (h *PrivateHandler) LookUpConnectorDefinitionAdmin(ctx context.Context, req *pipelinePB.LookUpConnectorDefinitionAdminRequest) (resp *pipelinePB.LookUpConnectorDefinitionAdminResponse, err error) { + + resp = &pipelinePB.LookUpConnectorDefinitionAdminResponse{} + + connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) + if err != nil { + return resp, err + } + + // TODO add a service wrapper + def, err := h.service.GetConnectorDefinitionByUIDAdmin(ctx, connUID, parseView(int32(*req.GetView().Enum()))) + if err != nil { + return resp, err + } + resp.ConnectorDefinition = def + + return resp, nil +} + +func (h *PublicHandler) ListConnectorDefinitions(ctx context.Context, req *pipelinePB.ListConnectorDefinitionsRequest) (resp *pipelinePB.ListConnectorDefinitionsResponse, err error) { + ctx, span := tracer.Start(ctx, "ListConnectorDefinitions", + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.ListConnectorDefinitionsResponse{} + pageSize := int64(req.GetPageSize()) + pageToken := req.GetPageToken() + + var connType pipelinePB.ConnectorType + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareEnumIdent("connector_type", connType.Type()), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + defs, totalSize, nextPageToken, err := h.service.ListConnectorDefinitions(ctx, int32(pageSize), pageToken, parseView(int32(*req.GetView().Enum())), filter) + + if err != nil { + return nil, err + } + + resp.ConnectorDefinitions = defs + resp.NextPageToken = nextPageToken + resp.TotalSize = int32(totalSize) + + logger.Info("ListConnectorDefinitions") + + return resp, nil +} + +func (h *PublicHandler) GetConnectorDefinition(ctx context.Context, req *pipelinePB.GetConnectorDefinitionRequest) (resp *pipelinePB.GetConnectorDefinitionResponse, err error) { + ctx, span := tracer.Start(ctx, "GetConnectorDefinition", + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.GetConnectorDefinitionResponse{} + + var connID string + + if connID, err = resource.GetRscNameID(req.GetName()); err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + + dbDef, err := h.service.GetConnectorDefinitionByID(ctx, connID, parseView(int32(*req.GetView().Enum()))) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + resp.ConnectorDefinition = dbDef + + logger.Info("GetConnectorDefinition") + return resp, nil + +} diff --git a/pkg/handler/handle.go b/pkg/handler/formdata_handler.go similarity index 100% rename from pkg/handler/handle.go rename to pkg/handler/formdata_handler.go diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go new file mode 100644 index 000000000..15bd23543 --- /dev/null +++ b/pkg/handler/handler.go @@ -0,0 +1,90 @@ +package handler + +import ( + "context" + + "go.opentelemetry.io/otel" + + "github.com/instill-ai/pipeline-backend/pkg/datamodel" + + "github.com/instill-ai/pipeline-backend/pkg/service" + + healthcheckPB "github.com/instill-ai/protogen-go/common/healthcheck/v1alpha" + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +// TODO: in the public_handler, we should convert all id to uuid when calling service + +var tracer = otel.Tracer("pipeline-backend.public-handler.tracer") + +// PublicHandler handles public API +type PublicHandler struct { + pipelinePB.UnimplementedPipelinePublicServiceServer + service service.Service +} + +type Streamer interface { + Context() context.Context +} + +type TriggerPipelineRequestInterface interface { + GetName() string +} + +// NewPublicHandler initiates a handler instance +func NewPublicHandler(ctx context.Context, s service.Service) pipelinePB.PipelinePublicServiceServer { + datamodel.InitJSONSchema(ctx) + return &PublicHandler{ + service: s, + } +} + +// GetService returns the service +func (h *PublicHandler) GetService() service.Service { + return h.service +} + +// SetService sets the service +func (h *PublicHandler) SetService(s service.Service) { + h.service = s +} + +func (h *PublicHandler) Liveness(ctx context.Context, req *pipelinePB.LivenessRequest) (*pipelinePB.LivenessResponse, error) { + return &pipelinePB.LivenessResponse{ + HealthCheckResponse: &healthcheckPB.HealthCheckResponse{ + Status: healthcheckPB.HealthCheckResponse_SERVING_STATUS_SERVING, + }, + }, nil +} + +func (h *PublicHandler) Readiness(ctx context.Context, req *pipelinePB.ReadinessRequest) (*pipelinePB.ReadinessResponse, error) { + return &pipelinePB.ReadinessResponse{ + HealthCheckResponse: &healthcheckPB.HealthCheckResponse{ + Status: healthcheckPB.HealthCheckResponse_SERVING_STATUS_SERVING, + }, + }, nil +} + +// PrivateHandler handles private API +type PrivateHandler struct { + pipelinePB.UnimplementedPipelinePrivateServiceServer + service service.Service +} + +// NewPrivateHandler initiates a handler instance +func NewPrivateHandler(ctx context.Context, s service.Service) pipelinePB.PipelinePrivateServiceServer { + datamodel.InitJSONSchema(ctx) + return &PrivateHandler{ + service: s, + } +} + +// GetService returns the service +func (h *PrivateHandler) GetService() service.Service { + return h.service +} + +// SetService sets the service +func (h *PrivateHandler) SetService(s service.Service) { + h.service = s +} diff --git a/pkg/handler/operation.go b/pkg/handler/operation.go new file mode 100644 index 000000000..699b4341e --- /dev/null +++ b/pkg/handler/operation.go @@ -0,0 +1,25 @@ +package handler + +import ( + "context" + + "github.com/instill-ai/pipeline-backend/internal/resource" + + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +func (h *PublicHandler) GetOperation(ctx context.Context, req *pipelinePB.GetOperationRequest) (*pipelinePB.GetOperationResponse, error) { + + operationId, err := resource.GetOperationID(req.Name) + if err != nil { + return &pipelinePB.GetOperationResponse{}, err + } + operation, err := h.service.GetOperation(ctx, operationId) + if err != nil { + return &pipelinePB.GetOperationResponse{}, err + } + + return &pipelinePB.GetOperationResponse{ + Operation: operation, + }, nil +} diff --git a/pkg/handler/operator_definition.go b/pkg/handler/operator_definition.go new file mode 100644 index 000000000..ac06c45a2 --- /dev/null +++ b/pkg/handler/operator_definition.go @@ -0,0 +1,159 @@ +package handler + +import ( + "context" + "fmt" + + "time" + + "go.opentelemetry.io/otel/trace" + "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/protobuf/proto" + + "github.com/instill-ai/pipeline-backend/internal/resource" + "github.com/instill-ai/pipeline-backend/pkg/logger" + "github.com/instill-ai/pipeline-backend/pkg/service" + + "github.com/instill-ai/pipeline-backend/pkg/repository" + "github.com/instill-ai/x/paginate" + "github.com/instill-ai/x/sterr" + + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +func (h *PrivateHandler) LookUpOperatorDefinitionAdmin(ctx context.Context, req *pipelinePB.LookUpOperatorDefinitionAdminRequest) (resp *pipelinePB.LookUpOperatorDefinitionAdminResponse, err error) { + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.LookUpOperatorDefinitionAdminResponse{} + + var connID string + + if connID, err = resource.GetRscNameID(req.GetPermalink()); err != nil { + return resp, err + } + + dbDef, err := h.service.GetOperatorDefinitionById(ctx, connID) + if err != nil { + return resp, err + } + resp.OperatorDefinition = proto.Clone(dbDef).(*pipelinePB.OperatorDefinition) + if parseView(int32(*req.GetView().Enum())) == service.VIEW_BASIC { + resp.OperatorDefinition.Spec = nil + } + resp.OperatorDefinition.Name = fmt.Sprintf("operator-definitions/%s", resp.OperatorDefinition.GetId()) + + logger.Info("GetOperatorDefinitionAdmin") + return resp, nil +} + +func (h *PublicHandler) ListOperatorDefinitions(ctx context.Context, req *pipelinePB.ListOperatorDefinitionsRequest) (resp *pipelinePB.ListOperatorDefinitionsResponse, err error) { + ctx, span := tracer.Start(ctx, "ListOperatorDefinitions", + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.ListOperatorDefinitionsResponse{} + pageSize := req.GetPageSize() + pageToken := req.GetPageToken() + isBasicView := (req.GetView() == pipelinePB.OperatorDefinition_VIEW_BASIC) || (req.GetView() == pipelinePB.OperatorDefinition_VIEW_UNSPECIFIED) + + prevLastUid := "" + + if pageToken != "" { + _, prevLastUid, err = paginate.DecodeToken(pageToken) + if err != nil { + st, err := sterr.CreateErrorBadRequest( + fmt.Sprintf("[db] list operator error: %s", err.Error()), + []*errdetails.BadRequest_FieldViolation{ + { + Field: "page_token", + Description: fmt.Sprintf("Invalid page token: %s", err.Error()), + }, + }, + ) + if err != nil { + logger.Error(err.Error()) + } + return nil, st.Err() + } + } + + if pageSize == 0 { + pageSize = repository.DefaultPageSize + } else if pageSize > repository.MaxPageSize { + pageSize = repository.MaxPageSize + } + + defs := h.service.ListOperatorDefinitions(ctx) + + startIdx := 0 + lastUid := "" + for idx, def := range defs { + if def.Uid == prevLastUid { + startIdx = idx + 1 + break + } + } + + page := []*pipelinePB.OperatorDefinition{} + for i := 0; i < int(pageSize) && startIdx+i < len(defs); i++ { + def := proto.Clone(defs[startIdx+i]).(*pipelinePB.OperatorDefinition) + page = append(page, def) + lastUid = def.Uid + } + + nextPageToken := "" + + if startIdx+len(page) < len(defs) { + nextPageToken = paginate.EncodeToken(time.Time{}, lastUid) + } + for _, def := range page { + def.Name = fmt.Sprintf("operator-definitions/%s", def.Id) + if isBasicView { + def.Spec = nil + } + resp.OperatorDefinitions = append( + resp.OperatorDefinitions, + def) + } + resp.NextPageToken = nextPageToken + resp.TotalSize = int32(len(defs)) + + logger.Info("ListOperatorDefinitions") + + return resp, nil +} + +func (h *PublicHandler) GetOperatorDefinition(ctx context.Context, req *pipelinePB.GetOperatorDefinitionRequest) (resp *pipelinePB.GetOperatorDefinitionResponse, err error) { + ctx, span := tracer.Start(ctx, "GetOperatorDefinition", + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logger, _ := logger.GetZapLogger(ctx) + + resp = &pipelinePB.GetOperatorDefinitionResponse{} + + var connID string + + if connID, err = resource.GetRscNameID(req.GetName()); err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + isBasicView := (req.GetView() == pipelinePB.OperatorDefinition_VIEW_BASIC) || (req.GetView() == pipelinePB.OperatorDefinition_VIEW_UNSPECIFIED) + + dbDef, err := h.service.GetOperatorDefinitionById(ctx, connID) + if err != nil { + span.SetStatus(1, err.Error()) + return resp, err + } + resp.OperatorDefinition = proto.Clone(dbDef).(*pipelinePB.OperatorDefinition) + if isBasicView { + resp.OperatorDefinition.Spec = nil + } + resp.OperatorDefinition.Name = fmt.Sprintf("operator-definitions/%s", resp.OperatorDefinition.GetId()) + + logger.Info("GetOperatorDefinition") + return resp, nil +} diff --git a/pkg/handler/pipeline.go b/pkg/handler/pipeline.go new file mode 100644 index 000000000..569a4f320 --- /dev/null +++ b/pkg/handler/pipeline.go @@ -0,0 +1,1788 @@ +package handler + +import ( + "context" + "fmt" + "net/http" + "strings" + + "strconv" + "time" + + "cloud.google.com/go/longrunning/autogen/longrunningpb" + "github.com/gofrs/uuid" + "github.com/iancoleman/strcase" + "go.einride.tech/aip/filtering" + "go.opentelemetry.io/otel/trace" + "golang.org/x/mod/semver" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/fieldmaskpb" + "google.golang.org/protobuf/types/known/structpb" + + fieldmask_utils "github.com/mennanov/fieldmask-utils" + + "github.com/instill-ai/pipeline-backend/internal/resource" + "github.com/instill-ai/pipeline-backend/pkg/constant" + "github.com/instill-ai/pipeline-backend/pkg/logger" + + "github.com/instill-ai/pipeline-backend/pkg/service" + "github.com/instill-ai/pipeline-backend/pkg/utils" + "github.com/instill-ai/x/checkfield" + + custom_otel "github.com/instill-ai/pipeline-backend/pkg/logger/otel" + mgmtPB "github.com/instill-ai/protogen-go/core/mgmt/v1alpha" + pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" +) + +func (h *PrivateHandler) ListPipelinesAdmin(ctx context.Context, req *pipelinePB.ListPipelinesAdminRequest) (*pipelinePB.ListPipelinesAdminResponse, error) { + + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), + filtering.DeclareIdent("uid", filtering.TypeString), + filtering.DeclareIdent("id", filtering.TypeString), + filtering.DeclareIdent("description", filtering.TypeString), + // only support "recipe.components.resource_name" for now + filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), + filtering.DeclareIdent("owner", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + filtering.DeclareIdent("update_time", filtering.TypeTimestamp), + }...) + if err != nil { + return &pipelinePB.ListPipelinesAdminResponse{}, err + } + + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + return &pipelinePB.ListPipelinesAdminResponse{}, err + } + + pbPipelines, totalSize, nextPageToken, err := h.service.ListPipelinesAdmin(ctx, req.GetPageSize(), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + return &pipelinePB.ListPipelinesAdminResponse{}, err + } + + resp := pipelinePB.ListPipelinesAdminResponse{ + Pipelines: pbPipelines, + NextPageToken: nextPageToken, + TotalSize: int32(totalSize), + } + + return &resp, nil +} + +func (h *PrivateHandler) LookUpPipelineAdmin(ctx context.Context, req *pipelinePB.LookUpPipelineAdminRequest) (*pipelinePB.LookUpPipelineAdminResponse, error) { + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, lookUpPipelineRequiredFields); err != nil { + return &pipelinePB.LookUpPipelineAdminResponse{}, status.Error(codes.InvalidArgument, err.Error()) + } + + view := pipelinePB.Pipeline_VIEW_BASIC + if req.GetView() != pipelinePB.Pipeline_VIEW_UNSPECIFIED { + view = req.GetView() + } + + uid, err := resource.GetRscPermalinkUID(req.GetPermalink()) + if err != nil { + return &pipelinePB.LookUpPipelineAdminResponse{}, err + } + pbPipeline, err := h.service.GetPipelineByUIDAdmin(ctx, uid, service.View(view)) + if err != nil { + return &pipelinePB.LookUpPipelineAdminResponse{}, err + } + + resp := pipelinePB.LookUpPipelineAdminResponse{ + Pipeline: pbPipeline, + } + + return &resp, nil +} + +func (h *PrivateHandler) ListPipelineReleasesAdmin(ctx context.Context, req *pipelinePB.ListPipelineReleasesAdminRequest) (*pipelinePB.ListPipelineReleasesAdminResponse, error) { + + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), + filtering.DeclareIdent("uid", filtering.TypeString), + filtering.DeclareIdent("id", filtering.TypeString), + filtering.DeclareIdent("description", filtering.TypeString), + // only support "recipe.components.resource_name" for now + filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), + filtering.DeclareIdent("owner", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + filtering.DeclareIdent("update_time", filtering.TypeTimestamp), + }...) + if err != nil { + return &pipelinePB.ListPipelineReleasesAdminResponse{}, err + } + + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + return &pipelinePB.ListPipelineReleasesAdminResponse{}, err + } + + pbPipelineReleases, totalSize, nextPageToken, err := h.service.ListPipelineReleasesAdmin(ctx, req.GetPageSize(), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + return &pipelinePB.ListPipelineReleasesAdminResponse{}, err + } + + resp := pipelinePB.ListPipelineReleasesAdminResponse{ + Releases: pbPipelineReleases, + NextPageToken: nextPageToken, + TotalSize: int32(totalSize), + } + + return &resp, nil +} + +func (h *PublicHandler) ListPipelines(ctx context.Context, req *pipelinePB.ListPipelinesRequest) (*pipelinePB.ListPipelinesResponse, error) { + + eventName := "ListPipelines" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return &pipelinePB.ListPipelinesResponse{}, err + } + + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), + filtering.DeclareIdent("uid", filtering.TypeString), + filtering.DeclareIdent("id", filtering.TypeString), + filtering.DeclareIdent("description", filtering.TypeString), + // only support "recipe.components.resource_name" for now + filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), + filtering.DeclareIdent("owner", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + filtering.DeclareIdent("update_time", filtering.TypeTimestamp), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return &pipelinePB.ListPipelinesResponse{}, err + } + + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return &pipelinePB.ListPipelinesResponse{}, err + } + + pbPipelines, totalSize, nextPageToken, err := h.service.ListPipelines(ctx, userUid, req.GetPageSize(), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + span.SetStatus(1, err.Error()) + return &pipelinePB.ListPipelinesResponse{}, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + + resp := pipelinePB.ListPipelinesResponse{ + Pipelines: pbPipelines, + NextPageToken: nextPageToken, + TotalSize: int32(totalSize), + } + + return &resp, nil +} + +type CreateNamespacePipelineRequestInterface interface { + GetPipeline() *pipelinePB.Pipeline + GetParent() string +} + +func (h *PublicHandler) CreateUserPipeline(ctx context.Context, req *pipelinePB.CreateUserPipelineRequest) (resp *pipelinePB.CreateUserPipelineResponse, err error) { + resp = &pipelinePB.CreateUserPipelineResponse{} + resp.Pipeline, err = h.createNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) CreateOrganizationPipeline(ctx context.Context, req *pipelinePB.CreateOrganizationPipelineRequest) (resp *pipelinePB.CreateOrganizationPipelineResponse, err error) { + resp = &pipelinePB.CreateOrganizationPipelineResponse{} + resp.Pipeline, err = h.createNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) createNamespacePipeline(ctx context.Context, req CreateNamespacePipelineRequestInterface) (pipeline *pipelinePB.Pipeline, err error) { + + eventName := "CreateNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + // Validate JSON Schema + // if err := datamodel.ValidatePipelineJSONSchema(req.GetPipeline()); err != nil { + // span.SetStatus(1, err.Error()) + // return nil, status.Error(codes.InvalidArgument, err.Error()) + // } + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req.GetPipeline(), append(createPipelineRequiredFields, immutablePipelineFields...)); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Set all OUTPUT_ONLY fields to zero value on the requested payload pipeline resource + if err := checkfield.CheckCreateOutputOnlyFields(req.GetPipeline(), outputOnlyPipelineFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Return error if resource ID does not follow RFC-1034 + if err := checkfield.CheckResourceID(req.GetPipeline().GetId()); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, _, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + _, userUid, err := h.service.GetCtxUser(ctx) + + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pipelineToCreate := req.GetPipeline() + + name, err := h.service.ConvertOwnerPermalinkToName(fmt.Sprintf("users/%s", userUid)) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pipelineToCreate.Owner = &pipelinePB.Pipeline_User{User: name} + + pipeline, err = h.service.CreateNamespacePipeline(ctx, ns, userUid, pipelineToCreate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + // Manually set the custom header to have a StatusCreated http response for REST endpoint + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pipeline), + ))) + + return pipeline, nil +} + +type ListNamespacePipelinesRequestInterface interface { + GetPageSize() int32 + GetPageToken() string + GetView() pipelinePB.Pipeline_View + GetFilter() string + GetParent() string + GetShowDeleted() bool +} + +func (h *PublicHandler) ListUserPipelines(ctx context.Context, req *pipelinePB.ListUserPipelinesRequest) (resp *pipelinePB.ListUserPipelinesResponse, err error) { + resp = &pipelinePB.ListUserPipelinesResponse{} + resp.Pipelines, resp.NextPageToken, resp.TotalSize, err = h.listNamespacePipelines(ctx, req) + return resp, err +} + +func (h *PublicHandler) ListOrganizationPipelines(ctx context.Context, req *pipelinePB.ListOrganizationPipelinesRequest) (resp *pipelinePB.ListOrganizationPipelinesResponse, err error) { + resp = &pipelinePB.ListOrganizationPipelinesResponse{} + resp.Pipelines, resp.NextPageToken, resp.TotalSize, err = h.listNamespacePipelines(ctx, req) + return resp, err +} + +func (h *PublicHandler) listNamespacePipelines(ctx context.Context, req ListNamespacePipelinesRequestInterface) (pipelines []*pipelinePB.Pipeline, nextPageToken string, totalSize int32, err error) { + + eventName := "ListNamespacePipelines" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, _, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), + filtering.DeclareIdent("uid", filtering.TypeString), + filtering.DeclareIdent("id", filtering.TypeString), + filtering.DeclareIdent("description", filtering.TypeString), + // only support "recipe.components.resource_name" for now + filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), + filtering.DeclareIdent("owner", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + filtering.DeclareIdent("update_time", filtering.TypeTimestamp), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + pbPipelines, totalSize, nextPageToken, err := h.service.ListNamespacePipelines(ctx, ns, userUid, req.GetPageSize(), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + + return pbPipelines, nextPageToken, int32(totalSize), nil +} + +type GetNamespacePipelineRequestInterface interface { + GetName() string + GetView() pipelinePB.Pipeline_View +} + +func (h *PublicHandler) GetUserPipeline(ctx context.Context, req *pipelinePB.GetUserPipelineRequest) (resp *pipelinePB.GetUserPipelineResponse, err error) { + resp = &pipelinePB.GetUserPipelineResponse{} + resp.Pipeline, err = h.getNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) GetOrganizationPipeline(ctx context.Context, req *pipelinePB.GetOrganizationPipelineRequest) (resp *pipelinePB.GetOrganizationPipelineResponse, err error) { + resp = &pipelinePB.GetOrganizationPipelineResponse{} + resp.Pipeline, err = h.getNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) getNamespacePipeline(ctx context.Context, req GetNamespacePipelineRequestInterface) (*pipelinePB.Pipeline, error) { + + eventName := "GetNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, id, parseView(int32(*req.GetView().Enum()))) + + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + return pbPipeline, nil +} + +type UpdateNamespacePipelineRequestInterface interface { + GetPipeline() *pipelinePB.Pipeline + GetUpdateMask() *fieldmaskpb.FieldMask +} + +func (h *PublicHandler) UpdateUserPipeline(ctx context.Context, req *pipelinePB.UpdateUserPipelineRequest) (resp *pipelinePB.UpdateUserPipelineResponse, err error) { + resp = &pipelinePB.UpdateUserPipelineResponse{} + resp.Pipeline, err = h.updateNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) UpdateOrganizationPipeline(ctx context.Context, req *pipelinePB.UpdateOrganizationPipelineRequest) (resp *pipelinePB.UpdateOrganizationPipelineResponse, err error) { + resp = &pipelinePB.UpdateOrganizationPipelineResponse{} + resp.Pipeline, err = h.updateNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) updateNamespacePipeline(ctx context.Context, req UpdateNamespacePipelineRequestInterface) (*pipelinePB.Pipeline, error) { + + eventName := "UpdateNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetPipeline().Name) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipelineReq := req.GetPipeline() + pbUpdateMask := req.GetUpdateMask() + + // metadata field is type google.protobuf.Struct, which needs to be updated as a whole + for idx, path := range pbUpdateMask.Paths { + if strings.Contains(path, "metadata") { + pbUpdateMask.Paths[idx] = "metadata" + } + } + // Validate the field mask + if !pbUpdateMask.IsValid(pbPipelineReq) { + return nil, status.Error(codes.InvalidArgument, "The update_mask is invalid") + } + + getResp, err := h.GetUserPipeline(ctx, &pipelinePB.GetUserPipelineRequest{Name: pbPipelineReq.GetName(), View: pipelinePB.Pipeline_VIEW_RECIPE.Enum()}) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, outputOnlyPipelineFields) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + mask, err := fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + if mask.IsEmpty() { + return getResp.GetPipeline(), nil + } + + pbPipelineToUpdate := getResp.GetPipeline() + + // Return error if IMMUTABLE fields are intentionally changed + if err := checkfield.CheckUpdateImmutableFields(pbPipelineReq, pbPipelineToUpdate, immutablePipelineFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact + err = fieldmask_utils.StructToStruct(mask, pbPipelineReq, pbPipelineToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipeline, err := h.service.UpdateNamespacePipelineByID(ctx, ns, userUid, id, pbPipelineToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + return pbPipeline, nil +} + +type DeleteNamespacePipelineRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) DeleteUserPipeline(ctx context.Context, req *pipelinePB.DeleteUserPipelineRequest) (resp *pipelinePB.DeleteUserPipelineResponse, err error) { + resp = &pipelinePB.DeleteUserPipelineResponse{} + err = h.deleteNamespacePipeline(ctx, req) + return resp, err +} +func (h *PublicHandler) DeleteOrganizationPipeline(ctx context.Context, req *pipelinePB.DeleteOrganizationPipelineRequest) (resp *pipelinePB.DeleteOrganizationPipelineResponse, err error) { + resp = &pipelinePB.DeleteOrganizationPipelineResponse{} + err = h.deleteNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) deleteNamespacePipeline(ctx context.Context, req DeleteNamespacePipelineRequestInterface) error { + + eventName := "DeleteNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + existPipeline, err := h.GetUserPipeline(ctx, &pipelinePB.GetUserPipelineRequest{Name: req.GetName()}) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + + if err := h.service.DeleteNamespacePipelineByID(ctx, ns, userUid, id); err != nil { + span.SetStatus(1, err.Error()) + return err + } + + // We need to manually set the custom header to have a StatusCreated http response for REST endpoint + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { + span.SetStatus(1, err.Error()) + return err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(existPipeline.GetPipeline()), + ))) + + return nil +} + +func (h *PublicHandler) LookUpPipeline(ctx context.Context, req *pipelinePB.LookUpPipelineRequest) (*pipelinePB.LookUpPipelineResponse, error) { + + eventName := "LookUpPipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, lookUpPipelineRequiredFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + uid, err := resource.GetRscPermalinkUID(req.Permalink) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipeline, err := h.service.GetPipelineByUID(ctx, userUid, uid, parseView(int32(*req.GetView().Enum()))) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + resp := pipelinePB.LookUpPipelineResponse{ + Pipeline: pbPipeline, + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + return &resp, nil +} + +type ValidateNamespacePipelineRequest interface { + GetName() string +} + +func (h *PublicHandler) ValidateUserPipeline(ctx context.Context, req *pipelinePB.ValidateUserPipelineRequest) (resp *pipelinePB.ValidateUserPipelineResponse, err error) { + resp = &pipelinePB.ValidateUserPipelineResponse{} + resp.Pipeline, err = h.validateNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) ValidateOrganizationPipeline(ctx context.Context, req *pipelinePB.ValidateOrganizationPipelineRequest) (resp *pipelinePB.ValidateOrganizationPipelineResponse, err error) { + resp = &pipelinePB.ValidateOrganizationPipelineResponse{} + resp.Pipeline, err = h.validateNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) validateNamespacePipeline(ctx context.Context, req ValidateNamespacePipelineRequest) (*pipelinePB.Pipeline, error) { + + eventName := "ValidateNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipeline, err := h.service.ValidateNamespacePipelineByID(ctx, ns, userUid, id) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + return pbPipeline, nil +} + +type RenameNamespacePipelineRequestInterface interface { + GetName() string + GetNewPipelineId() string +} + +func (h *PublicHandler) RenameUserPipeline(ctx context.Context, req *pipelinePB.RenameUserPipelineRequest) (resp *pipelinePB.RenameUserPipelineResponse, err error) { + resp = &pipelinePB.RenameUserPipelineResponse{} + resp.Pipeline, err = h.renameNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) RenameOrganizationPipeline(ctx context.Context, req *pipelinePB.RenameOrganizationPipelineRequest) (resp *pipelinePB.RenameOrganizationPipelineResponse, err error) { + resp = &pipelinePB.RenameOrganizationPipelineResponse{} + resp.Pipeline, err = h.renameNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) renameNamespacePipeline(ctx context.Context, req RenameNamespacePipelineRequestInterface) (*pipelinePB.Pipeline, error) { + + eventName := "RenameNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, renamePipelineRequiredFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + newID := req.GetNewPipelineId() + if err := checkfield.CheckResourceID(newID); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + pbPipeline, err := h.service.UpdateNamespacePipelineIDByID(ctx, ns, userUid, id, newID) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + return pbPipeline, nil +} + +func (h *PublicHandler) preTriggerUserPipeline(ctx context.Context, req TriggerPipelineRequestInterface) (resource.Namespace, uuid.UUID, string, *pipelinePB.Pipeline, bool, error) { + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, triggerPipelineRequiredFields); err != nil { + return resource.Namespace{}, uuid.Nil, "", nil, false, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) + if err != nil { + return ns, uuid.Nil, id, nil, false, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return ns, uuid.Nil, id, nil, false, err + } + + pbPipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, id, service.VIEW_FULL) + if err != nil { + return ns, uuid.Nil, id, nil, false, err + } + _, err = h.service.ValidateNamespacePipelineByID(ctx, ns, userUid, id) + if err != nil { + return ns, uuid.Nil, id, nil, false, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) + } + returnTraces := false + if md, ok := metadata.FromIncomingContext(ctx); ok { + if len(md.Get(constant.ReturnTracesKey)) > 0 { + returnTraces, err = strconv.ParseBool(md.Get(constant.ReturnTracesKey)[0]) + if err != nil { + return ns, uuid.Nil, id, nil, false, err + } + } + } + + return ns, userUid, id, pbPipeline, returnTraces, nil + +} + +type TriggerNamespacePipelineRequestInterface interface { + GetName() string + GetInputs() []*structpb.Struct +} + +func (h *PublicHandler) TriggerUserPipeline(ctx context.Context, req *pipelinePB.TriggerUserPipelineRequest) (resp *pipelinePB.TriggerUserPipelineResponse, err error) { + resp = &pipelinePB.TriggerUserPipelineResponse{} + resp.Outputs, resp.Metadata, err = h.triggerNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) TriggerOrganizationPipeline(ctx context.Context, req *pipelinePB.TriggerOrganizationPipelineRequest) (resp *pipelinePB.TriggerOrganizationPipelineResponse, err error) { + resp = &pipelinePB.TriggerOrganizationPipelineResponse{} + resp.Outputs, resp.Metadata, err = h.triggerNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) triggerNamespacePipeline(ctx context.Context, req TriggerNamespacePipelineRequestInterface) (outputs []*structpb.Struct, metadata *pipelinePB.TriggerMetadata, err error) { + + startTime := time.Now() + eventName := "TriggerNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, userUid, id, pbPipeline, returnTraces, err := h.preTriggerUserPipeline(ctx, req) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, nil, err + } + + dataPoint := utils.PipelineUsageMetricData{ + OwnerUID: userUid.String(), + TriggerMode: mgmtPB.Mode_MODE_SYNC, + PipelineID: pbPipeline.Id, + PipelineUID: pbPipeline.Uid, + PipelineReleaseID: "", + PipelineReleaseUID: uuid.Nil.String(), + PipelineTriggerUID: logUUID.String(), + TriggerTime: startTime.Format(time.RFC3339Nano), + } + + outputs, metadata, err = h.service.TriggerNamespacePipelineByID(ctx, ns, userUid, id, req.GetInputs(), logUUID.String(), returnTraces) + if err != nil { + span.SetStatus(1, err.Error()) + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_ERRORED + _ = h.service.WriteNewPipelineDataPoint(ctx, dataPoint) + return nil, nil, status.Error(codes.InvalidArgument, err.Error()) + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipeline), + ))) + + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED + if err := h.service.WriteNewPipelineDataPoint(ctx, dataPoint); err != nil { + logger.Warn(err.Error()) + } + + return outputs, metadata, nil +} + +type TriggerAsyncNamespacePipelineRequestInterface interface { + GetName() string + GetInputs() []*structpb.Struct +} + +func (h *PublicHandler) TriggerAsyncUserPipeline(ctx context.Context, req *pipelinePB.TriggerAsyncUserPipelineRequest) (resp *pipelinePB.TriggerAsyncUserPipelineResponse, err error) { + resp = &pipelinePB.TriggerAsyncUserPipelineResponse{} + resp.Operation, err = h.triggerAsyncNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) TriggerAsyncOrganizationPipeline(ctx context.Context, req *pipelinePB.TriggerAsyncOrganizationPipelineRequest) (resp *pipelinePB.TriggerAsyncOrganizationPipelineResponse, err error) { + resp = &pipelinePB.TriggerAsyncOrganizationPipelineResponse{} + resp.Operation, err = h.triggerAsyncNamespacePipeline(ctx, req) + return resp, err +} + +func (h *PublicHandler) triggerAsyncNamespacePipeline(ctx context.Context, req TriggerAsyncNamespacePipelineRequestInterface) (operation *longrunningpb.Operation, err error) { + + eventName := "TriggerAsyncNamespacePipeline" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, userUid, id, dbPipeline, returnTraces, err := h.preTriggerUserPipeline(ctx, req) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + operation, err = h.service.TriggerAsyncNamespacePipelineByID(ctx, ns, userUid, id, req.GetInputs(), logUUID.String(), returnTraces) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(dbPipeline), + ))) + + return operation, nil +} + +type CreateNamespacePipelineReleaseRequestInterface interface { + GetRelease() *pipelinePB.PipelineRelease + GetParent() string +} + +func (h *PublicHandler) CreateUserPipelineRelease(ctx context.Context, req *pipelinePB.CreateUserPipelineReleaseRequest) (resp *pipelinePB.CreateUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.CreateUserPipelineReleaseResponse{} + resp.Release, err = h.createNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) CreateOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.CreateOrganizationPipelineReleaseRequest) (resp *pipelinePB.CreateOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.CreateOrganizationPipelineReleaseResponse{} + resp.Release, err = h.createNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) createNamespacePipelineRelease(ctx context.Context, req CreateNamespacePipelineReleaseRequestInterface) (*pipelinePB.PipelineRelease, error) { + eventName := "CreateNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req.GetRelease(), append(releaseCreateRequiredFields, immutablePipelineFields...)); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Set all OUTPUT_ONLY fields to zero value on the requested payload pipeline resource + if err := checkfield.CheckCreateOutputOnlyFields(req.GetRelease(), releaseOutputOnlyFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Return error if resource ID does not a semantic version + if !semver.IsValid(req.GetRelease().GetId()) { + err := fmt.Errorf("not a sematic version") + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, pipelineId, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + if err != nil { + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, err + } + _, err = h.service.ValidateNamespacePipelineByID(ctx, ns, userUid, pipeline.Id) + if err != nil { + return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) + } + + pbPipelineRelease, err := h.service.CreateNamespacePipelineRelease(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), req.GetRelease()) + if err != nil { + span.SetStatus(1, err.Error()) + // Manually set the custom header to have a StatusBadRequest http response for REST endpoint + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusBadRequest))); err != nil { + return nil, err + } + return nil, err + } + + // Manually set the custom header to have a StatusCreated http response for REST endpoint + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + return pbPipelineRelease, nil + +} + +type ListNamespacePipelineReleasesRequestInterface interface { + GetPageSize() int32 + GetPageToken() string + GetView() pipelinePB.Pipeline_View + GetFilter() string + GetParent() string + GetShowDeleted() bool +} + +func (h *PublicHandler) ListUserPipelineReleases(ctx context.Context, req *pipelinePB.ListUserPipelineReleasesRequest) (resp *pipelinePB.ListUserPipelineReleasesResponse, err error) { + resp = &pipelinePB.ListUserPipelineReleasesResponse{} + resp.Releases, resp.NextPageToken, resp.TotalSize, err = h.listNamespacePipelineReleases(ctx, req) + return resp, err +} + +func (h *PublicHandler) ListOrganizationPipelineReleases(ctx context.Context, req *pipelinePB.ListOrganizationPipelineReleasesRequest) (resp *pipelinePB.ListOrganizationPipelineReleasesResponse, err error) { + resp = &pipelinePB.ListOrganizationPipelineReleasesResponse{} + resp.Releases, resp.NextPageToken, resp.TotalSize, err = h.listNamespacePipelineReleases(ctx, req) + return resp, err +} + +func (h *PublicHandler) listNamespacePipelineReleases(ctx context.Context, req ListNamespacePipelineReleasesRequestInterface) (releases []*pipelinePB.PipelineRelease, nextPageToken string, totalSize int32, err error) { + + eventName := "ListNamespacePipelineReleases" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) + if err != nil { + return nil, "", 0, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, "", 0, err + } + + declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ + filtering.DeclareStandardFunctions(), + filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), + filtering.DeclareIdent("uid", filtering.TypeString), + filtering.DeclareIdent("id", filtering.TypeString), + filtering.DeclareIdent("description", filtering.TypeString), + // only support "recipe.components.resource_name" for now + filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), + filtering.DeclareIdent("owner", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + filtering.DeclareIdent("update_time", filtering.TypeTimestamp), + }...) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, "", 0, err + } + + pbPipelineReleases, totalSize, nextPageToken, err := h.service.ListNamespacePipelineReleases(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), req.GetPageSize(), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, "", 0, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + ))) + + return pbPipelineReleases, nextPageToken, totalSize, nil + +} + +type GetNamespacePipelineReleaseRequestInterface interface { + GetName() string + GetView() pipelinePB.Pipeline_View +} + +func (h *PublicHandler) GetUserPipelineRelease(ctx context.Context, req *pipelinePB.GetUserPipelineReleaseRequest) (resp *pipelinePB.GetUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.GetUserPipelineReleaseResponse{} + resp.Release, err = h.getNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) GetOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.GetOrganizationPipelineReleaseRequest) (resp *pipelinePB.GetOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.GetOrganizationPipelineReleaseResponse{} + resp.Release, err = h.getNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) getNamespacePipelineRelease(ctx context.Context, req GetNamespacePipelineReleaseRequestInterface) (release *pipelinePB.PipelineRelease, err error) { + + eventName := "GetNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return nil, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, err + } + + pbPipelineRelease, err := h.service.GetNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, parseView(int32(*req.GetView().Enum()))) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + return pbPipelineRelease, nil + +} + +type UpdateNamespacePipelineReleaseRequestInterface interface { + GetRelease() *pipelinePB.PipelineRelease + GetUpdateMask() *fieldmaskpb.FieldMask +} + +func (h *PublicHandler) UpdateUserPipelineRelease(ctx context.Context, req *pipelinePB.UpdateUserPipelineReleaseRequest) (resp *pipelinePB.UpdateUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.UpdateUserPipelineReleaseResponse{} + resp.Release, err = h.updateNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) UpdateOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.UpdateOrganizationPipelineReleaseRequest) (resp *pipelinePB.UpdateOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.UpdateOrganizationPipelineReleaseResponse{} + resp.Release, err = h.updateNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) updateNamespacePipelineRelease(ctx context.Context, req UpdateNamespacePipelineReleaseRequestInterface) (release *pipelinePB.PipelineRelease, err error) { + + eventName := "UpdateNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetRelease().GetName()) + if err != nil { + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return nil, err + } + + pbPipelineReleaseReq := req.GetRelease() + pbUpdateMask := req.GetUpdateMask() + + // Validate the field mask + if !pbUpdateMask.IsValid(pbPipelineReleaseReq) { + return nil, status.Error(codes.InvalidArgument, "The update_mask is invalid") + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, err + } + + getResp, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: pbPipelineReleaseReq.GetName()}) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, releaseOutputOnlyFields) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + mask, err := fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + if mask.IsEmpty() { + return getResp.GetRelease(), nil + } + + pbPipelineReleaseToUpdate := getResp.GetRelease() + + // Return error if IMMUTABLE fields are intentionally changed + if err := checkfield.CheckUpdateImmutableFields(pbPipelineReleaseReq, pbPipelineReleaseToUpdate, immutablePipelineFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact + err = fieldmask_utils.StructToStruct(mask, pbPipelineReleaseReq, pbPipelineReleaseToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipelineRelease, err := h.service.UpdateNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, pbPipelineReleaseToUpdate) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + return pbPipelineRelease, nil +} + +type RenameNamespacePipelineReleaseRequestInterface interface { + GetName() string + GetNewPipelineReleaseId() string +} + +func (h *PublicHandler) RenameUserPipelineRelease(ctx context.Context, req *pipelinePB.RenameUserPipelineReleaseRequest) (resp *pipelinePB.RenameUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.RenameUserPipelineReleaseResponse{} + resp.Release, err = h.renameNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) RenameOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.RenameOrganizationPipelineReleaseRequest) (resp *pipelinePB.RenameOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.RenameOrganizationPipelineReleaseResponse{} + resp.Release, err = h.renameNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) renameNamespacePipelineRelease(ctx context.Context, req RenameNamespacePipelineReleaseRequestInterface) (release *pipelinePB.PipelineRelease, err error) { + + eventName := "RenameNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, releaseRenameRequiredFields); err != nil { + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return nil, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, err + } + + newID := req.GetNewPipelineReleaseId() + // Return error if resource ID does not a semantic version + if !semver.IsValid(newID) { + err := fmt.Errorf("not a sematic version") + span.SetStatus(1, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + pbPipelineRelease, err := h.service.UpdateNamespacePipelineReleaseIDByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, newID) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + return pbPipelineRelease, nil +} + +type DeleteNamespacePipelineReleaseRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) DeleteUserPipelineRelease(ctx context.Context, req *pipelinePB.DeleteUserPipelineReleaseRequest) (resp *pipelinePB.DeleteUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.DeleteUserPipelineReleaseResponse{} + err = h.deleteNamespacePipelineRelease(ctx, req) + return resp, err +} +func (h *PublicHandler) DeleteOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.DeleteOrganizationPipelineReleaseRequest) (resp *pipelinePB.DeleteOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.DeleteOrganizationPipelineReleaseResponse{} + err = h.deleteNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) deleteNamespacePipelineRelease(ctx context.Context, req DeleteNamespacePipelineReleaseRequestInterface) error { + + eventName := "DeleteNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return err + } + + existPipelineRelease, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: req.GetName()}) + if err != nil { + span.SetStatus(1, err.Error()) + return err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return err + } + + if err := h.service.DeleteNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId); err != nil { + span.SetStatus(1, err.Error()) + return err + } + + // We need to manually set the custom header to have a StatusCreated http response for REST endpoint + if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { + span.SetStatus(1, err.Error()) + return err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(existPipelineRelease.GetRelease()), + ))) + + return nil +} + +type RestoreNamespacePipelineReleaseRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) RestoreUserPipelineRelease(ctx context.Context, req *pipelinePB.RestoreUserPipelineReleaseRequest) (resp *pipelinePB.RestoreUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.RestoreUserPipelineReleaseResponse{} + resp.Release, err = h.restoreNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) RestoreOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.RestoreOrganizationPipelineReleaseRequest) (resp *pipelinePB.RestoreOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.RestoreOrganizationPipelineReleaseResponse{} + resp.Release, err = h.restoreNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) restoreNamespacePipelineRelease(ctx context.Context, req RestoreNamespacePipelineReleaseRequestInterface) (release *pipelinePB.PipelineRelease, err error) { + + eventName := "RestoreNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return nil, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return nil, err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return nil, err + } + + existPipelineRelease, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: req.GetName()}) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + return nil, err + } + + if err := h.service.RestoreNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId); err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + pbPipelineRelease, err := h.service.GetNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, service.VIEW_FULL) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(existPipelineRelease.GetRelease()), + ))) + + return pbPipelineRelease, nil +} + +func (h *PublicHandler) preTriggerUserPipelineRelease(ctx context.Context, req TriggerPipelineRequestInterface) (resource.Namespace, uuid.UUID, string, *pipelinePB.Pipeline, *pipelinePB.PipelineRelease, bool, error) { + + // Return error if REQUIRED fields are not provided in the requested payload pipeline resource + if err := checkfield.CheckRequiredFields(req, triggerPipelineRequiredFields); err != nil { + return resource.Namespace{}, uuid.Nil, "", nil, nil, false, status.Error(codes.InvalidArgument, err.Error()) + } + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + + pbPipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_FULL) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + + pbPipelineRelease, err := h.service.GetNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, service.VIEW_FULL) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + returnTraces := false + if md, ok := metadata.FromIncomingContext(ctx); ok { + if len(md.Get(constant.ReturnTracesKey)) > 0 { + returnTraces, err = strconv.ParseBool(md.Get(constant.ReturnTracesKey)[0]) + if err != nil { + return ns, uuid.Nil, "", nil, nil, false, err + } + } + } + + return ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, nil + +} + +type TriggerNamespacePipelineReleaseRequestInterface interface { + GetName() string + GetInputs() []*structpb.Struct +} + +func (h *PublicHandler) TriggerUserPipelineRelease(ctx context.Context, req *pipelinePB.TriggerUserPipelineReleaseRequest) (resp *pipelinePB.TriggerUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.TriggerUserPipelineReleaseResponse{} + resp.Outputs, resp.Metadata, err = h.triggerNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) TriggerOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.TriggerOrganizationPipelineReleaseRequest) (resp *pipelinePB.TriggerOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.TriggerOrganizationPipelineReleaseResponse{} + resp.Outputs, resp.Metadata, err = h.triggerNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) triggerNamespacePipelineRelease(ctx context.Context, req TriggerNamespacePipelineReleaseRequestInterface) (outputs []*structpb.Struct, metadata *pipelinePB.TriggerMetadata, err error) { + + startTime := time.Now() + eventName := "TriggerNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, err := h.preTriggerUserPipelineRelease(ctx, req) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, nil, err + } + + dataPoint := utils.PipelineUsageMetricData{ + OwnerUID: userUid.String(), + TriggerMode: mgmtPB.Mode_MODE_SYNC, + PipelineID: pbPipeline.Id, + PipelineUID: pbPipeline.Uid, + PipelineReleaseID: pbPipelineRelease.Id, + PipelineReleaseUID: pbPipelineRelease.Uid, + PipelineTriggerUID: logUUID.String(), + TriggerTime: startTime.Format(time.RFC3339Nano), + } + + outputs, metadata, err = h.service.TriggerNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, req.GetInputs(), logUUID.String(), returnTraces) + if err != nil { + span.SetStatus(1, err.Error()) + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_ERRORED + _ = h.service.WriteNewPipelineDataPoint(ctx, dataPoint) + return nil, nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() + dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED + if err := h.service.WriteNewPipelineDataPoint(ctx, dataPoint); err != nil { + logger.Warn(err.Error()) + } + + return outputs, metadata, nil +} + +type TriggerAsyncNamespacePipelineReleaseRequestInterface interface { + GetName() string + GetInputs() []*structpb.Struct +} + +func (h *PublicHandler) TriggerAsyncUserPipelineRelease(ctx context.Context, req *pipelinePB.TriggerAsyncUserPipelineReleaseRequest) (resp *pipelinePB.TriggerAsyncUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.TriggerAsyncUserPipelineReleaseResponse{} + resp.Operation, err = h.triggerAsyncNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) TriggerAsyncOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.TriggerAsyncOrganizationPipelineReleaseRequest) (resp *pipelinePB.TriggerAsyncOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.TriggerAsyncOrganizationPipelineReleaseResponse{} + resp.Operation, err = h.triggerAsyncNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) triggerAsyncNamespacePipelineRelease(ctx context.Context, req TriggerAsyncNamespacePipelineReleaseRequestInterface) (operation *longrunningpb.Operation, err error) { + + eventName := "TriggerAsyncNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, err := h.preTriggerUserPipelineRelease(ctx, req) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + operation, err = h.service.TriggerAsyncNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, req.GetInputs(), logUUID.String(), returnTraces) + if err != nil { + span.SetStatus(1, err.Error()) + return nil, err + } + + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetEventResource(pbPipelineRelease), + ))) + + return operation, nil +} + +type WatchNamespacePipelineReleaseRequestInterface interface { + GetName() string +} + +func (h *PublicHandler) WatchUserPipelineRelease(ctx context.Context, req *pipelinePB.WatchUserPipelineReleaseRequest) (resp *pipelinePB.WatchUserPipelineReleaseResponse, err error) { + resp = &pipelinePB.WatchUserPipelineReleaseResponse{} + resp.State, err = h.watchNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) WatchOrganizationPipelineRelease(ctx context.Context, req *pipelinePB.WatchOrganizationPipelineReleaseRequest) (resp *pipelinePB.WatchOrganizationPipelineReleaseResponse, err error) { + resp = &pipelinePB.WatchOrganizationPipelineReleaseResponse{} + resp.State, err = h.watchNamespacePipelineRelease(ctx, req) + return resp, err +} + +func (h *PublicHandler) watchNamespacePipelineRelease(ctx context.Context, req WatchNamespacePipelineReleaseRequestInterface) (pipelinePB.State, error) { + + eventName := "WatchNamespacePipelineRelease" + + ctx, span := tracer.Start(ctx, eventName, + trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + logUUID, _ := uuid.NewV4() + + logger, _ := logger.GetZapLogger(ctx) + + ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) + if err != nil { + return pipelinePB.State_STATE_UNSPECIFIED, err + } + _, userUid, err := h.service.GetCtxUser(ctx) + if err != nil { + return pipelinePB.State_STATE_UNSPECIFIED, err + } + releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) + if err != nil { + return pipelinePB.State_STATE_UNSPECIFIED, err + } + + pipeline, err := h.service.GetNamespacePipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) + if err != nil { + span.SetStatus(1, err.Error()) + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetErrorMessage(err.Error()), + custom_otel.SetEventResource(req.GetName()), + ))) + return pipelinePB.State_STATE_UNSPECIFIED, err + } + + dbPipelineRelease, err := h.service.GetNamespacePipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, service.VIEW_BASIC) + if err != nil { + span.SetStatus(1, err.Error()) + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetErrorMessage(err.Error()), + custom_otel.SetEventResource(req.GetName()), + ))) + return pipelinePB.State_STATE_UNSPECIFIED, err + } + state, err := h.service.GetPipelineState(uuid.FromStringOrNil(dbPipelineRelease.Uid)) + if err != nil { + span.SetStatus(1, err.Error()) + logger.Info(string(custom_otel.NewLogMessage( + span, + logUUID.String(), + userUid, + eventName, + custom_otel.SetErrorMessage(err.Error()), + custom_otel.SetEventResource(req.GetName()), + ))) + return pipelinePB.State_STATE_UNSPECIFIED, err + } + + return *state, nil +} diff --git a/pkg/handler/privateHandler.go b/pkg/handler/privateHandler.go deleted file mode 100644 index 30b82f50a..000000000 --- a/pkg/handler/privateHandler.go +++ /dev/null @@ -1,304 +0,0 @@ -package handler - -import ( - "context" - "fmt" - - "go.einride.tech/aip/filtering" - "google.golang.org/genproto/googleapis/rpc/errdetails" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - - "github.com/gofrs/uuid" - "github.com/instill-ai/pipeline-backend/internal/resource" - "github.com/instill-ai/pipeline-backend/pkg/datamodel" - "github.com/instill-ai/pipeline-backend/pkg/logger" - "github.com/instill-ai/pipeline-backend/pkg/service" - "github.com/instill-ai/x/checkfield" - "github.com/instill-ai/x/sterr" - - pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" -) - -// PrivateHandler handles private API -type PrivateHandler struct { - pipelinePB.UnimplementedPipelinePrivateServiceServer - service service.Service -} - -// NewPrivateHandler initiates a handler instance -func NewPrivateHandler(ctx context.Context, s service.Service) pipelinePB.PipelinePrivateServiceServer { - datamodel.InitJSONSchema(ctx) - return &PrivateHandler{ - service: s, - } -} - -// GetService returns the service -func (h *PrivateHandler) GetService() service.Service { - return h.service -} - -// SetService sets the service -func (h *PrivateHandler) SetService(s service.Service) { - h.service = s -} - -func (h *PrivateHandler) ListPipelinesAdmin(ctx context.Context, req *pipelinePB.ListPipelinesAdminRequest) (*pipelinePB.ListPipelinesAdminResponse, error) { - - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), - filtering.DeclareIdent("uid", filtering.TypeString), - filtering.DeclareIdent("id", filtering.TypeString), - filtering.DeclareIdent("description", filtering.TypeString), - // only support "recipe.components.resource_name" for now - filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), - filtering.DeclareIdent("owner", filtering.TypeString), - filtering.DeclareIdent("create_time", filtering.TypeTimestamp), - filtering.DeclareIdent("update_time", filtering.TypeTimestamp), - }...) - if err != nil { - return &pipelinePB.ListPipelinesAdminResponse{}, err - } - - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - return &pipelinePB.ListPipelinesAdminResponse{}, err - } - - pbPipelines, totalSize, nextPageToken, err := h.service.ListPipelinesAdmin(ctx, int64(req.GetPageSize()), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - return &pipelinePB.ListPipelinesAdminResponse{}, err - } - - resp := pipelinePB.ListPipelinesAdminResponse{ - Pipelines: pbPipelines, - NextPageToken: nextPageToken, - TotalSize: int32(totalSize), - } - - return &resp, nil -} - -func (h *PrivateHandler) LookUpPipelineAdmin(ctx context.Context, req *pipelinePB.LookUpPipelineAdminRequest) (*pipelinePB.LookUpPipelineAdminResponse, error) { - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, lookUpPipelineRequiredFields); err != nil { - return &pipelinePB.LookUpPipelineAdminResponse{}, status.Error(codes.InvalidArgument, err.Error()) - } - - view := pipelinePB.LookUpPipelineAdminRequest_VIEW_BASIC - if req.GetView() != pipelinePB.LookUpPipelineAdminRequest_VIEW_UNSPECIFIED { - view = req.GetView() - } - - uid, err := resource.GetRscPermalinkUID(req.GetPermalink()) - if err != nil { - return &pipelinePB.LookUpPipelineAdminResponse{}, err - } - pbPipeline, err := h.service.GetPipelineByUIDAdmin(ctx, uid, service.View(view)) - if err != nil { - return &pipelinePB.LookUpPipelineAdminResponse{}, err - } - - resp := pipelinePB.LookUpPipelineAdminResponse{ - Pipeline: pbPipeline, - } - - return &resp, nil -} - -func (h *PrivateHandler) LookUpOperatorDefinitionAdmin(ctx context.Context, req *pipelinePB.LookUpOperatorDefinitionAdminRequest) (resp *pipelinePB.LookUpOperatorDefinitionAdminResponse, err error) { - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.LookUpOperatorDefinitionAdminResponse{} - - var connID string - - if connID, err = resource.GetRscNameID(req.GetPermalink()); err != nil { - return resp, err - } - - dbDef, err := h.service.GetOperatorDefinitionById(ctx, connID) - if err != nil { - return resp, err - } - resp.OperatorDefinition = proto.Clone(dbDef).(*pipelinePB.OperatorDefinition) - if parseView(int32(*req.GetView().Enum())) == service.VIEW_BASIC { - resp.OperatorDefinition.Spec = nil - } - resp.OperatorDefinition.Name = fmt.Sprintf("operator-definitions/%s", resp.OperatorDefinition.GetId()) - - logger.Info("GetOperatorDefinitionAdmin") - return resp, nil -} - -func (h *PrivateHandler) ListPipelineReleasesAdmin(ctx context.Context, req *pipelinePB.ListPipelineReleasesAdminRequest) (*pipelinePB.ListPipelineReleasesAdminResponse, error) { - - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), - filtering.DeclareIdent("uid", filtering.TypeString), - filtering.DeclareIdent("id", filtering.TypeString), - filtering.DeclareIdent("description", filtering.TypeString), - // only support "recipe.components.resource_name" for now - filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), - filtering.DeclareIdent("owner", filtering.TypeString), - filtering.DeclareIdent("create_time", filtering.TypeTimestamp), - filtering.DeclareIdent("update_time", filtering.TypeTimestamp), - }...) - if err != nil { - return &pipelinePB.ListPipelineReleasesAdminResponse{}, err - } - - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - return &pipelinePB.ListPipelineReleasesAdminResponse{}, err - } - - pbPipelineReleases, totalSize, nextPageToken, err := h.service.ListPipelineReleasesAdmin(ctx, int64(req.GetPageSize()), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - return &pipelinePB.ListPipelineReleasesAdminResponse{}, err - } - - resp := pipelinePB.ListPipelineReleasesAdminResponse{ - Releases: pbPipelineReleases, - NextPageToken: nextPageToken, - TotalSize: int32(totalSize), - } - - return &resp, nil -} - -func (h *PrivateHandler) ListConnectorsAdmin(ctx context.Context, req *pipelinePB.ListConnectorsAdminRequest) (resp *pipelinePB.ListConnectorsAdminResponse, err error) { - - var pageSize int64 - var pageToken string - - resp = &pipelinePB.ListConnectorsAdminResponse{} - pageSize = int64(req.GetPageSize()) - pageToken = req.GetPageToken() - - var connType pipelinePB.ConnectorType - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareEnumIdent("connector_type", connType.Type()), - }...) - if err != nil { - return nil, err - } - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - return nil, err - } - - connectors, totalSize, nextPageToken, err := h.service.ListConnectorsAdmin(ctx, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - return nil, err - } - - resp.Connectors = connectors - resp.NextPageToken = nextPageToken - resp.TotalSize = int32(totalSize) - - return resp, nil - -} - -func (h *PrivateHandler) LookUpConnectorAdmin(ctx context.Context, req *pipelinePB.LookUpConnectorAdminRequest) (resp *pipelinePB.LookUpConnectorAdminResponse, err error) { - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.LookUpConnectorAdminResponse{} - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req, lookUpConnectorRequiredFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] lookup connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - return nil, st.Err() - } - - connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) - if err != nil { - return nil, err - } - - connector, err := h.service.GetConnectorByUIDAdmin(ctx, connUID, parseView(int32(*req.GetView().Enum()))) - if err != nil { - return nil, err - } - - resp.Connector = connector - - return resp, nil -} - -func (h *PrivateHandler) CheckConnector(ctx context.Context, req *pipelinePB.CheckConnectorRequest) (resp *pipelinePB.CheckConnectorResponse, err error) { - - resp = &pipelinePB.CheckConnectorResponse{} - connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) - if err != nil { - return resp, err - } - - connector, err := h.service.GetConnectorByUIDAdmin(ctx, connUID, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - if err != nil { - return nil, err - } - - if connector.Tombstone { - resp.State = pipelinePB.Connector_STATE_ERROR - return resp, nil - } - - if connector.State == pipelinePB.Connector_STATE_CONNECTED { - state, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) - if err != nil { - return resp, err - } - - resp.State = *state - return resp, nil - - } else { - resp.State = pipelinePB.Connector_STATE_DISCONNECTED - return resp, nil - } - -} - -func (h *PrivateHandler) LookUpConnectorDefinitionAdmin(ctx context.Context, req *pipelinePB.LookUpConnectorDefinitionAdminRequest) (resp *pipelinePB.LookUpConnectorDefinitionAdminResponse, err error) { - - resp = &pipelinePB.LookUpConnectorDefinitionAdminResponse{} - - connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) - if err != nil { - return resp, err - } - - // TODO add a service wrapper - def, err := h.service.GetConnectorDefinitionByUIDAdmin(ctx, connUID, parseView(int32(*req.GetView().Enum()))) - if err != nil { - return resp, err - } - resp.ConnectorDefinition = def - - return resp, nil -} diff --git a/pkg/handler/publicHandler.go b/pkg/handler/publicHandler.go deleted file mode 100644 index d9b7861dd..000000000 --- a/pkg/handler/publicHandler.go +++ /dev/null @@ -1,2800 +0,0 @@ -package handler - -import ( - "context" - "fmt" - "net/http" - "strings" - - "strconv" - "time" - - "github.com/gofrs/uuid" - "github.com/iancoleman/strcase" - "go.einride.tech/aip/filtering" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - "golang.org/x/mod/semver" - "google.golang.org/genproto/googleapis/rpc/errdetails" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/structpb" - - fieldmask_utils "github.com/mennanov/fieldmask-utils" - - "github.com/instill-ai/pipeline-backend/internal/resource" - "github.com/instill-ai/pipeline-backend/pkg/constant" - "github.com/instill-ai/pipeline-backend/pkg/datamodel" - "github.com/instill-ai/pipeline-backend/pkg/logger" - - "github.com/instill-ai/pipeline-backend/pkg/repository" - "github.com/instill-ai/pipeline-backend/pkg/service" - "github.com/instill-ai/pipeline-backend/pkg/utils" - "github.com/instill-ai/x/checkfield" - "github.com/instill-ai/x/paginate" - "github.com/instill-ai/x/sterr" - - custom_otel "github.com/instill-ai/pipeline-backend/pkg/logger/otel" - healthcheckPB "github.com/instill-ai/protogen-go/common/healthcheck/v1alpha" - mgmtPB "github.com/instill-ai/protogen-go/core/mgmt/v1alpha" - pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha" -) - -// TODO: in the public_handler, we should convert all id to uuid when calling service - -var tracer = otel.Tracer("pipeline-backend.public-handler.tracer") - -// PublicHandler handles public API -type PublicHandler struct { - pipelinePB.UnimplementedPipelinePublicServiceServer - service service.Service -} - -type Streamer interface { - Context() context.Context -} - -type TriggerPipelineRequestInterface interface { - GetName() string -} - -// NewPublicHandler initiates a handler instance -func NewPublicHandler(ctx context.Context, s service.Service) pipelinePB.PipelinePublicServiceServer { - datamodel.InitJSONSchema(ctx) - return &PublicHandler{ - service: s, - } -} - -// GetService returns the service -func (h *PublicHandler) GetService() service.Service { - return h.service -} - -// SetService sets the service -func (h *PublicHandler) SetService(s service.Service) { - h.service = s -} - -func (h *PublicHandler) Liveness(ctx context.Context, req *pipelinePB.LivenessRequest) (*pipelinePB.LivenessResponse, error) { - return &pipelinePB.LivenessResponse{ - HealthCheckResponse: &healthcheckPB.HealthCheckResponse{ - Status: healthcheckPB.HealthCheckResponse_SERVING_STATUS_SERVING, - }, - }, nil -} - -func (h *PublicHandler) Readiness(ctx context.Context, req *pipelinePB.ReadinessRequest) (*pipelinePB.ReadinessResponse, error) { - return &pipelinePB.ReadinessResponse{ - HealthCheckResponse: &healthcheckPB.HealthCheckResponse{ - Status: healthcheckPB.HealthCheckResponse_SERVING_STATUS_SERVING, - }, - }, nil -} - -func (h *PublicHandler) ListOperatorDefinitions(ctx context.Context, req *pipelinePB.ListOperatorDefinitionsRequest) (resp *pipelinePB.ListOperatorDefinitionsResponse, err error) { - ctx, span := tracer.Start(ctx, "ListOperatorDefinitions", - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.ListOperatorDefinitionsResponse{} - pageSize := req.GetPageSize() - pageToken := req.GetPageToken() - isBasicView := (req.GetView() == pipelinePB.ListOperatorDefinitionsRequest_VIEW_BASIC) || (req.GetView() == pipelinePB.ListOperatorDefinitionsRequest_VIEW_UNSPECIFIED) - - prevLastUid := "" - - if pageToken != "" { - _, prevLastUid, err = paginate.DecodeToken(pageToken) - if err != nil { - st, err := sterr.CreateErrorBadRequest( - fmt.Sprintf("[db] list operator error: %s", err.Error()), - []*errdetails.BadRequest_FieldViolation{ - { - Field: "page_token", - Description: fmt.Sprintf("Invalid page token: %s", err.Error()), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - return nil, st.Err() - } - } - - if pageSize == 0 { - pageSize = repository.DefaultPageSize - } else if pageSize > repository.MaxPageSize { - pageSize = repository.MaxPageSize - } - - defs := h.service.ListOperatorDefinitions(ctx) - - startIdx := 0 - lastUid := "" - for idx, def := range defs { - if def.Uid == prevLastUid { - startIdx = idx + 1 - break - } - } - - page := []*pipelinePB.OperatorDefinition{} - for i := 0; i < int(pageSize) && startIdx+i < len(defs); i++ { - def := proto.Clone(defs[startIdx+i]).(*pipelinePB.OperatorDefinition) - page = append(page, def) - lastUid = def.Uid - } - - nextPageToken := "" - - if startIdx+len(page) < len(defs) { - nextPageToken = paginate.EncodeToken(time.Time{}, lastUid) - } - for _, def := range page { - def.Name = fmt.Sprintf("operator-definitions/%s", def.Id) - if isBasicView { - def.Spec = nil - } - resp.OperatorDefinitions = append( - resp.OperatorDefinitions, - def) - } - resp.NextPageToken = nextPageToken - resp.TotalSize = int32(len(defs)) - - logger.Info("ListOperatorDefinitions") - - return resp, nil -} - -func (h *PublicHandler) GetOperatorDefinition(ctx context.Context, req *pipelinePB.GetOperatorDefinitionRequest) (resp *pipelinePB.GetOperatorDefinitionResponse, err error) { - ctx, span := tracer.Start(ctx, "GetOperatorDefinition", - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.GetOperatorDefinitionResponse{} - - var connID string - - if connID, err = resource.GetRscNameID(req.GetName()); err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - isBasicView := (req.GetView() == pipelinePB.GetOperatorDefinitionRequest_VIEW_BASIC) || (req.GetView() == pipelinePB.GetOperatorDefinitionRequest_VIEW_UNSPECIFIED) - - dbDef, err := h.service.GetOperatorDefinitionById(ctx, connID) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - resp.OperatorDefinition = proto.Clone(dbDef).(*pipelinePB.OperatorDefinition) - if isBasicView { - resp.OperatorDefinition.Spec = nil - } - resp.OperatorDefinition.Name = fmt.Sprintf("operator-definitions/%s", resp.OperatorDefinition.GetId()) - - logger.Info("GetOperatorDefinition") - return resp, nil -} - -func (h *PublicHandler) ListPipelines(ctx context.Context, req *pipelinePB.ListPipelinesRequest) (*pipelinePB.ListPipelinesResponse, error) { - - eventName := "ListPipelines" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListPipelinesResponse{}, err - } - - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), - filtering.DeclareIdent("uid", filtering.TypeString), - filtering.DeclareIdent("id", filtering.TypeString), - filtering.DeclareIdent("description", filtering.TypeString), - // only support "recipe.components.resource_name" for now - filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), - filtering.DeclareIdent("owner", filtering.TypeString), - filtering.DeclareIdent("create_time", filtering.TypeTimestamp), - filtering.DeclareIdent("update_time", filtering.TypeTimestamp), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListPipelinesResponse{}, err - } - - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListPipelinesResponse{}, err - } - - pbPipelines, totalSize, nextPageToken, err := h.service.ListPipelines(ctx, userUid, int64(req.GetPageSize()), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListPipelinesResponse{}, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - - resp := pipelinePB.ListPipelinesResponse{ - Pipelines: pbPipelines, - NextPageToken: nextPageToken, - TotalSize: int32(totalSize), - } - - return &resp, nil -} - -func (h *PublicHandler) CreateUserPipeline(ctx context.Context, req *pipelinePB.CreateUserPipelineRequest) (*pipelinePB.CreateUserPipelineResponse, error) { - - eventName := "CreateUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - // Validate JSON Schema - // if err := datamodel.ValidatePipelineJSONSchema(req.GetPipeline()); err != nil { - // span.SetStatus(1, err.Error()) - // return nil, status.Error(codes.InvalidArgument, err.Error()) - // } - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req.Pipeline, append(createPipelineRequiredFields, immutablePipelineFields...)); err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, status.Error(codes.InvalidArgument, err.Error()) - } - - // Set all OUTPUT_ONLY fields to zero value on the requested payload pipeline resource - if err := checkfield.CheckCreateOutputOnlyFields(req.Pipeline, outputOnlyPipelineFields); err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, status.Error(codes.InvalidArgument, err.Error()) - } - - // Return error if resource ID does not follow RFC-1034 - if err := checkfield.CheckResourceID(req.Pipeline.GetId()); err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, _, err := h.service.GetRscNamespaceAndNameID(req.Parent) - - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, err - } - - _, userUid, err := h.service.GetUser(ctx) - - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, err - } - - pipelineToCreate := req.GetPipeline() - - name, err := h.service.ConvertOwnerPermalinkToName(fmt.Sprintf("users/%s", userUid)) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, err - } - - pipelineToCreate.Owner = &pipelinePB.Pipeline_User{User: name} - - pipeline, err := h.service.CreateUserPipeline(ctx, ns, userUid, pipelineToCreate) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.CreateUserPipelineResponse{}, err - } - - resp := pipelinePB.CreateUserPipelineResponse{ - Pipeline: pipeline, - } - - // Manually set the custom header to have a StatusCreated http response for REST endpoint - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) ListUserPipelines(ctx context.Context, req *pipelinePB.ListUserPipelinesRequest) (*pipelinePB.ListUserPipelinesResponse, error) { - - eventName := "ListUserPipelines" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, _, err := h.service.GetRscNamespaceAndNameID(req.Parent) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListUserPipelinesResponse{}, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListUserPipelinesResponse{}, err - } - - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), - filtering.DeclareIdent("uid", filtering.TypeString), - filtering.DeclareIdent("id", filtering.TypeString), - filtering.DeclareIdent("description", filtering.TypeString), - // only support "recipe.components.resource_name" for now - filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), - filtering.DeclareIdent("owner", filtering.TypeString), - filtering.DeclareIdent("create_time", filtering.TypeTimestamp), - filtering.DeclareIdent("update_time", filtering.TypeTimestamp), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListUserPipelinesResponse{}, err - } - - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListUserPipelinesResponse{}, err - } - - pbPipelines, totalSize, nextPageToken, err := h.service.ListUserPipelines(ctx, ns, userUid, int64(req.GetPageSize()), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - span.SetStatus(1, err.Error()) - return &pipelinePB.ListUserPipelinesResponse{}, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - - resp := pipelinePB.ListUserPipelinesResponse{ - Pipelines: pbPipelines, - NextPageToken: nextPageToken, - TotalSize: int32(totalSize), - } - - return &resp, nil -} - -func (h *PublicHandler) GetUserPipeline(ctx context.Context, req *pipelinePB.GetUserPipelineRequest) (*pipelinePB.GetUserPipelineResponse, error) { - - eventName := "GetUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, id, parseView(int32(*req.GetView().Enum()))) - - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.GetUserPipelineResponse{ - Pipeline: pbPipeline, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) UpdateUserPipeline(ctx context.Context, req *pipelinePB.UpdateUserPipelineRequest) (*pipelinePB.UpdateUserPipelineResponse, error) { - - eventName := "UpdateUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.Pipeline.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipelineReq := req.GetPipeline() - pbUpdateMask := req.GetUpdateMask() - - // metadata field is type google.protobuf.Struct, which needs to be updated as a whole - for idx, path := range pbUpdateMask.Paths { - if strings.Contains(path, "metadata") { - pbUpdateMask.Paths[idx] = "metadata" - } - } - // Validate the field mask - if !pbUpdateMask.IsValid(pbPipelineReq) { - return nil, status.Error(codes.InvalidArgument, "The update_mask is invalid") - } - - getResp, err := h.GetUserPipeline(ctx, &pipelinePB.GetUserPipelineRequest{Name: pbPipelineReq.GetName(), View: pipelinePB.GetUserPipelineRequest_VIEW_RECIPE.Enum()}) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, outputOnlyPipelineFields) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - mask, err := fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - if mask.IsEmpty() { - return &pipelinePB.UpdateUserPipelineResponse{ - Pipeline: getResp.GetPipeline(), - }, nil - } - - pbPipelineToUpdate := getResp.GetPipeline() - - // Return error if IMMUTABLE fields are intentionally changed - if err := checkfield.CheckUpdateImmutableFields(pbPipelineReq, pbPipelineToUpdate, immutablePipelineFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact - err = fieldmask_utils.StructToStruct(mask, pbPipelineReq, pbPipelineToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipeline, err := h.service.UpdateUserPipelineByID(ctx, ns, userUid, id, pbPipelineToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.UpdateUserPipelineResponse{ - Pipeline: pbPipeline, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) DeleteUserPipeline(ctx context.Context, req *pipelinePB.DeleteUserPipelineRequest) (*pipelinePB.DeleteUserPipelineResponse, error) { - - eventName := "DeleteUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - existPipeline, err := h.GetUserPipeline(ctx, &pipelinePB.GetUserPipelineRequest{Name: req.GetName()}) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - if err := h.service.DeleteUserPipelineByID(ctx, ns, userUid, id); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - // We need to manually set the custom header to have a StatusCreated http response for REST endpoint - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(existPipeline.GetPipeline()), - ))) - - return &pipelinePB.DeleteUserPipelineResponse{}, nil -} - -func (h *PublicHandler) LookUpPipeline(ctx context.Context, req *pipelinePB.LookUpPipelineRequest) (*pipelinePB.LookUpPipelineResponse, error) { - - eventName := "LookUpPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, lookUpPipelineRequiredFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - uid, err := resource.GetRscPermalinkUID(req.Permalink) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipeline, err := h.service.GetPipelineByUID(ctx, userUid, uid, parseView(int32(*req.GetView().Enum()))) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.LookUpPipelineResponse{ - Pipeline: pbPipeline, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) ValidateUserPipeline(ctx context.Context, req *pipelinePB.ValidateUserPipelineRequest) (*pipelinePB.ValidateUserPipelineResponse, error) { - - eventName := "ValidateUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipeline, err := h.service.ValidateUserPipelineByID(ctx, ns, userUid, id) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) - } - - resp := pipelinePB.ValidateUserPipelineResponse{ - Pipeline: pbPipeline, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) RenameUserPipeline(ctx context.Context, req *pipelinePB.RenameUserPipelineRequest) (*pipelinePB.RenameUserPipelineResponse, error) { - - eventName := "RenameUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, renamePipelineRequiredFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - newID := req.GetNewPipelineId() - if err := checkfield.CheckResourceID(newID); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - pbPipeline, err := h.service.UpdateUserPipelineIDByID(ctx, ns, userUid, id, newID) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.RenameUserPipelineResponse{ - Pipeline: pbPipeline, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - return &resp, nil -} - -func (h *PublicHandler) preTriggerUserPipeline(ctx context.Context, req TriggerPipelineRequestInterface) (resource.Namespace, uuid.UUID, string, *pipelinePB.Pipeline, bool, error) { - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, triggerPipelineRequiredFields); err != nil { - return resource.Namespace{}, uuid.Nil, "", nil, false, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, id, err := h.service.GetRscNamespaceAndNameID(req.GetName()) - if err != nil { - return ns, uuid.Nil, id, nil, false, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return ns, uuid.Nil, id, nil, false, err - } - - pbPipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, id, service.VIEW_FULL) - if err != nil { - return ns, uuid.Nil, id, nil, false, err - } - _, err = h.service.ValidateUserPipelineByID(ctx, ns, userUid, id) - if err != nil { - return ns, uuid.Nil, id, nil, false, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) - } - returnTraces := false - if md, ok := metadata.FromIncomingContext(ctx); ok { - if len(md.Get(constant.ReturnTracesKey)) > 0 { - returnTraces, err = strconv.ParseBool(md.Get(constant.ReturnTracesKey)[0]) - if err != nil { - return ns, uuid.Nil, id, nil, false, err - } - } - } - - return ns, userUid, id, pbPipeline, returnTraces, nil - -} - -func (h *PublicHandler) TriggerUserPipeline(ctx context.Context, req *pipelinePB.TriggerUserPipelineRequest) (*pipelinePB.TriggerUserPipelineResponse, error) { - - startTime := time.Now() - eventName := "TriggerUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, userUid, id, pbPipeline, returnTraces, err := h.preTriggerUserPipeline(ctx, req) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - dataPoint := utils.PipelineUsageMetricData{ - OwnerUID: userUid.String(), - TriggerMode: mgmtPB.Mode_MODE_SYNC, - PipelineID: pbPipeline.Id, - PipelineUID: pbPipeline.Uid, - PipelineReleaseID: "", - PipelineReleaseUID: uuid.Nil.String(), - PipelineTriggerUID: logUUID.String(), - TriggerTime: startTime.Format(time.RFC3339Nano), - } - - outputs, metadata, err := h.service.TriggerUserPipelineByID(ctx, ns, userUid, id, req.Inputs, logUUID.String(), returnTraces) - if err != nil { - span.SetStatus(1, err.Error()) - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_ERRORED - _ = h.service.WriteNewPipelineDataPoint(ctx, dataPoint) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipeline), - ))) - - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED - if err := h.service.WriteNewPipelineDataPoint(ctx, dataPoint); err != nil { - logger.Warn(err.Error()) - } - - return &pipelinePB.TriggerUserPipelineResponse{Outputs: outputs, Metadata: metadata}, nil -} - -func (h *PublicHandler) TriggerAsyncUserPipeline(ctx context.Context, req *pipelinePB.TriggerAsyncUserPipelineRequest) (*pipelinePB.TriggerAsyncUserPipelineResponse, error) { - - eventName := "TriggerAsyncUserPipeline" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, userUid, id, dbPipeline, returnTraces, err := h.preTriggerUserPipeline(ctx, req) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - operation, err := h.service.TriggerAsyncUserPipelineByID(ctx, ns, userUid, id, req.Inputs, logUUID.String(), returnTraces) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(dbPipeline), - ))) - - return &pipelinePB.TriggerAsyncUserPipelineResponse{ - Operation: operation, - }, nil -} - -func (h *PublicHandler) GetOperation(ctx context.Context, req *pipelinePB.GetOperationRequest) (*pipelinePB.GetOperationResponse, error) { - - operationId, err := resource.GetOperationID(req.Name) - if err != nil { - return &pipelinePB.GetOperationResponse{}, err - } - operation, err := h.service.GetOperation(ctx, operationId) - if err != nil { - return &pipelinePB.GetOperationResponse{}, err - } - - return &pipelinePB.GetOperationResponse{ - Operation: operation, - }, nil -} - -func (h *PublicHandler) CreateUserPipelineRelease(ctx context.Context, req *pipelinePB.CreateUserPipelineReleaseRequest) (*pipelinePB.CreateUserPipelineReleaseResponse, error) { - eventName := "CreateUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req.Release, append(releaseCreateRequiredFields, immutablePipelineFields...)); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - // Set all OUTPUT_ONLY fields to zero value on the requested payload pipeline resource - if err := checkfield.CheckCreateOutputOnlyFields(req.Release, releaseOutputOnlyFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - // Return error if resource ID does not a semantic version - if !semver.IsValid(req.Release.GetId()) { - err := fmt.Errorf("not a sematic version") - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, pipelineId, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - _, err = h.service.ValidateUserPipelineByID(ctx, ns, userUid, pipeline.Id) - if err != nil { - return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("[Pipeline Recipe Error] %+v", err.Error())) - } - - pbPipelineRelease, err := h.service.CreateUserPipelineRelease(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), req.GetRelease()) - if err != nil { - span.SetStatus(1, err.Error()) - // Manually set the custom header to have a StatusBadRequest http response for REST endpoint - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusBadRequest))); err != nil { - return nil, err - } - return nil, err - } - - resp := pipelinePB.CreateUserPipelineReleaseResponse{ - Release: pbPipelineRelease, - } - - // Manually set the custom header to have a StatusCreated http response for REST endpoint - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - return &resp, nil - -} - -func (h *PublicHandler) ListUserPipelineReleases(ctx context.Context, req *pipelinePB.ListUserPipelineReleasesRequest) (*pipelinePB.ListUserPipelineReleasesResponse, error) { - - eventName := "ListUserPipelineReleases" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, err := h.service.GetRscNamespaceAndNameID(req.GetParent()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareFunction("time.now", filtering.NewFunctionOverload("time.now", filtering.TypeTimestamp)), - filtering.DeclareIdent("uid", filtering.TypeString), - filtering.DeclareIdent("id", filtering.TypeString), - filtering.DeclareIdent("description", filtering.TypeString), - // only support "recipe.components.resource_name" for now - filtering.DeclareIdent("recipe", filtering.TypeMap(filtering.TypeString, filtering.TypeMap(filtering.TypeString, filtering.TypeString))), - filtering.DeclareIdent("owner", filtering.TypeString), - filtering.DeclareIdent("create_time", filtering.TypeTimestamp), - filtering.DeclareIdent("update_time", filtering.TypeTimestamp), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - pbPipelineReleases, totalSize, nextPageToken, err := h.service.ListUserPipelineReleases(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), int64(req.GetPageSize()), req.GetPageToken(), parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - - resp := pipelinePB.ListUserPipelineReleasesResponse{ - Releases: pbPipelineReleases, - NextPageToken: nextPageToken, - TotalSize: int32(totalSize), - } - - return &resp, nil - -} - -func (h *PublicHandler) GetUserPipelineRelease(ctx context.Context, req *pipelinePB.GetUserPipelineReleaseRequest) (*pipelinePB.GetUserPipelineReleaseResponse, error) { - - eventName := "GetUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - pbPipelineRelease, err := h.service.GetUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, parseView(int32(*req.GetView().Enum()))) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.GetUserPipelineReleaseResponse{ - Release: pbPipelineRelease, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - return &resp, nil - -} - -func (h *PublicHandler) UpdateUserPipelineRelease(ctx context.Context, req *pipelinePB.UpdateUserPipelineReleaseRequest) (*pipelinePB.UpdateUserPipelineReleaseResponse, error) { - - eventName := "UpdateUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.Release.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - pbPipelineReleaseReq := req.GetRelease() - pbUpdateMask := req.GetUpdateMask() - - // Validate the field mask - if !pbUpdateMask.IsValid(pbPipelineReleaseReq) { - return nil, status.Error(codes.InvalidArgument, "The update_mask is invalid") - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - getResp, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: pbPipelineReleaseReq.GetName()}) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, releaseOutputOnlyFields) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - mask, err := fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - if mask.IsEmpty() { - return &pipelinePB.UpdateUserPipelineReleaseResponse{ - Release: getResp.GetRelease(), - }, nil - } - - pbPipelineReleaseToUpdate := getResp.GetRelease() - - // Return error if IMMUTABLE fields are intentionally changed - if err := checkfield.CheckUpdateImmutableFields(pbPipelineReleaseReq, pbPipelineReleaseToUpdate, immutablePipelineFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact - err = fieldmask_utils.StructToStruct(mask, pbPipelineReleaseReq, pbPipelineReleaseToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipelineRelease, err := h.service.UpdateUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, pbPipelineReleaseToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.UpdateUserPipelineReleaseResponse{ - Release: pbPipelineRelease, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - return &resp, nil -} - -func (h *PublicHandler) RenameUserPipelineRelease(ctx context.Context, req *pipelinePB.RenameUserPipelineReleaseRequest) (*pipelinePB.RenameUserPipelineReleaseResponse, error) { - - eventName := "RenameUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, releaseRenameRequiredFields); err != nil { - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - newID := req.GetNewPipelineReleaseId() - // Return error if resource ID does not a semantic version - if !semver.IsValid(newID) { - err := fmt.Errorf("not a sematic version") - span.SetStatus(1, err.Error()) - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - pbPipelineRelease, err := h.service.UpdateUserPipelineReleaseIDByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, newID) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - resp := pipelinePB.RenameUserPipelineReleaseResponse{ - Release: pbPipelineRelease, - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - return &resp, nil -} - -func (h *PublicHandler) DeleteUserPipelineRelease(ctx context.Context, req *pipelinePB.DeleteUserPipelineReleaseRequest) (*pipelinePB.DeleteUserPipelineReleaseResponse, error) { - - eventName := "DeleteUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - existPipelineRelease, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: req.GetName()}) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - if err := h.service.DeleteUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - // We need to manually set the custom header to have a StatusCreated http response for REST endpoint - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(existPipelineRelease.GetRelease()), - ))) - - return &pipelinePB.DeleteUserPipelineReleaseResponse{}, nil -} - -func (h *PublicHandler) SetDefaultUserPipelineRelease(ctx context.Context, req *pipelinePB.SetDefaultUserPipelineReleaseRequest) (*pipelinePB.SetDefaultUserPipelineReleaseResponse, error) { - - eventName := "SetDefaultUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - existPipelineRelease, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: req.GetName()}) - - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - if err := h.service.SetDefaultUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipelineRelease, err := h.service.GetUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, service.VIEW_FULL) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(existPipelineRelease.GetRelease()), - ))) - - return &pipelinePB.SetDefaultUserPipelineReleaseResponse{Release: pbPipelineRelease}, nil -} - -func (h *PublicHandler) RestoreUserPipelineRelease(ctx context.Context, req *pipelinePB.RestoreUserPipelineReleaseRequest) (*pipelinePB.RestoreUserPipelineReleaseResponse, error) { - - eventName := "RestoreUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - existPipelineRelease, err := h.GetUserPipelineRelease(ctx, &pipelinePB.GetUserPipelineReleaseRequest{Name: req.GetName()}) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - return nil, err - } - - if err := h.service.RestoreUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId); err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - pbPipelineRelease, err := h.service.GetUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, service.VIEW_FULL) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(existPipelineRelease.GetRelease()), - ))) - - return &pipelinePB.RestoreUserPipelineReleaseResponse{Release: pbPipelineRelease}, nil -} - -func (h *PublicHandler) preTriggerUserPipelineRelease(ctx context.Context, req TriggerPipelineRequestInterface) (resource.Namespace, uuid.UUID, string, *pipelinePB.Pipeline, *pipelinePB.PipelineRelease, bool, error) { - - // Return error if REQUIRED fields are not provided in the requested payload pipeline resource - if err := checkfield.CheckRequiredFields(req, triggerPipelineRequiredFields); err != nil { - return resource.Namespace{}, uuid.Nil, "", nil, nil, false, status.Error(codes.InvalidArgument, err.Error()) - } - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - - pbPipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_FULL) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - - pbPipelineRelease, err := h.service.GetUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, service.VIEW_FULL) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - returnTraces := false - if md, ok := metadata.FromIncomingContext(ctx); ok { - if len(md.Get(constant.ReturnTracesKey)) > 0 { - returnTraces, err = strconv.ParseBool(md.Get(constant.ReturnTracesKey)[0]) - if err != nil { - return ns, uuid.Nil, "", nil, nil, false, err - } - } - } - - return ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, nil - -} - -func (h *PublicHandler) TriggerUserPipelineRelease(ctx context.Context, req *pipelinePB.TriggerUserPipelineReleaseRequest) (*pipelinePB.TriggerUserPipelineReleaseResponse, error) { - - startTime := time.Now() - eventName := "TriggerUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, err := h.preTriggerUserPipelineRelease(ctx, req) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - dataPoint := utils.PipelineUsageMetricData{ - OwnerUID: userUid.String(), - TriggerMode: mgmtPB.Mode_MODE_SYNC, - PipelineID: pbPipeline.Id, - PipelineUID: pbPipeline.Uid, - PipelineReleaseID: pbPipelineRelease.Id, - PipelineReleaseUID: pbPipelineRelease.Uid, - PipelineTriggerUID: logUUID.String(), - TriggerTime: startTime.Format(time.RFC3339Nano), - } - - outputs, metadata, err := h.service.TriggerUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, req.Inputs, logUUID.String(), returnTraces) - if err != nil { - span.SetStatus(1, err.Error()) - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_ERRORED - _ = h.service.WriteNewPipelineDataPoint(ctx, dataPoint) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED - if err := h.service.WriteNewPipelineDataPoint(ctx, dataPoint); err != nil { - logger.Warn(err.Error()) - } - - return &pipelinePB.TriggerUserPipelineReleaseResponse{Outputs: outputs, Metadata: metadata}, nil -} - -func (h *PublicHandler) TriggerAsyncUserPipelineRelease(ctx context.Context, req *pipelinePB.TriggerAsyncUserPipelineReleaseRequest) (*pipelinePB.TriggerAsyncUserPipelineReleaseResponse, error) { - - eventName := "TriggerAsyncUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, userUid, releaseId, pbPipeline, pbPipelineRelease, returnTraces, err := h.preTriggerUserPipelineRelease(ctx, req) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - operation, err := h.service.TriggerAsyncUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pbPipeline.Uid), releaseId, req.Inputs, logUUID.String(), returnTraces) - if err != nil { - span.SetStatus(1, err.Error()) - return nil, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(pbPipelineRelease), - ))) - - return &pipelinePB.TriggerAsyncUserPipelineReleaseResponse{Operation: operation}, nil -} - -func (h *PublicHandler) WatchUserPipelineRelease(ctx context.Context, req *pipelinePB.WatchUserPipelineReleaseRequest) (*pipelinePB.WatchUserPipelineReleaseResponse, error) { - - eventName := "WatchUserPipelineRelease" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - ns, pipelineId, releaseId, err := h.service.GetRscNamespaceAndNameIDAndReleaseID(req.GetName()) - if err != nil { - return nil, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - return nil, err - } - releaseId, err = h.service.ConvertReleaseIdAlias(ctx, ns, userUid, pipelineId, releaseId) - if err != nil { - return nil, err - } - - pipeline, err := h.service.GetUserPipelineByID(ctx, ns, userUid, pipelineId, service.VIEW_BASIC) - if err != nil { - span.SetStatus(1, err.Error()) - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetErrorMessage(err.Error()), - custom_otel.SetEventResource(req.GetName()), - ))) - return nil, err - } - - dbPipelineRelease, err := h.service.GetUserPipelineReleaseByID(ctx, ns, userUid, uuid.FromStringOrNil(pipeline.Uid), releaseId, service.VIEW_BASIC) - if err != nil { - span.SetStatus(1, err.Error()) - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetErrorMessage(err.Error()), - custom_otel.SetEventResource(req.GetName()), - ))) - return nil, err - } - state, err := h.service.GetPipelineState(uuid.FromStringOrNil(dbPipelineRelease.Uid)) - if err != nil { - span.SetStatus(1, err.Error()) - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetErrorMessage(err.Error()), - custom_otel.SetEventResource(req.GetName()), - ))) - return nil, err - } - - return &pipelinePB.WatchUserPipelineReleaseResponse{ - State: *state, - }, nil -} - -func (h *PublicHandler) ListConnectorDefinitions(ctx context.Context, req *pipelinePB.ListConnectorDefinitionsRequest) (resp *pipelinePB.ListConnectorDefinitionsResponse, err error) { - ctx, span := tracer.Start(ctx, "ListConnectorDefinitions", - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.ListConnectorDefinitionsResponse{} - pageSize := int64(req.GetPageSize()) - pageToken := req.GetPageToken() - - var connType pipelinePB.ConnectorType - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareEnumIdent("connector_type", connType.Type()), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - defs, totalSize, nextPageToken, err := h.service.ListConnectorDefinitions(ctx, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter) - - if err != nil { - return nil, err - } - - resp.ConnectorDefinitions = defs - resp.NextPageToken = nextPageToken - resp.TotalSize = int32(totalSize) - - logger.Info("ListConnectorDefinitions") - - return resp, nil -} - -func (h *PublicHandler) GetConnectorDefinition(ctx context.Context, req *pipelinePB.GetConnectorDefinitionRequest) (resp *pipelinePB.GetConnectorDefinitionResponse, err error) { - ctx, span := tracer.Start(ctx, "GetConnectorDefinition", - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.GetConnectorDefinitionResponse{} - - var connID string - - if connID, err = resource.GetRscNameID(req.GetName()); err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - dbDef, err := h.service.GetConnectorDefinitionByID(ctx, connID, parseView(int32(*req.GetView().Enum()))) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - resp.ConnectorDefinition = dbDef - - logger.Info("GetConnectorDefinition") - return resp, nil - -} - -func (h *PublicHandler) ListConnectors(ctx context.Context, req *pipelinePB.ListConnectorsRequest) (resp *pipelinePB.ListConnectorsResponse, err error) { - - eventName := "ListConnectors" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var pageSize int64 - var pageToken string - - resp = &pipelinePB.ListConnectorsResponse{} - pageSize = int64(req.GetPageSize()) - pageToken = req.GetPageToken() - - var connType pipelinePB.ConnectorType - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareEnumIdent("connector_type", connType.Type()), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connectors, totalSize, nextPageToken, err := h.service.ListConnectors(ctx, userUid, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - - resp.Connectors = connectors - resp.NextPageToken = nextPageToken - resp.TotalSize = int32(totalSize) - - return resp, nil - -} - -func (h *PublicHandler) LookUpConnector(ctx context.Context, req *pipelinePB.LookUpConnectorRequest) (resp *pipelinePB.LookUpConnectorResponse, err error) { - - eventName := "LookUpConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.LookUpConnectorResponse{} - - connUID, err := resource.GetRscPermalinkUID(req.GetPermalink()) - if err != nil { - return nil, err - } - - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req, lookUpConnectorRequiredFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] lookup connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - connector, err := h.service.GetConnectorByUID(ctx, userUid, connUID, parseView(int32(*req.GetView().Enum())), true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.Connector = connector - - return resp, nil -} - -func (h *PublicHandler) CreateUserConnector(ctx context.Context, req *pipelinePB.CreateUserConnectorRequest) (resp *pipelinePB.CreateUserConnectorResponse, err error) { - - eventName := "CreateUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - resp = &pipelinePB.CreateUserConnectorResponse{} - - ns, _, err := h.service.GetRscNamespaceAndNameID(req.Parent) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - userId, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - // TODO: ACL - if ns.String() != resource.UserUidToUserPermalink(userUid) { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Description: "can not create in other user's namespace", - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - // Set all OUTPUT_ONLY fields to zero value on the requested payload - if err := checkfield.CheckCreateOutputOnlyFields(req.GetConnector(), outputOnlyConnectorFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "OUTPUT_ONLY fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req.GetConnector(), append(createConnectorRequiredFields, immutableConnectorFields...)); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - connID = req.GetConnector().GetId() - if len(connID) > 8 && connID[:8] == "instill-" { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "connector", - Description: "the id can not start with instill-", - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - // Return error if resource ID does not follow RFC-1034 - if err := checkfield.CheckResourceID(connID); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "id", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - req.Connector.Owner = &pipelinePB.Connector_User{User: fmt.Sprintf("users/%s", userId)} - - connector, err := h.service.CreateUserConnector(ctx, ns, userUid, req.Connector) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.Connector = connector - - if err != nil { - return resp, err - } - - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusCreated))); err != nil { - return resp, err - } - - return resp, nil -} - -func (h *PublicHandler) ListUserConnectors(ctx context.Context, req *pipelinePB.ListUserConnectorsRequest) (resp *pipelinePB.ListUserConnectorsResponse, err error) { - - eventName := "ListUserConnectors" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var pageSize int64 - var pageToken string - - resp = &pipelinePB.ListUserConnectorsResponse{} - pageSize = int64(req.GetPageSize()) - pageToken = req.GetPageToken() - - var connType pipelinePB.ConnectorType - declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{ - filtering.DeclareStandardFunctions(), - filtering.DeclareEnumIdent("connector_type", connType.Type()), - }...) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - filter, err := filtering.ParseFilter(req, declarations) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - ns, _, err := h.service.GetRscNamespaceAndNameID(req.Parent) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connectors, totalSize, nextPageToken, err := h.service.ListUserConnectors(ctx, ns, userUid, pageSize, pageToken, parseView(int32(*req.GetView().Enum())), filter, req.GetShowDeleted()) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - - resp.Connectors = connectors - resp.NextPageToken = nextPageToken - resp.TotalSize = int32(totalSize) - - return resp, nil - -} - -func (h *PublicHandler) GetUserConnector(ctx context.Context, req *pipelinePB.GetUserConnectorRequest) (resp *pipelinePB.GetUserConnectorResponse, err error) { - eventName := "GetUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.GetUserConnectorResponse{} - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, parseView(int32(*req.GetView().Enum())), true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - resp.Connector = connector - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - return resp, nil -} - -func (h *PublicHandler) UpdateUserConnector(ctx context.Context, req *pipelinePB.UpdateUserConnectorRequest) (resp *pipelinePB.UpdateUserConnectorResponse, err error) { - - eventName := "UpdateUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var mask fieldmask_utils.Mask - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Connector.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - resp = &pipelinePB.UpdateUserConnectorResponse{} - - pbConnectorReq := req.GetConnector() - pbUpdateMask := req.GetUpdateMask() - - // configuration filed is type google.protobuf.Struct, which needs to be updated as a whole - for idx, path := range pbUpdateMask.Paths { - if strings.Contains(path, "configuration") { - pbUpdateMask.Paths[idx] = "configuration" - } - } - - if !pbUpdateMask.IsValid(req.GetConnector()) { - st, err := sterr.CreateErrorBadRequest( - "[handler] update connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "update_mask", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - // Remove all OUTPUT_ONLY fields in the requested payload - pbUpdateMask, err = checkfield.CheckUpdateOutputOnlyFields(pbUpdateMask, outputOnlyConnectorFields) - if err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] update connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "OUTPUT_ONLY fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - existedConnector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, false) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - // Return error if IMMUTABLE fields are intentionally changed - if err := checkfield.CheckUpdateImmutableFields(req.GetConnector(), existedConnector, immutableConnectorFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] update connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "IMMUTABLE fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - mask, err = fieldmask_utils.MaskFromProtoFieldMask(pbUpdateMask, strcase.ToCamel) - if err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] update connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "update_mask", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - if mask.IsEmpty() { - existedConnector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - return &pipelinePB.UpdateUserConnectorResponse{ - Connector: existedConnector, - }, nil - } - - pbConnectorToUpdate := existedConnector - if pbConnectorToUpdate.State == pipelinePB.Connector_STATE_CONNECTED { - st, err := sterr.CreateErrorPreconditionFailure( - "[service] update connector", - []*errdetails.PreconditionFailure_Violation{ - { - Type: "UPDATE", - Subject: fmt.Sprintf("id %s", req.Connector.Id), - Description: fmt.Sprintf("Cannot update a connected %s connector", req.Connector.Id), - }, - }) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return nil, st.Err() - } - - dbConnDefID, err := resource.GetRscNameID(existedConnector.GetConnectorDefinitionName()) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - configuration := &structpb.Struct{} - h.service.KeepCredentialFieldsWithMaskString(dbConnDefID, pbConnectorToUpdate.Configuration) - proto.Merge(configuration, pbConnectorToUpdate.Configuration) - - // Only the fields mentioned in the field mask will be copied to `pbPipelineToUpdate`, other fields are left intact - err = fieldmask_utils.StructToStruct(mask, pbConnectorReq, pbConnectorToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - h.service.RemoveCredentialFieldsWithMaskString(dbConnDefID, req.Connector.Configuration) - proto.Merge(configuration, req.Connector.Configuration) - pbConnectorToUpdate.Configuration = configuration - - connector, err := h.service.UpdateUserConnectorByID(ctx, ns, userUid, connID, pbConnectorToUpdate) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - resp.Connector = connector - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - return resp, nil -} - -func (h *PublicHandler) DeleteUserConnector(ctx context.Context, req *pipelinePB.DeleteUserConnectorRequest) (resp *pipelinePB.DeleteUserConnectorResponse, err error) { - - eventName := "DeleteUserConnectorByID" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - // Cast all used types and data - - resp = &pipelinePB.DeleteUserConnectorResponse{} - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - dbConnector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - if err := h.service.DeleteUserConnectorByID(ctx, ns, userUid, connID); err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(dbConnector), - ))) - - if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.Itoa(http.StatusNoContent))); err != nil { - return resp, err - } - return resp, nil -} - -func (h *PublicHandler) ConnectUserConnector(ctx context.Context, req *pipelinePB.ConnectUserConnectorRequest) (resp *pipelinePB.ConnectUserConnectorResponse, err error) { - - eventName := "ConnectUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - resp = &pipelinePB.ConnectUserConnectorResponse{} - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req, connectConnectorRequiredFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] connect connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - state, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) - - if err != nil { - st, _ := sterr.CreateErrorBadRequest( - fmt.Sprintf("[handler] connect connector error %v", err), - []*errdetails.BadRequest_FieldViolation{}, - ) - span.SetStatus(1, fmt.Sprintf("connect connector error %v", err)) - return resp, st.Err() - } - if *state != pipelinePB.Connector_STATE_CONNECTED { - st, _ := sterr.CreateErrorBadRequest( - "[handler] connect connector error not Connector_STATE_CONNECTED", - []*errdetails.BadRequest_FieldViolation{}, - ) - span.SetStatus(1, "connect connector error not Connector_STATE_CONNECTED") - return resp, st.Err() - } - - connector, err = h.service.UpdateUserConnectorStateByID(ctx, ns, userUid, connID, *state) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.Connector = connector - - return resp, nil -} - -func (h *PublicHandler) DisconnectUserConnector(ctx context.Context, req *pipelinePB.DisconnectUserConnectorRequest) (resp *pipelinePB.DisconnectUserConnectorResponse, err error) { - - eventName := "DisconnectUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - resp = &pipelinePB.DisconnectUserConnectorResponse{} - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req, disconnectConnectorRequiredFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] disconnect connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.UpdateUserConnectorStateByID(ctx, ns, userUid, connID, pipelinePB.Connector_STATE_DISCONNECTED) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.Connector = connector - - return resp, nil -} - -func (h *PublicHandler) RenameUserConnector(ctx context.Context, req *pipelinePB.RenameUserConnectorRequest) (resp *pipelinePB.RenameUserConnectorResponse, err error) { - - eventName := "RenameUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - var connNewID string - - resp = &pipelinePB.RenameUserConnectorResponse{} - - // Return error if REQUIRED fields are not provided in the requested payload - if err := checkfield.CheckRequiredFields(req, renameConnectorRequiredFields); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] rename connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "REQUIRED fields", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - connNewID = req.GetNewConnectorId() - if len(connNewID) > 8 && connNewID[:8] == "instill-" { - st, err := sterr.CreateErrorBadRequest( - "[handler] create connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "connector", - Description: "the id can not start with instill-", - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - // Return error if resource ID does not follow RFC-1034 - if err := checkfield.CheckResourceID(connNewID); err != nil { - st, err := sterr.CreateErrorBadRequest( - "[handler] rename connector error", - []*errdetails.BadRequest_FieldViolation{ - { - Field: "id", - Description: err.Error(), - }, - }, - ) - if err != nil { - logger.Error(err.Error()) - } - span.SetStatus(1, st.Err().Error()) - return resp, st.Err() - } - - connector, err := h.service.UpdateUserConnectorIDByID(ctx, ns, userUid, connID, connNewID) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.Connector = connector - return resp, nil -} - -func (h *PublicHandler) WatchUserConnector(ctx context.Context, req *pipelinePB.WatchUserConnectorRequest) (resp *pipelinePB.WatchUserConnectorResponse, err error) { - - eventName := "WatchUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - resp = &pipelinePB.WatchUserConnectorResponse{} - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) - if err != nil { - span.SetStatus(1, err.Error()) - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetErrorMessage(err.Error()), - ))) - return resp, err - } - - state, err := h.service.GetConnectorState(uuid.FromStringOrNil(connector.Uid)) - - if err != nil { - span.SetStatus(1, err.Error()) - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetErrorMessage(err.Error()), - custom_otel.SetEventResource(connector), - ))) - state = pipelinePB.Connector_STATE_ERROR.Enum() - } - - resp.State = *state - - return resp, nil -} - -func (h *PublicHandler) TestUserConnector(ctx context.Context, req *pipelinePB.TestUserConnectorRequest) (resp *pipelinePB.TestUserConnectorResponse, err error) { - - eventName := "TestUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - var connID string - - resp = &pipelinePB.TestUserConnectorResponse{} - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_BASIC, true) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - state, err := h.service.CheckConnectorByUID(ctx, uuid.FromStringOrNil(connector.Uid)) - - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - custom_otel.SetEventResource(connector), - ))) - - resp.State = *state - - return resp, nil -} - -func (h *PublicHandler) ExecuteUserConnector(ctx context.Context, req *pipelinePB.ExecuteUserConnectorRequest) (resp *pipelinePB.ExecuteUserConnectorResponse, err error) { - - startTime := time.Now() - eventName := "ExecuteUserConnector" - - ctx, span := tracer.Start(ctx, eventName, - trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() - - logUUID, _ := uuid.NewV4() - - logger, _ := logger.GetZapLogger(ctx) - - resp = &pipelinePB.ExecuteUserConnectorResponse{} - ns, connID, err := h.service.GetRscNamespaceAndNameID(req.Name) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - _, userUid, err := h.service.GetUser(ctx) - if err != nil { - span.SetStatus(1, err.Error()) - return resp, err - } - - connector, err := h.service.GetUserConnectorByID(ctx, ns, userUid, connID, service.VIEW_FULL, true) - if err != nil { - return resp, err - } - if connector.Tombstone { - st, _ := sterr.CreateErrorPreconditionFailure( - "ExecuteConnector", - []*errdetails.PreconditionFailure_Violation{ - { - Type: "STATE", - Subject: fmt.Sprintf("id %s", connID), - Description: "the connector definition is deprecated, you can not use it anymore", - }, - }) - return resp, st.Err() - } - - dataPoint := utils.ConnectorUsageMetricData{ - OwnerUID: userUid.String(), - ConnectorID: connector.Id, - ConnectorUID: connector.Uid, - ConnectorExecuteUID: logUUID.String(), - ConnectorDefinitionUid: connector.ConnectorDefinition.Uid, - ExecuteTime: startTime.Format(time.RFC3339Nano), - } - - md, _ := metadata.FromIncomingContext(ctx) - - pipelineVal := &structpb.Value{} - if len(md.Get("id")) > 0 && - len(md.Get("uid")) > 0 && - len(md.Get("release_id")) > 0 && - len(md.Get("release_uid")) > 0 && - len(md.Get("owner")) > 0 && - len(md.Get("trigger_id")) > 0 { - pipelineVal, _ = structpb.NewValue(map[string]interface{}{ - "id": md.Get("id")[0], - "uid": md.Get("uid")[0], - "release_id": md.Get("release_id")[0], - "release_uid": md.Get("release_uid")[0], - "owner": md.Get("owner")[0], - "trigger_id": md.Get("trigger_id")[0], - }) - } - - if outputs, err := h.service.Execute(ctx, ns, userUid, connID, req.GetTask(), req.GetInputs()); err != nil { - span.SetStatus(1, err.Error()) - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_ERRORED - _ = h.service.WriteNewConnectorDataPoint(ctx, dataPoint, pipelineVal) - return nil, err - } else { - resp.Outputs = outputs - logger.Info(string(custom_otel.NewLogMessage( - span, - logUUID.String(), - userUid, - eventName, - ))) - dataPoint.ComputeTimeDuration = time.Since(startTime).Seconds() - dataPoint.Status = mgmtPB.Status_STATUS_COMPLETED - if err := h.service.WriteNewConnectorDataPoint(ctx, dataPoint, pipelineVal); err != nil { - logger.Warn("usage and metric data write fail") - } - } - return resp, nil - -} diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go index 1efd4f137..8c15ce78e 100644 --- a/pkg/repository/repository.go +++ b/pkg/repository/repository.go @@ -38,22 +38,22 @@ type Repository interface { ListPipelines(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool, code string) (*datamodel.Pipeline, error) - CreateUserPipeline(ctx context.Context, ownerPermalink string, userPermalink string, pipeline *datamodel.Pipeline) error - ListUserPipelines(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) - GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error) - - UpdateUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, pipeline *datamodel.Pipeline) error - DeleteUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string) error - UpdateUserPipelineIDByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, newID string) error - - CreateUserPipelineRelease(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, pipelineRelease *datamodel.PipelineRelease) error - ListUserPipelineReleases(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.PipelineRelease, int64, string, error) - GetUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, isBasicView bool) (*datamodel.PipelineRelease, error) - GetUserPipelineReleaseByUID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, uid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) - UpdateUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, pipelineRelease *datamodel.PipelineRelease) error - DeleteUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string) error - UpdateUserPipelineReleaseIDByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, newID string) error - GetLatestUserPipelineRelease(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) + CreateNamespacePipeline(ctx context.Context, ownerPermalink string, pipeline *datamodel.Pipeline) error + ListNamespacePipelines(ctx context.Context, ownerPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) + GetNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error) + + UpdateNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string, pipeline *datamodel.Pipeline) error + DeleteNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string) error + UpdateNamespacePipelineIDByID(ctx context.Context, ownerPermalink string, id string, newID string) error + + CreateNamespacePipelineRelease(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, pipelineRelease *datamodel.PipelineRelease) error + ListNamespacePipelineReleases(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.PipelineRelease, int64, string, error) + GetNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, isBasicView bool) (*datamodel.PipelineRelease, error) + GetNamespacePipelineReleaseByUID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, uid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) + UpdateNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, pipelineRelease *datamodel.PipelineRelease) error + DeleteNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string) error + UpdateNamespacePipelineReleaseIDByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, newID string) error + GetLatestNamespacePipelineRelease(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) ListPipelinesAdmin(ctx context.Context, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) GetPipelineByIDAdmin(ctx context.Context, id string, isBasicView bool) (*datamodel.Pipeline, error) @@ -63,13 +63,13 @@ type Repository interface { ListConnectors(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Connector, int64, string, error) GetConnectorByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool) (*datamodel.Connector, error) - CreateUserConnector(ctx context.Context, ownerPermalink string, userPermalink string, connector *datamodel.Connector) error - ListUserConnectors(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Connector, int64, string, error) - GetUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool) (*datamodel.Connector, error) - UpdateUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, connector *datamodel.Connector) error - DeleteUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string) error - UpdateUserConnectorIDByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, newID string) error - UpdateUserConnectorStateByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, state datamodel.ConnectorState) error + CreateNamespaceConnector(ctx context.Context, ownerPermalink string, connector *datamodel.Connector) error + ListNamespaceConnectors(ctx context.Context, ownerPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Connector, int64, string, error) + GetNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string, isBasicView bool) (*datamodel.Connector, error) + UpdateNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string, connector *datamodel.Connector) error + DeleteNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string) error + UpdateNamespaceConnectorIDByID(ctx context.Context, ownerPermalink string, id string, newID string) error + UpdateNamespaceConnectorStateByID(ctx context.Context, ownerPermalink string, id string, state datamodel.ConnectorState) error ListConnectorsAdmin(ctx context.Context, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Connector, int64, string, error) GetConnectorByUIDAdmin(ctx context.Context, uid uuid.UUID, isBasicView bool) (*datamodel.Connector, error) @@ -86,7 +86,7 @@ func NewRepository(db *gorm.DB) Repository { } } -func (r *repository) CreateUserPipeline(ctx context.Context, ownerPermalink string, userPermalink string, pipeline *datamodel.Pipeline) error { +func (r *repository) CreateNamespacePipeline(ctx context.Context, ownerPermalink string, pipeline *datamodel.Pipeline) error { if result := r.db.Model(&datamodel.Pipeline{}).Create(pipeline); result.Error != nil { var pgErr *pgconn.PgError if errors.As(result.Error, &pgErr) { @@ -229,14 +229,14 @@ func (r *repository) listPipelines(ctx context.Context, where string, whereArgs func (r *repository) ListPipelines(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) { return r.listPipelines(ctx, - "(owner = ? OR (permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}'))", + "(owner = ?)", []interface{}{userPermalink}, pageSize, pageToken, isBasicView, filter, showDeleted) } -func (r *repository) ListUserPipelines(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) { +func (r *repository) ListNamespacePipelines(ctx context.Context, ownerPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) { return r.listPipelines(ctx, - "(owner = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR ? = ?))", - []interface{}{ownerPermalink, ownerPermalink, userPermalink}, + "(owner = ?)", + []interface{}{ownerPermalink}, pageSize, pageToken, isBasicView, filter, showDeleted) } @@ -244,7 +244,7 @@ func (r *repository) ListPipelinesAdmin(ctx context.Context, pageSize int64, pag return r.listPipelines(ctx, "", []interface{}{}, pageSize, pageToken, isBasicView, filter, showDeleted) } -func (r *repository) getUserPipeline(ctx context.Context, where string, whereArgs []interface{}, isBasicView bool) (*datamodel.Pipeline, error) { +func (r *repository) getNamespacePipeline(ctx context.Context, where string, whereArgs []interface{}, isBasicView bool) (*datamodel.Pipeline, error) { logger, _ := logger.GetZapLogger(ctx) var pipeline datamodel.Pipeline @@ -258,7 +258,7 @@ func (r *repository) getUserPipeline(ctx context.Context, where string, whereArg if result := queryBuilder.First(&pipeline); result.Error != nil { st, err := sterr.CreateErrorResourceInfo( codes.NotFound, - fmt.Sprintf("[db] getUserPipeline error: %s", result.Error.Error()), + fmt.Sprintf("[db] getNamespacePipeline error: %s", result.Error.Error()), "pipeline", "", "", @@ -272,38 +272,38 @@ func (r *repository) getUserPipeline(ctx context.Context, where string, whereArg return &pipeline, nil } -func (r *repository) GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error) { - return r.getUserPipeline(ctx, - "(id = ? AND owner = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR (permission @> '{\"share_code\":{\"user\":\"users/*\", \"role\": \"ROLE_VIEWER\", \"enabled\": true}}' AND share_code = ?) OR ? = ?))", - []interface{}{id, ownerPermalink, code, ownerPermalink, userPermalink}, +func (r *repository) GetNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error) { + return r.getNamespacePipeline(ctx, + "(id = ? AND owner = ? )", + []interface{}{id, ownerPermalink}, isBasicView) } func (r *repository) GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool, code string) (*datamodel.Pipeline, error) { // TODO: ACL - return r.getUserPipeline(ctx, - "(uid = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR (permission @> '{\"share_code\":{\"user\":\"users/*\", \"role\": \"ROLE_VIEWER\", \"enabled\": true}}' AND share_code = ?) OR owner = ?))", - []interface{}{uid, code, userPermalink}, + return r.getNamespacePipeline(ctx, + "(uid = ?)", + []interface{}{uid}, isBasicView) } func (r *repository) GetPipelineByIDAdmin(ctx context.Context, id string, isBasicView bool) (*datamodel.Pipeline, error) { - return r.getUserPipeline(ctx, + return r.getNamespacePipeline(ctx, "(id = ?)", []interface{}{id}, isBasicView) } func (r *repository) GetPipelineByUIDAdmin(ctx context.Context, uid uuid.UUID, isBasicView bool) (*datamodel.Pipeline, error) { - return r.getUserPipeline(ctx, + return r.getNamespacePipeline(ctx, "(uid = ?)", []interface{}{uid}, isBasicView) } -func (r *repository) UpdateUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, pipeline *datamodel.Pipeline) error { +func (r *repository) UpdateNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string, pipeline *datamodel.Pipeline) error { if result := r.db.Model(&datamodel.Pipeline{}). - Where("(id = ? AND owner = ? AND ? = ? )", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ?)", id, ownerPermalink). Updates(pipeline); result.Error != nil { return status.Error(codes.Internal, result.Error.Error()) } else if result.RowsAffected == 0 { @@ -312,9 +312,9 @@ func (r *repository) UpdateUserPipelineByID(ctx context.Context, ownerPermalink return nil } -func (r *repository) DeleteUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string) error { +func (r *repository) DeleteNamespacePipelineByID(ctx context.Context, ownerPermalink string, id string) error { result := r.db.Model(&datamodel.Pipeline{}). - Where("(id = ? AND owner = ? AND ? = ? )", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ?)", id, ownerPermalink). Delete(&datamodel.Pipeline{}) if result.Error != nil { @@ -328,9 +328,9 @@ func (r *repository) DeleteUserPipelineByID(ctx context.Context, ownerPermalink return nil } -func (r *repository) UpdateUserPipelineIDByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, newID string) error { +func (r *repository) UpdateNamespacePipelineIDByID(ctx context.Context, ownerPermalink string, id string, newID string) error { if result := r.db.Model(&datamodel.Pipeline{}). - Where("(id = ? AND owner = ? AND ? = ? )", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ?)", id, ownerPermalink). Update("id", newID); result.Error != nil { return status.Error(codes.Internal, result.Error.Error()) } else if result.RowsAffected == 0 { @@ -346,7 +346,7 @@ func (r *repository) transpileFilter(filter filtering.Filter) (*clause.Expr, err }).Transpile() } -func (r *repository) CreateUserPipelineRelease(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, pipelineRelease *datamodel.PipelineRelease) error { +func (r *repository) CreateNamespacePipelineRelease(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, pipelineRelease *datamodel.PipelineRelease) error { if result := r.db.Model(&datamodel.PipelineRelease{}).Create(pipelineRelease); result.Error != nil { var pgErr *pgconn.PgError if errors.As(result.Error, &pgErr) { @@ -358,7 +358,7 @@ func (r *repository) CreateUserPipelineRelease(ctx context.Context, ownerPermali return nil } -func (r *repository) ListUserPipelineReleases(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) (pipelineReleases []*datamodel.PipelineRelease, totalSize int64, nextPageToken string, err error) { +func (r *repository) ListNamespacePipelineReleases(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) (pipelineReleases []*datamodel.PipelineRelease, totalSize int64, nextPageToken string, err error) { db := r.db if showDeleted { @@ -503,7 +503,7 @@ func (r *repository) ListPipelineReleasesAdmin(ctx context.Context, pageSize int return pipelineReleases, totalSize, nextPageToken, nil } -func (r *repository) GetUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, isBasicView bool) (*datamodel.PipelineRelease, error) { +func (r *repository) GetNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, isBasicView bool) (*datamodel.PipelineRelease, error) { queryBuilder := r.db.Model(&datamodel.PipelineRelease{}).Where("id = ? AND pipeline_uid = ?", id, pipelineUid) if isBasicView { queryBuilder.Omit("pipeline_release.recipe") @@ -515,7 +515,7 @@ func (r *repository) GetUserPipelineReleaseByID(ctx context.Context, ownerPermal return &pipelineRelease, nil } -func (r *repository) GetUserPipelineReleaseByUID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, uid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) { +func (r *repository) GetNamespacePipelineReleaseByUID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, uid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) { queryBuilder := r.db.Model(&datamodel.PipelineRelease{}).Where("uid = ? AND pipeline_uid = ?", uid, pipelineUid) if isBasicView { queryBuilder.Omit("pipeline_release.recipe") @@ -527,7 +527,7 @@ func (r *repository) GetUserPipelineReleaseByUID(ctx context.Context, ownerPerma return &pipelineRelease, nil } -func (r *repository) UpdateUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, pipelineRelease *datamodel.PipelineRelease) error { +func (r *repository) UpdateNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, pipelineRelease *datamodel.PipelineRelease) error { if result := r.db.Model(&datamodel.PipelineRelease{}). Where("id = ? AND pipeline_uid = ?", id, pipelineUid). Updates(pipelineRelease); result.Error != nil { @@ -538,7 +538,7 @@ func (r *repository) UpdateUserPipelineReleaseByID(ctx context.Context, ownerPer return nil } -func (r *repository) DeleteUserPipelineReleaseByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string) error { +func (r *repository) DeleteNamespacePipelineReleaseByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string) error { result := r.db.Model(&datamodel.PipelineRelease{}). Where("id = ? AND pipeline_uid = ?", id, pipelineUid). Delete(&datamodel.PipelineRelease{}) @@ -554,7 +554,7 @@ func (r *repository) DeleteUserPipelineReleaseByID(ctx context.Context, ownerPer return nil } -func (r *repository) UpdateUserPipelineReleaseIDByID(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, id string, newID string) error { +func (r *repository) UpdateNamespacePipelineReleaseIDByID(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, id string, newID string) error { if result := r.db.Model(&datamodel.PipelineRelease{}). Where("id = ? AND pipeline_uid = ?", id, pipelineUid). Update("id", newID); result.Error != nil { @@ -565,7 +565,7 @@ func (r *repository) UpdateUserPipelineReleaseIDByID(ctx context.Context, ownerP return nil } -func (r *repository) GetLatestUserPipelineRelease(ctx context.Context, ownerPermalink string, userPermalink string, pipelineUid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) { +func (r *repository) GetLatestNamespacePipelineRelease(ctx context.Context, ownerPermalink string, pipelineUid uuid.UUID, isBasicView bool) (*datamodel.PipelineRelease, error) { queryBuilder := r.db.Model(&datamodel.PipelineRelease{}).Where("pipeline_uid = ?", pipelineUid).Order("id DESC") if isBasicView { queryBuilder.Omit("pipeline_release.recipe") @@ -713,22 +713,22 @@ func (r *repository) ListConnectorsAdmin(ctx context.Context, pageSize int64, pa func (r *repository) ListConnectors(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) (connectors []*datamodel.Connector, totalSize int64, nextPageToken string, err error) { return r.listConnectors(ctx, - "(owner = ? OR visibility = ?)", - []interface{}{userPermalink, VisibilityPublic}, + "(owner = ?)", + []interface{}{userPermalink}, pageSize, pageToken, isBasicView, filter, showDeleted) } -func (r *repository) ListUserConnectors(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) (connectors []*datamodel.Connector, totalSize int64, nextPageToken string, err error) { +func (r *repository) ListNamespaceConnectors(ctx context.Context, ownerPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) (connectors []*datamodel.Connector, totalSize int64, nextPageToken string, err error) { return r.listConnectors(ctx, - "(owner = ? AND (visibility = ? OR ? = ?))", - []interface{}{ownerPermalink, VisibilityPublic, ownerPermalink, userPermalink}, + "(owner = ? )", + []interface{}{ownerPermalink}, pageSize, pageToken, isBasicView, filter, showDeleted) } -func (r *repository) CreateUserConnector(ctx context.Context, ownerPermalink string, userPermalink string, connector *datamodel.Connector) error { +func (r *repository) CreateNamespaceConnector(ctx context.Context, ownerPermalink string, connector *datamodel.Connector) error { logger, _ := logger.GetZapLogger(ctx) @@ -754,7 +754,7 @@ func (r *repository) CreateUserConnector(ctx context.Context, ownerPermalink str return nil } -func (r *repository) getUserConnector(ctx context.Context, where string, whereArgs []interface{}, isBasicView bool) (*datamodel.Connector, error) { +func (r *repository) getNamespaceConnector(ctx context.Context, where string, whereArgs []interface{}, isBasicView bool) (*datamodel.Connector, error) { logger, _ := logger.GetZapLogger(ctx) var connector datamodel.Connector @@ -768,7 +768,7 @@ func (r *repository) getUserConnector(ctx context.Context, where string, whereAr if result := queryBuilder.First(&connector); result.Error != nil { st, err := sterr.CreateErrorResourceInfo( codes.NotFound, - fmt.Sprintf("[db] getUserConnector error: %s", result.Error.Error()), + fmt.Sprintf("[db] getNamespaceConnector error: %s", result.Error.Error()), "connector", "", "", @@ -782,37 +782,37 @@ func (r *repository) getUserConnector(ctx context.Context, where string, whereAr return &connector, nil } -func (r *repository) GetUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool) (*datamodel.Connector, error) { +func (r *repository) GetNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string, isBasicView bool) (*datamodel.Connector, error) { - return r.getUserConnector(ctx, - "(id = ? AND (owner = ? AND (visibility = ? OR ? = ?)))", - []interface{}{id, ownerPermalink, VisibilityPublic, ownerPermalink, userPermalink}, + return r.getNamespaceConnector(ctx, + "(id = ? AND (owner = ?))", + []interface{}{id, ownerPermalink}, isBasicView) } func (r *repository) GetConnectorByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool) (*datamodel.Connector, error) { // TODO: ACL - return r.getUserConnector(ctx, - "(uid = ? AND (visibility = ? OR owner = ?))", - []interface{}{uid, VisibilityPublic, userPermalink}, + return r.getNamespaceConnector(ctx, + "(uid = ? AND (owner = ?))", + []interface{}{uid, userPermalink}, isBasicView) } func (r *repository) GetConnectorByUIDAdmin(ctx context.Context, uid uuid.UUID, isBasicView bool) (*datamodel.Connector, error) { - return r.getUserConnector(ctx, + return r.getNamespaceConnector(ctx, "(uid = ?)", []interface{}{uid}, isBasicView) } -func (r *repository) UpdateUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, connector *datamodel.Connector) error { +func (r *repository) UpdateNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string, connector *datamodel.Connector) error { logger, _ := logger.GetZapLogger(ctx) if result := r.db.Model(&datamodel.Connector{}). - Where("(id = ? AND owner = ? AND ? = ? )", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ? )", id, ownerPermalink). Updates(connector); result.Error != nil { st, err := sterr.CreateErrorResourceInfo( codes.Internal, @@ -843,12 +843,12 @@ func (r *repository) UpdateUserConnectorByID(ctx context.Context, ownerPermalink return nil } -func (r *repository) DeleteUserConnectorByID(ctx context.Context, ownerPermalink string, userPermalink string, id string) error { +func (r *repository) DeleteNamespaceConnectorByID(ctx context.Context, ownerPermalink string, id string) error { logger, _ := logger.GetZapLogger(ctx) result := r.db.Model(&datamodel.Connector{}). - Where("(id = ? AND owner = ? AND ? = ?)", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ? )", id, ownerPermalink). Delete(&datamodel.Connector{}) if result.Error != nil { @@ -884,12 +884,12 @@ func (r *repository) DeleteUserConnectorByID(ctx context.Context, ownerPermalink return nil } -func (r *repository) UpdateUserConnectorIDByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, newID string) error { +func (r *repository) UpdateNamespaceConnectorIDByID(ctx context.Context, ownerPermalink string, id string, newID string) error { logger, _ := logger.GetZapLogger(ctx) if result := r.db.Model(&datamodel.Connector{}). - Where("(id = ? AND owner = ? AND ? = ?)", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ?)", id, ownerPermalink). Update("id", newID); result.Error != nil { st, err := sterr.CreateErrorResourceInfo( codes.Internal, @@ -920,12 +920,12 @@ func (r *repository) UpdateUserConnectorIDByID(ctx context.Context, ownerPermali return nil } -func (r *repository) UpdateUserConnectorStateByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, state datamodel.ConnectorState) error { +func (r *repository) UpdateNamespaceConnectorStateByID(ctx context.Context, ownerPermalink string, id string, state datamodel.ConnectorState) error { logger, _ := logger.GetZapLogger(ctx) if result := r.db.Model(&datamodel.Connector{}). - Where("(id = ? AND owner = ? AND ? = ?)", id, ownerPermalink, ownerPermalink, userPermalink). + Where("(id = ? AND owner = ?)", id, ownerPermalink). Update("state", state); result.Error != nil { st, err := sterr.CreateErrorResourceInfo( codes.Internal, diff --git a/pkg/service/convert.go b/pkg/service/convert.go index 301d9162c..16b55d329 100644 --- a/pkg/service/convert.go +++ b/pkg/service/convert.go @@ -29,7 +29,7 @@ const ( VIEW_RECIPE View = 3 ) -func (s *service) recipeNameToPermalink(userUid uuid.UUID, recipeRscName *pipelinePB.Recipe) (*pipelinePB.Recipe, error) { +func (s *service) recipeNameToPermalink(recipeRscName *pipelinePB.Recipe) (*pipelinePB.Recipe, error) { recipePermalink := &pipelinePB.Recipe{Version: recipeRscName.Version} for _, component := range recipeRscName.Components { @@ -41,7 +41,7 @@ func (s *service) recipeNameToPermalink(userUid uuid.UUID, recipeRscName *pipeli permalink := "" var err error if utils.IsConnectorWithNamespace(component.ResourceName) { - permalink, err = s.connectorNameToPermalink(userUid, component.ResourceName) + permalink, err = s.connectorNameToPermalink(component.ResourceName) if err != nil { // Allow not created resource componentPermalink.ResourceName = "" @@ -110,13 +110,13 @@ func (s *service) recipePermalinkToName(recipePermalink *pipelinePB.Recipe) (*pi return recipe, nil } -func (s *service) connectorNameToPermalink(userUid uuid.UUID, name string) (string, error) { +func (s *service) connectorNameToPermalink(name string) (string, error) { - ownerPermalink, err := s.ConvertOwnerNameToPermalink(fmt.Sprintf("users/%s", strings.Split(name, "/")[1])) + ownerPermalink, err := s.ConvertOwnerNameToPermalink(fmt.Sprintf("%s/%s", strings.Split(name, "/")[0], strings.Split(name, "/")[1])) if err != nil { return "", err } - dbConnector, err := s.repository.GetUserConnectorByID(context.Background(), ownerPermalink, fmt.Sprintf("users/%s", userUid), strings.Split(name, "/")[3], true) + dbConnector, err := s.repository.GetNamespaceConnectorByID(context.Background(), ownerPermalink, strings.Split(name, "/")[3], true) if err != nil { return "", err } @@ -263,7 +263,7 @@ func (s *service) includeDetailInRecipe(recipe *pipelinePB.Recipe) error { } // PBToDBPipeline converts protobuf data model to db data model -func (s *service) PBToDBPipeline(ctx context.Context, userUid uuid.UUID, pbPipeline *pipelinePB.Pipeline) (*datamodel.Pipeline, error) { +func (s *service) PBToDBPipeline(ctx context.Context, pbPipeline *pipelinePB.Pipeline) (*datamodel.Pipeline, error) { logger, _ := logger.GetZapLogger(ctx) var owner string @@ -275,14 +275,14 @@ func (s *service) PBToDBPipeline(ctx context.Context, userUid uuid.UUID, pbPipel if err != nil { return nil, err } - case *pipelinePB.Pipeline_Org: + case *pipelinePB.Pipeline_Organization: return nil, fmt.Errorf("org not supported") } recipe := &datamodel.Recipe{} if pbPipeline.GetRecipe() != nil { - recipePermalink, err := s.recipeNameToPermalink(userUid, pbPipeline.Recipe) + recipePermalink, err := s.recipeNameToPermalink(pbPipeline.Recipe) if err != nil { return nil, err } @@ -491,8 +491,8 @@ func (s *service) DBToPBPipeline(ctx context.Context, dbPipeline *datamodel.Pipe if strings.HasPrefix(dbPipeline.Owner, "users/") { pbPipeline.Owner = &pipelinePB.Pipeline_User{User: owner} - } else if strings.HasPrefix(dbPipeline.Owner, "orgs/") { - pbPipeline.Owner = &pipelinePB.Pipeline_Org{Org: owner} + } else if strings.HasPrefix(dbPipeline.Owner, "organizations/") { + pbPipeline.Owner = &pipelinePB.Pipeline_Organization{Organization: owner} } return &pbPipeline, nil @@ -517,12 +517,12 @@ func (s *service) DBToPBPipelines(ctx context.Context, dbPipelines []*datamodel. } // PBToDBPipelineRelease converts protobuf data model to db data model -func (s *service) PBToDBPipelineRelease(ctx context.Context, userUid uuid.UUID, pipelineUid uuid.UUID, pbPipelineRelease *pipelinePB.PipelineRelease) (*datamodel.PipelineRelease, error) { +func (s *service) PBToDBPipelineRelease(ctx context.Context, pipelineUid uuid.UUID, pbPipelineRelease *pipelinePB.PipelineRelease) (*datamodel.PipelineRelease, error) { logger, _ := logger.GetZapLogger(ctx) recipe := &datamodel.Recipe{} if pbPipelineRelease.GetRecipe() != nil { - recipePermalink, err := s.recipeNameToPermalink(userUid, pbPipelineRelease.Recipe) + recipePermalink, err := s.recipeNameToPermalink(pbPipelineRelease.Recipe) if err != nil { return nil, err } @@ -772,7 +772,7 @@ func (s *service) convertProtoToDatamodel( if err != nil { return nil, err } - case *pipelinePB.Connector_Org: + case *pipelinePB.Connector_Organization: return nil, fmt.Errorf("org not supported") } @@ -860,7 +860,7 @@ func (s *service) convertDatamodelToProto( if strings.HasPrefix(owner, "users/") { pbConnector.Owner = &pipelinePB.Connector_User{User: owner} } else if strings.HasPrefix(owner, "organizations/") { - pbConnector.Owner = &pipelinePB.Connector_Org{Org: owner} + pbConnector.Owner = &pipelinePB.Connector_Organization{Organization: owner} } if view != VIEW_BASIC { if credentialMask { diff --git a/pkg/service/mock_user_grpc_test.go b/pkg/service/mock_user_grpc_test.go index b66970770..0e61faa91 100644 --- a/pkg/service/mock_user_grpc_test.go +++ b/pkg/service/mock_user_grpc_test.go @@ -36,26 +36,6 @@ func (m *MockMgmtPrivateServiceClient) EXPECT() *MockMgmtPrivateServiceClientMoc return m.recorder } -// CreateUserAdmin mocks base method. -func (m *MockMgmtPrivateServiceClient) CreateUserAdmin(arg0 context.Context, arg1 *mgmtv1alpha.CreateUserAdminRequest, arg2 ...grpc.CallOption) (*mgmtv1alpha.CreateUserAdminResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateUserAdmin", varargs...) - ret0, _ := ret[0].(*mgmtv1alpha.CreateUserAdminResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateUserAdmin indicates an expected call of CreateUserAdmin. -func (mr *MockMgmtPrivateServiceClientMockRecorder) CreateUserAdmin(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserAdmin", reflect.TypeOf((*MockMgmtPrivateServiceClient)(nil).CreateUserAdmin), varargs...) -} - // GetUserAdmin mocks base method. func (m *MockMgmtPrivateServiceClient) GetUserAdmin(arg0 context.Context, arg1 *mgmtv1alpha.GetUserAdminRequest, arg2 ...grpc.CallOption) (*mgmtv1alpha.GetUserAdminResponse, error) { m.ctrl.T.Helper() diff --git a/pkg/service/service.go b/pkg/service/service.go index f99b87b14..d24487dbe 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -58,32 +58,32 @@ type Service interface { GetOperatorDefinitionById(ctx context.Context, defId string) (*pipelinePB.OperatorDefinition, error) ListOperatorDefinitions(ctx context.Context) []*pipelinePB.OperatorDefinition - ListPipelines(ctx context.Context, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) + ListPipelines(ctx context.Context, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) GetPipelineByUID(ctx context.Context, userUid uuid.UUID, uid uuid.UUID, view View) (*pipelinePB.Pipeline, error) - CreateUserPipeline(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) - ListUserPipelines(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) - GetUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View) (*pipelinePB.Pipeline, error) - UpdateUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, updatedPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) - UpdateUserPipelineIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Pipeline, error) - DeleteUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error - ValidateUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (*pipelinePB.Pipeline, error) - GetUserPipelineDefaultReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) - GetUserPipelineLatestReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) - - ListPipelinesAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) + CreateNamespacePipeline(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) + ListNamespacePipelines(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) + GetNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View) (*pipelinePB.Pipeline, error) + UpdateNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, updatedPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) + UpdateNamespacePipelineIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Pipeline, error) + DeleteNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error + ValidateNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (*pipelinePB.Pipeline, error) + GetNamespacePipelineDefaultReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) + GetNamespacePipelineLatestReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) + + ListPipelinesAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) GetPipelineByUIDAdmin(ctx context.Context, uid uuid.UUID, view View) (*pipelinePB.Pipeline, error) - CreateUserPipelineRelease(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) - ListUserPipelineReleases(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int64, string, error) - GetUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, view View) (*pipelinePB.PipelineRelease, error) - GetUserPipelineReleaseByUID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, uid uuid.UUID, view View) (*pipelinePB.PipelineRelease, error) - UpdateUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, updatedPipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) - DeleteUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error - RestoreUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error - SetDefaultUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error - UpdateUserPipelineReleaseIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, newID string) (*pipelinePB.PipelineRelease, error) + CreateNamespacePipelineRelease(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) + ListNamespacePipelineReleases(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int32, string, error) + GetNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, view View) (*pipelinePB.PipelineRelease, error) + GetNamespacePipelineReleaseByUID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, uid uuid.UUID, view View) (*pipelinePB.PipelineRelease, error) + UpdateNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, updatedPipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) + DeleteNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error + RestoreNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error + SetDefaultNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error + UpdateNamespacePipelineReleaseIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, newID string) (*pipelinePB.PipelineRelease, error) - ListPipelineReleasesAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int64, string, error) + ListPipelineReleasesAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int32, string, error) // Controller APIs GetPipelineState(uid uuid.UUID) (*pipelinePB.State, error) @@ -92,11 +92,11 @@ type Service interface { // Influx API - TriggerUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) - TriggerAsyncUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) + TriggerNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) + TriggerAsyncNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) - TriggerUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) - TriggerAsyncUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) + TriggerNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) + TriggerAsyncNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, req []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) GetOperation(ctx context.Context, workflowId string) (*longrunningpb.Operation, error) WriteNewPipelineDataPoint(ctx context.Context, data utils.PipelineUsageMetricData) error @@ -108,32 +108,32 @@ type Service interface { ConvertOwnerNameToPermalink(name string) (string, error) ConvertReleaseIdAlias(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineId string, releaseId string) (string, error) - PBToDBPipeline(ctx context.Context, userUid uuid.UUID, pbPipeline *pipelinePB.Pipeline) (*datamodel.Pipeline, error) + PBToDBPipeline(ctx context.Context, pbPipeline *pipelinePB.Pipeline) (*datamodel.Pipeline, error) DBToPBPipeline(ctx context.Context, dbPipeline *datamodel.Pipeline, view View) (*pipelinePB.Pipeline, error) DBToPBPipelines(ctx context.Context, dbPipeline []*datamodel.Pipeline, view View) ([]*pipelinePB.Pipeline, error) - PBToDBPipelineRelease(ctx context.Context, userUid uuid.UUID, pipelineUid uuid.UUID, pbPipelineRelease *pipelinePB.PipelineRelease) (*datamodel.PipelineRelease, error) + PBToDBPipelineRelease(ctx context.Context, pipelineUid uuid.UUID, pbPipelineRelease *pipelinePB.PipelineRelease) (*datamodel.PipelineRelease, error) DBToPBPipelineRelease(ctx context.Context, dbPipelineRelease *datamodel.PipelineRelease, view View, latestUUID uuid.UUID, defaultUUID uuid.UUID) (*pipelinePB.PipelineRelease, error) DBToPBPipelineReleases(ctx context.Context, dbPipelineRelease []*datamodel.PipelineRelease, view View, latestUUID uuid.UUID, defaultUUID uuid.UUID) ([]*pipelinePB.PipelineRelease, error) - GetUser(ctx context.Context) (string, uuid.UUID, error) + GetCtxUser(ctx context.Context) (string, uuid.UUID, error) - ListConnectorDefinitions(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter) ([]*pipelinePB.ConnectorDefinition, int64, string, error) + ListConnectorDefinitions(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter) ([]*pipelinePB.ConnectorDefinition, int32, string, error) GetConnectorByUID(ctx context.Context, userUid uuid.UUID, uid uuid.UUID, view View, credentialMask bool) (*pipelinePB.Connector, error) GetConnectorDefinitionByID(ctx context.Context, id string, view View) (*pipelinePB.ConnectorDefinition, error) GetConnectorDefinitionByUIDAdmin(ctx context.Context, uid uuid.UUID, view View) (*pipelinePB.ConnectorDefinition, error) // Connector common - ListConnectors(ctx context.Context, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) - CreateUserConnector(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) - ListUserConnectors(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) - GetUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View, credentialMask bool) (*pipelinePB.Connector, error) - UpdateUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) - UpdateUserConnectorIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Connector, error) - UpdateUserConnectorStateByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, state pipelinePB.Connector_State) (*pipelinePB.Connector, error) - DeleteUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error - - ListConnectorsAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) + ListConnectors(ctx context.Context, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) + CreateNamespaceConnector(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) + ListNamespaceConnectors(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) + GetNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View, credentialMask bool) (*pipelinePB.Connector, error) + UpdateNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) + UpdateNamespaceConnectorIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Connector, error) + UpdateNamespaceConnectorStateByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, state pipelinePB.Connector_State) (*pipelinePB.Connector, error) + DeleteNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error + + ListConnectorsAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) GetConnectorByUIDAdmin(ctx context.Context, uid uuid.UUID, view View) (*pipelinePB.Connector, error) // Execute connector @@ -205,8 +205,7 @@ func GenerateShareCode() string { return randomStrWithCharset(32, charset) } -// GetUserPermalink returns the api user -func (s *service) GetUser(ctx context.Context) (string, uuid.UUID, error) { +func (s *service) GetCtxUser(ctx context.Context) (string, uuid.UUID, error) { // Verify if "jwt-sub" is in the header headerUserUId := resource.GetRequestSingleHeader(ctx, constant.HeaderUserUIDKey) if headerUserUId != "" { @@ -232,18 +231,35 @@ func (s *service) getCode(ctx context.Context) string { } func (s *service) ConvertOwnerPermalinkToName(permalink string) (string, error) { - userResp, err := s.mgmtPrivateServiceClient.LookUpUserAdmin(context.Background(), &mgmtPB.LookUpUserAdminRequest{Permalink: permalink}) - if err != nil { - return "", fmt.Errorf("ConvertNamespaceToOwnerPath error") + if strings.HasPrefix(permalink, "users") { + userResp, err := s.mgmtPrivateServiceClient.LookUpUserAdmin(context.Background(), &mgmtPB.LookUpUserAdminRequest{Permalink: permalink}) + if err != nil { + return "", fmt.Errorf("ConvertNamespaceToOwnerPath error") + } + return fmt.Sprintf("users/%s", userResp.User.Id), nil + } else { + userResp, err := s.mgmtPrivateServiceClient.LookUpOrganizationAdmin(context.Background(), &mgmtPB.LookUpOrganizationAdminRequest{Permalink: permalink}) + if err != nil { + return "", fmt.Errorf("ConvertNamespaceToOwnerPath error") + } + return fmt.Sprintf("organizations/%s", userResp.Organization.Id), nil } - return fmt.Sprintf("users/%s", userResp.User.Id), nil } + func (s *service) ConvertOwnerNameToPermalink(name string) (string, error) { - userResp, err := s.mgmtPrivateServiceClient.GetUserAdmin(context.Background(), &mgmtPB.GetUserAdminRequest{Name: name}) - if err != nil { - return "", fmt.Errorf("ConvertOwnerNameToPermalink error") + if strings.HasPrefix(name, "users") { + userResp, err := s.mgmtPrivateServiceClient.GetUserAdmin(context.Background(), &mgmtPB.GetUserAdminRequest{Name: name}) + if err != nil { + return "", fmt.Errorf("ConvertOwnerNameToPermalink error") + } + return fmt.Sprintf("users/%s", *userResp.User.Uid), nil + } else { + orgResp, err := s.mgmtPrivateServiceClient.GetOrganizationAdmin(context.Background(), &mgmtPB.GetOrganizationAdminRequest{Name: name}) + if err != nil { + return "", fmt.Errorf("ConvertOwnerNameToPermalink error") + } + return fmt.Sprintf("organizations/%s", orgResp.Organization.Uid), nil } - return fmt.Sprintf("users/%s", *userResp.User.Uid), nil } func (s *service) GetRscNamespaceAndNameID(path string) (resource.Namespace, string, error) { @@ -305,33 +321,33 @@ func (s *service) GetRscNamespaceAndNameIDAndReleaseID(path string) (resource.Na func (s *service) ConvertReleaseIdAlias(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineId string, releaseId string) (string, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) // TODO: simplify these if releaseId == "default" { - releaseUid, err := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipelineId) + releaseUid, err := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipelineId) if err != nil { return "", err } - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, pipelineId, true, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, pipelineId, true, s.getCode(ctx)) if err != nil { return "", err } - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByUID(ctx, ownerPermalink, userPermalink, dbPipeline.UID, releaseUid, true) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByUID(ctx, ownerPermalink, dbPipeline.UID, releaseUid, true) if err != nil { return "", err } return dbPipelineRelease.ID, nil } else if releaseId == "latest" { - releaseUid, err := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipelineId) + releaseUid, err := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipelineId) if err != nil { return "", err } - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, pipelineId, true, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, pipelineId, true, s.getCode(ctx)) if err != nil { return "", err } - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByUID(ctx, ownerPermalink, userPermalink, dbPipeline.UID, releaseUid, true) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByUID(ctx, ownerPermalink, dbPipeline.UID, releaseUid, true) if err != nil { return "", err } @@ -349,15 +365,15 @@ func (s *service) ListOperatorDefinitions(ctx context.Context) []*pipelinePB.Ope return s.operator.ListOperatorDefinitions() } -func (s *service) ListPipelines(ctx context.Context, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) { +func (s *service) ListPipelines(ctx context.Context, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) { userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelines, totalSize, nextPageToken, err := s.repository.ListPipelines(ctx, userPermalink, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbPipelines, totalSize, nextPageToken, err := s.repository.ListPipelines(ctx, userPermalink, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbPipelines, err := s.DBToPBPipelines(ctx, dbPipelines, view) - return pbPipelines, totalSize, nextPageToken, err + return pbPipelines, int32(totalSize), nextPageToken, err } @@ -373,12 +389,12 @@ func (s *service) GetPipelineByUID(ctx context.Context, userUid uuid.UUID, uid u return s.DBToPBPipeline(ctx, dbPipeline, view) } -func (s *service) CreateUserPipeline(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pbPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) { +func (s *service) CreateNamespacePipeline(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pbPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.PBToDBPipeline(ctx, userUid, pbPipeline) + dbPipeline, err := s.PBToDBPipeline(ctx, pbPipeline) if err != nil { return nil, status.Errorf(codes.InvalidArgument, err.Error()) @@ -388,11 +404,11 @@ func (s *service) CreateUserPipeline(ctx context.Context, ns resource.Namespace, dbPipeline.ShareCode = GenerateShareCode() } - if err := s.repository.CreateUserPipeline(ctx, ownerPermalink, userPermalink, dbPipeline); err != nil { + if err := s.repository.CreateNamespacePipeline(ctx, ownerPermalink, dbPipeline); err != nil { return nil, err } - dbCreatedPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, dbPipeline.ID, false, s.getCode(ctx)) + dbCreatedPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, dbPipeline.ID, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -400,37 +416,37 @@ func (s *service) CreateUserPipeline(ctx context.Context, ns resource.Namespace, return s.DBToPBPipeline(ctx, dbCreatedPipeline, VIEW_FULL) } -func (s *service) ListUserPipelines(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) { +func (s *service) ListNamespacePipelines(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelines, ps, pt, err := s.repository.ListUserPipelines(ctx, ownerPermalink, userPermalink, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + // userPermalink := resource.UserUidToUserPermalink(userUid) + dbPipelines, ps, pt, err := s.repository.ListNamespacePipelines(ctx, ownerPermalink, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbPipelines, err := s.DBToPBPipelines(ctx, dbPipelines, view) - return pbPipelines, ps, pt, err + return pbPipelines, int32(ps), pt, err } -func (s *service) ListPipelinesAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int64, string, error) { +func (s *service) ListPipelinesAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Pipeline, int32, string, error) { - dbPipelines, ps, pt, err := s.repository.ListPipelinesAdmin(ctx, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbPipelines, ps, pt, err := s.repository.ListPipelinesAdmin(ctx, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbPipelines, err := s.DBToPBPipelines(ctx, dbPipelines, view) - return pbPipelines, ps, pt, err + return pbPipelines, int32(ps), pt, err } -func (s *service) GetUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View) (*pipelinePB.Pipeline, error) { +func (s *service) GetNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View) (*pipelinePB.Pipeline, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, view == VIEW_BASIC, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, view == VIEW_BASIC, s.getCode(ctx)) if err != nil { return nil, err } @@ -438,12 +454,12 @@ func (s *service) GetUserPipelineByID(ctx context.Context, ns resource.Namespace return s.DBToPBPipeline(ctx, dbPipeline, view) } -func (s *service) GetUserPipelineDefaultReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) { +func (s *service) GetNamespacePipelineDefaultReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, true, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, true, s.getCode(ctx)) if err != nil { return uuid.Nil, err } @@ -451,17 +467,17 @@ func (s *service) GetUserPipelineDefaultReleaseUid(ctx context.Context, ns resou return dbPipeline.DefaultReleaseUID, nil } -func (s *service) GetUserPipelineLatestReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) { +func (s *service) GetNamespacePipelineLatestReleaseUid(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (uuid.UUID, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, true, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, true, s.getCode(ctx)) if err != nil { return uuid.Nil, err } - dbPipelineRelease, err := s.repository.GetLatestUserPipelineRelease(ctx, ownerPermalink, userPermalink, dbPipeline.UID, true) + dbPipelineRelease, err := s.repository.GetLatestNamespacePipelineRelease(ctx, ownerPermalink, dbPipeline.UID, true) if err != nil { return uuid.Nil, err } @@ -480,18 +496,18 @@ func (s *service) GetPipelineByUIDAdmin(ctx context.Context, uid uuid.UUID, view } -func (s *service) UpdateUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, toUpdPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) { +func (s *service) UpdateNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, toUpdPipeline *pipelinePB.Pipeline) (*pipelinePB.Pipeline, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineToCreate, err := s.PBToDBPipeline(ctx, userUid, toUpdPipeline) + dbPipelineToCreate, err := s.PBToDBPipeline(ctx, toUpdPipeline) if err != nil { return nil, err } var existingPipeline *datamodel.Pipeline // Validation: Pipeline existence - if existingPipeline, _ = s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, true, s.getCode(ctx)); existingPipeline == nil { + if existingPipeline, _ = s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, true, s.getCode(ctx)); existingPipeline == nil { return nil, status.Errorf(codes.NotFound, "Pipeline id %s is not found", id) } // TODO: use ACL @@ -503,11 +519,11 @@ func (s *service) UpdateUserPipelineByID(ctx context.Context, ns resource.Namesp dbPipelineToCreate.ShareCode = GenerateShareCode() } - if err := s.repository.UpdateUserPipelineByID(ctx, ownerPermalink, userPermalink, id, dbPipelineToCreate); err != nil { + if err := s.repository.UpdateNamespacePipelineByID(ctx, ownerPermalink, id, dbPipelineToCreate); err != nil { return nil, err } - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, toUpdPipeline.Id, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, toUpdPipeline.Id, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -515,11 +531,11 @@ func (s *service) UpdateUserPipelineByID(ctx context.Context, ns resource.Namesp return s.DBToPBPipeline(ctx, dbPipeline, VIEW_FULL) } -func (s *service) DeleteUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error { +func (s *service) DeleteNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, false, s.getCode(ctx)) if err != nil { return err } @@ -529,26 +545,26 @@ func (s *service) DeleteUserPipelineByID(ctx context.Context, ns resource.Namesp } // TODO: pagination - pipelineReleases, _, _, err := s.repository.ListUserPipelineReleases(ctx, ownerPermalink, userPermalink, dbPipeline.UID, 1000, "", false, filtering.Filter{}, false) + pipelineReleases, _, _, err := s.repository.ListNamespacePipelineReleases(ctx, ownerPermalink, dbPipeline.UID, 1000, "", false, filtering.Filter{}, false) if err != nil { return err } for _, pipelineRelease := range pipelineReleases { - err := s.DeleteUserPipelineReleaseByID(ctx, ns, userUid, dbPipeline.UID, pipelineRelease.ID) + err := s.DeleteNamespacePipelineReleaseByID(ctx, ns, userUid, dbPipeline.UID, pipelineRelease.ID) if err != nil { return err } } - return s.repository.DeleteUserPipelineByID(ctx, ownerPermalink, userPermalink, id) + return s.repository.DeleteNamespacePipelineByID(ctx, ownerPermalink, id) } -func (s *service) ValidateUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (*pipelinePB.Pipeline, error) { +func (s *service) ValidateNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) (*pipelinePB.Pipeline, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -566,7 +582,7 @@ func (s *service) ValidateUserPipelineByID(ctx context.Context, ns resource.Name return nil, recipeErr } - dbPipeline, err = s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, false, s.getCode(ctx)) + dbPipeline, err = s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -575,13 +591,13 @@ func (s *service) ValidateUserPipelineByID(ctx context.Context, ns resource.Name } -func (s *service) UpdateUserPipelineIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Pipeline, error) { +func (s *service) UpdateNamespacePipelineIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Pipeline, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) // Validation: Pipeline existence - existingPipeline, _ := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, true, s.getCode(ctx)) + existingPipeline, _ := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, true, s.getCode(ctx)) if existingPipeline == nil { return nil, status.Errorf(codes.NotFound, "Pipeline id %s is not found", id) } @@ -591,11 +607,11 @@ func (s *service) UpdateUserPipelineIDByID(ctx context.Context, ns resource.Name return nil, status.Errorf(codes.PermissionDenied, "Permission Denied") } - if err := s.repository.UpdateUserPipelineIDByID(ctx, ownerPermalink, userPermalink, id, newID); err != nil { + if err := s.repository.UpdateNamespacePipelineIDByID(ctx, ownerPermalink, id, newID); err != nil { return nil, err } - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, newID, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, newID, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -748,7 +764,7 @@ func (s *service) getOperationFromWorkflowInfo(workflowExecutionInfo *workflowpb if err != nil { return nil, err } - resp.TypeUrl = "buf.build/instill-ai/protobufs/vdp.pipeline.v1alpha.TriggerUserPipelineResponse" + resp.TypeUrl = "buf.build/instill-ai/protobufs/vdp.pipeline.v1alpha.TriggerNamespacePipelineResponse" operation = longrunningpb.Operation{ Done: true, Result: &longrunningpb.Operation_Response{ @@ -780,7 +796,7 @@ func (s *service) getOperationFromWorkflowInfo(workflowExecutionInfo *workflowpb return &operation, nil } -func (s *service) CreateUserPipelineRelease(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) { +func (s *service) CreateNamespacePipelineRelease(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pipelineRelease *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) @@ -797,16 +813,16 @@ func (s *service) CreateUserPipelineRelease(ctx context.Context, ns resource.Nam pipelineRelease.Recipe = proto.Clone(pipeline.Recipe).(*pipelinePB.Recipe) pipelineRelease.Metadata = proto.Clone(pipeline.Metadata).(*structpb.Struct) - dbPipelineReleaseToCreate, err := s.PBToDBPipelineRelease(ctx, userUid, pipelineUid, pipelineRelease) + dbPipelineReleaseToCreate, err := s.PBToDBPipelineRelease(ctx, pipelineUid, pipelineRelease) if err != nil { return nil, err } - if err := s.repository.CreateUserPipelineRelease(ctx, ownerPermalink, userPermalink, pipelineUid, dbPipelineReleaseToCreate); err != nil { + if err := s.repository.CreateNamespacePipelineRelease(ctx, ownerPermalink, pipelineUid, dbPipelineReleaseToCreate); err != nil { return nil, err } - dbCreatedPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, pipelineRelease.Id, false) + dbCreatedPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, pipelineRelease.Id, false) if err != nil { return nil, err } @@ -815,18 +831,18 @@ func (s *service) CreateUserPipelineRelease(ctx context.Context, ns resource.Nam return nil, err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) return s.DBToPBPipelineRelease(ctx, dbCreatedPipelineRelease, VIEW_FULL, latestUUID, defaultUUID) } -func (s *service) ListUserPipelineReleases(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int64, string, error) { +func (s *service) ListNamespacePipelineReleases(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int32, string, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineReleases, ps, pt, err := s.repository.ListUserPipelineReleases(ctx, ownerPermalink, userPermalink, pipelineUid, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbPipelineReleases, ps, pt, err := s.repository.ListNamespacePipelineReleases(ctx, ownerPermalink, pipelineUid, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } @@ -835,29 +851,29 @@ func (s *service) ListUserPipelineReleases(ctx context.Context, ns resource.Name if err != nil { return nil, 0, "", err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) pbPipelineReleases, err := s.DBToPBPipelineReleases(ctx, dbPipelineReleases, view, latestUUID, defaultUUID) - return pbPipelineReleases, ps, pt, err + return pbPipelineReleases, int32(ps), pt, err } -func (s *service) ListPipelineReleasesAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int64, string, error) { +func (s *service) ListPipelineReleasesAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.PipelineRelease, int32, string, error) { - dbPipelineReleases, ps, pt, err := s.repository.ListPipelineReleasesAdmin(ctx, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbPipelineReleases, ps, pt, err := s.repository.ListPipelineReleasesAdmin(ctx, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbPipelineReleases, err := s.DBToPBPipelineReleases(ctx, dbPipelineReleases, view, uuid.Nil, uuid.Nil) - return pbPipelineReleases, ps, pt, err + return pbPipelineReleases, int32(ps), pt, err } -func (s *service) GetUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, view View) (*pipelinePB.PipelineRelease, error) { +func (s *service) GetNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, view View) (*pipelinePB.PipelineRelease, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, view == VIEW_BASIC) + // userPermalink := resource.UserUidToUserPermalink(userUid) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, view == VIEW_BASIC) if err != nil { return nil, err } @@ -866,17 +882,17 @@ func (s *service) GetUserPipelineReleaseByID(ctx context.Context, ns resource.Na if err != nil { return nil, err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) return s.DBToPBPipelineRelease(ctx, dbPipelineRelease, view, latestUUID, defaultUUID) } -func (s *service) GetUserPipelineReleaseByUID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, uid uuid.UUID, view View) (*pipelinePB.PipelineRelease, error) { +func (s *service) GetNamespacePipelineReleaseByUID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, uid uuid.UUID, view View) (*pipelinePB.PipelineRelease, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByUID(ctx, ownerPermalink, userPermalink, pipelineUid, uid, view == VIEW_BASIC) + // userPermalink := resource.UserUidToUserPermalink(userUid) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByUID(ctx, ownerPermalink, pipelineUid, uid, view == VIEW_BASIC) if err != nil { return nil, err } @@ -886,19 +902,19 @@ func (s *service) GetUserPipelineReleaseByUID(ctx context.Context, ns resource.N return nil, err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) return s.DBToPBPipelineRelease(ctx, dbPipelineRelease, view, latestUUID, defaultUUID) } -func (s *service) UpdateUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, toUpdPipeline *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) { +func (s *service) UpdateNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, toUpdPipeline *pipelinePB.PipelineRelease) (*pipelinePB.PipelineRelease, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) // Validation: Pipeline existence - if existingPipeline, _ := s.GetUserPipelineReleaseByID(ctx, ns, userUid, pipelineUid, id, VIEW_BASIC); existingPipeline == nil { + if existingPipeline, _ := s.GetNamespacePipelineReleaseByID(ctx, ns, userUid, pipelineUid, id, VIEW_BASIC); existingPipeline == nil { return nil, status.Errorf(codes.NotFound, "Pipeline id %s is not found", id) } // TODO: use ACL @@ -906,15 +922,15 @@ func (s *service) UpdateUserPipelineReleaseByID(ctx context.Context, ns resource return nil, status.Errorf(codes.PermissionDenied, "Permission Denied") } - pbPipelineReleaseToUpdate, err := s.PBToDBPipelineRelease(ctx, userUid, pipelineUid, toUpdPipeline) + pbPipelineReleaseToUpdate, err := s.PBToDBPipelineRelease(ctx, pipelineUid, toUpdPipeline) if err != nil { return nil, err } - if err := s.repository.UpdateUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, pbPipelineReleaseToUpdate); err != nil { + if err := s.repository.UpdateNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, pbPipelineReleaseToUpdate); err != nil { return nil, err } - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, toUpdPipeline.Id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, toUpdPipeline.Id, false) if err != nil { return nil, err } @@ -928,18 +944,18 @@ func (s *service) UpdateUserPipelineReleaseByID(ctx context.Context, ns resource return nil, err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) return s.DBToPBPipelineRelease(ctx, dbPipelineRelease, VIEW_FULL, latestUUID, defaultUUID) } -func (s *service) UpdateUserPipelineReleaseIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, newID string) (*pipelinePB.PipelineRelease, error) { +func (s *service) UpdateNamespacePipelineReleaseIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, newID string) (*pipelinePB.PipelineRelease, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) // Validation: Pipeline existence - existingPipeline, _ := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, true) + existingPipeline, _ := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, true) if existingPipeline == nil { return nil, status.Errorf(codes.NotFound, "Pipeline id %s is not found", id) } @@ -948,11 +964,11 @@ func (s *service) UpdateUserPipelineReleaseIDByID(ctx context.Context, ns resour return nil, status.Errorf(codes.PermissionDenied, "Permission Denied") } - if err := s.repository.UpdateUserPipelineReleaseIDByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, newID); err != nil { + if err := s.repository.UpdateNamespacePipelineReleaseIDByID(ctx, ownerPermalink, pipelineUid, id, newID); err != nil { return nil, err } - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, newID, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, newID, false) if err != nil { return nil, err } @@ -965,16 +981,16 @@ func (s *service) UpdateUserPipelineReleaseIDByID(ctx context.Context, ns resour if err := s.UpdatePipelineState(dbPipelineRelease.UID, pipelinePB.State_STATE_ACTIVE, nil); err != nil { return nil, err } - latestUUID, _ := s.GetUserPipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) - defaultUUID, _ := s.GetUserPipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) + latestUUID, _ := s.GetNamespacePipelineLatestReleaseUid(ctx, ns, userUid, pipeline.Id) + defaultUUID, _ := s.GetNamespacePipelineDefaultReleaseUid(ctx, ns, userUid, pipeline.Id) return s.DBToPBPipelineRelease(ctx, dbPipelineRelease, VIEW_FULL, latestUUID, defaultUUID) } -func (s *service) DeleteUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { +func (s *service) DeleteNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, false) if err != nil { return err } @@ -988,13 +1004,13 @@ func (s *service) DeleteUserPipelineReleaseByID(ctx context.Context, ns resource } // TODO - return s.repository.DeleteUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id) + return s.repository.DeleteNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id) } -func (s *service) RestoreUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { +func (s *service) RestoreNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, false) if err != nil { return err } @@ -1010,18 +1026,18 @@ func (s *service) RestoreUserPipelineReleaseByID(ctx context.Context, ns resourc } existingPipeline.Recipe = dbPipelineRelease.Recipe - if err := s.repository.UpdateUserPipelineByID(ctx, ownerPermalink, userPermalink, id, existingPipeline); err != nil { + if err := s.repository.UpdateNamespacePipelineByID(ctx, ownerPermalink, id, existingPipeline); err != nil { return err } return nil } -func (s *service) SetDefaultUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { +func (s *service) SetDefaultNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string) error { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, false) if err != nil { return err } @@ -1038,7 +1054,7 @@ func (s *service) SetDefaultUserPipelineReleaseByID(ctx context.Context, ns reso existingPipeline.DefaultReleaseUID = dbPipelineRelease.UID - if err := s.repository.UpdateUserPipelineByID(ctx, ownerPermalink, userPermalink, existingPipeline.ID, existingPipeline); err != nil { + if err := s.repository.UpdateNamespacePipelineByID(ctx, ownerPermalink, existingPipeline.ID, existingPipeline); err != nil { return err } return nil @@ -1377,11 +1393,11 @@ func (s *service) triggerAsyncPipeline( } -func (s *service) TriggerUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) { +func (s *service) TriggerNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, false, s.getCode(ctx)) if err != nil { return nil, nil, err } @@ -1394,11 +1410,11 @@ func (s *service) TriggerUserPipelineByID(ctx context.Context, ns resource.Names } -func (s *service) TriggerAsyncUserPipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) { +func (s *service) TriggerAsyncNamespacePipelineByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipeline, err := s.repository.GetUserPipelineByID(ctx, ownerPermalink, userPermalink, id, false, s.getCode(ctx)) + dbPipeline, err := s.repository.GetNamespacePipelineByID(ctx, ownerPermalink, id, false, s.getCode(ctx)) if err != nil { return nil, err } @@ -1411,12 +1427,12 @@ func (s *service) TriggerAsyncUserPipelineByID(ctx context.Context, ns resource. } -func (s *service) TriggerUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) { +func (s *service) TriggerNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) ([]*structpb.Struct, *pipelinePB.TriggerMetadata, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, false) if err != nil { return nil, nil, err } @@ -1433,11 +1449,11 @@ func (s *service) TriggerUserPipelineReleaseByID(ctx context.Context, ns resourc return s.triggerPipeline(ctx, ownerPermalink, dbPipelineRelease.Recipe, dbPipeline.ID, dbPipeline.UID, dbPipelineRelease.ID, dbPipelineRelease.UID, inputs, pipelineTriggerId, returnTraces) } -func (s *service) TriggerAsyncUserPipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) { +func (s *service) TriggerAsyncNamespacePipelineReleaseByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pipelineUid uuid.UUID, id string, inputs []*structpb.Struct, pipelineTriggerId string, returnTraces bool) (*longrunningpb.Operation, error) { ownerPermalink := ns.String() userPermalink := resource.UserUidToUserPermalink(userUid) - dbPipelineRelease, err := s.repository.GetUserPipelineReleaseByID(ctx, ownerPermalink, userPermalink, pipelineUid, id, false) + dbPipelineRelease, err := s.repository.GetNamespacePipelineReleaseByID(ctx, ownerPermalink, pipelineUid, id, false) if err != nil { return nil, err } @@ -1461,7 +1477,7 @@ func (s *service) KeepCredentialFieldsWithMaskString(dbConnDefID string, config utils.KeepCredentialFieldsWithMaskString(s.connector, dbConnDefID, config) } -func (s *service) ListConnectorDefinitions(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter) ([]*pipelinePB.ConnectorDefinition, int64, string, error) { +func (s *service) ListConnectorDefinitions(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter) ([]*pipelinePB.ConnectorDefinition, int32, string, error) { logger, _ := logger.GetZapLogger(ctx) @@ -1559,7 +1575,7 @@ func (s *service) ListConnectorDefinitions(ctx context.Context, pageSize int64, def.VendorAttributes = nil pageDefs = append(pageDefs, def) } - return pageDefs, int64(len(defs)), nextPageToken, err + return pageDefs, int32(len(defs)), nextPageToken, err } @@ -1603,26 +1619,26 @@ func (s *service) GetConnectorDefinitionByUIDAdmin(ctx context.Context, uid uuid return def, nil } -func (s *service) ListConnectors(ctx context.Context, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) { +func (s *service) ListConnectors(ctx context.Context, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) { userPermalink := resource.UserUidToUserPermalink(userUid) - dbConnectors, totalSize, nextPageToken, err := s.repository.ListConnectors(ctx, userPermalink, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbConnectors, totalSize, nextPageToken, err := s.repository.ListConnectors(ctx, userPermalink, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbConnectors, err := s.convertDatamodelArrayToProtoArray(ctx, dbConnectors, view, true) - return pbConnectors, totalSize, nextPageToken, err + return pbConnectors, int32(totalSize), nextPageToken, err } -func (s *service) CreateUserConnector(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) { +func (s *service) CreateNamespaceConnector(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) { logger, _ := logger.GetZapLogger(ctx) ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) connDefResp, err := s.connector.GetConnectorDefinitionByID(strings.Split(connector.ConnectorDefinitionName, "/")[1]) if err != nil { @@ -1647,7 +1663,7 @@ func (s *service) CreateUserConnector(ctx context.Context, ns resource.Namespace dbConnectorToCreate := &datamodel.Connector{ ID: connector.Id, - Owner: resource.UserUidToUserPermalink(userUid), + Owner: ns.String(), ConnectorDefinitionUID: connDefUID, Tombstone: false, Configuration: connConfig, @@ -1656,7 +1672,7 @@ func (s *service) CreateUserConnector(ctx context.Context, ns resource.Namespace Visibility: datamodel.ConnectorVisibility(connector.Visibility), } - if existingConnector, _ := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, dbConnectorToCreate.ID, true); existingConnector != nil { + if existingConnector, _ := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, dbConnectorToCreate.ID, true); existingConnector != nil { st, err := sterr.CreateErrorResourceInfo( codes.AlreadyExists, "[service] create connector", @@ -1671,19 +1687,19 @@ func (s *service) CreateUserConnector(ctx context.Context, ns resource.Namespace return nil, st.Err() } - if err := s.repository.CreateUserConnector(ctx, ownerPermalink, userPermalink, dbConnectorToCreate); err != nil { + if err := s.repository.CreateNamespaceConnector(ctx, ownerPermalink, dbConnectorToCreate); err != nil { return nil, err } // User desire state = DISCONNECTED - if err := s.repository.UpdateUserConnectorStateByID(ctx, ownerPermalink, userPermalink, dbConnectorToCreate.ID, datamodel.ConnectorState(pipelinePB.Connector_STATE_DISCONNECTED)); err != nil { + if err := s.repository.UpdateNamespaceConnectorStateByID(ctx, ownerPermalink, dbConnectorToCreate.ID, datamodel.ConnectorState(pipelinePB.Connector_STATE_DISCONNECTED)); err != nil { return nil, err } if err := s.UpdateConnectorState(dbConnectorToCreate.UID, pipelinePB.Connector_STATE_DISCONNECTED, nil); err != nil { return nil, err } - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, dbConnectorToCreate.ID, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, dbConnectorToCreate.ID, false) if err != nil { return nil, err } @@ -1692,37 +1708,37 @@ func (s *service) CreateUserConnector(ctx context.Context, ns resource.Namespace } -func (s *service) ListUserConnectors(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) { +func (s *service) ListNamespaceConnectors(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) - dbConnectors, totalSize, nextPageToken, err := s.repository.ListUserConnectors(ctx, ownerPermalink, userPermalink, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + // userPermalink := resource.UserUidToUserPermalink(userUid) + dbConnectors, totalSize, nextPageToken, err := s.repository.ListNamespaceConnectors(ctx, ownerPermalink, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbConnectors, err := s.convertDatamodelArrayToProtoArray(ctx, dbConnectors, view, true) - return pbConnectors, totalSize, nextPageToken, err + return pbConnectors, int32(totalSize), nextPageToken, err } -func (s *service) ListConnectorsAdmin(ctx context.Context, pageSize int64, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int64, string, error) { +func (s *service) ListConnectorsAdmin(ctx context.Context, pageSize int32, pageToken string, view View, filter filtering.Filter, showDeleted bool) ([]*pipelinePB.Connector, int32, string, error) { - dbConnectors, totalSize, nextPageToken, err := s.repository.ListConnectorsAdmin(ctx, pageSize, pageToken, view == VIEW_BASIC, filter, showDeleted) + dbConnectors, totalSize, nextPageToken, err := s.repository.ListConnectorsAdmin(ctx, int64(pageSize), pageToken, view == VIEW_BASIC, filter, showDeleted) if err != nil { return nil, 0, "", err } pbConnectors, err := s.convertDatamodelArrayToProtoArray(ctx, dbConnectors, view, true) - return pbConnectors, totalSize, nextPageToken, err + return pbConnectors, int32(totalSize), nextPageToken, err } -func (s *service) GetUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View, credentialMask bool) (*pipelinePB.Connector, error) { +func (s *service) GetNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, view View, credentialMask bool) (*pipelinePB.Connector, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, id, view == VIEW_BASIC) + // userPermalink := resource.UserUidToUserPermalink(userUid) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, id, view == VIEW_BASIC) if err != nil { return nil, err } @@ -1740,10 +1756,10 @@ func (s *service) GetConnectorByUIDAdmin(ctx context.Context, uid uuid.UUID, vie return s.convertDatamodelToProto(ctx, dbConnector, view, true) } -func (s *service) UpdateUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) { +func (s *service) UpdateNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, connector *pipelinePB.Connector) (*pipelinePB.Connector, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) dbConnectorToUpdate, err := s.convertProtoToDatamodel(ctx, connector) if err != nil { @@ -1751,7 +1767,7 @@ func (s *service) UpdateUserConnectorByID(ctx context.Context, ns resource.Names } dbConnectorToUpdate.Owner = ownerPermalink - if err := s.repository.UpdateUserConnectorByID(ctx, ownerPermalink, userPermalink, id, dbConnectorToUpdate); err != nil { + if err := s.repository.UpdateNamespaceConnectorByID(ctx, ownerPermalink, id, dbConnectorToUpdate); err != nil { return nil, err } @@ -1760,7 +1776,7 @@ func (s *service) UpdateUserConnectorByID(ctx context.Context, ns resource.Names return nil, err } - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, dbConnectorToUpdate.ID, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, dbConnectorToUpdate.ID, false) if err != nil { return nil, err } @@ -1769,13 +1785,13 @@ func (s *service) UpdateUserConnectorByID(ctx context.Context, ns resource.Names } -func (s *service) DeleteUserConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error { +func (s *service) DeleteNamespaceConnectorByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string) error { // logger, _ := logger.GetZapLogger(ctx) ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, id, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, id, false) if err != nil { return err } @@ -1814,16 +1830,16 @@ func (s *service) DeleteUserConnectorByID(ctx context.Context, ns resource.Names return err } - return s.repository.DeleteUserConnectorByID(ctx, ownerPermalink, userPermalink, id) + return s.repository.DeleteNamespaceConnectorByID(ctx, ownerPermalink, id) } -func (s *service) UpdateUserConnectorStateByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, state pipelinePB.Connector_State) (*pipelinePB.Connector, error) { +func (s *service) UpdateNamespaceConnectorStateByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, state pipelinePB.Connector_State) (*pipelinePB.Connector, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) // Validation: trigger and response connector cannot be disconnected - conn, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, id, false) + conn, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, id, false) if err != nil { return nil, err } @@ -1845,7 +1861,7 @@ func (s *service) UpdateUserConnectorStateByID(ctx context.Context, ns resource. case pipelinePB.Connector_STATE_CONNECTED: // Set connector state to user desire state - if err := s.repository.UpdateUserConnectorStateByID(ctx, ownerPermalink, userPermalink, id, datamodel.ConnectorState(pipelinePB.Connector_STATE_CONNECTED)); err != nil { + if err := s.repository.UpdateNamespaceConnectorStateByID(ctx, ownerPermalink, id, datamodel.ConnectorState(pipelinePB.Connector_STATE_CONNECTED)); err != nil { return nil, err } @@ -1855,7 +1871,7 @@ func (s *service) UpdateUserConnectorStateByID(ctx context.Context, ns resource. case pipelinePB.Connector_STATE_DISCONNECTED: - if err := s.repository.UpdateUserConnectorStateByID(ctx, ownerPermalink, userPermalink, id, datamodel.ConnectorState(pipelinePB.Connector_STATE_DISCONNECTED)); err != nil { + if err := s.repository.UpdateNamespaceConnectorStateByID(ctx, ownerPermalink, id, datamodel.ConnectorState(pipelinePB.Connector_STATE_DISCONNECTED)); err != nil { return nil, err } if err := s.UpdateConnectorState(conn.UID, pipelinePB.Connector_State(state), nil); err != nil { @@ -1863,7 +1879,7 @@ func (s *service) UpdateUserConnectorStateByID(ctx context.Context, ns resource. } } - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, id, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, id, false) if err != nil { return nil, err } @@ -1875,16 +1891,16 @@ func (s *service) UpdateUserConnectorStateByID(ctx context.Context, ns resource. return s.convertDatamodelToProto(ctx, dbConnector, VIEW_FULL, true) } -func (s *service) UpdateUserConnectorIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Connector, error) { +func (s *service) UpdateNamespaceConnectorIDByID(ctx context.Context, ns resource.Namespace, userUid uuid.UUID, id string, newID string) (*pipelinePB.Connector, error) { ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - if err := s.repository.UpdateUserConnectorIDByID(ctx, ownerPermalink, userPermalink, id, newID); err != nil { + if err := s.repository.UpdateNamespaceConnectorIDByID(ctx, ownerPermalink, id, newID); err != nil { return nil, err } - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, newID, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, newID, false) if err != nil { return nil, err } @@ -1897,9 +1913,9 @@ func (s *service) Execute(ctx context.Context, ns resource.Namespace, userUid uu logger, _ := logger.GetZapLogger(ctx) ownerPermalink := ns.String() - userPermalink := resource.UserUidToUserPermalink(userUid) + // userPermalink := resource.UserUidToUserPermalink(userUid) - dbConnector, err := s.repository.GetUserConnectorByID(ctx, ownerPermalink, userPermalink, id, false) + dbConnector, err := s.repository.GetNamespaceConnectorByID(ctx, ownerPermalink, id, false) if err != nil { return nil, err }