Add initial backend proto and example

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2020-04-06 11:22:34 -04:00
parent 9659b5df51
commit bae830a1b1
7 changed files with 405 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bin/

View File

@ -27,11 +27,16 @@ PACKAGES=$(shell go list ./... | grep -v /vendor/)
GIT_COMMIT=$(shell git rev-parse --short HEAD) GIT_COMMIT=$(shell git rev-parse --short HEAD)
GOOS ?= $(shell go env GOOS) GOOS ?= $(shell go env GOOS)
export GO111MODULE=off
all: protos all: protos
protos: protos:
@protobuild --quiet ${PACKAGES} @protobuild --quiet ${PACKAGES}
example:
cd example/backend && go build -v -o ../../bin/backend-example
FORCE: FORCE:
.PHONY: protos .PHONY: protos example

View File

@ -10,3 +10,12 @@ to install the correct version of protobufs on your system and get the protobuil
```bash ```bash
> make > make
``` ```
## Build the example backend
The example backend code is located in `/example/backend`.
Build the service with the resulting binary placed in the `/bin` directory.
```bash
> make example
```

172
backend/v1/backend.pb.go Normal file
View File

@ -0,0 +1,172 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: github.com/docker/api/backend/v1/backend.proto
package v1
import (
context "context"
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type BackendInformationResponse struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BackendInformationResponse) Reset() { *m = BackendInformationResponse{} }
func (m *BackendInformationResponse) String() string { return proto.CompactTextString(m) }
func (*BackendInformationResponse) ProtoMessage() {}
func (*BackendInformationResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_511f43e0e6c515ac, []int{0}
}
func (m *BackendInformationResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BackendInformationResponse.Unmarshal(m, b)
}
func (m *BackendInformationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BackendInformationResponse.Marshal(b, m, deterministic)
}
func (m *BackendInformationResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_BackendInformationResponse.Merge(m, src)
}
func (m *BackendInformationResponse) XXX_Size() int {
return xxx_messageInfo_BackendInformationResponse.Size(m)
}
func (m *BackendInformationResponse) XXX_DiscardUnknown() {
xxx_messageInfo_BackendInformationResponse.DiscardUnknown(m)
}
var xxx_messageInfo_BackendInformationResponse proto.InternalMessageInfo
func (m *BackendInformationResponse) GetID() string {
if m != nil {
return m.ID
}
return ""
}
func init() {
proto.RegisterType((*BackendInformationResponse)(nil), "com.docker.api.backend.v1.BackendInformationResponse")
}
func init() {
proto.RegisterFile("github.com/docker/api/backend/v1/backend.proto", fileDescriptor_511f43e0e6c515ac)
}
var fileDescriptor_511f43e0e6c515ac = []byte{
// 218 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4b, 0xcf, 0x2c, 0xc9,
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xc9, 0x4f, 0xce, 0x4e, 0x2d, 0xd2, 0x4f, 0x2c,
0xc8, 0xd4, 0x4f, 0x4a, 0x4c, 0xce, 0x4e, 0xcd, 0x4b, 0xd1, 0x2f, 0x33, 0x84, 0x31, 0xf5, 0x0a,
0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x24, 0x93, 0xf3, 0x73, 0xf5, 0x20, 0x0a, 0xf5, 0x12, 0x0b, 0x32,
0xf5, 0x60, 0xb2, 0x65, 0x86, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x55, 0xfa, 0x20, 0x16,
0x44, 0x83, 0x94, 0x74, 0x7a, 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x3e, 0x98, 0x97, 0x54, 0x9a, 0xa6,
0x9f, 0x9a, 0x5b, 0x50, 0x52, 0x09, 0x91, 0x54, 0x32, 0xe1, 0x92, 0x72, 0x82, 0x18, 0xe0, 0x99,
0x97, 0x96, 0x5f, 0x94, 0x9b, 0x58, 0x92, 0x99, 0x9f, 0x17, 0x94, 0x5a, 0x5c, 0x90, 0x9f, 0x57,
0x9c, 0x2a, 0x24, 0xc6, 0xc5, 0x94, 0x99, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0xc4, 0xf6,
0xe8, 0x9e, 0x3c, 0x93, 0xa7, 0x4b, 0x10, 0x53, 0x66, 0x8a, 0x51, 0x1e, 0x17, 0x3b, 0x54, 0x97,
0x50, 0x32, 0x97, 0x10, 0xa6, 0x01, 0x42, 0x62, 0x7a, 0x10, 0x4b, 0xf5, 0x60, 0x96, 0xea, 0xb9,
0x82, 0x2c, 0x95, 0x32, 0xd5, 0xc3, 0xe9, 0x7a, 0x3d, 0xdc, 0xee, 0x70, 0x52, 0x8d, 0x52, 0x26,
0x14, 0x4a, 0xd6, 0x65, 0x86, 0x11, 0x0c, 0x49, 0x6c, 0x60, 0xfb, 0x8c, 0x01, 0x01, 0x00, 0x00,
0xff, 0xff, 0x3d, 0x73, 0x02, 0xd8, 0x55, 0x01, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// BackendClient is the client API for Backend service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type BackendClient interface {
// BackendInformation returns implementation specific information on the backend.
BackendInformation(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*BackendInformationResponse, error)
}
type backendClient struct {
cc *grpc.ClientConn
}
func NewBackendClient(cc *grpc.ClientConn) BackendClient {
return &backendClient{cc}
}
func (c *backendClient) BackendInformation(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*BackendInformationResponse, error) {
out := new(BackendInformationResponse)
err := c.cc.Invoke(ctx, "/com.docker.api.backend.v1.Backend/BackendInformation", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// BackendServer is the server API for Backend service.
type BackendServer interface {
// BackendInformation returns implementation specific information on the backend.
BackendInformation(context.Context, *types.Empty) (*BackendInformationResponse, error)
}
// UnimplementedBackendServer can be embedded to have forward compatible implementations.
type UnimplementedBackendServer struct {
}
func (*UnimplementedBackendServer) BackendInformation(ctx context.Context, req *types.Empty) (*BackendInformationResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BackendInformation not implemented")
}
func RegisterBackendServer(s *grpc.Server, srv BackendServer) {
s.RegisterService(&_Backend_serviceDesc, srv)
}
func _Backend_BackendInformation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendServer).BackendInformation(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/com.docker.api.backend.v1.Backend/BackendInformation",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendServer).BackendInformation(ctx, req.(*types.Empty))
}
return interceptor(ctx, in, info, handler)
}
var _Backend_serviceDesc = grpc.ServiceDesc{
ServiceName: "com.docker.api.backend.v1.Backend",
HandlerType: (*BackendServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "BackendInformation",
Handler: _Backend_BackendInformation_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "github.com/docker/api/backend/v1/backend.proto",
}

49
client/client.go Normal file
View File

@ -0,0 +1,49 @@
/*
Copyright (c) 2019 Docker Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package client
import "google.golang.org/grpc"
// New returns a GRPC client
func New(address string) (*Client, error) {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
return nil, err
}
return &Client{
conn: conn,
}, nil
}
type Client struct {
conn *grpc.ClientConn
}
func (c *Client) Close() error {
return c.conn.Close()
}

112
example/backend/main.go Normal file
View File

@ -0,0 +1,112 @@
/*
Copyright (c) 2019 Docker Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package main
import (
"context"
"fmt"
"net"
"os"
"os/signal"
"syscall"
"github.com/docker/api/server"
_ "github.com/gogo/googleapis/google/rpc"
_ "github.com/gogo/protobuf/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "example"
app.Usage = "example backend"
app.Description = ""
app.UseShortOptionHandling = true
app.EnableBashCompletion = true
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "debug",
Usage: "enable debug output in the logs",
},
cli.StringFlag{
Name: "address,a",
Usage: "address of the server",
},
}
app.Before = func(clix *cli.Context) error {
if clix.GlobalBool("debug") {
logrus.SetLevel(logrus.DebugLevel)
}
return nil
}
app.Action = func(clix *cli.Context) error {
ctx, cancel := cancelContext()
defer cancel()
// create a new GRPC server with the provided server package
s := server.New()
// listen on a socket to accept connects
l, err := net.Listen("tcp", clix.GlobalString("address"))
if err != nil {
return errors.Wrap(err, "listen tcp")
}
defer l.Close()
// handle context being closed or canceled
go func() {
<-ctx.Done()
logrus.Info("backend signaled to stop")
s.Stop()
}()
logrus.WithField("address", clix.GlobalString("address")).Info("serving daemon API")
// start the GRPC server to serve on the listener
return s.Serve(l)
}
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// cancelContext is a context that is canceled when a signal is
// sent to the process
func cancelContext() (context.Context, func()) {
ctx, cancel := context.WithCancel(context.Background())
s := make(chan os.Signal)
signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
go func() {
<-s
cancel()
}()
return ctx, cancel
}

56
server/server.go Normal file
View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2019 Docker Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package server
import (
"context"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
)
// New returns a new GRPC server.
func New() *grpc.Server {
s := grpc.NewServer(
grpc.UnaryInterceptor(unary),
grpc.StreamInterceptor(stream),
)
hs := health.NewServer()
grpc_health_v1.RegisterHealthServer(s, hs)
return s
}
func unary(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
return grpc_prometheus.UnaryServerInterceptor(ctx, req, info, handler)
}
func stream(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
return grpc_prometheus.StreamServerInterceptor(srv, ss, info, handler)
}