diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e5a6f57f8844673bac5247019a0d7928bb3c6340..9a68bdb7477ab7da0394827ca3b1ec64e5190b49 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ before_script: - cd /go/src/code.vereign.com/${CI_PROJECT_PATH} lint: - image: golangci/golangci-lint:v1.44.2 + image: golangci/golangci-lint:v1.46.2 stage: test tags: - amd64-docker @@ -15,7 +15,7 @@ lint: - golangci-lint run unit tests: - image: golang:1.17.8 + image: golang:1.17.10 stage: test tags: - amd64-docker diff --git a/cmd/infohub/main.go b/cmd/infohub/main.go new file mode 100644 index 0000000000000000000000000000000000000000..844f6b23fc884ce34c284e03522f22bad2fcac40 --- /dev/null +++ b/cmd/infohub/main.go @@ -0,0 +1,162 @@ +package main + +import ( + "context" + "errors" + "log" + "net/http" + "time" + + "github.com/kelseyhightower/envconfig" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" + "golang.org/x/sync/errgroup" + + "code.vereign.com/gaiax/tsa/golib/graceful" + goahealth "code.vereign.com/gaiax/tsa/infohub/gen/health" + goahealthsrv "code.vereign.com/gaiax/tsa/infohub/gen/http/health/server" + goainfohubsrv "code.vereign.com/gaiax/tsa/infohub/gen/http/infohub/server" + goaopenapisrv "code.vereign.com/gaiax/tsa/infohub/gen/http/openapi/server" + goainfohub "code.vereign.com/gaiax/tsa/infohub/gen/infohub" + "code.vereign.com/gaiax/tsa/infohub/gen/openapi" + "code.vereign.com/gaiax/tsa/infohub/internal/config" + "code.vereign.com/gaiax/tsa/infohub/internal/service" + "code.vereign.com/gaiax/tsa/infohub/internal/service/health" + "code.vereign.com/gaiax/tsa/infohub/internal/service/infohub" +) + +var Version = "0.0.0+development" + +func main() { + // load configuration from environment + var cfg config.Config + if err := envconfig.Process("", &cfg); err != nil { + log.Fatalf("cannot load configuration: %v", err) + } + + // create logger + logger, err := createLogger(cfg.LogLevel) + if err != nil { + log.Fatalln(err) + } + defer logger.Sync() //nolint:errcheck + + logger.Info("infohub service started", zap.String("version", Version), zap.String("goa", goa.Version())) + + // create services + var ( + infohubSvc goainfohub.Service + healthSvc goahealth.Service + ) + { + infohubSvc = infohub.New(logger) + healthSvc = health.New() + } + + // create endpoints + var ( + infohubEndpoints *goainfohub.Endpoints + healthEndpoints *goahealth.Endpoints + openapiEndpoints *openapi.Endpoints + ) + { + infohubEndpoints = goainfohub.NewEndpoints(infohubSvc) + healthEndpoints = goahealth.NewEndpoints(healthSvc) + openapiEndpoints = openapi.NewEndpoints(nil) + } + + // Provide the transport specific request decoder and response encoder. + // The goa http package has built-in support for JSON, XML and gob. + // Other encodings can be used by providing the corresponding functions, + // see goa.design/implement/encoding. + var ( + dec = goahttp.RequestDecoder + enc = goahttp.ResponseEncoder + ) + + // Build the service HTTP request multiplexer and configure it to serve + // HTTP requests to the service endpoints. + mux := goahttp.NewMuxer() + + // Wrap the endpoints with the transport specific layers. The generated + // server packages contains code generated from the design which maps + // the service input and output data structures to HTTP requests and + // responses. + var ( + infohubServer *goainfohubsrv.Server + healthServer *goahealthsrv.Server + openapiServer *goaopenapisrv.Server + ) + { + infohubServer = goainfohubsrv.New(infohubEndpoints, mux, dec, enc, nil, errFormatter) + healthServer = goahealthsrv.New(healthEndpoints, mux, dec, enc, nil, errFormatter) + openapiServer = goaopenapisrv.New(openapiEndpoints, mux, dec, enc, nil, errFormatter, nil, nil) + } + + // Configure the mux. + goainfohubsrv.Mount(mux, infohubServer) + goahealthsrv.Mount(mux, healthServer) + goaopenapisrv.Mount(mux, openapiServer) + + var handler http.Handler = mux + srv := &http.Server{ + Addr: cfg.HTTP.Host + ":" + cfg.HTTP.Port, + Handler: handler, + IdleTimeout: cfg.HTTP.IdleTimeout, + ReadTimeout: cfg.HTTP.ReadTimeout, + WriteTimeout: cfg.HTTP.WriteTimeout, + } + + g, ctx := errgroup.WithContext(context.Background()) + g.Go(func() error { + if err := graceful.Shutdown(ctx, srv, 20*time.Second); err != nil { + logger.Error("server shutdown error", zap.Error(err)) + return err + } + return errors.New("server stopped successfully") + }) + if err := g.Wait(); err != nil { + logger.Error("run group stopped", zap.Error(err)) + } + + logger.Info("bye bye") +} + +func createLogger(logLevel string, opts ...zap.Option) (*zap.Logger, error) { + var level = zapcore.InfoLevel + if logLevel != "" { + err := level.UnmarshalText([]byte(logLevel)) + if err != nil { + return nil, err + } + } + + config := zap.NewProductionConfig() + config.Level = zap.NewAtomicLevelAt(level) + config.DisableStacktrace = true + config.EncoderConfig.TimeKey = "ts" + config.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder + return config.Build(opts...) +} + +func errFormatter(e error) goahttp.Statuser { + return service.NewErrorResponse(e) +} + +//func httpClient() *http.Client { +// return &http.Client{ +// Transport: &http.Transport{ +// Proxy: http.ProxyFromEnvironment, +// DialContext: (&net.Dialer{ +// Timeout: 30 * time.Second, +// }).DialContext, +// MaxIdleConns: 100, +// MaxIdleConnsPerHost: 100, +// TLSHandshakeTimeout: 10 * time.Second, +// IdleConnTimeout: 60 * time.Second, +// }, +// Timeout: 30 * time.Second, +// } +//} diff --git a/design/design.go b/design/design.go index bbf49482bf8d54d6ab01823bca1c227eeeadfa45..75b1d81bdee22c909a1ac1491172a62dd91171ea 100644 --- a/design/design.go +++ b/design/design.go @@ -19,7 +19,7 @@ var _ = Service("infohub", func() { Description("Information Hub Service enables exporting and importing information.") Method("Export", func() { - Description("Evaluate executes a policy with the given 'data' as input.") + Description("Export returns data signed as Verifiable Presentation.") Payload(ExportRequest) Result(Any) HTTP(func() { diff --git a/gen/http/cli/infohub/cli.go b/gen/http/cli/infohub/cli.go index dc1b97d429da3a0ce7abf8480375b7f73d3ea40f..1f962614eaae7cfa1247e17813842a58825dd3cc 100644 --- a/gen/http/cli/infohub/cli.go +++ b/gen/http/cli/infohub/cli.go @@ -202,7 +202,7 @@ Usage: %[1]s [globalflags] infohub COMMAND [flags] COMMAND: - export: Evaluate executes a policy with the given 'data' as input. + export: Export returns data signed as Verifiable Presentation. Additional help: %[1]s infohub COMMAND --help @@ -211,7 +211,7 @@ Additional help: func infohubExportUsage() { fmt.Fprintf(os.Stderr, `%[1]s [flags] infohub export -export-name STRING -Evaluate executes a policy with the given 'data' as input. +Export returns data signed as Verifiable Presentation. -export-name STRING: Name of export to be performed. Example: diff --git a/gen/http/openapi.json b/gen/http/openapi.json index c0e3b5ff40a9fb5cdef9545b6e09cebe4c9ae1f4..73d9f18fbc12c419e358c01fa76ffcd19cec29f8 100644 --- a/gen/http/openapi.json +++ b/gen/http/openapi.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Information Hub Service","description":"Information Hub Service exposes HTTP API for exporting and importing information.","version":""},"host":"localhost:8084","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/export/{exportName}":{"get":{"tags":["infohub"],"summary":"Export infohub","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"infohub#Export","parameters":[{"name":"exportName","in":"path","description":"Name of export to be performed.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Information Hub Service","description":"Information Hub Service exposes HTTP API for exporting and importing information.","version":""},"host":"localhost:8084","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/export/{exportName}":{"get":{"tags":["infohub"],"summary":"Export infohub","description":"Export returns data signed as Verifiable Presentation.","operationId":"infohub#Export","parameters":[{"name":"exportName","in":"path","description":"Name of export to be performed.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}}} \ No newline at end of file diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml index da28dc9b1dcc8ba4af650c4b77ee0d88a88bf846..1d2f51fd9a8c9a46cacf823aa59499353dd1102a 100644 --- a/gen/http/openapi.yaml +++ b/gen/http/openapi.yaml @@ -41,7 +41,7 @@ paths: tags: - infohub summary: Export infohub - description: Evaluate executes a policy with the given 'data' as input. + description: Export returns data signed as Verifiable Presentation. operationId: infohub#Export parameters: - name: exportName diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json index 9699ac68517680535c789f0162926c39ddf16560..d35523af06ed4596e8772857a7727ecfe73e750e 100644 --- a/gen/http/openapi3.json +++ b/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Information Hub Service","description":"Information Hub Service exposes HTTP API for exporting and importing information.","version":"1.0"},"servers":[{"url":"http://localhost:8084","description":"Information Hub Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/export/{exportName}":{"get":{"tags":["infohub"],"summary":"Export infohub","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"infohub#Export","parameters":[{"name":"exportName","in":"path","description":"Name of export to be performed.","required":true,"schema":{"type":"string","description":"Name of export to be performed.","example":"myexport"},"example":"myexport"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Veniam non.","format":"binary"},"example":"Ipsam similique nulla quis."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"infohub","description":"Information Hub Service enables exporting and importing information."}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Information Hub Service","description":"Information Hub Service exposes HTTP API for exporting and importing information.","version":"1.0"},"servers":[{"url":"http://localhost:8084","description":"Information Hub Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/export/{exportName}":{"get":{"tags":["infohub"],"summary":"Export infohub","description":"Export returns data signed as Verifiable Presentation.","operationId":"infohub#Export","parameters":[{"name":"exportName","in":"path","description":"Name of export to be performed.","required":true,"schema":{"type":"string","description":"Name of export to be performed.","example":"myexport"},"example":"myexport"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Veniam non.","format":"binary"},"example":"Ipsam similique nulla quis."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"infohub","description":"Information Hub Service enables exporting and importing information."}]} \ No newline at end of file diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml index 1a932d4ffa4036f1e18f21d37f188d884476b5fb..9faf4e1c8bf3236cc130cddde6f220d762fd0613 100644 --- a/gen/http/openapi3.yaml +++ b/gen/http/openapi3.yaml @@ -31,7 +31,7 @@ paths: tags: - infohub summary: Export infohub - description: Evaluate executes a policy with the given 'data' as input. + description: Export returns data signed as Verifiable Presentation. operationId: infohub#Export parameters: - name: exportName diff --git a/gen/infohub/service.go b/gen/infohub/service.go index 608c9284d4bfe86614f0845d7de95291ec27c41c..e65ec3bcdbeea60e3a14b144e30e9297cdea52c8 100644 --- a/gen/infohub/service.go +++ b/gen/infohub/service.go @@ -13,7 +13,7 @@ import ( // Information Hub Service enables exporting and importing information. type Service interface { - // Evaluate executes a policy with the given 'data' as input. + // Export returns data signed as Verifiable Presentation. Export(context.Context, *ExportRequest) (res interface{}, err error) } diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000000000000000000000000000000000000..1e7598ced85d5550863920a2e37d90f191e01a96 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,16 @@ +package config + +import "time" + +type Config struct { + HTTP httpConfig + LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"` +} + +type httpConfig struct { + Host string `envconfig:"HTTP_HOST"` + Port string `envconfig:"HTTP_PORT" default:"8080"` + IdleTimeout time.Duration `envconfig:"HTTP_IDLE_TIMEOUT" default:"120s"` + ReadTimeout time.Duration `envconfig:"HTTP_READ_TIMEOUT" default:"10s"` + WriteTimeout time.Duration `envconfig:"HTTP_WRITE_TIMEOUT" default:"10s"` +} diff --git a/internal/service/error_response.go b/internal/service/error_response.go new file mode 100644 index 0000000000000000000000000000000000000000..cbe74c6bb5180af664d93f5d00912f61ce8b85d3 --- /dev/null +++ b/internal/service/error_response.go @@ -0,0 +1,39 @@ +package service + +import ( + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" + + "code.vereign.com/gaiax/tsa/golib/errors" +) + +func NewErrorResponse(err error) goahttp.Statuser { + if err == nil { + return nil + } + + var newerr *errors.Error + switch e := err.(type) { + case *errors.Error: + newerr = e + case *goa.ServiceError: + // Use goahttp.ErrorResponse to determine error kind + goaerr := goahttp.NewErrorResponse(e) + kind := errors.GetKind(goaerr.StatusCode()) + newerr = &errors.Error{ + ID: e.ID, + Kind: kind, + Message: e.Message, + Err: e, + } + default: + newerr = &errors.Error{ + ID: errors.NewID(), + Kind: errors.Internal, + Message: e.Error(), + Err: e, + } + } + + return newerr +} diff --git a/internal/service/health/service.go b/internal/service/health/service.go new file mode 100644 index 0000000000000000000000000000000000000000..ffa6d9af3d67b8681ce5464bc555ca38aa6b801e --- /dev/null +++ b/internal/service/health/service.go @@ -0,0 +1,17 @@ +package health + +import "context" + +type Service struct{} + +func New() *Service { + return &Service{} +} + +func (s *Service) Liveness(ctx context.Context) error { + return nil +} + +func (s *Service) Readiness(ctx context.Context) error { + return nil +} diff --git a/internal/service/infohub/service.go b/internal/service/infohub/service.go new file mode 100644 index 0000000000000000000000000000000000000000..1c737b62ba51d47c4681efc89182eee2c41f2b54 --- /dev/null +++ b/internal/service/infohub/service.go @@ -0,0 +1,22 @@ +package infohub + +import ( + "context" + "fmt" + + "go.uber.org/zap" + + "code.vereign.com/gaiax/tsa/infohub/gen/infohub" +) + +type Service struct { + logger *zap.Logger +} + +func New(logger *zap.Logger) *Service { + return &Service{logger: logger} +} + +func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (interface{}, error) { + return nil, fmt.Errorf("not implemented") +}