Merge pull request #35 from coreos/remove-api

Remove api and ctl
This commit is contained in:
Eric Chiang
2016-08-05 10:03:09 -07:00
committed by GitHub
138 changed files with 8 additions and 27329 deletions
+1 -8
View File
@@ -46,13 +46,6 @@ lint:
golint $$package; \
done
# TODO(ericchiang): Grab protoc as well.
grpc: bin/protoc-gen-go
@protoc --go_out=plugins=grpc:. ./api/apipb/*.proto
bin/protoc-gen-go:
@go install ${REPO_PATH}/vendor/github.com/golang/protobuf/protoc-gen-go
clean:
@rm bin/*
@@ -60,4 +53,4 @@ testall: testrace vet fmt lint
FORCE:
.PHONY: test testrace vet fmt lint testall grpc
.PHONY: test testrace vet fmt lint testall
-136
View File
@@ -1,136 +0,0 @@
package api
import (
"errors"
"golang.org/x/net/context"
"github.com/coreos/poke/api/apipb"
"github.com/coreos/poke/storage"
)
// NewServer returns a gRPC server for talking to a storage.
func NewServer(s storage.Storage) apipb.StorageServer {
return &server{s}
}
type server struct {
storage storage.Storage
}
func fromPBClient(client *apipb.Client) storage.Client {
return storage.Client{
ID: client.Id,
Secret: client.Secret,
RedirectURIs: client.RedirectUris,
TrustedPeers: client.TrustedPeers,
Public: client.Public,
Name: client.Name,
LogoURL: client.LogoUrl,
}
}
func toPBClient(client storage.Client) *apipb.Client {
return &apipb.Client{
Id: client.ID,
Secret: client.Secret,
RedirectUris: client.RedirectURIs,
TrustedPeers: client.TrustedPeers,
Public: client.Public,
Name: client.Name,
LogoUrl: client.LogoURL,
}
}
func (s *server) CreateClient(ctx context.Context, req *apipb.CreateClientReq) (*apipb.CreateClientResp, error) {
// TODO(ericchiang): Create a more centralized strategy for creating client IDs
// and secrets which are restricted based on the storage.
client := fromPBClient(req.Client)
if client.ID == "" {
client.ID = storage.NewID()
}
if client.Secret == "" {
client.Secret = storage.NewID() + storage.NewID()
}
if err := s.storage.CreateClient(client); err != nil {
return nil, err
}
return &apipb.CreateClientResp{Client: toPBClient(client)}, nil
}
func (s *server) UpdateClient(ctx context.Context, req *apipb.UpdateClientReq) (*apipb.UpdateClientResp, error) {
switch {
case req.Id == "":
return nil, errors.New("no ID supplied")
case req.MakePublic && req.MakePrivate:
return nil, errors.New("cannot both make public and private")
case req.MakePublic && len(req.RedirectUris) != 0:
return nil, errors.New("redirect uris supplied for a public client")
}
var client *storage.Client
updater := func(old storage.Client) (storage.Client, error) {
if req.MakePublic {
old.Public = true
}
if req.MakePrivate {
old.Public = false
}
if req.Secret != "" {
old.Secret = req.Secret
}
if req.Name != "" {
old.Name = req.Name
}
if req.LogoUrl != "" {
old.LogoURL = req.LogoUrl
}
if len(req.RedirectUris) != 0 {
if old.Public {
return old, errors.New("public clients cannot have redirect URIs")
}
old.RedirectURIs = req.RedirectUris
}
client = &old
return old, nil
}
if err := s.storage.UpdateClient(req.Id, updater); err != nil {
return nil, err
}
return &apipb.UpdateClientResp{Client: toPBClient(*client)}, nil
}
func (s *server) DeleteClient(ctx context.Context, req *apipb.DeleteClientReq) (*apipb.DeleteClientReq, error) {
if req.Id == "" {
return nil, errors.New("no client ID supplied")
}
if err := s.storage.DeleteClient(req.Id); err != nil {
return nil, err
}
return &apipb.DeleteClientReq{}, nil
}
func (s *server) ListClients(ctx context.Context, req *apipb.ListClientsReq) (*apipb.ListClientsResp, error) {
clients, err := s.storage.ListClients()
if err != nil {
return nil, err
}
resp := make([]*apipb.Client, len(clients))
for i, client := range clients {
resp[i] = toPBClient(client)
}
return &apipb.ListClientsResp{Clients: resp}, nil
}
func (s *server) GetClient(ctx context.Context, req *apipb.GetClientReq) (*apipb.GetClientResp, error) {
if req.Id == "" {
return nil, errors.New("no client ID supplied")
}
client, err := s.storage.GetClient(req.Id)
if err != nil {
return nil, err
}
return &apipb.GetClientResp{Client: toPBClient(client)}, nil
}
-443
View File
@@ -1,443 +0,0 @@
// Code generated by protoc-gen-go.
// source: api/apipb/api.proto
// DO NOT EDIT!
/*
Package apipb is a generated protocol buffer package.
It is generated from these files:
api/apipb/api.proto
It has these top-level messages:
Client
CreateClientReq
CreateClientResp
UpdateClientReq
UpdateClientResp
ListClientsReq
ListClientsResp
DeleteClientReq
DeleteClientResp
GetClientReq
GetClientResp
*/
package apipb
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// 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.ProtoPackageIsVersion2 // please upgrade the proto package
type Client struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Secret string `protobuf:"bytes,2,opt,name=secret" json:"secret,omitempty"`
RedirectUris []string `protobuf:"bytes,3,rep,name=redirect_uris,json=redirectUris" json:"redirect_uris,omitempty"`
TrustedPeers []string `protobuf:"bytes,4,rep,name=trusted_peers,json=trustedPeers" json:"trusted_peers,omitempty"`
Public bool `protobuf:"varint,5,opt,name=public" json:"public,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
LogoUrl string `protobuf:"bytes,7,opt,name=logo_url,json=logoUrl" json:"logo_url,omitempty"`
}
func (m *Client) Reset() { *m = Client{} }
func (m *Client) String() string { return proto.CompactTextString(m) }
func (*Client) ProtoMessage() {}
func (*Client) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type CreateClientReq struct {
Client *Client `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
}
func (m *CreateClientReq) Reset() { *m = CreateClientReq{} }
func (m *CreateClientReq) String() string { return proto.CompactTextString(m) }
func (*CreateClientReq) ProtoMessage() {}
func (*CreateClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *CreateClientReq) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
type CreateClientResp struct {
Client *Client `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
}
func (m *CreateClientResp) Reset() { *m = CreateClientResp{} }
func (m *CreateClientResp) String() string { return proto.CompactTextString(m) }
func (*CreateClientResp) ProtoMessage() {}
func (*CreateClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *CreateClientResp) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
type UpdateClientReq struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
// Empty strings indicate that string fields should not be updated.
Secret string `protobuf:"bytes,2,opt,name=secret" json:"secret,omitempty"`
Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"`
LogoUrl string `protobuf:"bytes,4,opt,name=logo_url,json=logoUrl" json:"logo_url,omitempty"`
MakePublic bool `protobuf:"varint,5,opt,name=make_public,json=makePublic" json:"make_public,omitempty"`
MakePrivate bool `protobuf:"varint,6,opt,name=make_private,json=makePrivate" json:"make_private,omitempty"`
// If no redirect URIs are specified, the current redirect URIs are preserved.
RedirectUris []string `protobuf:"bytes,7,rep,name=redirect_uris,json=redirectUris" json:"redirect_uris,omitempty"`
}
func (m *UpdateClientReq) Reset() { *m = UpdateClientReq{} }
func (m *UpdateClientReq) String() string { return proto.CompactTextString(m) }
func (*UpdateClientReq) ProtoMessage() {}
func (*UpdateClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
type UpdateClientResp struct {
Client *Client `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
}
func (m *UpdateClientResp) Reset() { *m = UpdateClientResp{} }
func (m *UpdateClientResp) String() string { return proto.CompactTextString(m) }
func (*UpdateClientResp) ProtoMessage() {}
func (*UpdateClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *UpdateClientResp) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
type ListClientsReq struct {
}
func (m *ListClientsReq) Reset() { *m = ListClientsReq{} }
func (m *ListClientsReq) String() string { return proto.CompactTextString(m) }
func (*ListClientsReq) ProtoMessage() {}
func (*ListClientsReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
type ListClientsResp struct {
Clients []*Client `protobuf:"bytes,1,rep,name=clients" json:"clients,omitempty"`
}
func (m *ListClientsResp) Reset() { *m = ListClientsResp{} }
func (m *ListClientsResp) String() string { return proto.CompactTextString(m) }
func (*ListClientsResp) ProtoMessage() {}
func (*ListClientsResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *ListClientsResp) GetClients() []*Client {
if m != nil {
return m.Clients
}
return nil
}
type DeleteClientReq struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
}
func (m *DeleteClientReq) Reset() { *m = DeleteClientReq{} }
func (m *DeleteClientReq) String() string { return proto.CompactTextString(m) }
func (*DeleteClientReq) ProtoMessage() {}
func (*DeleteClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
type DeleteClientResp struct {
}
func (m *DeleteClientResp) Reset() { *m = DeleteClientResp{} }
func (m *DeleteClientResp) String() string { return proto.CompactTextString(m) }
func (*DeleteClientResp) ProtoMessage() {}
func (*DeleteClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
type GetClientReq struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
}
func (m *GetClientReq) Reset() { *m = GetClientReq{} }
func (m *GetClientReq) String() string { return proto.CompactTextString(m) }
func (*GetClientReq) ProtoMessage() {}
func (*GetClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
type GetClientResp struct {
Client *Client `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
}
func (m *GetClientResp) Reset() { *m = GetClientResp{} }
func (m *GetClientResp) String() string { return proto.CompactTextString(m) }
func (*GetClientResp) ProtoMessage() {}
func (*GetClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *GetClientResp) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
func init() {
proto.RegisterType((*Client)(nil), "apipb.Client")
proto.RegisterType((*CreateClientReq)(nil), "apipb.CreateClientReq")
proto.RegisterType((*CreateClientResp)(nil), "apipb.CreateClientResp")
proto.RegisterType((*UpdateClientReq)(nil), "apipb.UpdateClientReq")
proto.RegisterType((*UpdateClientResp)(nil), "apipb.UpdateClientResp")
proto.RegisterType((*ListClientsReq)(nil), "apipb.ListClientsReq")
proto.RegisterType((*ListClientsResp)(nil), "apipb.ListClientsResp")
proto.RegisterType((*DeleteClientReq)(nil), "apipb.DeleteClientReq")
proto.RegisterType((*DeleteClientResp)(nil), "apipb.DeleteClientResp")
proto.RegisterType((*GetClientReq)(nil), "apipb.GetClientReq")
proto.RegisterType((*GetClientResp)(nil), "apipb.GetClientResp")
}
// 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.SupportPackageIsVersion3
// Client API for Storage service
type StorageClient interface {
GetClient(ctx context.Context, in *GetClientReq, opts ...grpc.CallOption) (*GetClientResp, error)
CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error)
UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error)
DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientReq, error)
ListClients(ctx context.Context, in *ListClientsReq, opts ...grpc.CallOption) (*ListClientsResp, error)
}
type storageClient struct {
cc *grpc.ClientConn
}
func NewStorageClient(cc *grpc.ClientConn) StorageClient {
return &storageClient{cc}
}
func (c *storageClient) GetClient(ctx context.Context, in *GetClientReq, opts ...grpc.CallOption) (*GetClientResp, error) {
out := new(GetClientResp)
err := grpc.Invoke(ctx, "/apipb.Storage/GetClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storageClient) CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error) {
out := new(CreateClientResp)
err := grpc.Invoke(ctx, "/apipb.Storage/CreateClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storageClient) UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error) {
out := new(UpdateClientResp)
err := grpc.Invoke(ctx, "/apipb.Storage/UpdateClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storageClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientReq, error) {
out := new(DeleteClientReq)
err := grpc.Invoke(ctx, "/apipb.Storage/DeleteClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storageClient) ListClients(ctx context.Context, in *ListClientsReq, opts ...grpc.CallOption) (*ListClientsResp, error) {
out := new(ListClientsResp)
err := grpc.Invoke(ctx, "/apipb.Storage/ListClients", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Storage service
type StorageServer interface {
GetClient(context.Context, *GetClientReq) (*GetClientResp, error)
CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error)
UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error)
DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientReq, error)
ListClients(context.Context, *ListClientsReq) (*ListClientsResp, error)
}
func RegisterStorageServer(s *grpc.Server, srv StorageServer) {
s.RegisterService(&_Storage_serviceDesc, srv)
}
func _Storage_GetClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageServer).GetClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apipb.Storage/GetClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageServer).GetClient(ctx, req.(*GetClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Storage_CreateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageServer).CreateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apipb.Storage/CreateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageServer).CreateClient(ctx, req.(*CreateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Storage_UpdateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageServer).UpdateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apipb.Storage/UpdateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageServer).UpdateClient(ctx, req.(*UpdateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Storage_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageServer).DeleteClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apipb.Storage/DeleteClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageServer).DeleteClient(ctx, req.(*DeleteClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Storage_ListClients_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListClientsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageServer).ListClients(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apipb.Storage/ListClients",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageServer).ListClients(ctx, req.(*ListClientsReq))
}
return interceptor(ctx, in, info, handler)
}
var _Storage_serviceDesc = grpc.ServiceDesc{
ServiceName: "apipb.Storage",
HandlerType: (*StorageServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetClient",
Handler: _Storage_GetClient_Handler,
},
{
MethodName: "CreateClient",
Handler: _Storage_CreateClient_Handler,
},
{
MethodName: "UpdateClient",
Handler: _Storage_UpdateClient_Handler,
},
{
MethodName: "DeleteClient",
Handler: _Storage_DeleteClient_Handler,
},
{
MethodName: "ListClients",
Handler: _Storage_ListClients_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: fileDescriptor0,
}
func init() { proto.RegisterFile("api/apipb/api.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 459 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x54, 0x41, 0x8f, 0xd2, 0x40,
0x14, 0xa6, 0xc0, 0xb6, 0xf0, 0x28, 0x0b, 0x79, 0xab, 0x6b, 0xe5, 0xa0, 0xec, 0x18, 0x23, 0x27,
0x4c, 0xd6, 0xc4, 0xac, 0x1e, 0x8c, 0x66, 0x4d, 0xbc, 0x78, 0x20, 0x35, 0x9c, 0x49, 0xa1, 0x2f,
0x9b, 0x89, 0xdd, 0xed, 0x30, 0x33, 0xf8, 0xff, 0x3c, 0x7b, 0xf2, 0x1f, 0x99, 0xce, 0xb4, 0x4d,
0x07, 0x64, 0xc3, 0x85, 0xf0, 0xbe, 0xf9, 0xde, 0x7b, 0xf9, 0xbe, 0xef, 0xa5, 0x70, 0x91, 0x08,
0xfe, 0x36, 0x11, 0x5c, 0xac, 0x8b, 0xdf, 0xb9, 0x90, 0xb9, 0xce, 0xf1, 0xcc, 0x00, 0xec, 0xb7,
0x07, 0xfe, 0x6d, 0xc6, 0xe9, 0x41, 0xe3, 0x39, 0xb4, 0x79, 0x1a, 0x79, 0x53, 0x6f, 0xd6, 0x8f,
0xdb, 0x3c, 0xc5, 0x4b, 0xf0, 0x15, 0x6d, 0x24, 0xe9, 0xa8, 0x6d, 0xb0, 0xb2, 0xc2, 0x57, 0x30,
0x94, 0x94, 0x72, 0x49, 0x1b, 0xbd, 0xda, 0x49, 0xae, 0xa2, 0xce, 0xb4, 0x33, 0xeb, 0xc7, 0x61,
0x05, 0x2e, 0x25, 0x57, 0x05, 0x49, 0xcb, 0x9d, 0xd2, 0x94, 0xae, 0x04, 0x91, 0x54, 0x51, 0xd7,
0x92, 0x4a, 0x70, 0x51, 0x60, 0xc5, 0x06, 0xb1, 0x5b, 0x67, 0x7c, 0x13, 0x9d, 0x4d, 0xbd, 0x59,
0x2f, 0x2e, 0x2b, 0x44, 0xe8, 0x3e, 0x24, 0xf7, 0x14, 0xf9, 0x66, 0xaf, 0xf9, 0x8f, 0xcf, 0xa1,
0x97, 0xe5, 0x77, 0xf9, 0x6a, 0x27, 0xb3, 0x28, 0x30, 0x78, 0x50, 0xd4, 0x4b, 0x99, 0xb1, 0x1b,
0x18, 0xdd, 0x4a, 0x4a, 0x34, 0x59, 0x21, 0x31, 0x6d, 0xf1, 0x35, 0xf8, 0x1b, 0x53, 0x18, 0x3d,
0x83, 0xeb, 0xe1, 0xdc, 0xc8, 0x9d, 0x97, 0x8c, 0xf2, 0x91, 0x7d, 0x80, 0xb1, 0xdb, 0xa9, 0xc4,
0xa9, 0xad, 0x7f, 0x3d, 0x18, 0x2d, 0x45, 0xea, 0x6c, 0x3d, 0xd5, 0xc1, 0x4a, 0x5f, 0xe7, 0x88,
0xbe, 0xae, 0xa3, 0x0f, 0x5f, 0xc2, 0xe0, 0x3e, 0xf9, 0x49, 0x2b, 0xc7, 0x2b, 0x28, 0xa0, 0x85,
0xf5, 0xeb, 0x0a, 0x42, 0x4b, 0x90, 0xfc, 0x57, 0xa2, 0xad, 0x6f, 0xbd, 0xd8, 0x34, 0x2d, 0x2c,
0x74, 0x18, 0x5a, 0x70, 0x18, 0x5a, 0x61, 0x87, 0x2b, 0xe9, 0x74, 0x3b, 0xc6, 0x70, 0xfe, 0x9d,
0x2b, 0x6d, 0x51, 0x15, 0xd3, 0x96, 0x7d, 0x84, 0x91, 0x83, 0x28, 0x81, 0x6f, 0x20, 0xb0, 0x74,
0x15, 0x79, 0xd3, 0xce, 0xe1, 0xb0, 0xea, 0x95, 0x5d, 0xc1, 0xe8, 0x2b, 0x65, 0xf4, 0x88, 0xb7,
0x0c, 0x61, 0xec, 0x52, 0x94, 0x60, 0x2f, 0x20, 0xfc, 0x46, 0xfa, 0x78, 0xcf, 0x7b, 0x18, 0x36,
0xde, 0x4f, 0x16, 0x77, 0xfd, 0xa7, 0x0d, 0xc1, 0x0f, 0x9d, 0xcb, 0xe4, 0x8e, 0xf0, 0x06, 0xfa,
0xf5, 0x0c, 0xbc, 0x28, 0xf9, 0xcd, 0xad, 0x93, 0x27, 0x87, 0xa0, 0x12, 0xac, 0x85, 0x5f, 0x20,
0x6c, 0x1e, 0x1b, 0x5e, 0x56, 0xcb, 0xdc, 0xdb, 0x9d, 0x3c, 0xfb, 0x2f, 0x5e, 0x8d, 0x68, 0x06,
0x54, 0x8f, 0xd8, 0x3b, 0xc4, 0x7a, 0xc4, 0x7e, 0x9a, 0xac, 0x85, 0x9f, 0x21, 0x6c, 0xfa, 0x56,
0x8f, 0xd8, 0xf3, 0x7b, 0x72, 0x04, 0x67, 0x2d, 0xfc, 0x04, 0x83, 0x46, 0xb0, 0xf8, 0xb4, 0x24,
0xba, 0xf1, 0xd7, 0xfd, 0x7b, 0x37, 0xc0, 0x5a, 0x6b, 0xdf, 0x7c, 0x80, 0xde, 0xfd, 0x0b, 0x00,
0x00, 0xff, 0xff, 0x76, 0xa0, 0x50, 0x77, 0x97, 0x04, 0x00, 0x00,
}
-74
View File
@@ -1,74 +0,0 @@
syntax = "proto3";
// Run `make grpc` at the top level directory to regenerate Go source code.
package apipb;
message Client {
string id = 1;
string secret = 2;
repeated string redirect_uris = 3;
repeated string trusted_peers = 4;
bool public = 5;
string name = 6;
string logo_url = 7;
}
message CreateClientReq {
Client client = 1;
}
message CreateClientResp {
Client client = 1;
}
message UpdateClientReq {
string id = 1;
// Empty strings indicate that string fields should not be updated.
string secret = 2;
string name = 3;
string logo_url = 4;
bool make_public = 5;
bool make_private = 6;
// If no redirect URIs are specified, the current redirect URIs are preserved.
repeated string redirect_uris = 7;
}
message UpdateClientResp {
Client client = 1;
}
message ListClientsReq {
}
message ListClientsResp {
repeated Client clients = 1;
}
message DeleteClientReq {
string id = 1;
}
message DeleteClientResp {}
message GetClientReq {
string id = 1;
}
message GetClientResp {
Client client = 1;
}
service Storage {
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {}
rpc DeleteClient(DeleteClientReq) returns (DeleteClientReq) {}
rpc GetClient(GetClientReq) returns (GetClientResp) {}
rpc ListClients(ListClientsReq) returns (ListClientsResp) {}
rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {}
}
-2
View File
@@ -1,2 +0,0 @@
// Package api implements a gRPC interface for interacting with a storage.
package api
-24
View File
@@ -1,24 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "pokectl",
RunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}
func init() {}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
}
Generated
+2 -18
View File
@@ -1,5 +1,5 @@
hash: 2b694ffd26e854f519064b43f437545dfb7cfdc437b3890552dc1f6e7955a2b5
updated: 2016-08-03T23:07:24.402853601-07:00
hash: 4442a097b81856345ae5f80101ad1a692a0b4e5d9b7627f5ad09cd20926122f4
updated: 2016-08-05T09:58:15.61704222-07:00
imports:
- name: github.com/ericchiang/oidc
version: 69fec81d167d815f4f455c741b2a94ffaf547ed2
@@ -40,11 +40,6 @@ imports:
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context
- http2
- http2/hpack
- trace
- lex/httplex
- internal/timeseries
- name: golang.org/x/oauth2
version: 08c8d727d2392d18286f9f88ad775ad98f09ab33
subpackages:
@@ -60,17 +55,6 @@ imports:
- internal/datastore
- internal/log
- internal/remote_api
- name: google.golang.org/grpc
version: 13edeeffdea7a41d5aad96c28deb4c7bd01a9397
subpackages:
- codes
- credentials
- grpclog
- internal
- metadata
- naming
- transport
- peer
- name: gopkg.in/asn1-ber.v1
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
- name: gopkg.in/ldap.v2
+5 -21
View File
@@ -22,6 +22,11 @@ import:
- cipher
- json
- package: golang.org/x/net
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context
- package: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
@@ -67,27 +72,6 @@ import:
- package: github.com/mitchellh/go-homedir
verison: 756f7b183b7ab78acdbbee5c7f392838ed459dda
- package: google.golang.org/grpc
version: v1.0.0
subpackages:
- codes
- credentials
- grpclog
- internal
- metadata
- naming
- transport
- peer
- package: golang.org/x/net
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context # context is also imported directly by this repo.
- http2
- http2/hpack
- trace
- lex/httplex
- internal/timeseries
- package: github.com/kylelemons/godebug
subpackages:
- diff
-17
View File
@@ -1,17 +0,0 @@
language: go
go:
- 1.5.3
- 1.6
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
install:
- mkdir -p "$GOPATH/src/google.golang.org"
- mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/google.golang.org/grpc"
script:
- make test testrace
-46
View File
@@ -1,46 +0,0 @@
# How to contribute
We definitely welcome patches and contribution to grpc! Here are some guidelines
and information about how to do so.
## Sending patches
### Getting started
1. Check out the code:
$ go get google.golang.org/grpc
$ cd $GOPATH/src/google.golang.org/grpc
1. Create a fork of the grpc-go repository.
1. Add your fork as a remote:
$ git remote add fork git@github.com:$YOURGITHUBUSERNAME/grpc-go.git
1. Make changes, commit them.
1. Run the test suite:
$ make test
1. Push your changes to your fork:
$ git push fork ...
1. Open a pull request.
## Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
## Filing Issues
When filing an issue, make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
### Contributing code
Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file.
-41
View File
@@ -1,41 +0,0 @@
# Authentication
As outlined in the [gRPC authentication guide](http://www.grpc.io/docs/guides/auth.html) there are a number of different mechanisms for asserting identity between an client and server. We'll present some code-samples here demonstrating how to provide TLS support encryption and identity assertions as well as passing OAuth2 tokens to services that support it.
# Enabling TLS on a gRPC client
```Go
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")))
```
# Enabling TLS on a gRPC server
```Go
creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
if err != nil {
log.Fatalf("Failed to generate credentials %v", err)
}
lis, err := net.Listen("tcp", ":0")
server := grpc.NewServer(grpc.Creds(creds))
...
server.Serve(lis)
```
# Authenticating with Google
## Google Compute Engine (GCE)
```Go
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, ""), grpc.WithPerRPCCredentials(oauth.NewComputeEngine())))
```
## JWT
```Go
jwtCreds, err := oauth.NewServiceAccountFromFile(*serviceAccountKeyFile, *oauthScope)
if err != nil {
log.Fatalf("Failed to create JWT credentials: %v", err)
}
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, ""), grpc.WithPerRPCCredentials(jwtCreds)))
```
-201
View File
@@ -1,201 +0,0 @@
# Metadata
gRPC supports sending metadata between client and server.
This doc shows how to send and receive metadata in gRPC-go.
## Background
Four kinds of service method:
- [Unary RPC](http://www.grpc.io/docs/guides/concepts.html#unary-rpc)
- [Server streaming RPC](http://www.grpc.io/docs/guides/concepts.html#server-streaming-rpc)
- [Client streaming RPC](http://www.grpc.io/docs/guides/concepts.html#client-streaming-rpc)
- [Bidirectional streaming RPC](http://www.grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc)
And concept of [metadata](http://www.grpc.io/docs/guides/concepts.html#metadata).
## Constructing metadata
A metadata can be created using package [metadata](https://godoc.org/google.golang.org/grpc/metadata).
The type MD is actually a map from string to a list of strings:
```go
type MD map[string][]string
```
Metadata can be read like a normal map.
Note that the value type of this map is `[]string`,
so that users can attach multiple values using a single key.
### Creating a new metadata
A metadata can be created from a `map[string]string` using function `New`:
```go
md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
```
Another way is to use `Pairs`.
Values with the same key will be merged into a list:
```go
md := metadata.Pairs(
"key1", "val1",
"key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
"key2", "val2",
)
```
__Note:__ all the keys will be automatically converted to lowercase,
so "key1" and "kEy1" will be the same key and their values will be merged into the same list.
This happens for both `New` and `Pairs`.
### Storing binary data in metadata
In metadata, keys are always strings. But values can be strings or binary data.
To store binary data value in metadata, simply add "-bin" surfix to the key.
The values with "-bin" surffixed keys will be encoded when creating the metadata:
```go
md := metadata.Pairs(
"key", "string value",
"key-bin", string([]byte{96, 102}), // this binary data will be encoded (base64) before sending
// and will be decoded after being transferred.
)
```
## Retrieving metadata from context
Metadata can be retrieved from context using `FromContext`:
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
md, ok := metadata.FromContext(ctx)
// do something with metadata
}
```
## Sending and receiving metadata - client side
[//]: # "TODO: uncomment next line after example source added"
[//]: # "Real metadata sending and receiving examples are available [here](TODO:example_dir)."
### Sending metadata
To send metadata to server, the client can wrap the metadata into a context using `NewContext`, and make the RPC with this context:
```go
md := metadata.Pairs("key", "val")
// create a new context with this metadata
ctx := metadata.NewContext(context.Background(), md)
// make unary RPC
response, err := client.SomeRPC(ctx, someRequest)
// or make streaming RPC
stream, err := client.SomeStreamingRPC(ctx)
```
### Receiving metadata
Metadata that a client can receive includes header and trailer.
#### Unary call
Header and trailer sent along with a unary call can be retrieved using function [Header](https://godoc.org/google.golang.org/grpc#Header) and [Trailer](https://godoc.org/google.golang.org/grpc#Trailer) in [CallOption](https://godoc.org/google.golang.org/grpc#CallOption):
```go
var header, trailer metadata.MD // variable to store header and trailer
r, err := client.SomeRPC(
ctx,
someRequest,
grpc.Header(&header), // will retrieve header
grpc.Trailer(&trailer), // will retrieve trailer
)
// do something with header and trailer
```
#### Streaming call
For streaming calls including:
- Server streaming RPC
- Client streaming RPC
- Bidirectional streaming RPC
Header and trailer can be retrieved from the returned stream using function `Header` and `Trailer` in interface [ClientStream](https://godoc.org/google.golang.org/grpc#ClientStream):
```go
stream, err := client.SomeStreamingRPC(ctx)
// retrieve header
header, err := stream.Header()
// retrieve trailer
trailer := stream.Trailer()
```
## Sending and receiving metadata - server side
[//]: # "TODO: uncomment next line after example source added"
[//]: # "Real metadata sending and receiving examples are available [here](TODO:example_dir)."
### Receiving metadata
To read metadata sent by the client, the server needs to retrieve it from RPC context.
If it is a unary call, the RPC handler's context can be used.
For streaming calls, the server needs to get context from the stream.
#### Unary call
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
md, ok := metadata.FromContext(ctx)
// do something with metadata
}
```
#### Streaming call
```go
func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
md, ok := metadata.FromContext(stream.Context()) // get context from stream
// do something with metadata
}
```
### Sending metadata
#### Unary call
To send header and trailer to client in unary call, the server can call [SendHeader](https://godoc.org/google.golang.org/grpc#SendHeader) and [SetTrailer](https://godoc.org/google.golang.org/grpc#SetTrailer) functions in module [grpc](https://godoc.org/google.golang.org/grpc).
These two functions take a context as the first parameter.
It should be the RPC handler's context or one derived from it:
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
// create and send header
header := metadata.Pairs("header-key", "val")
grpc.SendHeader(ctx, header)
// create and set trailer
trailer := metadata.Pairs("trailer-key", "val")
grpc.SetTrailer(ctx, trailer)
}
```
#### Streaming call
For streaming calls, header and trailer can be sent using function `SendHeader` and `SetTrailer` in interface [ServerStream](https://godoc.org/google.golang.org/grpc#ServerStream):
```go
func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
// create and send header
header := metadata.Pairs("header-key", "val")
stream.SendHeader(header)
// create and set trailer
trailer := metadata.Pairs("trailer-key", "val")
stream.SetTrailer(trailer)
}
```
-28
View File
@@ -1,28 +0,0 @@
Copyright 2014, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-52
View File
@@ -1,52 +0,0 @@
all: test testrace
deps:
go get -d -v google.golang.org/grpc/...
updatedeps:
go get -d -v -u -f google.golang.org/grpc/...
testdeps:
go get -d -v -t google.golang.org/grpc/...
updatetestdeps:
go get -d -v -t -u -f google.golang.org/grpc/...
build: deps
go build google.golang.org/grpc/...
proto:
@ if ! which protoc > /dev/null; then \
echo "error: protoc not installed" >&2; \
exit 1; \
fi
go get -u -v github.com/golang/protobuf/protoc-gen-go
# use $$dir as the root for all proto files in the same directory
for dir in $$(git ls-files '*.proto' | xargs -n1 dirname | uniq); do \
protoc -I $$dir --go_out=plugins=grpc:$$dir $$dir/*.proto; \
done
test: testdeps
go test -v -cpu 1,4 google.golang.org/grpc/...
testrace: testdeps
go test -v -race -cpu 1,4 google.golang.org/grpc/...
clean:
go clean -i google.golang.org/grpc/...
coverage: testdeps
./coverage.sh --coveralls
.PHONY: \
all \
deps \
updatedeps \
testdeps \
updatetestdeps \
build \
proto \
test \
testrace \
clean \
coverage
-22
View File
@@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the gRPC project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of gRPC, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of gRPC. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of gRPC or any code incorporated within this
implementation of gRPC constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of gRPC
shall terminate as of the date such litigation is filed.
-32
View File
@@ -1,32 +0,0 @@
#gRPC-Go
[![Build Status](https://travis-ci.org/grpc/grpc-go.svg)](https://travis-ci.org/grpc/grpc-go) [![GoDoc](https://godoc.org/google.golang.org/grpc?status.svg)](https://godoc.org/google.golang.org/grpc)
The Go implementation of [gRPC](http://www.grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the [gRPC Quick Start](http://www.grpc.io/docs/) guide.
Installation
------------
To install this package, you need to install Go and setup your Go workspace on your computer. The simplest way to install the library is to run:
```
$ go get google.golang.org/grpc
```
Prerequisites
-------------
This requires Go 1.5 or later .
Constraints
-----------
The grpc package should only depend on standard Go packages and a small number of exceptions. If your contribution introduces new dependencies which are NOT in the [list](http://godoc.org/google.golang.org/grpc?imports), you need a discussion with gRPC-Go authors and consultants.
Documentation
-------------
See [API documentation](https://godoc.org/google.golang.org/grpc) for package and API descriptions and find examples in the [examples directory](examples/).
Status
------
Beta release
-80
View File
@@ -1,80 +0,0 @@
package grpc
import (
"math/rand"
"time"
)
// DefaultBackoffConfig uses values specified for backoff in
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
var (
DefaultBackoffConfig = BackoffConfig{
MaxDelay: 120 * time.Second,
baseDelay: 1.0 * time.Second,
factor: 1.6,
jitter: 0.2,
}
)
// backoffStrategy defines the methodology for backing off after a grpc
// connection failure.
//
// This is unexported until the gRPC project decides whether or not to allow
// alternative backoff strategies. Once a decision is made, this type and its
// method may be exported.
type backoffStrategy interface {
// backoff returns the amount of time to wait before the next retry given
// the number of consecutive failures.
backoff(retries int) time.Duration
}
// BackoffConfig defines the parameters for the default gRPC backoff strategy.
type BackoffConfig struct {
// MaxDelay is the upper bound of backoff delay.
MaxDelay time.Duration
// TODO(stevvooe): The following fields are not exported, as allowing
// changes would violate the current gRPC specification for backoff. If
// gRPC decides to allow more interesting backoff strategies, these fields
// may be opened up in the future.
// baseDelay is the amount of time to wait before retrying after the first
// failure.
baseDelay time.Duration
// factor is applied to the backoff after each retry.
factor float64
// jitter provides a range to randomize backoff delays.
jitter float64
}
func setDefaults(bc *BackoffConfig) {
md := bc.MaxDelay
*bc = DefaultBackoffConfig
if md > 0 {
bc.MaxDelay = md
}
}
func (bc BackoffConfig) backoff(retries int) (t time.Duration) {
if retries == 0 {
return bc.baseDelay
}
backoff, max := float64(bc.baseDelay), float64(bc.MaxDelay)
for backoff < max && retries > 0 {
backoff *= bc.factor
retries--
}
if backoff > max {
backoff = max
}
// Randomize backoff delays so that if a cluster of requests start at
// the same time, they won't operate in lockstep.
backoff *= 1 + bc.jitter*(rand.Float64()*2-1)
if backoff < 0 {
return 0
}
return time.Duration(backoff)
}
-11
View File
@@ -1,11 +0,0 @@
package grpc
import "testing"
func TestBackoffConfigDefaults(t *testing.T) {
b := BackoffConfig{}
setDefaults(&b)
if b != DefaultBackoffConfig {
t.Fatalf("expected BackoffConfig to pickup default parameters: %v != %v", b, DefaultBackoffConfig)
}
}
-385
View File
@@ -1,385 +0,0 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package grpc
import (
"fmt"
"sync"
"golang.org/x/net/context"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/naming"
)
// Address represents a server the client connects to.
// This is the EXPERIMENTAL API and may be changed or extended in the future.
type Address struct {
// Addr is the server address on which a connection will be established.
Addr string
// Metadata is the information associated with Addr, which may be used
// to make load balancing decision.
Metadata interface{}
}
// BalancerGetOptions configures a Get call.
// This is the EXPERIMENTAL API and may be changed or extended in the future.
type BalancerGetOptions struct {
// BlockingWait specifies whether Get should block when there is no
// connected address.
BlockingWait bool
}
// Balancer chooses network addresses for RPCs.
// This is the EXPERIMENTAL API and may be changed or extended in the future.
type Balancer interface {
// Start does the initialization work to bootstrap a Balancer. For example,
// this function may start the name resolution and watch the updates. It will
// be called when dialing.
Start(target string) error
// Up informs the Balancer that gRPC has a connection to the server at
// addr. It returns down which is called once the connection to addr gets
// lost or closed.
// TODO: It is not clear how to construct and take advantage the meaningful error
// parameter for down. Need realistic demands to guide.
Up(addr Address) (down func(error))
// Get gets the address of a server for the RPC corresponding to ctx.
// i) If it returns a connected address, gRPC internals issues the RPC on the
// connection to this address;
// ii) If it returns an address on which the connection is under construction
// (initiated by Notify(...)) but not connected, gRPC internals
// * fails RPC if the RPC is fail-fast and connection is in the TransientFailure or
// Shutdown state;
// or
// * issues RPC on the connection otherwise.
// iii) If it returns an address on which the connection does not exist, gRPC
// internals treats it as an error and will fail the corresponding RPC.
//
// Therefore, the following is the recommended rule when writing a custom Balancer.
// If opts.BlockingWait is true, it should return a connected address or
// block if there is no connected address. It should respect the timeout or
// cancellation of ctx when blocking. If opts.BlockingWait is false (for fail-fast
// RPCs), it should return an address it has notified via Notify(...) immediately
// instead of blocking.
//
// The function returns put which is called once the rpc has completed or failed.
// put can collect and report RPC stats to a remote load balancer.
//
// This function should only return the errors Balancer cannot recover by itself.
// gRPC internals will fail the RPC if an error is returned.
Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error)
// Notify returns a channel that is used by gRPC internals to watch the addresses
// gRPC needs to connect. The addresses might be from a name resolver or remote
// load balancer. gRPC internals will compare it with the existing connected
// addresses. If the address Balancer notified is not in the existing connected
// addresses, gRPC starts to connect the address. If an address in the existing
// connected addresses is not in the notification list, the corresponding connection
// is shutdown gracefully. Otherwise, there are no operations to take. Note that
// the Address slice must be the full list of the Addresses which should be connected.
// It is NOT delta.
Notify() <-chan []Address
// Close shuts down the balancer.
Close() error
}
// downErr implements net.Error. It is constructed by gRPC internals and passed to the down
// call of Balancer.
type downErr struct {
timeout bool
temporary bool
desc string
}
func (e downErr) Error() string { return e.desc }
func (e downErr) Timeout() bool { return e.timeout }
func (e downErr) Temporary() bool { return e.temporary }
func downErrorf(timeout, temporary bool, format string, a ...interface{}) downErr {
return downErr{
timeout: timeout,
temporary: temporary,
desc: fmt.Sprintf(format, a...),
}
}
// RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch
// the name resolution updates and updates the addresses available correspondingly.
func RoundRobin(r naming.Resolver) Balancer {
return &roundRobin{r: r}
}
type addrInfo struct {
addr Address
connected bool
}
type roundRobin struct {
r naming.Resolver
w naming.Watcher
addrs []*addrInfo // all the addresses the client should potentially connect
mu sync.Mutex
addrCh chan []Address // the channel to notify gRPC internals the list of addresses the client should connect to.
next int // index of the next address to return for Get()
waitCh chan struct{} // the channel to block when there is no connected address available
done bool // The Balancer is closed.
}
func (rr *roundRobin) watchAddrUpdates() error {
updates, err := rr.w.Next()
if err != nil {
grpclog.Printf("grpc: the naming watcher stops working due to %v.\n", err)
return err
}
rr.mu.Lock()
defer rr.mu.Unlock()
for _, update := range updates {
addr := Address{
Addr: update.Addr,
Metadata: update.Metadata,
}
switch update.Op {
case naming.Add:
var exist bool
for _, v := range rr.addrs {
if addr == v.addr {
exist = true
grpclog.Println("grpc: The name resolver wanted to add an existing address: ", addr)
break
}
}
if exist {
continue
}
rr.addrs = append(rr.addrs, &addrInfo{addr: addr})
case naming.Delete:
for i, v := range rr.addrs {
if addr == v.addr {
copy(rr.addrs[i:], rr.addrs[i+1:])
rr.addrs = rr.addrs[:len(rr.addrs)-1]
break
}
}
default:
grpclog.Println("Unknown update.Op ", update.Op)
}
}
// Make a copy of rr.addrs and write it onto rr.addrCh so that gRPC internals gets notified.
open := make([]Address, len(rr.addrs))
for i, v := range rr.addrs {
open[i] = v.addr
}
if rr.done {
return ErrClientConnClosing
}
rr.addrCh <- open
return nil
}
func (rr *roundRobin) Start(target string) error {
if rr.r == nil {
// If there is no name resolver installed, it is not needed to
// do name resolution. In this case, target is added into rr.addrs
// as the only address available and rr.addrCh stays nil.
rr.addrs = append(rr.addrs, &addrInfo{addr: Address{Addr: target}})
return nil
}
w, err := rr.r.Resolve(target)
if err != nil {
return err
}
rr.w = w
rr.addrCh = make(chan []Address)
go func() {
for {
if err := rr.watchAddrUpdates(); err != nil {
return
}
}
}()
return nil
}
// Up sets the connected state of addr and sends notification if there are pending
// Get() calls.
func (rr *roundRobin) Up(addr Address) func(error) {
rr.mu.Lock()
defer rr.mu.Unlock()
var cnt int
for _, a := range rr.addrs {
if a.addr == addr {
if a.connected {
return nil
}
a.connected = true
}
if a.connected {
cnt++
}
}
// addr is only one which is connected. Notify the Get() callers who are blocking.
if cnt == 1 && rr.waitCh != nil {
close(rr.waitCh)
rr.waitCh = nil
}
return func(err error) {
rr.down(addr, err)
}
}
// down unsets the connected state of addr.
func (rr *roundRobin) down(addr Address, err error) {
rr.mu.Lock()
defer rr.mu.Unlock()
for _, a := range rr.addrs {
if addr == a.addr {
a.connected = false
break
}
}
}
// Get returns the next addr in the rotation.
func (rr *roundRobin) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) {
var ch chan struct{}
rr.mu.Lock()
if rr.done {
rr.mu.Unlock()
err = ErrClientConnClosing
return
}
if len(rr.addrs) > 0 {
if rr.next >= len(rr.addrs) {
rr.next = 0
}
next := rr.next
for {
a := rr.addrs[next]
next = (next + 1) % len(rr.addrs)
if a.connected {
addr = a.addr
rr.next = next
rr.mu.Unlock()
return
}
if next == rr.next {
// Has iterated all the possible address but none is connected.
break
}
}
}
if !opts.BlockingWait {
if len(rr.addrs) == 0 {
rr.mu.Unlock()
err = fmt.Errorf("there is no address available")
return
}
// Returns the next addr on rr.addrs for failfast RPCs.
addr = rr.addrs[rr.next].addr
rr.next++
rr.mu.Unlock()
return
}
// Wait on rr.waitCh for non-failfast RPCs.
if rr.waitCh == nil {
ch = make(chan struct{})
rr.waitCh = ch
} else {
ch = rr.waitCh
}
rr.mu.Unlock()
for {
select {
case <-ctx.Done():
err = ctx.Err()
return
case <-ch:
rr.mu.Lock()
if rr.done {
rr.mu.Unlock()
err = ErrClientConnClosing
return
}
if len(rr.addrs) > 0 {
if rr.next >= len(rr.addrs) {
rr.next = 0
}
next := rr.next
for {
a := rr.addrs[next]
next = (next + 1) % len(rr.addrs)
if a.connected {
addr = a.addr
rr.next = next
rr.mu.Unlock()
return
}
if next == rr.next {
// Has iterated all the possible address but none is connected.
break
}
}
}
// The newly added addr got removed by Down() again.
if rr.waitCh == nil {
ch = make(chan struct{})
rr.waitCh = ch
} else {
ch = rr.waitCh
}
rr.mu.Unlock()
}
}
}
func (rr *roundRobin) Notify() <-chan []Address {
return rr.addrCh
}
func (rr *roundRobin) Close() error {
rr.mu.Lock()
defer rr.mu.Unlock()
rr.done = true
if rr.w != nil {
rr.w.Close()
}
if rr.waitCh != nil {
close(rr.waitCh)
rr.waitCh = nil
}
if rr.addrCh != nil {
close(rr.addrCh)
}
return nil
}
-322
View File
@@ -1,322 +0,0 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package grpc
import (
"fmt"
"math"
"sync"
"testing"
"time"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/naming"
)
type testWatcher struct {
// the channel to receives name resolution updates
update chan *naming.Update
// the side channel to get to know how many updates in a batch
side chan int
// the channel to notifiy update injector that the update reading is done
readDone chan int
}
func (w *testWatcher) Next() (updates []*naming.Update, err error) {
n := <-w.side
if n == 0 {
return nil, fmt.Errorf("w.side is closed")
}
for i := 0; i < n; i++ {
u := <-w.update
if u != nil {
updates = append(updates, u)
}
}
w.readDone <- 0
return
}
func (w *testWatcher) Close() {
}
// Inject naming resolution updates to the testWatcher.
func (w *testWatcher) inject(updates []*naming.Update) {
w.side <- len(updates)
for _, u := range updates {
w.update <- u
}
<-w.readDone
}
type testNameResolver struct {
w *testWatcher
addr string
}
func (r *testNameResolver) Resolve(target string) (naming.Watcher, error) {
r.w = &testWatcher{
update: make(chan *naming.Update, 1),
side: make(chan int, 1),
readDone: make(chan int),
}
r.w.side <- 1
r.w.update <- &naming.Update{
Op: naming.Add,
Addr: r.addr,
}
go func() {
<-r.w.readDone
}()
return r.w, nil
}
func startServers(t *testing.T, numServers int, maxStreams uint32) ([]*server, *testNameResolver) {
var servers []*server
for i := 0; i < numServers; i++ {
s := newTestServer()
servers = append(servers, s)
go s.start(t, 0, maxStreams)
s.wait(t, 2*time.Second)
}
// Point to server[0]
addr := "127.0.0.1:" + servers[0].port
return servers, &testNameResolver{
addr: addr,
}
}
func TestNameDiscovery(t *testing.T) {
// Start 2 servers on 2 ports.
numServers := 2
servers, r := startServers(t, numServers, math.MaxUint32)
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
if err != nil {
t.Fatalf("Failed to create ClientConn: %v", err)
}
req := "port"
var reply string
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err == nil || ErrorDesc(err) != servers[0].port {
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want %s", err, servers[0].port)
}
// Inject the name resolution change to remove servers[0] and add servers[1].
var updates []*naming.Update
updates = append(updates, &naming.Update{
Op: naming.Delete,
Addr: "127.0.0.1:" + servers[0].port,
})
updates = append(updates, &naming.Update{
Op: naming.Add,
Addr: "127.0.0.1:" + servers[1].port,
})
r.w.inject(updates)
// Loop until the rpcs in flight talks to servers[1].
for {
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
break
}
time.Sleep(10 * time.Millisecond)
}
cc.Close()
for i := 0; i < numServers; i++ {
servers[i].stop()
}
}
func TestEmptyAddrs(t *testing.T) {
servers, r := startServers(t, 1, math.MaxUint32)
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
if err != nil {
t.Fatalf("Failed to create ClientConn: %v", err)
}
var reply string
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, reply = %q, want %q, <nil>", err, reply, expectedResponse)
}
// Inject name resolution change to remove the server so that there is no address
// available after that.
u := &naming.Update{
Op: naming.Delete,
Addr: "127.0.0.1:" + servers[0].port,
}
r.w.inject([]*naming.Update{u})
// Loop until the above updates apply.
for {
time.Sleep(10 * time.Millisecond)
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc); err != nil {
break
}
}
cc.Close()
servers[0].stop()
}
func TestRoundRobin(t *testing.T) {
// Start 3 servers on 3 ports.
numServers := 3
servers, r := startServers(t, numServers, math.MaxUint32)
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
if err != nil {
t.Fatalf("Failed to create ClientConn: %v", err)
}
// Add servers[1] to the service discovery.
u := &naming.Update{
Op: naming.Add,
Addr: "127.0.0.1:" + servers[1].port,
}
r.w.inject([]*naming.Update{u})
req := "port"
var reply string
// Loop until servers[1] is up
for {
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[1].port {
break
}
time.Sleep(10 * time.Millisecond)
}
// Add server2[2] to the service discovery.
u = &naming.Update{
Op: naming.Add,
Addr: "127.0.0.1:" + servers[2].port,
}
r.w.inject([]*naming.Update{u})
// Loop until both servers[2] are up.
for {
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil && ErrorDesc(err) == servers[2].port {
break
}
time.Sleep(10 * time.Millisecond)
}
// Check the incoming RPCs served in a round-robin manner.
for i := 0; i < 10; i++ {
if err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err == nil || ErrorDesc(err) != servers[i%numServers].port {
t.Fatalf("Index %d: Invoke(_, _, _, _, _) = %v, want %s", i, err, servers[i%numServers].port)
}
}
cc.Close()
for i := 0; i < numServers; i++ {
servers[i].stop()
}
}
func TestCloseWithPendingRPC(t *testing.T) {
servers, r := startServers(t, 1, math.MaxUint32)
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
if err != nil {
t.Fatalf("Failed to create ClientConn: %v", err)
}
var reply string
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err != nil {
t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want %s", err, servers[0].port)
}
// Remove the server.
updates := []*naming.Update{&naming.Update{
Op: naming.Delete,
Addr: "127.0.0.1:" + servers[0].port,
}}
r.w.inject(updates)
// Loop until the above update applies.
for {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); Code(err) == codes.DeadlineExceeded {
break
}
time.Sleep(10 * time.Millisecond)
}
// Issue 2 RPCs which should be completed with error status once cc is closed.
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
var reply string
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err == nil {
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want not nil", err)
}
}()
go func() {
defer wg.Done()
var reply string
time.Sleep(5 * time.Millisecond)
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err == nil {
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want not nil", err)
}
}()
time.Sleep(5 * time.Millisecond)
cc.Close()
wg.Wait()
servers[0].stop()
}
func TestGetOnWaitChannel(t *testing.T) {
servers, r := startServers(t, 1, math.MaxUint32)
cc, err := Dial("foo.bar.com", WithBalancer(RoundRobin(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
if err != nil {
t.Fatalf("Failed to create ClientConn: %v", err)
}
// Remove all servers so that all upcoming RPCs will block on waitCh.
updates := []*naming.Update{&naming.Update{
Op: naming.Delete,
Addr: "127.0.0.1:" + servers[0].port,
}}
r.w.inject(updates)
for {
var reply string
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); Code(err) == codes.DeadlineExceeded {
break
}
time.Sleep(10 * time.Millisecond)
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
var reply string
if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc, FailFast(false)); err != nil {
t.Errorf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
}
}()
// Add a connected server to get the above RPC through.
updates = []*naming.Update{&naming.Update{
Op: naming.Add,
Addr: "127.0.0.1:" + servers[0].port,
}}
r.w.inject(updates)
// Wait until the above RPC succeeds.
wg.Wait()
cc.Close()
servers[0].stop()
}

Some files were not shown because too many files have changed in this diff Show More