From 30432bc5d3a84801d8b633ba6de299553f06d7ce Mon Sep 17 00:00:00 2001 From: wuhuizuo Date: Wed, 30 Oct 2024 13:42:52 +0800 Subject: [PATCH] feat(publisher): implement fileserver publisher service (#187) Signed-off-by: wuhuizuo --------- Signed-off-by: wuhuizuo --- publisher/cmd/publisher-cli/http.go | 3 +- publisher/cmd/publisher/http.go | 12 +- publisher/cmd/publisher/main.go | 23 ++- publisher/cmd/worker/main.go | 10 +- publisher/design/design.go | 35 +++- publisher/gen/fileserver/client.go | 50 +++++ publisher/gen/fileserver/endpoints.go | 52 +++++ publisher/gen/fileserver/service.go | 51 +++++ publisher/gen/http/cli/publisher/cli.go | 96 ++++++++- publisher/gen/http/fileserver/client/cli.go | 46 +++++ .../gen/http/fileserver/client/client.go | 99 ++++++++++ .../http/fileserver/client/encode_decode.go | 153 +++++++++++++++ publisher/gen/http/fileserver/client/paths.go | 22 +++ publisher/gen/http/fileserver/client/types.go | 29 +++ .../http/fileserver/server/encode_decode.go | 87 ++++++++ publisher/gen/http/fileserver/server/paths.go | 22 +++ .../gen/http/fileserver/server/server.go | 185 ++++++++++++++++++ publisher/gen/http/fileserver/server/types.go | 49 +++++ publisher/gen/http/openapi.json | 2 +- publisher/gen/http/openapi.yaml | 81 +++++++- publisher/gen/http/openapi3.json | 2 +- publisher/gen/http/openapi3.yaml | 125 +++++++++--- publisher/gen/http/tiup/client/cli.go | 2 +- publisher/gen/http/tiup/client/types.go | 4 +- publisher/gen/http/tiup/server/types.go | 4 +- publisher/gen/tiup/service.go | 4 +- publisher/pkg/impl/fileserver_service.go | 109 +++++++++++ publisher/pkg/impl/{tiup => }/funcs.go | 6 +- publisher/pkg/impl/{tiup => }/funcs_test.go | 2 +- .../impl/{tiup/service.go => tiup_service.go} | 11 +- publisher/pkg/impl/{tiup => }/types.go | 19 +- .../pkg/impl/{tiup/publisher.go => worker.go} | 70 +++++-- 32 files changed, 1360 insertions(+), 105 deletions(-) create mode 100644 publisher/gen/fileserver/client.go create mode 100644 publisher/gen/fileserver/endpoints.go create mode 100644 publisher/gen/fileserver/service.go create mode 100644 publisher/gen/http/fileserver/client/cli.go create mode 100644 publisher/gen/http/fileserver/client/client.go create mode 100644 publisher/gen/http/fileserver/client/encode_decode.go create mode 100644 publisher/gen/http/fileserver/client/paths.go create mode 100644 publisher/gen/http/fileserver/client/types.go create mode 100644 publisher/gen/http/fileserver/server/encode_decode.go create mode 100644 publisher/gen/http/fileserver/server/paths.go create mode 100644 publisher/gen/http/fileserver/server/server.go create mode 100644 publisher/gen/http/fileserver/server/types.go create mode 100644 publisher/pkg/impl/fileserver_service.go rename publisher/pkg/impl/{tiup => }/funcs.go (98%) rename publisher/pkg/impl/{tiup => }/funcs_test.go (99%) rename publisher/pkg/impl/{tiup/service.go => tiup_service.go} (91%) rename publisher/pkg/impl/{tiup => }/types.go (58%) rename publisher/pkg/impl/{tiup/publisher.go => worker.go} (69%) diff --git a/publisher/cmd/publisher-cli/http.go b/publisher/cmd/publisher-cli/http.go index 8bc27569..45195966 100644 --- a/publisher/cmd/publisher-cli/http.go +++ b/publisher/cmd/publisher-cli/http.go @@ -4,9 +4,10 @@ import ( "net/http" "time" - cli "github.com/PingCAP-QE/ee-apps/publisher/gen/http/cli/publisher" goahttp "goa.design/goa/v3/http" goa "goa.design/goa/v3/pkg" + + cli "github.com/PingCAP-QE/ee-apps/publisher/gen/http/cli/publisher" ) func doHTTP(scheme, host string, timeout int, debug bool) (goa.Endpoint, any, error) { diff --git a/publisher/cmd/publisher/http.go b/publisher/cmd/publisher/http.go index 93e0c46e..0d794866 100644 --- a/publisher/cmd/publisher/http.go +++ b/publisher/cmd/publisher/http.go @@ -7,16 +7,19 @@ import ( "sync" "time" - tiupsvr "github.com/PingCAP-QE/ee-apps/publisher/gen/http/tiup/server" - tiup "github.com/PingCAP-QE/ee-apps/publisher/gen/tiup" "goa.design/clue/debug" "goa.design/clue/log" goahttp "goa.design/goa/v3/http" + + "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" + fssvr "github.com/PingCAP-QE/ee-apps/publisher/gen/http/fileserver/server" + tiupsvr "github.com/PingCAP-QE/ee-apps/publisher/gen/http/tiup/server" + tiup "github.com/PingCAP-QE/ee-apps/publisher/gen/tiup" ) // handleHTTPServer starts configures and starts a HTTP server on the given // URL. It shuts down the server if any error is received in the error channel. -func handleHTTPServer(ctx context.Context, u *url.URL, tiupEndpoints *tiup.Endpoints, wg *sync.WaitGroup, errc chan error, dbg bool) { +func handleHTTPServer(ctx context.Context, u *url.URL, tiupEndpoints *tiup.Endpoints, fsEndpoints *fileserver.Endpoints, wg *sync.WaitGroup, errc chan error, dbg bool) { // Provide the transport specific request decoder and response encoder. // The goa http package has built-in support for JSON, XML and gob. @@ -46,14 +49,17 @@ func handleHTTPServer(ctx context.Context, u *url.URL, tiupEndpoints *tiup.Endpo // responses. var ( tiupServer *tiupsvr.Server + fsServer *fssvr.Server ) { eh := errorHandler(ctx) tiupServer = tiupsvr.New(tiupEndpoints, mux, dec, enc, eh, nil) + fsServer = fssvr.New(fsEndpoints, mux, dec, enc, eh, nil) } // Configure the mux. tiupsvr.Mount(mux, tiupServer) + fssvr.Mount(mux, fsServer) var handler http.Handler = mux if dbg { diff --git a/publisher/cmd/publisher/main.go b/publisher/cmd/publisher/main.go index 53152dcb..7ef4ea7d 100644 --- a/publisher/cmd/publisher/main.go +++ b/publisher/cmd/publisher/main.go @@ -17,8 +17,9 @@ import ( "goa.design/clue/debug" "goa.design/clue/log" - gentiup "github.com/PingCAP-QE/ee-apps/publisher/gen/tiup" - "github.com/PingCAP-QE/ee-apps/publisher/pkg/impl/tiup" + "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" + "github.com/PingCAP-QE/ee-apps/publisher/gen/tiup" + "github.com/PingCAP-QE/ee-apps/publisher/pkg/impl" ) func main() { @@ -52,7 +53,7 @@ func main() { logLevel = zerolog.DebugLevel } zerolog.SetGlobalLevel(logLevel) - logger := zerolog.New(os.Stderr).With().Timestamp().Str("service", gentiup.ServiceName).Logger() + logger := zerolog.New(os.Stderr).With().Timestamp().Str("service", tiup.ServiceName).Logger() // Load and parse configuration config, err := loadConfig(*configFile) @@ -62,7 +63,8 @@ func main() { // Initialize the services. var ( - tiupSvc gentiup.Service + tiupSvc tiup.Service + fsSvc fileserver.Service ) { // Configure Kafka kafkaWriter @@ -81,18 +83,23 @@ func main() { DB: config.Redis.DB, }) - tiupSvc = tiup.NewService(&logger, kafkaWriter, redisClient, config.EventSource) + tiupSvc = impl.NewTiup(&logger, kafkaWriter, redisClient, config.EventSource) + fsSvc = impl.NewFileserver(&logger, kafkaWriter, redisClient, config.EventSource) } // Wrap the services in endpoints that can be invoked from other services // potentially running in different processes. var ( - tiupEndpoints *gentiup.Endpoints + tiupEndpoints *tiup.Endpoints + fsEndpoints *fileserver.Endpoints ) { - tiupEndpoints = gentiup.NewEndpoints(tiupSvc) + tiupEndpoints = tiup.NewEndpoints(tiupSvc) tiupEndpoints.Use(debug.LogPayloads()) tiupEndpoints.Use(log.Endpoint) + fsEndpoints = fileserver.NewEndpoints(fsSvc) + fsEndpoints.Use(debug.LogPayloads()) + fsEndpoints.Use(log.Endpoint) } // Create channel used by both the signal handler and server goroutines @@ -134,7 +141,7 @@ func main() { } else if u.Port() == "" { u.Host = net.JoinHostPort(u.Host, "80") } - handleHTTPServer(ctx, u, tiupEndpoints, &wg, errc, *dbgF) + handleHTTPServer(ctx, u, tiupEndpoints, fsEndpoints, &wg, errc, *dbgF) } default: diff --git a/publisher/cmd/worker/main.go b/publisher/cmd/worker/main.go index fa923fcd..cec0ec1c 100644 --- a/publisher/cmd/worker/main.go +++ b/publisher/cmd/worker/main.go @@ -19,7 +19,7 @@ import ( "gopkg.in/yaml.v3" "github.com/PingCAP-QE/ee-apps/publisher/pkg/config" - "github.com/PingCAP-QE/ee-apps/publisher/pkg/impl/tiup" + "github.com/PingCAP-QE/ee-apps/publisher/pkg/impl" ) func main() { @@ -60,14 +60,14 @@ func main() { ctx := log.Logger.WithContext(context.Background()) // Create TiUP publisher - var handler *tiup.Publisher + var handler *impl.Worker { var err error nigthlyInterval, err := time.ParseDuration(config.Options.NightlyInterval) if err != nil { log.Fatal().Err(err).Msg("Error parsing nightly interval") } - handler, err = tiup.NewPublisher(&log.Logger, redisClient, tiup.PublisherOptions{ + handler, err = impl.NewWorker(&log.Logger, redisClient, impl.WorkerOptions{ MirrorURL: config.Options.MirrorURL, LarkWebhookURL: config.Options.LarkWebhookURL, NightlyInterval: nigthlyInterval, @@ -106,7 +106,7 @@ func main() { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) - Start(ctx, reader, handler, &wg, errc) + start(ctx, reader, handler, &wg, errc) // Wait for signal. log.Warn().Msgf("exiting (%v)", <-errc) @@ -118,7 +118,7 @@ func main() { log.Warn().Msg("exited") } -func Start(ctx context.Context, reader *kafka.Reader, handler *tiup.Publisher, wg *sync.WaitGroup, errc chan error) { +func start(ctx context.Context, reader *kafka.Reader, handler *impl.Worker, wg *sync.WaitGroup, errc chan error) { (*wg).Add(1) go func() { defer (*wg).Done() diff --git a/publisher/design/design.go b/publisher/design/design.go index e8444b3b..0f8c86b7 100644 --- a/publisher/design/design.go +++ b/publisher/design/design.go @@ -31,7 +31,7 @@ var _ = Service("tiup", func() { Method("request-to-publish", func() { Payload(func() { Attribute("artifact_url", String, func() { - Description("The full url of the pushed image, contain the tag part. It will parse the repo from it.") + Description("The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.") }) Attribute("version", String, func() { Description("Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config.") @@ -65,3 +65,36 @@ var _ = Service("tiup", func() { }) }) }) + +var _ = Service("fileserver", func() { + Description("Publisher service for static file server ") + HTTP(func() { + Path("/fs") + }) + Method("request-to-publish", func() { + Payload(func() { + Attribute("artifact_url", String, func() { + Description("The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.") + }) + Required("artifact_url") + }) + Result(ArrayOf(String), "request track ids") + HTTP(func() { + POST("/publish-request") + Response(StatusOK) + }) + }) + Method("query-publishing-status", func() { + Payload(func() { + Attribute("request_id", String, "request track id") + Required("request_id") + }) + Result(String, "request state", func() { + Enum("queued", "processing", "success", "failed", "canceled") + }) + HTTP(func() { + GET("/publish-request/{request_id}") + Response(StatusOK) + }) + }) +}) diff --git a/publisher/gen/fileserver/client.go b/publisher/gen/fileserver/client.go new file mode 100644 index 00000000..bfd27e10 --- /dev/null +++ b/publisher/gen/fileserver/client.go @@ -0,0 +1,50 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver client +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package fileserver + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// Client is the "fileserver" service client. +type Client struct { + RequestToPublishEndpoint goa.Endpoint + QueryPublishingStatusEndpoint goa.Endpoint +} + +// NewClient initializes a "fileserver" service client given the endpoints. +func NewClient(requestToPublish, queryPublishingStatus goa.Endpoint) *Client { + return &Client{ + RequestToPublishEndpoint: requestToPublish, + QueryPublishingStatusEndpoint: queryPublishingStatus, + } +} + +// RequestToPublish calls the "request-to-publish" endpoint of the "fileserver" +// service. +func (c *Client) RequestToPublish(ctx context.Context, p *RequestToPublishPayload) (res []string, err error) { + var ires any + ires, err = c.RequestToPublishEndpoint(ctx, p) + if err != nil { + return + } + return ires.([]string), nil +} + +// QueryPublishingStatus calls the "query-publishing-status" endpoint of the +// "fileserver" service. +func (c *Client) QueryPublishingStatus(ctx context.Context, p *QueryPublishingStatusPayload) (res string, err error) { + var ires any + ires, err = c.QueryPublishingStatusEndpoint(ctx, p) + if err != nil { + return + } + return ires.(string), nil +} diff --git a/publisher/gen/fileserver/endpoints.go b/publisher/gen/fileserver/endpoints.go new file mode 100644 index 00000000..b3fccd02 --- /dev/null +++ b/publisher/gen/fileserver/endpoints.go @@ -0,0 +1,52 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver endpoints +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package fileserver + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// Endpoints wraps the "fileserver" service endpoints. +type Endpoints struct { + RequestToPublish goa.Endpoint + QueryPublishingStatus goa.Endpoint +} + +// NewEndpoints wraps the methods of the "fileserver" service with endpoints. +func NewEndpoints(s Service) *Endpoints { + return &Endpoints{ + RequestToPublish: NewRequestToPublishEndpoint(s), + QueryPublishingStatus: NewQueryPublishingStatusEndpoint(s), + } +} + +// Use applies the given middleware to all the "fileserver" service endpoints. +func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { + e.RequestToPublish = m(e.RequestToPublish) + e.QueryPublishingStatus = m(e.QueryPublishingStatus) +} + +// NewRequestToPublishEndpoint returns an endpoint function that calls the +// method "request-to-publish" of service "fileserver". +func NewRequestToPublishEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req any) (any, error) { + p := req.(*RequestToPublishPayload) + return s.RequestToPublish(ctx, p) + } +} + +// NewQueryPublishingStatusEndpoint returns an endpoint function that calls the +// method "query-publishing-status" of service "fileserver". +func NewQueryPublishingStatusEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req any) (any, error) { + p := req.(*QueryPublishingStatusPayload) + return s.QueryPublishingStatus(ctx, p) + } +} diff --git a/publisher/gen/fileserver/service.go b/publisher/gen/fileserver/service.go new file mode 100644 index 00000000..9084cbf0 --- /dev/null +++ b/publisher/gen/fileserver/service.go @@ -0,0 +1,51 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver service +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package fileserver + +import ( + "context" +) + +// Publisher service for static file server +type Service interface { + // RequestToPublish implements request-to-publish. + RequestToPublish(context.Context, *RequestToPublishPayload) (res []string, err error) + // QueryPublishingStatus implements query-publishing-status. + QueryPublishingStatus(context.Context, *QueryPublishingStatusPayload) (res string, err error) +} + +// APIName is the name of the API as defined in the design. +const APIName = "publisher" + +// APIVersion is the version of the API as defined in the design. +const APIVersion = "1.0.0" + +// ServiceName is the name of the service as defined in the design. This is the +// same value that is set in the endpoint request contexts under the ServiceKey +// key. +const ServiceName = "fileserver" + +// MethodNames lists the service method names as defined in the design. These +// are the same values that are set in the endpoint request contexts under the +// MethodKey key. +var MethodNames = [2]string{"request-to-publish", "query-publishing-status"} + +// QueryPublishingStatusPayload is the payload type of the fileserver service +// query-publishing-status method. +type QueryPublishingStatusPayload struct { + // request track id + RequestID string +} + +// RequestToPublishPayload is the payload type of the fileserver service +// request-to-publish method. +type RequestToPublishPayload struct { + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. + ArtifactURL string +} diff --git a/publisher/gen/http/cli/publisher/cli.go b/publisher/gen/http/cli/publisher/cli.go index 4d1162d2..396b3cd7 100644 --- a/publisher/gen/http/cli/publisher/cli.go +++ b/publisher/gen/http/cli/publisher/cli.go @@ -13,6 +13,7 @@ import ( "net/http" "os" + fileserverc "github.com/PingCAP-QE/ee-apps/publisher/gen/http/fileserver/client" tiupc "github.com/PingCAP-QE/ee-apps/publisher/gen/http/tiup/client" goahttp "goa.design/goa/v3/http" goa "goa.design/goa/v3/pkg" @@ -23,16 +24,20 @@ import ( // command (subcommand1|subcommand2|...) func UsageCommands() string { return `tiup (request-to-publish|query-publishing-status) +fileserver (request-to-publish|query-publishing-status) ` } // UsageExamples produces an example of a valid invocation of the CLI tool. func UsageExamples() string { return os.Args[0] + ` tiup request-to-publish --body '{ - "artifact_url": "Omnis expedita.", - "request_id": "Est sequi placeat.", - "tiup-mirror": "Pariatur rerum consectetur deleniti architecto sunt.", - "version": "Dicta id perferendis rem a." + "artifact_url": "Placeat blanditiis est iusto.", + "request_id": "Quo ut dolor perspiciatis rem assumenda enim.", + "tiup-mirror": "Totam omnis sunt cum voluptatem amet.", + "version": "Eum eligendi." + }'` + "\n" + + os.Args[0] + ` fileserver request-to-publish --body '{ + "artifact_url": "Quis voluptatem earum et ullam esse." }'` + "\n" + "" } @@ -54,11 +59,23 @@ func ParseEndpoint( tiupQueryPublishingStatusFlags = flag.NewFlagSet("query-publishing-status", flag.ExitOnError) tiupQueryPublishingStatusRequestIDFlag = tiupQueryPublishingStatusFlags.String("request-id", "REQUIRED", "request track id") + + fileserverFlags = flag.NewFlagSet("fileserver", flag.ContinueOnError) + + fileserverRequestToPublishFlags = flag.NewFlagSet("request-to-publish", flag.ExitOnError) + fileserverRequestToPublishBodyFlag = fileserverRequestToPublishFlags.String("body", "REQUIRED", "") + + fileserverQueryPublishingStatusFlags = flag.NewFlagSet("query-publishing-status", flag.ExitOnError) + fileserverQueryPublishingStatusRequestIDFlag = fileserverQueryPublishingStatusFlags.String("request-id", "REQUIRED", "request track id") ) tiupFlags.Usage = tiupUsage tiupRequestToPublishFlags.Usage = tiupRequestToPublishUsage tiupQueryPublishingStatusFlags.Usage = tiupQueryPublishingStatusUsage + fileserverFlags.Usage = fileserverUsage + fileserverRequestToPublishFlags.Usage = fileserverRequestToPublishUsage + fileserverQueryPublishingStatusFlags.Usage = fileserverQueryPublishingStatusUsage + if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { return nil, nil, err } @@ -76,6 +93,8 @@ func ParseEndpoint( switch svcn { case "tiup": svcf = tiupFlags + case "fileserver": + svcf = fileserverFlags default: return nil, nil, fmt.Errorf("unknown service %q", svcn) } @@ -101,6 +120,16 @@ func ParseEndpoint( } + case "fileserver": + switch epn { + case "request-to-publish": + epf = fileserverRequestToPublishFlags + + case "query-publishing-status": + epf = fileserverQueryPublishingStatusFlags + + } + } } if epf == nil { @@ -131,6 +160,16 @@ func ParseEndpoint( endpoint = c.QueryPublishingStatus() data, err = tiupc.BuildQueryPublishingStatusPayload(*tiupQueryPublishingStatusRequestIDFlag) } + case "fileserver": + c := fileserverc.NewClient(scheme, host, doer, enc, dec, restore) + switch epn { + case "request-to-publish": + endpoint = c.RequestToPublish() + data, err = fileserverc.BuildRequestToPublishPayload(*fileserverRequestToPublishBodyFlag) + case "query-publishing-status": + endpoint = c.QueryPublishingStatus() + data, err = fileserverc.BuildQueryPublishingStatusPayload(*fileserverQueryPublishingStatusRequestIDFlag) + } } } if err != nil { @@ -162,10 +201,10 @@ RequestToPublish implements request-to-publish. Example: %[1]s tiup request-to-publish --body '{ - "artifact_url": "Omnis expedita.", - "request_id": "Est sequi placeat.", - "tiup-mirror": "Pariatur rerum consectetur deleniti architecto sunt.", - "version": "Dicta id perferendis rem a." + "artifact_url": "Placeat blanditiis est iusto.", + "request_id": "Quo ut dolor perspiciatis rem assumenda enim.", + "tiup-mirror": "Totam omnis sunt cum voluptatem amet.", + "version": "Eum eligendi." }' `, os.Args[0]) } @@ -177,6 +216,45 @@ QueryPublishingStatus implements query-publishing-status. -request-id STRING: request track id Example: - %[1]s tiup query-publishing-status --request-id "Aspernatur quis voluptas." + %[1]s tiup query-publishing-status --request-id "Expedita et necessitatibus ut molestias." +`, os.Args[0]) +} + +// fileserverUsage displays the usage of the fileserver command and its +// subcommands. +func fileserverUsage() { + fmt.Fprintf(os.Stderr, `Publisher service for static file server +Usage: + %[1]s [globalflags] fileserver COMMAND [flags] + +COMMAND: + request-to-publish: RequestToPublish implements request-to-publish. + query-publishing-status: QueryPublishingStatus implements query-publishing-status. + +Additional help: + %[1]s fileserver COMMAND --help +`, os.Args[0]) +} +func fileserverRequestToPublishUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] fileserver request-to-publish -body JSON + +RequestToPublish implements request-to-publish. + -body JSON: + +Example: + %[1]s fileserver request-to-publish --body '{ + "artifact_url": "Quis voluptatem earum et ullam esse." + }' +`, os.Args[0]) +} + +func fileserverQueryPublishingStatusUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] fileserver query-publishing-status -request-id STRING + +QueryPublishingStatus implements query-publishing-status. + -request-id STRING: request track id + +Example: + %[1]s fileserver query-publishing-status --request-id "Voluptas ratione hic libero nisi." `, os.Args[0]) } diff --git a/publisher/gen/http/fileserver/client/cli.go b/publisher/gen/http/fileserver/client/cli.go new file mode 100644 index 00000000..4700e16d --- /dev/null +++ b/publisher/gen/http/fileserver/client/cli.go @@ -0,0 +1,46 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP client CLI support package +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package client + +import ( + "encoding/json" + "fmt" + + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" +) + +// BuildRequestToPublishPayload builds the payload for the fileserver +// request-to-publish endpoint from CLI flags. +func BuildRequestToPublishPayload(fileserverRequestToPublishBody string) (*fileserver.RequestToPublishPayload, error) { + var err error + var body RequestToPublishRequestBody + { + err = json.Unmarshal([]byte(fileserverRequestToPublishBody), &body) + if err != nil { + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"artifact_url\": \"Quis voluptatem earum et ullam esse.\"\n }'") + } + } + v := &fileserver.RequestToPublishPayload{ + ArtifactURL: body.ArtifactURL, + } + + return v, nil +} + +// BuildQueryPublishingStatusPayload builds the payload for the fileserver +// query-publishing-status endpoint from CLI flags. +func BuildQueryPublishingStatusPayload(fileserverQueryPublishingStatusRequestID string) (*fileserver.QueryPublishingStatusPayload, error) { + var requestID string + { + requestID = fileserverQueryPublishingStatusRequestID + } + v := &fileserver.QueryPublishingStatusPayload{} + v.RequestID = requestID + + return v, nil +} diff --git a/publisher/gen/http/fileserver/client/client.go b/publisher/gen/http/fileserver/client/client.go new file mode 100644 index 00000000..b4063b88 --- /dev/null +++ b/publisher/gen/http/fileserver/client/client.go @@ -0,0 +1,99 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver client HTTP transport +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package client + +import ( + "context" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Client lists the fileserver service endpoint HTTP clients. +type Client struct { + // RequestToPublish Doer is the HTTP client used to make requests to the + // request-to-publish endpoint. + RequestToPublishDoer goahttp.Doer + + // QueryPublishingStatus Doer is the HTTP client used to make requests to the + // query-publishing-status endpoint. + QueryPublishingStatusDoer goahttp.Doer + + // RestoreResponseBody controls whether the response bodies are reset after + // decoding so they can be read again. + RestoreResponseBody bool + + scheme string + host string + encoder func(*http.Request) goahttp.Encoder + decoder func(*http.Response) goahttp.Decoder +} + +// NewClient instantiates HTTP clients for all the fileserver service servers. +func NewClient( + scheme string, + host string, + doer goahttp.Doer, + enc func(*http.Request) goahttp.Encoder, + dec func(*http.Response) goahttp.Decoder, + restoreBody bool, +) *Client { + return &Client{ + RequestToPublishDoer: doer, + QueryPublishingStatusDoer: doer, + RestoreResponseBody: restoreBody, + scheme: scheme, + host: host, + decoder: dec, + encoder: enc, + } +} + +// RequestToPublish returns an endpoint that makes HTTP requests to the +// fileserver service request-to-publish server. +func (c *Client) RequestToPublish() goa.Endpoint { + var ( + encodeRequest = EncodeRequestToPublishRequest(c.encoder) + decodeResponse = DecodeRequestToPublishResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v any) (any, error) { + req, err := c.BuildRequestToPublishRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.RequestToPublishDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("fileserver", "request-to-publish", err) + } + return decodeResponse(resp) + } +} + +// QueryPublishingStatus returns an endpoint that makes HTTP requests to the +// fileserver service query-publishing-status server. +func (c *Client) QueryPublishingStatus() goa.Endpoint { + var ( + decodeResponse = DecodeQueryPublishingStatusResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v any) (any, error) { + req, err := c.BuildQueryPublishingStatusRequest(ctx, v) + if err != nil { + return nil, err + } + resp, err := c.QueryPublishingStatusDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("fileserver", "query-publishing-status", err) + } + return decodeResponse(resp) + } +} diff --git a/publisher/gen/http/fileserver/client/encode_decode.go b/publisher/gen/http/fileserver/client/encode_decode.go new file mode 100644 index 00000000..29442c55 --- /dev/null +++ b/publisher/gen/http/fileserver/client/encode_decode.go @@ -0,0 +1,153 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP client encoders and decoders +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package client + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// BuildRequestToPublishRequest instantiates a HTTP request object with method +// and path set to call the "fileserver" service "request-to-publish" endpoint +func (c *Client) BuildRequestToPublishRequest(ctx context.Context, v any) (*http.Request, error) { + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: RequestToPublishFileserverPath()} + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("fileserver", "request-to-publish", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeRequestToPublishRequest returns an encoder for requests sent to the +// fileserver request-to-publish server. +func EncodeRequestToPublishRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, any) error { + return func(req *http.Request, v any) error { + p, ok := v.(*fileserver.RequestToPublishPayload) + if !ok { + return goahttp.ErrInvalidType("fileserver", "request-to-publish", "*fileserver.RequestToPublishPayload", v) + } + body := NewRequestToPublishRequestBody(p) + if err := encoder(req).Encode(&body); err != nil { + return goahttp.ErrEncodingError("fileserver", "request-to-publish", err) + } + return nil + } +} + +// DecodeRequestToPublishResponse returns a decoder for responses returned by +// the fileserver request-to-publish endpoint. restoreBody controls whether the +// response body should be restored after having been read. +func DecodeRequestToPublishResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (any, error) { + return func(resp *http.Response) (any, error) { + if restoreBody { + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body []string + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("fileserver", "request-to-publish", err) + } + return body, nil + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("fileserver", "request-to-publish", resp.StatusCode, string(body)) + } + } +} + +// BuildQueryPublishingStatusRequest instantiates a HTTP request object with +// method and path set to call the "fileserver" service +// "query-publishing-status" endpoint +func (c *Client) BuildQueryPublishingStatusRequest(ctx context.Context, v any) (*http.Request, error) { + var ( + requestID string + ) + { + p, ok := v.(*fileserver.QueryPublishingStatusPayload) + if !ok { + return nil, goahttp.ErrInvalidType("fileserver", "query-publishing-status", "*fileserver.QueryPublishingStatusPayload", v) + } + requestID = p.RequestID + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: QueryPublishingStatusFileserverPath(requestID)} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("fileserver", "query-publishing-status", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// DecodeQueryPublishingStatusResponse returns a decoder for responses returned +// by the fileserver query-publishing-status endpoint. restoreBody controls +// whether the response body should be restored after having been read. +func DecodeQueryPublishingStatusResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (any, error) { + return func(resp *http.Response) (any, error) { + if restoreBody { + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body string + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("fileserver", "query-publishing-status", err) + } + if !(body == "queued" || body == "processing" || body == "success" || body == "failed" || body == "canceled") { + err = goa.MergeErrors(err, goa.InvalidEnumValueError("body", body, []any{"queued", "processing", "success", "failed", "canceled"})) + } + if err != nil { + return nil, goahttp.ErrValidationError("fileserver", "query-publishing-status", err) + } + return body, nil + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("fileserver", "query-publishing-status", resp.StatusCode, string(body)) + } + } +} diff --git a/publisher/gen/http/fileserver/client/paths.go b/publisher/gen/http/fileserver/client/paths.go new file mode 100644 index 00000000..fbbba2c2 --- /dev/null +++ b/publisher/gen/http/fileserver/client/paths.go @@ -0,0 +1,22 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// HTTP request path constructors for the fileserver service. +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package client + +import ( + "fmt" +) + +// RequestToPublishFileserverPath returns the URL path to the fileserver service request-to-publish HTTP endpoint. +func RequestToPublishFileserverPath() string { + return "/fs/publish-request" +} + +// QueryPublishingStatusFileserverPath returns the URL path to the fileserver service query-publishing-status HTTP endpoint. +func QueryPublishingStatusFileserverPath(requestID string) string { + return fmt.Sprintf("/fs/publish-request/%v", requestID) +} diff --git a/publisher/gen/http/fileserver/client/types.go b/publisher/gen/http/fileserver/client/types.go new file mode 100644 index 00000000..e9f5ab17 --- /dev/null +++ b/publisher/gen/http/fileserver/client/types.go @@ -0,0 +1,29 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP client types +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package client + +import ( + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" +) + +// RequestToPublishRequestBody is the type of the "fileserver" service +// "request-to-publish" endpoint HTTP request body. +type RequestToPublishRequestBody struct { + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. + ArtifactURL string `form:"artifact_url" json:"artifact_url" xml:"artifact_url"` +} + +// NewRequestToPublishRequestBody builds the HTTP request body from the payload +// of the "request-to-publish" endpoint of the "fileserver" service. +func NewRequestToPublishRequestBody(p *fileserver.RequestToPublishPayload) *RequestToPublishRequestBody { + body := &RequestToPublishRequestBody{ + ArtifactURL: p.ArtifactURL, + } + return body +} diff --git a/publisher/gen/http/fileserver/server/encode_decode.go b/publisher/gen/http/fileserver/server/encode_decode.go new file mode 100644 index 00000000..407ffc35 --- /dev/null +++ b/publisher/gen/http/fileserver/server/encode_decode.go @@ -0,0 +1,87 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP server encoders and decoders +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package server + +import ( + "context" + "errors" + "io" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// EncodeRequestToPublishResponse returns an encoder for responses returned by +// the fileserver request-to-publish endpoint. +func EncodeRequestToPublishResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error { + return func(ctx context.Context, w http.ResponseWriter, v any) error { + res, _ := v.([]string) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeRequestToPublishRequest returns a decoder for requests sent to the +// fileserver request-to-publish endpoint. +func DecodeRequestToPublishRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) { + return func(r *http.Request) (any, error) { + var ( + body RequestToPublishRequestBody + err error + ) + err = decoder(r).Decode(&body) + if err != nil { + if err == io.EOF { + return nil, goa.MissingPayloadError() + } + var gerr *goa.ServiceError + if errors.As(err, &gerr) { + return nil, gerr + } + return nil, goa.DecodePayloadError(err.Error()) + } + err = ValidateRequestToPublishRequestBody(&body) + if err != nil { + return nil, err + } + payload := NewRequestToPublishPayload(&body) + + return payload, nil + } +} + +// EncodeQueryPublishingStatusResponse returns an encoder for responses +// returned by the fileserver query-publishing-status endpoint. +func EncodeQueryPublishingStatusResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error { + return func(ctx context.Context, w http.ResponseWriter, v any) error { + res, _ := v.(string) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeQueryPublishingStatusRequest returns a decoder for requests sent to +// the fileserver query-publishing-status endpoint. +func DecodeQueryPublishingStatusRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) { + return func(r *http.Request) (any, error) { + var ( + requestID string + + params = mux.Vars(r) + ) + requestID = params["request_id"] + payload := NewQueryPublishingStatusPayload(requestID) + + return payload, nil + } +} diff --git a/publisher/gen/http/fileserver/server/paths.go b/publisher/gen/http/fileserver/server/paths.go new file mode 100644 index 00000000..65d5dcbe --- /dev/null +++ b/publisher/gen/http/fileserver/server/paths.go @@ -0,0 +1,22 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// HTTP request path constructors for the fileserver service. +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package server + +import ( + "fmt" +) + +// RequestToPublishFileserverPath returns the URL path to the fileserver service request-to-publish HTTP endpoint. +func RequestToPublishFileserverPath() string { + return "/fs/publish-request" +} + +// QueryPublishingStatusFileserverPath returns the URL path to the fileserver service query-publishing-status HTTP endpoint. +func QueryPublishingStatusFileserverPath(requestID string) string { + return fmt.Sprintf("/fs/publish-request/%v", requestID) +} diff --git a/publisher/gen/http/fileserver/server/server.go b/publisher/gen/http/fileserver/server/server.go new file mode 100644 index 00000000..74a402f3 --- /dev/null +++ b/publisher/gen/http/fileserver/server/server.go @@ -0,0 +1,185 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP server +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package server + +import ( + "context" + "net/http" + + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Server lists the fileserver service endpoint HTTP handlers. +type Server struct { + Mounts []*MountPoint + RequestToPublish http.Handler + QueryPublishingStatus http.Handler +} + +// MountPoint holds information about the mounted endpoints. +type MountPoint struct { + // Method is the name of the service method served by the mounted HTTP handler. + Method string + // Verb is the HTTP method used to match requests to the mounted handler. + Verb string + // Pattern is the HTTP request path pattern used to match requests to the + // mounted handler. + Pattern string +} + +// New instantiates HTTP handlers for all the fileserver service endpoints +// using the provided encoder and decoder. The handlers are mounted on the +// given mux using the HTTP verb and path defined in the design. errhandler is +// called whenever a response fails to be encoded. formatter is used to format +// errors returned by the service methods prior to encoding. Both errhandler +// and formatter are optional and can be nil. +func New( + e *fileserver.Endpoints, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(ctx context.Context, err error) goahttp.Statuser, +) *Server { + return &Server{ + Mounts: []*MountPoint{ + {"RequestToPublish", "POST", "/fs/publish-request"}, + {"QueryPublishingStatus", "GET", "/fs/publish-request/{request_id}"}, + }, + RequestToPublish: NewRequestToPublishHandler(e.RequestToPublish, mux, decoder, encoder, errhandler, formatter), + QueryPublishingStatus: NewQueryPublishingStatusHandler(e.QueryPublishingStatus, mux, decoder, encoder, errhandler, formatter), + } +} + +// Service returns the name of the service served. +func (s *Server) Service() string { return "fileserver" } + +// Use wraps the server handlers with the given middleware. +func (s *Server) Use(m func(http.Handler) http.Handler) { + s.RequestToPublish = m(s.RequestToPublish) + s.QueryPublishingStatus = m(s.QueryPublishingStatus) +} + +// MethodNames returns the methods served. +func (s *Server) MethodNames() []string { return fileserver.MethodNames[:] } + +// Mount configures the mux to serve the fileserver endpoints. +func Mount(mux goahttp.Muxer, h *Server) { + MountRequestToPublishHandler(mux, h.RequestToPublish) + MountQueryPublishingStatusHandler(mux, h.QueryPublishingStatus) +} + +// Mount configures the mux to serve the fileserver endpoints. +func (s *Server) Mount(mux goahttp.Muxer) { + Mount(mux, s) +} + +// MountRequestToPublishHandler configures the mux to serve the "fileserver" +// service "request-to-publish" endpoint. +func MountRequestToPublishHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("POST", "/fs/publish-request", f) +} + +// NewRequestToPublishHandler creates a HTTP handler which loads the HTTP +// request and calls the "fileserver" service "request-to-publish" endpoint. +func NewRequestToPublishHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(ctx context.Context, err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeRequestToPublishRequest(mux, decoder) + encodeResponse = EncodeRequestToPublishResponse(encoder) + encodeError = goahttp.ErrorEncoder(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "request-to-publish") + ctx = context.WithValue(ctx, goa.ServiceKey, "fileserver") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} + +// MountQueryPublishingStatusHandler configures the mux to serve the +// "fileserver" service "query-publishing-status" endpoint. +func MountQueryPublishingStatusHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/fs/publish-request/{request_id}", f) +} + +// NewQueryPublishingStatusHandler creates a HTTP handler which loads the HTTP +// request and calls the "fileserver" service "query-publishing-status" +// endpoint. +func NewQueryPublishingStatusHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(ctx context.Context, err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeQueryPublishingStatusRequest(mux, decoder) + encodeResponse = EncodeQueryPublishingStatusResponse(encoder) + encodeError = goahttp.ErrorEncoder(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "query-publishing-status") + ctx = context.WithValue(ctx, goa.ServiceKey, "fileserver") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} diff --git a/publisher/gen/http/fileserver/server/types.go b/publisher/gen/http/fileserver/server/types.go new file mode 100644 index 00000000..54d6f99b --- /dev/null +++ b/publisher/gen/http/fileserver/server/types.go @@ -0,0 +1,49 @@ +// Code generated by goa v3.19.1, DO NOT EDIT. +// +// fileserver HTTP server types +// +// Command: +// $ goa gen github.com/PingCAP-QE/ee-apps/publisher/design + +package server + +import ( + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" + goa "goa.design/goa/v3/pkg" +) + +// RequestToPublishRequestBody is the type of the "fileserver" service +// "request-to-publish" endpoint HTTP request body. +type RequestToPublishRequestBody struct { + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. + ArtifactURL *string `form:"artifact_url,omitempty" json:"artifact_url,omitempty" xml:"artifact_url,omitempty"` +} + +// NewRequestToPublishPayload builds a fileserver service request-to-publish +// endpoint payload. +func NewRequestToPublishPayload(body *RequestToPublishRequestBody) *fileserver.RequestToPublishPayload { + v := &fileserver.RequestToPublishPayload{ + ArtifactURL: *body.ArtifactURL, + } + + return v +} + +// NewQueryPublishingStatusPayload builds a fileserver service +// query-publishing-status endpoint payload. +func NewQueryPublishingStatusPayload(requestID string) *fileserver.QueryPublishingStatusPayload { + v := &fileserver.QueryPublishingStatusPayload{} + v.RequestID = requestID + + return v +} + +// ValidateRequestToPublishRequestBody runs the validations defined on +// Request-To-PublishRequestBody +func ValidateRequestToPublishRequestBody(body *RequestToPublishRequestBody) (err error) { + if body.ArtifactURL == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("artifact_url", "body")) + } + return +} diff --git a/publisher/gen/http/openapi.json b/publisher/gen/http/openapi.json index 8be87663..b70bb87d 100644 --- a/publisher/gen/http/openapi.json +++ b/publisher/gen/http/openapi.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Publish API","description":"Publish API","contact":{"name":"WuHui Zuo","email":"wuhui.zuo@pingcap.com","url":"https://github.com/wuhuizuo"},"version":"1.0.0"},"host":"0.0.0.0:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/tiup/publish-request":{"post":{"tags":["tiup"],"summary":"request-to-publish tiup","operationId":"tiup#request-to-publish","parameters":[{"name":"Request-To-PublishRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/TiupRequestToPublishRequestBody","required":["artifact_url","tiup-mirror"]}}],"responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Cupiditate suscipit hic quidem voluptates nostrum necessitatibus."}}}},"schemes":["http"]}},"/tiup/publish-request/{request_id}":{"get":{"tags":["tiup"],"summary":"query-publishing-status tiup","operationId":"tiup#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","enum":["queued","processing","success","failed","canceled"]}}},"schemes":["http"]}}},"definitions":{"TiupRequestToPublishRequestBody":{"title":"TiupRequestToPublishRequestBody","type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed image, contain the tag part. It will parse the repo from it.","example":"Optio necessitatibus ipsa incidunt."},"request_id":{"type":"string","description":"The request id","example":"Et ullam."},"tiup-mirror":{"type":"string","description":"Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987.","default":"http://tiup.pingcap.net:8988","example":"Illo harum quis voluptatem."},"version":{"type":"string","description":"Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config.","example":"Expedita et necessitatibus ut molestias."}},"example":{"artifact_url":"Et suscipit et.","request_id":"Corrupti ut natus aut ipsam reprehenderit.","tiup-mirror":"Assumenda tempora autem accusantium est.","version":"Ab expedita repellendus."},"required":["artifact_url","tiup-mirror"]}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Publish API","description":"Publish API","contact":{"name":"WuHui Zuo","email":"wuhui.zuo@pingcap.com","url":"https://github.com/wuhuizuo"},"version":"1.0.0"},"host":"0.0.0.0:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/fs/publish-request":{"post":{"tags":["fileserver"],"summary":"request-to-publish fileserver","operationId":"fileserver#request-to-publish","parameters":[{"name":"Request-To-PublishRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/FileserverRequestToPublishRequestBody","required":["artifact_url"]}}],"responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Ut laborum nulla at error."}}}},"schemes":["http"]}},"/fs/publish-request/{request_id}":{"get":{"tags":["fileserver"],"summary":"query-publishing-status fileserver","operationId":"fileserver#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","enum":["queued","processing","success","failed","canceled"]}}},"schemes":["http"]}},"/tiup/publish-request":{"post":{"tags":["tiup"],"summary":"request-to-publish tiup","operationId":"tiup#request-to-publish","parameters":[{"name":"Request-To-PublishRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/TiupRequestToPublishRequestBody","required":["artifact_url","tiup-mirror"]}}],"responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Accusantium optio distinctio magni quia adipisci excepturi."}}}},"schemes":["http"]}},"/tiup/publish-request/{request_id}":{"get":{"tags":["tiup"],"summary":"query-publishing-status tiup","operationId":"tiup#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","enum":["queued","processing","success","failed","canceled"]}}},"schemes":["http"]}}},"definitions":{"FileserverRequestToPublishRequestBody":{"title":"FileserverRequestToPublishRequestBody","type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.","example":"Dolores et ipsa molestiae rem nisi non."}},"example":{"artifact_url":"Necessitatibus officia distinctio officia voluptas laudantium iure."},"required":["artifact_url"]},"TiupRequestToPublishRequestBody":{"title":"TiupRequestToPublishRequestBody","type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.","example":"Quibusdam nisi quam."},"request_id":{"type":"string","description":"The request id","example":"Nemo rerum voluptas."},"tiup-mirror":{"type":"string","description":"Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987.","default":"http://tiup.pingcap.net:8988","example":"Eum saepe nihil omnis dolorem eveniet."},"version":{"type":"string","description":"Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config.","example":"Atque vero in molestiae odit consequatur."}},"example":{"artifact_url":"Eos eveniet vero.","request_id":"Est dignissimos exercitationem atque amet optio et.","tiup-mirror":"Repellat voluptates possimus pariatur consequuntur.","version":"Distinctio voluptates voluptatem accusamus nisi omnis quia."},"required":["artifact_url","tiup-mirror"]}}} \ No newline at end of file diff --git a/publisher/gen/http/openapi.yaml b/publisher/gen/http/openapi.yaml index f95cf57f..08923da7 100644 --- a/publisher/gen/http/openapi.yaml +++ b/publisher/gen/http/openapi.yaml @@ -17,6 +17,55 @@ produces: - application/xml - application/gob paths: + /fs/publish-request: + post: + tags: + - fileserver + summary: request-to-publish fileserver + operationId: fileserver#request-to-publish + parameters: + - name: Request-To-PublishRequestBody + in: body + required: true + schema: + $ref: '#/definitions/FileserverRequestToPublishRequestBody' + required: + - artifact_url + responses: + "200": + description: OK response. + schema: + type: array + items: + type: string + example: Ut laborum nulla at error. + schemes: + - http + /fs/publish-request/{request_id}: + get: + tags: + - fileserver + summary: query-publishing-status fileserver + operationId: fileserver#query-publishing-status + parameters: + - name: request_id + in: path + description: request track id + required: true + type: string + responses: + "200": + description: OK response. + schema: + type: string + enum: + - queued + - processing + - success + - failed + - canceled + schemes: + - http /tiup/publish-request: post: tags: @@ -39,7 +88,7 @@ paths: type: array items: type: string - example: Cupiditate suscipit hic quidem voluptates nostrum necessitatibus. + example: Accusantium optio distinctio magni quia adipisci excepturi. schemes: - http /tiup/publish-request/{request_id}: @@ -68,32 +117,44 @@ paths: schemes: - http definitions: + FileserverRequestToPublishRequestBody: + title: FileserverRequestToPublishRequestBody + type: object + properties: + artifact_url: + type: string + description: The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it. + example: Dolores et ipsa molestiae rem nisi non. + example: + artifact_url: Necessitatibus officia distinctio officia voluptas laudantium iure. + required: + - artifact_url TiupRequestToPublishRequestBody: title: TiupRequestToPublishRequestBody type: object properties: artifact_url: type: string - description: The full url of the pushed image, contain the tag part. It will parse the repo from it. - example: Optio necessitatibus ipsa incidunt. + description: The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it. + example: Quibusdam nisi quam. request_id: type: string description: The request id - example: Et ullam. + example: Nemo rerum voluptas. tiup-mirror: type: string description: Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987. default: http://tiup.pingcap.net:8988 - example: Illo harum quis voluptatem. + example: Eum saepe nihil omnis dolorem eveniet. version: type: string description: Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config. - example: Expedita et necessitatibus ut molestias. + example: Atque vero in molestiae odit consequatur. example: - artifact_url: Et suscipit et. - request_id: Corrupti ut natus aut ipsam reprehenderit. - tiup-mirror: Assumenda tempora autem accusantium est. - version: Ab expedita repellendus. + artifact_url: Eos eveniet vero. + request_id: Est dignissimos exercitationem atque amet optio et. + tiup-mirror: Repellat voluptates possimus pariatur consequuntur. + version: Distinctio voluptates voluptatem accusamus nisi omnis quia. required: - artifact_url - tiup-mirror diff --git a/publisher/gen/http/openapi3.json b/publisher/gen/http/openapi3.json index a22b8d6d..47ac5a3b 100644 --- a/publisher/gen/http/openapi3.json +++ b/publisher/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Publish API","description":"Publish API","contact":{"name":"WuHui Zuo","url":"https://github.com/wuhuizuo","email":"wuhui.zuo@pingcap.com"},"version":"1.0.0"},"servers":[{"url":"http://0.0.0.0:80"}],"paths":{"/tiup/publish-request":{"post":{"tags":["tiup"],"summary":"request-to-publish tiup","operationId":"tiup#request-to-publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestToPublishRequestBody"},"example":{"artifact_url":"Omnis expedita.","request_id":"Est sequi placeat.","tiup-mirror":"Pariatur rerum consectetur deleniti architecto sunt.","version":"Dicta id perferendis rem a."}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","example":"Eum saepe nihil omnis dolorem eveniet."},"description":"request track ids","example":["Rerum voluptas dolore.","Eveniet vero voluptas.","Voluptates voluptatem accusamus nisi omnis quia molestias."]},"example":["Pariatur consequuntur itaque est.","Exercitationem atque amet optio."]}}}}}},"/tiup/publish-request/{request_id}":{"get":{"tags":["tiup"],"summary":"query-publishing-status tiup","operationId":"tiup#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"schema":{"type":"string","description":"request track id","example":"Aliquam ut laborum nulla."},"example":"Error qui dolores et."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","description":"request state","example":"processing","enum":["queued","processing","success","failed","canceled"]},"example":"queued"}}}}}}},"components":{"schemas":{"RequestToPublishRequestBody":{"type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed image, contain the tag part. It will parse the repo from it.","example":"Et eum odit eos ratione."},"request_id":{"type":"string","description":"The request id","example":"Voluptas ratione hic libero nisi."},"tiup-mirror":{"type":"string","description":"Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987.","default":"http://tiup.pingcap.net:8988","example":"Rerum tempore voluptas."},"version":{"type":"string","description":"Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config.","example":"Laboriosam optio omnis cupiditate magnam nisi."}},"example":{"artifact_url":"Rerum voluptate accusantium optio.","request_id":"Atque vero in molestiae odit consequatur.","tiup-mirror":"Quibusdam nisi quam.","version":"Magni quia adipisci excepturi."},"required":["artifact_url","tiup-mirror"]}}},"tags":[{"name":"tiup","description":"TiUP Publisher service"}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Publish API","description":"Publish API","contact":{"name":"WuHui Zuo","url":"https://github.com/wuhuizuo","email":"wuhui.zuo@pingcap.com"},"version":"1.0.0"},"servers":[{"url":"http://0.0.0.0:80"}],"paths":{"/fs/publish-request":{"post":{"tags":["fileserver"],"summary":"request-to-publish fileserver","operationId":"fileserver#request-to-publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestToPublishRequestBody2"},"example":{"artifact_url":"Quis voluptatem earum et ullam esse."}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","example":"Sit id eaque laboriosam nostrum eaque consequatur."},"description":"request track ids","example":["Cumque voluptatem amet at.","Consequatur fuga earum sit sit ipsum ea.","Est magnam a."]},"example":["Tenetur qui perferendis ducimus.","In quo enim.","Ipsam et in non enim."]}}}}}},"/fs/publish-request/{request_id}":{"get":{"tags":["fileserver"],"summary":"query-publishing-status fileserver","operationId":"fileserver#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"schema":{"type":"string","description":"request track id","example":"Ipsa sunt aut harum quo fuga earum."},"example":"Labore cumque id quod ut repudiandae id."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","description":"request state","example":"queued","enum":["queued","processing","success","failed","canceled"]},"example":"canceled"}}}}}},"/tiup/publish-request":{"post":{"tags":["tiup"],"summary":"request-to-publish tiup","operationId":"tiup#request-to-publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestToPublishRequestBody"},"example":{"artifact_url":"Placeat blanditiis est iusto.","request_id":"Quo ut dolor perspiciatis rem assumenda enim.","tiup-mirror":"Totam omnis sunt cum voluptatem amet.","version":"Eum eligendi."}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","example":"Quos consequatur."},"description":"request track ids","example":["Pariatur maiores neque enim perferendis.","Qui eligendi iusto ut.","Deserunt nisi voluptates quis quia sed.","Vero qui autem rerum ipsa maxime."]},"example":["Enim facere odio et cupiditate ut exercitationem.","Ratione autem magnam excepturi incidunt suscipit.","Laboriosam ea.","Officia recusandae vel qui voluptates dicta rerum."]}}}}}},"/tiup/publish-request/{request_id}":{"get":{"tags":["tiup"],"summary":"query-publishing-status tiup","operationId":"tiup#query-publishing-status","parameters":[{"name":"request_id","in":"path","description":"request track id","required":true,"schema":{"type":"string","description":"request track id","example":"Et laborum."},"example":"Eligendi dignissimos a itaque et et."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","description":"request state","example":"processing","enum":["queued","processing","success","failed","canceled"]},"example":"failed"}}}}}}},"components":{"schemas":{"RequestToPublishRequestBody":{"type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.","example":"Dolorum molestiae vitae ut commodi."},"request_id":{"type":"string","description":"The request id","example":"Nisi earum earum pariatur et animi."},"tiup-mirror":{"type":"string","description":"Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987.","default":"http://tiup.pingcap.net:8988","example":"Facere maiores tenetur mollitia consequatur perferendis sint."},"version":{"type":"string","description":"Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config.","example":"Consectetur dolor magnam aut et labore."}},"example":{"artifact_url":"Aperiam consequatur consequatur.","request_id":"Et sit odio molestiae debitis aut.","tiup-mirror":"Voluptas et saepe autem sint rem corrupti.","version":"Sint a dolores ab veritatis eaque ex."},"required":["artifact_url","tiup-mirror"]},"RequestToPublishRequestBody2":{"type":"object","properties":{"artifact_url":{"type":"string","description":"The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it.","example":"Excepturi est."}},"example":{"artifact_url":"Ab accusamus."},"required":["artifact_url"]}}},"tags":[{"name":"tiup","description":"TiUP Publisher service"},{"name":"fileserver","description":"Publisher service for static file server "}]} \ No newline at end of file diff --git a/publisher/gen/http/openapi3.yaml b/publisher/gen/http/openapi3.yaml index 50a28058..e18b3f7c 100644 --- a/publisher/gen/http/openapi3.yaml +++ b/publisher/gen/http/openapi3.yaml @@ -10,6 +10,71 @@ info: servers: - url: http://0.0.0.0:80 paths: + /fs/publish-request: + post: + tags: + - fileserver + summary: request-to-publish fileserver + operationId: fileserver#request-to-publish + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RequestToPublishRequestBody2' + example: + artifact_url: Quis voluptatem earum et ullam esse. + responses: + "200": + description: OK response. + content: + application/json: + schema: + type: array + items: + type: string + example: Sit id eaque laboriosam nostrum eaque consequatur. + description: request track ids + example: + - Cumque voluptatem amet at. + - Consequatur fuga earum sit sit ipsum ea. + - Est magnam a. + example: + - Tenetur qui perferendis ducimus. + - In quo enim. + - Ipsam et in non enim. + /fs/publish-request/{request_id}: + get: + tags: + - fileserver + summary: query-publishing-status fileserver + operationId: fileserver#query-publishing-status + parameters: + - name: request_id + in: path + description: request track id + required: true + schema: + type: string + description: request track id + example: Ipsa sunt aut harum quo fuga earum. + example: Labore cumque id quod ut repudiandae id. + responses: + "200": + description: OK response. + content: + application/json: + schema: + type: string + description: request state + example: queued + enum: + - queued + - processing + - success + - failed + - canceled + example: canceled /tiup/publish-request: post: tags: @@ -23,10 +88,10 @@ paths: schema: $ref: '#/components/schemas/RequestToPublishRequestBody' example: - artifact_url: Omnis expedita. - request_id: Est sequi placeat. - tiup-mirror: Pariatur rerum consectetur deleniti architecto sunt. - version: Dicta id perferendis rem a. + artifact_url: Placeat blanditiis est iusto. + request_id: Quo ut dolor perspiciatis rem assumenda enim. + tiup-mirror: Totam omnis sunt cum voluptatem amet. + version: Eum eligendi. responses: "200": description: OK response. @@ -36,15 +101,18 @@ paths: type: array items: type: string - example: Eum saepe nihil omnis dolorem eveniet. + example: Quos consequatur. description: request track ids example: - - Rerum voluptas dolore. - - Eveniet vero voluptas. - - Voluptates voluptatem accusamus nisi omnis quia molestias. + - Pariatur maiores neque enim perferendis. + - Qui eligendi iusto ut. + - Deserunt nisi voluptates quis quia sed. + - Vero qui autem rerum ipsa maxime. example: - - Pariatur consequuntur itaque est. - - Exercitationem atque amet optio. + - Enim facere odio et cupiditate ut exercitationem. + - Ratione autem magnam excepturi incidunt suscipit. + - Laboriosam ea. + - Officia recusandae vel qui voluptates dicta rerum. /tiup/publish-request/{request_id}: get: tags: @@ -59,8 +127,8 @@ paths: schema: type: string description: request track id - example: Aliquam ut laborum nulla. - example: Error qui dolores et. + example: Et laborum. + example: Eligendi dignissimos a itaque et et. responses: "200": description: OK response. @@ -76,7 +144,7 @@ paths: - success - failed - canceled - example: queued + example: failed components: schemas: RequestToPublishRequestBody: @@ -84,29 +152,42 @@ components: properties: artifact_url: type: string - description: The full url of the pushed image, contain the tag part. It will parse the repo from it. - example: Et eum odit eos ratione. + description: The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it. + example: Dolorum molestiae vitae ut commodi. request_id: type: string description: The request id - example: Voluptas ratione hic libero nisi. + example: Nisi earum earum pariatur et animi. tiup-mirror: type: string description: Staging is http://tiup.pingcap.net:8988, product is http://tiup.pingcap.net:8987. default: http://tiup.pingcap.net:8988 - example: Rerum tempore voluptas. + example: Facere maiores tenetur mollitia consequatur perferendis sint. version: type: string description: Force set the version. Default is the artifact version read from `org.opencontainers.image.version` of the manifest config. - example: Laboriosam optio omnis cupiditate magnam nisi. + example: Consectetur dolor magnam aut et labore. example: - artifact_url: Rerum voluptate accusantium optio. - request_id: Atque vero in molestiae odit consequatur. - tiup-mirror: Quibusdam nisi quam. - version: Magni quia adipisci excepturi. + artifact_url: Aperiam consequatur consequatur. + request_id: Et sit odio molestiae debitis aut. + tiup-mirror: Voluptas et saepe autem sint rem corrupti. + version: Sint a dolores ab veritatis eaque ex. required: - artifact_url - tiup-mirror + RequestToPublishRequestBody2: + type: object + properties: + artifact_url: + type: string + description: The full url of the pushed OCI artifact, contain the tag part. It will parse the repo from it. + example: Excepturi est. + example: + artifact_url: Ab accusamus. + required: + - artifact_url tags: - name: tiup description: TiUP Publisher service + - name: fileserver + description: 'Publisher service for static file server ' diff --git a/publisher/gen/http/tiup/client/cli.go b/publisher/gen/http/tiup/client/cli.go index a7e84656..8ccbfecc 100644 --- a/publisher/gen/http/tiup/client/cli.go +++ b/publisher/gen/http/tiup/client/cli.go @@ -22,7 +22,7 @@ func BuildRequestToPublishPayload(tiupRequestToPublishBody string) (*tiup.Reques { err = json.Unmarshal([]byte(tiupRequestToPublishBody), &body) if err != nil { - return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"artifact_url\": \"Omnis expedita.\",\n \"request_id\": \"Est sequi placeat.\",\n \"tiup-mirror\": \"Pariatur rerum consectetur deleniti architecto sunt.\",\n \"version\": \"Dicta id perferendis rem a.\"\n }'") + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"artifact_url\": \"Placeat blanditiis est iusto.\",\n \"request_id\": \"Quo ut dolor perspiciatis rem assumenda enim.\",\n \"tiup-mirror\": \"Totam omnis sunt cum voluptatem amet.\",\n \"version\": \"Eum eligendi.\"\n }'") } } v := &tiup.RequestToPublishPayload{ diff --git a/publisher/gen/http/tiup/client/types.go b/publisher/gen/http/tiup/client/types.go index 4e1c42e8..08f0aad4 100644 --- a/publisher/gen/http/tiup/client/types.go +++ b/publisher/gen/http/tiup/client/types.go @@ -14,8 +14,8 @@ import ( // RequestToPublishRequestBody is the type of the "tiup" service // "request-to-publish" endpoint HTTP request body. type RequestToPublishRequestBody struct { - // The full url of the pushed image, contain the tag part. It will parse the - // repo from it. + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. ArtifactURL string `form:"artifact_url" json:"artifact_url" xml:"artifact_url"` // Force set the version. Default is the artifact version read from // `org.opencontainers.image.version` of the manifest config. diff --git a/publisher/gen/http/tiup/server/types.go b/publisher/gen/http/tiup/server/types.go index 81da60b1..021681df 100644 --- a/publisher/gen/http/tiup/server/types.go +++ b/publisher/gen/http/tiup/server/types.go @@ -15,8 +15,8 @@ import ( // RequestToPublishRequestBody is the type of the "tiup" service // "request-to-publish" endpoint HTTP request body. type RequestToPublishRequestBody struct { - // The full url of the pushed image, contain the tag part. It will parse the - // repo from it. + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. ArtifactURL *string `form:"artifact_url,omitempty" json:"artifact_url,omitempty" xml:"artifact_url,omitempty"` // Force set the version. Default is the artifact version read from // `org.opencontainers.image.version` of the manifest config. diff --git a/publisher/gen/tiup/service.go b/publisher/gen/tiup/service.go index 77b42801..bb9cced2 100644 --- a/publisher/gen/tiup/service.go +++ b/publisher/gen/tiup/service.go @@ -45,8 +45,8 @@ type QueryPublishingStatusPayload struct { // RequestToPublishPayload is the payload type of the tiup service // request-to-publish method. type RequestToPublishPayload struct { - // The full url of the pushed image, contain the tag part. It will parse the - // repo from it. + // The full url of the pushed OCI artifact, contain the tag part. It will parse + // the repo from it. ArtifactURL string // Force set the version. Default is the artifact version read from // `org.opencontainers.image.version` of the manifest config. diff --git a/publisher/pkg/impl/fileserver_service.go b/publisher/pkg/impl/fileserver_service.go new file mode 100644 index 00000000..47fe1f98 --- /dev/null +++ b/publisher/pkg/impl/fileserver_service.go @@ -0,0 +1,109 @@ +package impl + +import ( + "context" + "fmt" + "time" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/go-redis/redis/v8" + "github.com/google/uuid" + "github.com/rs/zerolog" + "github.com/segmentio/kafka-go" + + fileserver "github.com/PingCAP-QE/ee-apps/publisher/gen/fileserver" +) + +// fileserver service example implementation. +// The example methods log the requests and return zero values. +type fileserversrvc struct { + logger *zerolog.Logger + kafkaWriter *kafka.Writer + redisClient redis.Cmdable + eventSource string + stateTTL time.Duration +} + +// NewFileserver returns the fileserver service implementation. +func NewFileserver(logger *zerolog.Logger, kafkaWriter *kafka.Writer, redisClient redis.Cmdable, eventSrc string) fileserver.Service { + return &fileserversrvc{ + logger: logger, + kafkaWriter: kafkaWriter, + redisClient: redisClient, + eventSource: eventSrc, + stateTTL: DefaultStateTTL, + } +} + +// RequestToPublish implements request-to-publish. +func (s *fileserversrvc) RequestToPublish(ctx context.Context, p *fileserver.RequestToPublishPayload) (res []string, err error) { + s.logger.Info().Msgf("fileserver.request-to-publish") + // 1. Analyze the artifact_url to get the repo and tag and the tiup package information. + publishRequests, err := analyzeFromOciArtifactUrl(p.ArtifactURL) + if err != nil { + return nil, err + } + + // 2. Compose cloud events with the analyzed results. + events := s.composeEvents(publishRequests) + + // 3. Send it to kafka topic with the request id as key and the event as value. + var messages []kafka.Message + for _, event := range events { + bs, _ := event.MarshalJSON() + messages = append(messages, kafka.Message{ + Key: []byte(event.ID()), + Value: bs, + }) + } + err = s.kafkaWriter.WriteMessages(ctx, messages...) + if err != nil { + return nil, fmt.Errorf("failed to send message to Kafka: %v", err) + } + + var requestIDs []string + for _, event := range events { + requestIDs = append(requestIDs, event.ID()) + } + + // 4. Init the request dealing status in redis with the request id. + for _, requestID := range requestIDs { + if err := s.redisClient.SetNX(ctx, requestID, PublishStateQueued, s.stateTTL).Err(); err != nil { + return nil, fmt.Errorf("failed to set initial status in Redis: %v", err) + } + } + + // 5. Return the request id. + return requestIDs, nil +} + +// QueryPublishingStatus implements query-publishing-status. +func (s *fileserversrvc) QueryPublishingStatus(ctx context.Context, p *fileserver.QueryPublishingStatusPayload) (res string, err error) { + s.logger.Info().Msgf("fileserver.query-publishing-status") + // 1. Get the request dealing status from redis with the request id. + status, err := s.redisClient.Get(ctx, p.RequestID).Result() + if err != nil { + if err == redis.Nil { + return "", fmt.Errorf("request ID not found") + } + return "", fmt.Errorf("failed to get status from Redis: %v", err) + } + + // 2. Return the request dealing status. + return status, nil +} + +func (s *fileserversrvc) composeEvents(requests []PublishRequest) []cloudevents.Event { + var ret []cloudevents.Event + for _, request := range requests { + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetType(EventTypeFsPublishRequest) + event.SetSource(s.eventSource) + event.SetSubject(request.Publish.Name) + event.SetData(cloudevents.ApplicationJSON, request) + ret = append(ret, event) + } + + return ret +} diff --git a/publisher/pkg/impl/tiup/funcs.go b/publisher/pkg/impl/funcs.go similarity index 98% rename from publisher/pkg/impl/tiup/funcs.go rename to publisher/pkg/impl/funcs.go index aad1fb02..179e7bea 100644 --- a/publisher/pkg/impl/tiup/funcs.go +++ b/publisher/pkg/impl/funcs.go @@ -1,4 +1,4 @@ -package tiup +package impl import ( "context" @@ -40,7 +40,7 @@ var ( // # - set the version to "vX.Y.Z" // check the remote file after published. -func postCheck(localFile, remoteFileURL string) error { +func postCheckTiupPkg(localFile, remoteFileURL string) error { // 1. Calculate the sha256sum of the local file localSum, err := calculateSHA256(localFile) if err != nil { @@ -297,7 +297,7 @@ func transformVer(version, tag string) string { return strings.TrimSuffix(version, "-pre") case ociNightlyTagRegex.MatchString(tag): // Nightly case // we replace the suffix part of version: '-[0-9]+-g[0-9a-f]+$' to "-nightly" - return pkgVersionNightlyRegex.ReplaceAllString(version, nightlyVerSuffix) + return pkgVersionNightlyRegex.ReplaceAllString(version, "") + "-nightly" default: return version } diff --git a/publisher/pkg/impl/tiup/funcs_test.go b/publisher/pkg/impl/funcs_test.go similarity index 99% rename from publisher/pkg/impl/tiup/funcs_test.go rename to publisher/pkg/impl/funcs_test.go index 19fb703b..54a59237 100644 --- a/publisher/pkg/impl/tiup/funcs_test.go +++ b/publisher/pkg/impl/funcs_test.go @@ -1,4 +1,4 @@ -package tiup +package impl import ( "reflect" diff --git a/publisher/pkg/impl/tiup/service.go b/publisher/pkg/impl/tiup_service.go similarity index 91% rename from publisher/pkg/impl/tiup/service.go rename to publisher/pkg/impl/tiup_service.go index 139a11ff..c5abf48b 100644 --- a/publisher/pkg/impl/tiup/service.go +++ b/publisher/pkg/impl/tiup_service.go @@ -1,4 +1,4 @@ -package tiup +package impl import ( "context" @@ -24,8 +24,8 @@ type tiupsrvc struct { stateTTL time.Duration } -// NewService returns the tiup service implementation. -func NewService(logger *zerolog.Logger, kafkaWriter *kafka.Writer, redisClient redis.Cmdable, eventSrc string) gentiup.Service { +// NewTiup returns the tiup service implementation. +func NewTiup(logger *zerolog.Logger, kafkaWriter *kafka.Writer, redisClient redis.Cmdable, eventSrc string) gentiup.Service { return &tiupsrvc{ logger: logger, kafkaWriter: kafkaWriter, @@ -61,7 +61,6 @@ func (s *tiupsrvc) RequestToPublish(ctx context.Context, p *gentiup.RequestToPub Value: bs, }) } - err = s.kafkaWriter.WriteMessages(ctx, messages...) if err != nil { return nil, fmt.Errorf("failed to send message to Kafka: %v", err) @@ -104,9 +103,9 @@ func (s *tiupsrvc) composeEvents(requests []PublishRequest) []cloudevents.Event for _, request := range requests { event := cloudevents.NewEvent() event.SetID(uuid.New().String()) - event.SetType(EventTypePublishRequest) + event.SetType(EventTypeTiupPublishRequest) event.SetSource(s.eventSource) - event.SetSubject(EventTypePublishRequest) + event.SetSubject(request.Publish.Name) event.SetData(cloudevents.ApplicationJSON, request) ret = append(ret, event) } diff --git a/publisher/pkg/impl/tiup/types.go b/publisher/pkg/impl/types.go similarity index 58% rename from publisher/pkg/impl/tiup/types.go rename to publisher/pkg/impl/types.go index ebfca3e8..57ae9e24 100644 --- a/publisher/pkg/impl/tiup/types.go +++ b/publisher/pkg/impl/types.go @@ -1,9 +1,10 @@ -package tiup +package impl import "time" const ( - EventTypePublishRequest = "net.pingcap.tibuild.tiup-publish-request" + EventTypeTiupPublishRequest = "net.pingcap.tibuild.tiup-publish-request" + EventTypeFsPublishRequest = "net.pingcap.tibuild.fs-publish-request" FromTypeOci = "oci" FromTypeHTTP = "http" @@ -14,8 +15,8 @@ const ( PublishStateFailed = "failed" PublishStateCanceled = "canceled" - DefaultStateTTL = 12 * time.Hour - DefaultNightlyInternal = 12 * time.Hour + DefaultStateTTL = 12 * time.Hour + DefaultTiupNightlyInternal = 12 * time.Hour ) type PublishRequest struct { @@ -30,16 +31,16 @@ type From struct { } type PublishInfo struct { - Name string `json:"name,omitempty"` + Name string `json:"name,omitempty"` // tiup pkg name or component name for fileserver OS string `json:"os,omitempty"` Arch string `json:"arch,omitempty"` Version string `json:"version,omitempty"` - Description string `json:"description,omitempty"` - EntryPoint string `json:"entry_point,omitempty"` - Standalone bool `json:"standalone,omitempty"` + Description string `json:"description,omitempty"` // ignore for `EventTypeFsPublishRequest` + EntryPoint string `json:"entry_point,omitempty"` // ignore for `EventTypeFsPublishRequest` + Standalone bool `json:"standalone,omitempty"` // ignore for `EventTypeFsPublishRequest` } -func (p *PublishInfo) IsNightly() bool { +func (p *PublishInfo) IsNightlyTiup() bool { return tiupVersionRegex.MatchString(p.Version) } diff --git a/publisher/pkg/impl/tiup/publisher.go b/publisher/pkg/impl/worker.go similarity index 69% rename from publisher/pkg/impl/tiup/publisher.go rename to publisher/pkg/impl/worker.go index 852b5558..dae80c91 100644 --- a/publisher/pkg/impl/tiup/publisher.go +++ b/publisher/pkg/impl/worker.go @@ -1,9 +1,10 @@ -package tiup +package impl import ( "bytes" "context" "encoding/json" + "errors" "fmt" "net/http" "os" @@ -16,20 +17,20 @@ import ( "github.com/rs/zerolog" ) -type Publisher struct { +type Worker struct { logger zerolog.Logger redisClient redis.Cmdable - options PublisherOptions + options WorkerOptions } -type PublisherOptions struct { - MirrorURL string +type WorkerOptions struct { LarkWebhookURL string + MirrorURL string NightlyInterval time.Duration } -func NewPublisher(logger *zerolog.Logger, redisClient redis.Cmdable, options PublisherOptions) (*Publisher, error) { - handler := Publisher{options: options, redisClient: redisClient} +func NewWorker(logger *zerolog.Logger, redisClient redis.Cmdable, options WorkerOptions) (*Worker, error) { + handler := Worker{options: options, redisClient: redisClient} if logger == nil { handler.logger = zerolog.New(os.Stderr).With().Timestamp().Logger() } else { @@ -39,12 +40,12 @@ func NewPublisher(logger *zerolog.Logger, redisClient redis.Cmdable, options Pub return &handler, nil } -func (p *Publisher) SupportEventTypes() []string { - return []string{EventTypePublishRequest} +func (p *Worker) SupportEventTypes() []string { + return []string{EventTypeTiupPublishRequest, EventTypeFsPublishRequest} } // Handle for test case run events -func (p *Publisher) Handle(event cloudevents.Event) cloudevents.Result { +func (p *Worker) Handle(event cloudevents.Event) cloudevents.Result { if !slices.Contains(p.SupportEventTypes(), event.Type()) { return cloudevents.ResultNACK } @@ -55,7 +56,16 @@ func (p *Publisher) Handle(event cloudevents.Event) cloudevents.Result { return cloudevents.NewReceipt(false, "invalid data: %v", err) } - result := p.rateLimit(data, p.options.NightlyInterval, p.handleImpl) + var result cloudevents.Result + switch event.Type() { + case EventTypeTiupPublishRequest: + result = p.rateLimitForTiup(data, p.options.NightlyInterval, p.handleTiup) + case EventTypeFsPublishRequest: + result = p.handleFs(data) + default: + result = fmt.Errorf("unsupported event type: %s", event.Type()) + } + switch { case cloudevents.IsACK(result): p.redisClient.SetXX(context.Background(), event.ID(), PublishStateSuccess, redis.KeepTTL) @@ -69,9 +79,9 @@ func (p *Publisher) Handle(event cloudevents.Event) cloudevents.Result { return result } -func (p *Publisher) rateLimit(data *PublishRequest, ttl time.Duration, run func(*PublishRequest) cloudevents.Result) cloudevents.Result { +func (p *Worker) rateLimitForTiup(data *PublishRequest, ttl time.Duration, run func(*PublishRequest) cloudevents.Result) cloudevents.Result { // Skip rate limiting for no nightly builds - if !data.Publish.IsNightly() || ttl <= 0 { + if !data.Publish.IsNightlyTiup() || ttl <= 0 { return run(data) } @@ -102,7 +112,7 @@ func (p *Publisher) rateLimit(data *PublishRequest, ttl time.Duration, run func( return fmt.Errorf("skip: rate limit exceeded for package %s", data.Publish.Name) } -func (p *Publisher) handleImpl(data *PublishRequest) cloudevents.Result { +func (p *Worker) handleTiup(data *PublishRequest) cloudevents.Result { // 1. get the the tarball from data.From. saveTo, err := downloadFile(data) if err != nil { @@ -112,7 +122,7 @@ func (p *Publisher) handleImpl(data *PublishRequest) cloudevents.Result { p.logger.Info().Msg("download file success") // 2. publish the tarball to the mirror. - if err := p.publish(saveTo, &data.Publish); err != nil { + if err := p.publishTiupPkg(saveTo, &data.Publish); err != nil { p.logger.Err(err).Msg("publish to mirror failed") return cloudevents.NewReceipt(false, "publish to mirror failed: %v", err) } @@ -121,7 +131,7 @@ func (p *Publisher) handleImpl(data *PublishRequest) cloudevents.Result { // 3. check the package is in the mirror. // printf 'post_check "$(tiup mirror show)/%s-%s-%s-%s.tar.gz" "%s"\n' \ remoteURL := fmt.Sprintf("%s/%s-%s-%s-%s.tar.gz", p.options.MirrorURL, data.Publish.Name, data.Publish.Version, data.Publish.OS, data.Publish.Arch) - if err := postCheck(saveTo, remoteURL); err != nil { + if err := postCheckTiupPkg(saveTo, remoteURL); err != nil { p.logger.Err(err).Str("remote", remoteURL).Msg("post check failed") return cloudevents.NewReceipt(false, "post check failed: %v", err) } @@ -130,7 +140,26 @@ func (p *Publisher) handleImpl(data *PublishRequest) cloudevents.Result { return cloudevents.ResultACK } -func (p *Publisher) notifyLark(publishInfo *PublishInfo, err error) { +func (p *Worker) handleFs(data *PublishRequest) cloudevents.Result { + // 1. get the the tarball from data.From. + saveTo, err := downloadFile(data) + if err != nil { + p.logger.Err(err).Msg("download file failed") + return cloudevents.NewReceipt(false, "download file failed: %v", err) + } + p.logger.Info().Msg("download file success") + + // 2. publish the tarball to the mirror. + if err := p.publishFileserver(saveTo, &data.Publish); err != nil { + p.logger.Err(err).Msg("publish to fileserver failed") + return cloudevents.NewReceipt(false, "publish to fileserver failed: %v", err) + } + p.logger.Info().Msg("publish to fs success") + + return cloudevents.ResultACK +} + +func (p *Worker) notifyLark(publishInfo *PublishInfo, err error) { if p.options.LarkWebhookURL == "" { return } @@ -166,7 +195,7 @@ func (p *Publisher) notifyLark(publishInfo *PublishInfo, err error) { } } -func (p *Publisher) publish(file string, info *PublishInfo) error { +func (p *Worker) publishTiupPkg(file string, info *PublishInfo) error { args := []string{"mirror", "publish", info.Name, info.Version, file, info.EntryPoint, "--os", info.OS, "--arch", info.Arch, "--desc", info.Description} if info.Standalone { args = append(args, "--standalone") @@ -187,3 +216,8 @@ func (p *Publisher) publish(file string, info *PublishInfo) error { return nil } + +func (p *Worker) publishFileserver(file string, info *PublishInfo) error { + // to implement + return errors.New("not implemented") +}