From 3cecd83b85be89ada54efb0f8f7c578f41a8d1dd Mon Sep 17 00:00:00 2001 From: pritesh-patel Date: Tue, 8 Oct 2019 12:08:57 -0700 Subject: [PATCH 1/3] finish up docker and http gateway generation --- Dockerfile | 2 +- cmd/generate.go | 10 ++ example/hello-world/.dockerignore | 0 example/hello-world/docker/app/Dockerfile | 11 ++ example/hello-world/docker/http/Dockerfile | 10 ++ example/hello-world/hello-world-idl/Makefile | 4 +- .../gen/http/health/health.pb.gw.go | 162 ----------------- .../gen/http/health/health.swagger.json | 117 ------------- .../gen/http/helloworld/helloworld.pb.gw.go | 163 ------------------ .../http/helloworld/helloworld.swagger.json | 63 ------- example/hello-world/http/main.go | 41 +++++ generate/docker/generate.go | 18 ++ generate/http/generate.go | 12 ++ generate/proto/generate.go | 8 +- go.sum | 1 + templates/docker/dockerfile_app.tmpl | 11 ++ templates/docker/dockerfile_http.tmpl | 10 ++ templates/docker/dockerignore.tmpl | 0 templates/golang/http_gw.tmpl | 45 +++++ templates/proto/makefile.tmpl | 4 +- templator/templator.go | 30 ++++ util/util.go | 20 +++ 22 files changed, 228 insertions(+), 514 deletions(-) create mode 100644 example/hello-world/.dockerignore create mode 100644 example/hello-world/docker/app/Dockerfile create mode 100644 example/hello-world/docker/http/Dockerfile delete mode 100644 example/hello-world/hello-world-idl/gen/http/health/health.pb.gw.go delete mode 100644 example/hello-world/hello-world-idl/gen/http/health/health.swagger.json delete mode 100644 example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.pb.gw.go delete mode 100644 example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.swagger.json create mode 100644 example/hello-world/http/main.go create mode 100644 generate/docker/generate.go create mode 100644 generate/http/generate.go create mode 100644 templates/docker/dockerfile_app.tmpl create mode 100644 templates/docker/dockerfile_http.tmpl create mode 100644 templates/docker/dockerignore.tmpl create mode 100644 templates/golang/http_gw.tmpl diff --git a/Dockerfile b/Dockerfile index 23127a7e8..43089614d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,6 +58,6 @@ COPY --from=builder /usr/local/bin /usr/local/bin COPY --from=builder /usr/local/include /usr/local/include COPY --from=builder /go/src/github.com/grpc-ecosystem/grpc-gateway ${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway WORKDIR /project -RUN apk add --update --no-cache make bash curl git protobuf=${PROTOBUF_VERSION}-${ALPINE_PROTOBUF_VERSION_SUFFIX} && \ +RUN apk add --update --no-cache make protobuf=${PROTOBUF_VERSION}-${ALPINE_PROTOBUF_VERSION_SUFFIX} && \ rm -rf /var/cache/apk/* ENTRYPOINT ["sprout"] diff --git a/cmd/generate.go b/cmd/generate.go index 9281dcf93..1a0059905 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -4,6 +4,10 @@ import ( "github.com/commitdev/sprout/config" "github.com/commitdev/sprout/generate/golang" "github.com/commitdev/sprout/generate/proto" + "github.com/commitdev/sprout/generate/docker" + "github.com/commitdev/sprout/generate/http" + + "log" "github.com/spf13/cobra" @@ -42,7 +46,13 @@ var generateCmd = &cobra.Command{ switch language { case Go: golang.Generate(Templator, cfg) + docker.GenerateGoAppDockerFile(Templator, cfg) + + } + if cfg.Network.Http.Enabled { + http.GenerateHttpGW(Templator, cfg) + docker.GenerateGoHttpGWDockerFile(Templator, cfg) } }, } diff --git a/example/hello-world/.dockerignore b/example/hello-world/.dockerignore new file mode 100644 index 000000000..e69de29bb diff --git a/example/hello-world/docker/app/Dockerfile b/example/hello-world/docker/app/Dockerfile new file mode 100644 index 000000000..c9cbdba6e --- /dev/null +++ b/example/hello-world/docker/app/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:1.12.6@sha256:83e8267be041b3ddf6a5792c7e464528408f75c446745642db08cfe4e8d58d18 AS build +WORKDIR /cache +COPY go.mod . +COPY . . +RUN go build -o hello-world + +FROM alpine +RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 +RUN apk update && apk add ca-certificates +COPY --from=build /cache/hello-world /app/ +ENTRYPOINT /app/hello-world diff --git a/example/hello-world/docker/http/Dockerfile b/example/hello-world/docker/http/Dockerfile new file mode 100644 index 000000000..af5b4716e --- /dev/null +++ b/example/hello-world/docker/http/Dockerfile @@ -0,0 +1,10 @@ +FROM golang:1.12.6@sha256:83e8267be041b3ddf6a5792c7e464528408f75c446745642db08cfe4e8d58d18 AS build +WORKDIR /cache +COPY . . +RUN go build http/main.go -o hello-world-http + +FROM alpine +RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 +RUN apk update && apk add ca-certificates +COPY --from=build /cache/hello-world /app/ +ENTRYPOINT /app/hello-world-http diff --git a/example/hello-world/hello-world-idl/Makefile b/example/hello-world/hello-world-idl/Makefile index 20e02c511..33530a38e 100644 --- a/example/hello-world/hello-world-idl/Makefile +++ b/example/hello-world/hello-world-idl/Makefile @@ -42,9 +42,9 @@ generate-web: cp -f -rv proto/Proto/* gen/web rm -rf proto/proto proto/Proto generate-http: - mkdir -p gen/http + mkdir -p gen/go protoc ${PROTO_SOURCES} --grpc-gateway_out=logtostderr=true,paths=source_relative:proto --swagger_out=logtostderr=true:proto ./proto/health/*.proto protoc ${PROTO_SOURCES} --grpc-gateway_out=logtostderr=true,paths=source_relative:proto --swagger_out=logtostderr=true:proto ./proto/helloworld/*.proto - cp -f -rv proto/proto/* gen/http + cp -f -rv proto/proto/* gen/go rm -rf proto/proto diff --git a/example/hello-world/hello-world-idl/gen/http/health/health.pb.gw.go b/example/hello-world/hello-world-idl/gen/http/health/health.pb.gw.go deleted file mode 100644 index 16fe3bea7..000000000 --- a/example/hello-world/hello-world-idl/gen/http/health/health.pb.gw.go +++ /dev/null @@ -1,162 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: proto/health/health.proto - -/* -Package health is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package health - -import ( - "context" - "io" - "net/http" - - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/status" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage - -var ( - filter_Health_Check_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_Health_Check_0(ctx context.Context, marshaler runtime.Marshaler, client HealthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq HealthCheckRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Health_Check_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.Check(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Health_Check_0(ctx context.Context, marshaler runtime.Marshaler, server HealthServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq HealthCheckRequest - var metadata runtime.ServerMetadata - - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Health_Check_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Check(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterHealthHandlerServer registers the http handlers for service Health to "mux". -// UnaryRPC :call HealthServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -func RegisterHealthHandlerServer(ctx context.Context, mux *runtime.ServeMux, server HealthServer) error { - - mux.Handle("GET", pattern_Health_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Health_Check_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Health_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// RegisterHealthHandlerFromEndpoint is same as RegisterHealthHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterHealthHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterHealthHandler(ctx, mux, conn) -} - -// RegisterHealthHandler registers the http handlers for service Health to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterHealthHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterHealthHandlerClient(ctx, mux, NewHealthClient(conn)) -} - -// RegisterHealthHandlerClient registers the http handlers for service Health -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "HealthClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "HealthClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "HealthClient" to call the correct interceptors. -func RegisterHealthHandlerClient(ctx context.Context, mux *runtime.ServeMux, client HealthClient) error { - - mux.Handle("GET", pattern_Health_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Health_Check_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Health_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -var ( - pattern_Health_Check_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "health"}, "", runtime.AssumeColonVerbOpt(true))) -) - -var ( - forward_Health_Check_0 = runtime.ForwardResponseMessage -) diff --git a/example/hello-world/hello-world-idl/gen/http/health/health.swagger.json b/example/hello-world/hello-world-idl/gen/http/health/health.swagger.json deleted file mode 100644 index 5ecef0a83..000000000 --- a/example/hello-world/hello-world-idl/gen/http/health/health.swagger.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "Health Checks", - "version": "1.0" - }, - "schemes": [ - "http", - "https" - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/health": { - "get": { - "operationId": "Check", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/healthHealthCheckResponse" - } - } - }, - "parameters": [ - { - "name": "service", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "Health" - ] - } - } - }, - "definitions": { - "HealthCheckResponseServingStatus": { - "type": "string", - "enum": [ - "UNKNOWN", - "SERVING", - "NOT_SERVING", - "SERVICE_UNKNOWN" - ], - "default": "UNKNOWN" - }, - "healthHealthCheckResponse": { - "type": "object", - "properties": { - "status": { - "$ref": "#/definitions/HealthCheckResponseServingStatus" - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "type_url": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - }, - "value": { - "type": "string", - "format": "byte", - "description": "Must be a valid serialized protocol buffer of the above specified type." - } - }, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "runtimeStreamError": { - "type": "object", - "properties": { - "grpc_code": { - "type": "integer", - "format": "int32" - }, - "http_code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "http_status": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/protobufAny" - } - } - } - } - }, - "x-stream-definitions": { - "healthHealthCheckResponse": { - "type": "object", - "properties": { - "result": { - "$ref": "#/definitions/healthHealthCheckResponse" - }, - "error": { - "$ref": "#/definitions/runtimeStreamError" - } - }, - "title": "Stream result of healthHealthCheckResponse" - } - } -} diff --git a/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.pb.gw.go b/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.pb.gw.go deleted file mode 100644 index 1e17d4153..000000000 --- a/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.pb.gw.go +++ /dev/null @@ -1,163 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: proto/helloworld/helloworld.proto - -/* -Package helloworld is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package helloworld - -import ( - "context" - "io" - "net/http" - - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "github.com/yourrepo/hello-world-idl/gen/go/health" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/status" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage - -var ( - filter_Helloworld_Check_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_Helloworld_Check_0(ctx context.Context, marshaler runtime.Marshaler, client HelloworldClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq health.HealthCheckRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Helloworld_Check_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.Check(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Helloworld_Check_0(ctx context.Context, marshaler runtime.Marshaler, server HelloworldServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq health.HealthCheckRequest - var metadata runtime.ServerMetadata - - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Helloworld_Check_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Check(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterHelloworldHandlerServer registers the http handlers for service Helloworld to "mux". -// UnaryRPC :call HelloworldServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -func RegisterHelloworldHandlerServer(ctx context.Context, mux *runtime.ServeMux, server HelloworldServer) error { - - mux.Handle("GET", pattern_Helloworld_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Helloworld_Check_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Helloworld_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// RegisterHelloworldHandlerFromEndpoint is same as RegisterHelloworldHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterHelloworldHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterHelloworldHandler(ctx, mux, conn) -} - -// RegisterHelloworldHandler registers the http handlers for service Helloworld to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterHelloworldHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterHelloworldHandlerClient(ctx, mux, NewHelloworldClient(conn)) -} - -// RegisterHelloworldHandlerClient registers the http handlers for service Helloworld -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "HelloworldClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "HelloworldClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "HelloworldClient" to call the correct interceptors. -func RegisterHelloworldHandlerClient(ctx context.Context, mux *runtime.ServeMux, client HelloworldClient) error { - - mux.Handle("GET", pattern_Helloworld_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Helloworld_Check_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Helloworld_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -var ( - pattern_Helloworld_Check_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "helloworld", "health"}, "", runtime.AssumeColonVerbOpt(true))) -) - -var ( - forward_Helloworld_Check_0 = runtime.ForwardResponseMessage -) diff --git a/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.swagger.json b/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.swagger.json deleted file mode 100644 index daf0e175e..000000000 --- a/example/hello-world/hello-world-idl/gen/http/helloworld/helloworld.swagger.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "Helloworld", - "version": "1.0" - }, - "schemes": [ - "http", - "https" - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/helloworld/health": { - "get": { - "operationId": "Check", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/healthHealthCheckResponse" - } - } - }, - "parameters": [ - { - "name": "service", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "Helloworld" - ] - } - } - }, - "definitions": { - "HealthCheckResponseServingStatus": { - "type": "string", - "enum": [ - "UNKNOWN", - "SERVING", - "NOT_SERVING", - "SERVICE_UNKNOWN" - ], - "default": "UNKNOWN" - }, - "healthHealthCheckResponse": { - "type": "object", - "properties": { - "status": { - "$ref": "#/definitions/HealthCheckResponseServingStatus" - } - } - } - } -} diff --git a/example/hello-world/http/main.go b/example/hello-world/http/main.go new file mode 100644 index 000000000..903cb39ed --- /dev/null +++ b/example/hello-world/http/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "log" + "context" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/grpc" + + health "github.com/yourrepo/hello-world-idl/gen/go/health" + helloworld "github.com/yourrepo/hello-world-idl/gen/go/helloworld" +) + +func run(endpoint string, listening string) error { + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + mux := runtime.NewServeMux() + opts := []grpc.DialOption{grpc.WithInsecure()} + err := health.RegisterHealthHandlerFromEndpoint(ctx, mux, endpoint, opts) + err = helloworld.RegisterHelloworldHandlerFromEndpoint(ctx, mux, endpoint, opts) + + if err != nil { + return err + } + + return http.ListenAndServe(listening, mux) +} + +func main() { + endpoint := "0.0.0.0:3000" + listening := "0.0.0.0:8080" + log.Printf("Starting http grpc gateway server on %v...", listening) + + if err := run(endpoint, listening); err != nil { + log.Fatal(err) + } +} diff --git a/generate/docker/generate.go b/generate/docker/generate.go new file mode 100644 index 000000000..35ef57a04 --- /dev/null +++ b/generate/docker/generate.go @@ -0,0 +1,18 @@ +package docker + +import ( + "github.com/commitdev/sprout/util" + + "github.com/commitdev/sprout/config" + "github.com/commitdev/sprout/templator" +) + +func GenerateGoAppDockerFile(templator *templator.Templator, config *config.SproutConfig) { + util.TemplateFileIfDoesNotExist("docker/app", "Dockerfile", templator.Docker.ApplicationDocker, config) + util.TemplateFileIfDoesNotExist("./", ".dockerignore", templator.Docker.DockerIgnore, config) + +} + +func GenerateGoHttpGWDockerFile(templator *templator.Templator, config *config.SproutConfig) { + util.TemplateFileIfDoesNotExist("docker/http", "Dockerfile", templator.Docker.HttpGatewayDocker, config) +} diff --git a/generate/http/generate.go b/generate/http/generate.go new file mode 100644 index 000000000..0a0c34e0e --- /dev/null +++ b/generate/http/generate.go @@ -0,0 +1,12 @@ +package http + +import ( + "github.com/commitdev/sprout/util" + + "github.com/commitdev/sprout/config" + "github.com/commitdev/sprout/templator" +) + +func GenerateHttpGW(templator *templator.Templator, config *config.SproutConfig) { + util.TemplateFileIfDoesNotExist("http", "main.go", templator.Go.GoHttpGW, config) +} diff --git a/generate/proto/generate.go b/generate/proto/generate.go index 89ae2817b..a2426ae23 100644 --- a/generate/proto/generate.go +++ b/generate/proto/generate.go @@ -1,12 +1,12 @@ package proto import ( - "fmt" "bytes" + "fmt" - "github.com/commitdev/sprout/util" "github.com/commitdev/sprout/config" "github.com/commitdev/sprout/templator" + "github.com/commitdev/sprout/util" "log" "os" "os/exec" @@ -80,10 +80,10 @@ func GenerateServiceProtobufFiles(templator *templator.Templator, cfg *config.Sp f, err := os.Create(serviceProtoFilePath) - data:= struct { + data := struct { *config.SproutConfig ServiceName string - } { + }{ cfg, s.Name, } diff --git a/go.sum b/go.sum index b67ea5014..80d74ab6c 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/commitdev/sprout/example/hello-world v0.0.0-20190827182108-cfad4c3d94cc h1:zBLjQxkC2LT1e9eMs0I2k26NXXZVT/XGrnuqdAsFt3A= github.com/commitdev/sprout/example/hello-world v0.0.0-20190827183525-9eeb1651f4f4 h1:pQw2XR8va971sW7QIX18I7FWft54TjLdQex5MHCcVtg= github.com/commitdev/sprout/example/hello-world v0.0.0-20191006174419-73168768419f h1:zfmpI6udrSYU1Ly4YYqEvE3WyoGrgzqLgevS6FHWlsw= +github.com/commitdev/sprout/example/hello-world v0.0.0-20191007000403-b09452cbef06 h1:L6MAZtnpxfjj15iW3zllF3tVNjXaUB1qsNjMGISYRVI= github.com/commitdev/sprout/example/hello-world-idl v0.0.0-20190910021125-8ac64211bb19 h1:ULmWBQ848cHxodGxtQWas0lWPAh/ZntpV1QsobbasMA= github.com/commitdev/sprout/example/hello-world/hello-world-idl v0.0.0-20191006174419-73168768419f h1:yT3SIhGDFr+Pf7uW0wllWwp+HFeRvObO2s++6upn8g4= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= diff --git a/templates/docker/dockerfile_app.tmpl b/templates/docker/dockerfile_app.tmpl new file mode 100644 index 000000000..952d5baf7 --- /dev/null +++ b/templates/docker/dockerfile_app.tmpl @@ -0,0 +1,11 @@ +FROM golang:1.12.6@sha256:83e8267be041b3ddf6a5792c7e464528408f75c446745642db08cfe4e8d58d18 AS build +WORKDIR /cache +COPY go.mod . +COPY . . +RUN go build -o {{ .Name }} + +FROM alpine +RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 +RUN apk update && apk add ca-certificates +COPY --from=build /cache/{{ .Name }} /app/ +ENTRYPOINT /app/{{ .Name }} diff --git a/templates/docker/dockerfile_http.tmpl b/templates/docker/dockerfile_http.tmpl new file mode 100644 index 000000000..36c7ae162 --- /dev/null +++ b/templates/docker/dockerfile_http.tmpl @@ -0,0 +1,10 @@ +FROM golang:1.12.6@sha256:83e8267be041b3ddf6a5792c7e464528408f75c446745642db08cfe4e8d58d18 AS build +WORKDIR /cache +COPY . . +RUN go build http/main.go -o {{ .Name }}-http + +FROM alpine +RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 +RUN apk update && apk add ca-certificates +COPY --from=build /cache/{{ .Name }} /app/ +ENTRYPOINT /app/{{ .Name }}-http diff --git a/templates/docker/dockerignore.tmpl b/templates/docker/dockerignore.tmpl new file mode 100644 index 000000000..e69de29bb diff --git a/templates/golang/http_gw.tmpl b/templates/golang/http_gw.tmpl new file mode 100644 index 000000000..c2c36403c --- /dev/null +++ b/templates/golang/http_gw.tmpl @@ -0,0 +1,45 @@ +package main + +import ( + "log" + "context" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/grpc" + + health "{{ $.GitRepo }}/{{ $.Name }}-idl/gen/go/health" + {{- range .Services}} + {{ .Name }} "{{ $.GitRepo }}/{{ $.Name }}-idl/gen/go/{{ .Name }}" + {{- end}} +) + +func run(endpoint string, listening string) error { + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + mux := runtime.NewServeMux() + opts := []grpc.DialOption{grpc.WithInsecure()} + err := health.RegisterHealthHandlerFromEndpoint(ctx, mux, endpoint, opts) + {{- range .Services}} + err = {{ .Name }}.Register{{ .Name | Title }}HandlerFromEndpoint(ctx, mux, endpoint, opts) + {{- end}} + + if err != nil { + return err + } + + return http.ListenAndServe(listening, mux) +} + +func main() { + endpoint := "0.0.0.0:{{ .Network.Grpc.Port }}" + listening := "0.0.0.0:{{ .Network.Http.Port }}" + log.Printf("Starting http grpc gateway server on %v...", listening) + + if err := run(endpoint, listening); err != nil { + log.Fatal(err) + } +} diff --git a/templates/proto/makefile.tmpl b/templates/proto/makefile.tmpl index 417d2b6ec..b8d6a5bc5 100644 --- a/templates/proto/makefile.tmpl +++ b/templates/proto/makefile.tmpl @@ -56,12 +56,12 @@ generate-web: {{- if .Network.Http.Enabled }} generate-http: - mkdir -p gen/http + mkdir -p gen/go protoc ${PROTO_SOURCES} --grpc-gateway_out=logtostderr=true,paths=source_relative:proto --swagger_out=logtostderr=true:proto ./proto/health/*.proto {{- range .Services}} protoc ${PROTO_SOURCES} --grpc-gateway_out=logtostderr=true,paths=source_relative:proto --swagger_out=logtostderr=true:proto ./proto/{{ .Name }}/*.proto {{- end }} - cp -f -rv proto/proto/* gen/http + cp -f -rv proto/proto/* gen/go rm -rf proto/proto {{- end}} diff --git a/templator/templator.go b/templator/templator.go index 830b4ca81..e0e63aae0 100644 --- a/templator/templator.go +++ b/templator/templator.go @@ -6,12 +6,19 @@ import ( "text/template" ) +type DockerTemplator struct { + ApplicationDocker *template.Template + HttpGatewayDocker *template.Template + DockerIgnore *template.Template +} + type GoTemplator struct { GoMain *template.Template GoMod *template.Template GoModIDL *template.Template GoServer *template.Template GoHealthServer *template.Template + GoHttpGW *template.Template } type Templator struct { @@ -21,6 +28,7 @@ type Templator struct { ProtoHealthTemplate *template.Template ProtoServiceTemplate *template.Template Go *GoTemplator + Docker *DockerTemplator } func NewTemplator(box *packr.Box) *Templator { @@ -40,6 +48,7 @@ func NewTemplator(box *packr.Box) *Templator { Go: NewGoTemplator(box), Sprout: NewSproutTemplator(box), GitIgnore: NewGitIgnoreTemplator(box), + Docker: NewDockerFileTemplator(box), } } @@ -59,12 +68,16 @@ func NewGoTemplator(box *packr.Box) *GoTemplator { goMainTemplateSource, _ := box.FindString("golang/main.tmpl") goMainTemplate, _ := template.New("GoMainTemplate").Funcs(util.FuncMap).Parse(goMainTemplateSource) + goHttpTemplateSource, _ := box.FindString("golang/http_gw.tmpl") + goHttpTemplate, _ := template.New("GoHttpGWTemplate").Funcs(util.FuncMap).Parse(goHttpTemplateSource) + return &GoTemplator{ GoMain: goMainTemplate, GoMod: goModTemplate, GoModIDL: goModIDLTemplate, GoServer: goServerTemplate, GoHealthServer: goHealthServerTemplate, + GoHttpGW: goHttpTemplate, } } @@ -81,3 +94,20 @@ func NewGitIgnoreTemplator(box *packr.Box) *template.Template { template, _ := template.New("GitIgnore").Parse(templateSource) return template } + +func NewDockerFileTemplator(box *packr.Box) *DockerTemplator { + appTemplateSource, _ := box.FindString("docker/dockerfile_app.tmpl") + appTemplate, _ := template.New("AppDockerfile").Parse(appTemplateSource) + + httpTemplateSource, _ := box.FindString("docker/dockerfile_http.tmpl") + httpTemplate, _ := template.New("HttpDockerfile").Parse(httpTemplateSource) + + ignoreTemplateSource, _ := box.FindString("docker/dockerignore.tmpl") + ignoreTemplate, _ := template.New("Dockerignore").Parse(ignoreTemplateSource) + + return &DockerTemplator{ + ApplicationDocker: appTemplate, + HttpGatewayDocker: httpTemplate, + DockerIgnore: ignoreTemplate, + } +} diff --git a/util/util.go b/util/util.go index 68646c046..36444ffaf 100644 --- a/util/util.go +++ b/util/util.go @@ -3,6 +3,8 @@ package util import ( "os" "strings" + "fmt" + "log" "text/template" ) @@ -17,3 +19,21 @@ func CreateDirIfDoesNotExist(path string) error { var FuncMap = template.FuncMap{ "Title": strings.Title, } + +func TemplateFileIfDoesNotExist(fileDir string, fileName string, template *template.Template, data interface{}) { + fullFilePath := fmt.Sprintf("%v/%v", fileDir, fileName) + + if _, err := os.Stat(fullFilePath); os.IsNotExist(err) { + err := CreateDirIfDoesNotExist(fileDir) + f, err := os.Create(fullFilePath) + if err != nil { + log.Printf("Error creating file: %v", err) + } + err = template.Execute(f, data) + if err != nil { + log.Printf("Error templating: %v", err) + } + } else { + log.Printf("%v already exists. skipping.", fullFilePath) + } +} From c3a4a6f47aff5c2877a173b57a0c25315f69ba4a Mon Sep 17 00:00:00 2001 From: pritesh-patel Date: Tue, 8 Oct 2019 12:09:44 -0700 Subject: [PATCH 2/3] updated example --- example/hello-world/.gitignore | 1 - .../gen/go/health/health.pb.gw.go | 162 +++++++++++++++++ .../gen/go/health/health.swagger.json | 117 +++++++++++++ .../gen/go/helloworld/helloworld.pb.gw.go | 163 ++++++++++++++++++ .../gen/go/helloworld/helloworld.swagger.json | 63 +++++++ 5 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 example/hello-world/hello-world-idl/gen/go/health/health.pb.gw.go create mode 100644 example/hello-world/hello-world-idl/gen/go/health/health.swagger.json create mode 100644 example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.pb.gw.go create mode 100644 example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.swagger.json diff --git a/example/hello-world/.gitignore b/example/hello-world/.gitignore index 55283c232..e69de29bb 100644 --- a/example/hello-world/.gitignore +++ b/example/hello-world/.gitignore @@ -1 +0,0 @@ -/hello-world-idl diff --git a/example/hello-world/hello-world-idl/gen/go/health/health.pb.gw.go b/example/hello-world/hello-world-idl/gen/go/health/health.pb.gw.go new file mode 100644 index 000000000..16fe3bea7 --- /dev/null +++ b/example/hello-world/hello-world-idl/gen/go/health/health.pb.gw.go @@ -0,0 +1,162 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: proto/health/health.proto + +/* +Package health is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package health + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_Health_Check_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Health_Check_0(ctx context.Context, marshaler runtime.Marshaler, client HealthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq HealthCheckRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Health_Check_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Check(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Health_Check_0(ctx context.Context, marshaler runtime.Marshaler, server HealthServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq HealthCheckRequest + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Health_Check_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Check(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterHealthHandlerServer registers the http handlers for service Health to "mux". +// UnaryRPC :call HealthServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +func RegisterHealthHandlerServer(ctx context.Context, mux *runtime.ServeMux, server HealthServer) error { + + mux.Handle("GET", pattern_Health_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Health_Check_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Health_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterHealthHandlerFromEndpoint is same as RegisterHealthHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterHealthHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterHealthHandler(ctx, mux, conn) +} + +// RegisterHealthHandler registers the http handlers for service Health to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterHealthHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterHealthHandlerClient(ctx, mux, NewHealthClient(conn)) +} + +// RegisterHealthHandlerClient registers the http handlers for service Health +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "HealthClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "HealthClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "HealthClient" to call the correct interceptors. +func RegisterHealthHandlerClient(ctx context.Context, mux *runtime.ServeMux, client HealthClient) error { + + mux.Handle("GET", pattern_Health_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Health_Check_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Health_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Health_Check_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "health"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Health_Check_0 = runtime.ForwardResponseMessage +) diff --git a/example/hello-world/hello-world-idl/gen/go/health/health.swagger.json b/example/hello-world/hello-world-idl/gen/go/health/health.swagger.json new file mode 100644 index 000000000..5ecef0a83 --- /dev/null +++ b/example/hello-world/hello-world-idl/gen/go/health/health.swagger.json @@ -0,0 +1,117 @@ +{ + "swagger": "2.0", + "info": { + "title": "Health Checks", + "version": "1.0" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/health": { + "get": { + "operationId": "Check", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/healthHealthCheckResponse" + } + } + }, + "parameters": [ + { + "name": "service", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "Health" + ] + } + } + }, + "definitions": { + "HealthCheckResponseServingStatus": { + "type": "string", + "enum": [ + "UNKNOWN", + "SERVING", + "NOT_SERVING", + "SERVICE_UNKNOWN" + ], + "default": "UNKNOWN" + }, + "healthHealthCheckResponse": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/HealthCheckResponseServingStatus" + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "type_url": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + }, + "value": { + "type": "string", + "format": "byte", + "description": "Must be a valid serialized protocol buffer of the above specified type." + } + }, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := ptypes.MarshalAny(foo)\n ...\n foo := \u0026pb.Foo{}\n if err := ptypes.UnmarshalAny(any, foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "runtimeStreamError": { + "type": "object", + "properties": { + "grpc_code": { + "type": "integer", + "format": "int32" + }, + "http_code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "http_status": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + } + }, + "x-stream-definitions": { + "healthHealthCheckResponse": { + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/healthHealthCheckResponse" + }, + "error": { + "$ref": "#/definitions/runtimeStreamError" + } + }, + "title": "Stream result of healthHealthCheckResponse" + } + } +} diff --git a/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.pb.gw.go b/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.pb.gw.go new file mode 100644 index 000000000..1e17d4153 --- /dev/null +++ b/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.pb.gw.go @@ -0,0 +1,163 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: proto/helloworld/helloworld.proto + +/* +Package helloworld is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package helloworld + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "github.com/yourrepo/hello-world-idl/gen/go/health" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_Helloworld_Check_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Helloworld_Check_0(ctx context.Context, marshaler runtime.Marshaler, client HelloworldClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq health.HealthCheckRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Helloworld_Check_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Check(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Helloworld_Check_0(ctx context.Context, marshaler runtime.Marshaler, server HelloworldServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq health.HealthCheckRequest + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Helloworld_Check_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Check(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterHelloworldHandlerServer registers the http handlers for service Helloworld to "mux". +// UnaryRPC :call HelloworldServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +func RegisterHelloworldHandlerServer(ctx context.Context, mux *runtime.ServeMux, server HelloworldServer) error { + + mux.Handle("GET", pattern_Helloworld_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Helloworld_Check_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Helloworld_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterHelloworldHandlerFromEndpoint is same as RegisterHelloworldHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterHelloworldHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterHelloworldHandler(ctx, mux, conn) +} + +// RegisterHelloworldHandler registers the http handlers for service Helloworld to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterHelloworldHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterHelloworldHandlerClient(ctx, mux, NewHelloworldClient(conn)) +} + +// RegisterHelloworldHandlerClient registers the http handlers for service Helloworld +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "HelloworldClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "HelloworldClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "HelloworldClient" to call the correct interceptors. +func RegisterHelloworldHandlerClient(ctx context.Context, mux *runtime.ServeMux, client HelloworldClient) error { + + mux.Handle("GET", pattern_Helloworld_Check_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Helloworld_Check_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Helloworld_Check_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Helloworld_Check_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "helloworld", "health"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Helloworld_Check_0 = runtime.ForwardResponseMessage +) diff --git a/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.swagger.json b/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.swagger.json new file mode 100644 index 000000000..daf0e175e --- /dev/null +++ b/example/hello-world/hello-world-idl/gen/go/helloworld/helloworld.swagger.json @@ -0,0 +1,63 @@ +{ + "swagger": "2.0", + "info": { + "title": "Helloworld", + "version": "1.0" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/helloworld/health": { + "get": { + "operationId": "Check", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/healthHealthCheckResponse" + } + } + }, + "parameters": [ + { + "name": "service", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "Helloworld" + ] + } + } + }, + "definitions": { + "HealthCheckResponseServingStatus": { + "type": "string", + "enum": [ + "UNKNOWN", + "SERVING", + "NOT_SERVING", + "SERVICE_UNKNOWN" + ], + "default": "UNKNOWN" + }, + "healthHealthCheckResponse": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/HealthCheckResponseServingStatus" + } + } + } + } +} From 2303df3e29878a77afddaeb2dd6ab6574f7faf8c Mon Sep 17 00:00:00 2001 From: pritesh-patel Date: Tue, 8 Oct 2019 12:10:09 -0700 Subject: [PATCH 3/3] updated example --- example/hello-world/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/example/hello-world/.gitignore b/example/hello-world/.gitignore index e69de29bb..55283c232 100644 --- a/example/hello-world/.gitignore +++ b/example/hello-world/.gitignore @@ -0,0 +1 @@ +/hello-world-idl