From ed73f97bd3a1a53586a15846bad4800e2e00cf18 Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Fri, 4 Oct 2019 22:56:46 -0400 Subject: [PATCH] add basic client; enable node level routing Signed-off-by: Evan Hazlett --- api/v1/heimdall.pb.go | 540 +++++++++++++++++++++++++++++++++++++++--- api/v1/heimdall.proto | 36 ++- client/node.go | 39 +++ client/peer.go | 39 +++ client/route.go | 64 +++++ cmd/hctl/main.go | 10 +- cmd/hctl/nodes.go | 65 +++++ cmd/hctl/peers.go | 63 +++++ cmd/hctl/routes.go | 111 +++++++++ go.mod | 5 +- go.sum | 21 ++ server/node.go | 45 ++++ server/peer.go | 261 ++++++++++++-------- server/route.go | 113 +++++++++ server/server.go | 17 +- server/wireguard.go | 6 +- 16 files changed, 1292 insertions(+), 143 deletions(-) create mode 100644 client/node.go create mode 100644 client/peer.go create mode 100644 client/route.go create mode 100644 cmd/hctl/nodes.go create mode 100644 cmd/hctl/peers.go create mode 100644 cmd/hctl/routes.go create mode 100644 server/route.go diff --git a/api/v1/heimdall.pb.go b/api/v1/heimdall.pb.go index 859936a..71cd58d 100644 --- a/api/v1/heimdall.pb.go +++ b/api/v1/heimdall.pb.go @@ -8,6 +8,7 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" 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" @@ -409,6 +410,272 @@ func (m *Peer) GetEndpoint() string { return "" } +type PeersRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PeersRequest) Reset() { *m = PeersRequest{} } +func (m *PeersRequest) String() string { return proto.CompactTextString(m) } +func (*PeersRequest) ProtoMessage() {} +func (*PeersRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{8} +} +func (m *PeersRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PeersRequest.Unmarshal(m, b) +} +func (m *PeersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PeersRequest.Marshal(b, m, deterministic) +} +func (m *PeersRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeersRequest.Merge(m, src) +} +func (m *PeersRequest) XXX_Size() int { + return xxx_messageInfo_PeersRequest.Size(m) +} +func (m *PeersRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PeersRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PeersRequest proto.InternalMessageInfo + +type PeersResponse struct { + Peers []*Peer `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PeersResponse) Reset() { *m = PeersResponse{} } +func (m *PeersResponse) String() string { return proto.CompactTextString(m) } +func (*PeersResponse) ProtoMessage() {} +func (*PeersResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{9} +} +func (m *PeersResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PeersResponse.Unmarshal(m, b) +} +func (m *PeersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PeersResponse.Marshal(b, m, deterministic) +} +func (m *PeersResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeersResponse.Merge(m, src) +} +func (m *PeersResponse) XXX_Size() int { + return xxx_messageInfo_PeersResponse.Size(m) +} +func (m *PeersResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PeersResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_PeersResponse proto.InternalMessageInfo + +func (m *PeersResponse) GetPeers() []*Peer { + if m != nil { + return m.Peers + } + return nil +} + +type Route struct { + NodeID string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Route) Reset() { *m = Route{} } +func (m *Route) String() string { return proto.CompactTextString(m) } +func (*Route) ProtoMessage() {} +func (*Route) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{10} +} +func (m *Route) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Route.Unmarshal(m, b) +} +func (m *Route) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Route.Marshal(b, m, deterministic) +} +func (m *Route) XXX_Merge(src proto.Message) { + xxx_messageInfo_Route.Merge(m, src) +} +func (m *Route) XXX_Size() int { + return xxx_messageInfo_Route.Size(m) +} +func (m *Route) XXX_DiscardUnknown() { + xxx_messageInfo_Route.DiscardUnknown(m) +} + +var xxx_messageInfo_Route proto.InternalMessageInfo + +func (m *Route) GetNodeID() string { + if m != nil { + return m.NodeID + } + return "" +} + +func (m *Route) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +type CreateRouteRequest struct { + NodeID string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateRouteRequest) Reset() { *m = CreateRouteRequest{} } +func (m *CreateRouteRequest) String() string { return proto.CompactTextString(m) } +func (*CreateRouteRequest) ProtoMessage() {} +func (*CreateRouteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{11} +} +func (m *CreateRouteRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateRouteRequest.Unmarshal(m, b) +} +func (m *CreateRouteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateRouteRequest.Marshal(b, m, deterministic) +} +func (m *CreateRouteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateRouteRequest.Merge(m, src) +} +func (m *CreateRouteRequest) XXX_Size() int { + return xxx_messageInfo_CreateRouteRequest.Size(m) +} +func (m *CreateRouteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateRouteRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateRouteRequest proto.InternalMessageInfo + +func (m *CreateRouteRequest) GetNodeID() string { + if m != nil { + return m.NodeID + } + return "" +} + +func (m *CreateRouteRequest) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +type DeleteRouteRequest struct { + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteRouteRequest) Reset() { *m = DeleteRouteRequest{} } +func (m *DeleteRouteRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteRouteRequest) ProtoMessage() {} +func (*DeleteRouteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{12} +} +func (m *DeleteRouteRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteRouteRequest.Unmarshal(m, b) +} +func (m *DeleteRouteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteRouteRequest.Marshal(b, m, deterministic) +} +func (m *DeleteRouteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteRouteRequest.Merge(m, src) +} +func (m *DeleteRouteRequest) XXX_Size() int { + return xxx_messageInfo_DeleteRouteRequest.Size(m) +} +func (m *DeleteRouteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteRouteRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteRouteRequest proto.InternalMessageInfo + +func (m *DeleteRouteRequest) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +type RoutesRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoutesRequest) Reset() { *m = RoutesRequest{} } +func (m *RoutesRequest) String() string { return proto.CompactTextString(m) } +func (*RoutesRequest) ProtoMessage() {} +func (*RoutesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{13} +} +func (m *RoutesRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RoutesRequest.Unmarshal(m, b) +} +func (m *RoutesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RoutesRequest.Marshal(b, m, deterministic) +} +func (m *RoutesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutesRequest.Merge(m, src) +} +func (m *RoutesRequest) XXX_Size() int { + return xxx_messageInfo_RoutesRequest.Size(m) +} +func (m *RoutesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RoutesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutesRequest proto.InternalMessageInfo + +type RoutesResponse struct { + Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoutesResponse) Reset() { *m = RoutesResponse{} } +func (m *RoutesResponse) String() string { return proto.CompactTextString(m) } +func (*RoutesResponse) ProtoMessage() {} +func (*RoutesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{14} +} +func (m *RoutesResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RoutesResponse.Unmarshal(m, b) +} +func (m *RoutesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RoutesResponse.Marshal(b, m, deterministic) +} +func (m *RoutesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutesResponse.Merge(m, src) +} +func (m *RoutesResponse) XXX_Size() int { + return xxx_messageInfo_RoutesResponse.Size(m) +} +func (m *RoutesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RoutesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutesResponse proto.InternalMessageInfo + +func (m *RoutesResponse) GetRoutes() []*Route { + if m != nil { + return m.Routes + } + return nil +} + func init() { proto.RegisterType((*Master)(nil), "io.stellarproject.heimdall.api.v1.Master") proto.RegisterType((*ConnectRequest)(nil), "io.stellarproject.heimdall.api.v1.ConnectRequest") @@ -418,6 +685,13 @@ func init() { proto.RegisterType((*NodesRequest)(nil), "io.stellarproject.heimdall.api.v1.NodesRequest") proto.RegisterType((*NodesResponse)(nil), "io.stellarproject.heimdall.api.v1.NodesResponse") proto.RegisterType((*Peer)(nil), "io.stellarproject.heimdall.api.v1.Peer") + proto.RegisterType((*PeersRequest)(nil), "io.stellarproject.heimdall.api.v1.PeersRequest") + proto.RegisterType((*PeersResponse)(nil), "io.stellarproject.heimdall.api.v1.PeersResponse") + proto.RegisterType((*Route)(nil), "io.stellarproject.heimdall.api.v1.Route") + proto.RegisterType((*CreateRouteRequest)(nil), "io.stellarproject.heimdall.api.v1.CreateRouteRequest") + proto.RegisterType((*DeleteRouteRequest)(nil), "io.stellarproject.heimdall.api.v1.DeleteRouteRequest") + proto.RegisterType((*RoutesRequest)(nil), "io.stellarproject.heimdall.api.v1.RoutesRequest") + proto.RegisterType((*RoutesResponse)(nil), "io.stellarproject.heimdall.api.v1.RoutesResponse") } func init() { @@ -425,42 +699,56 @@ func init() { } var fileDescriptor_b6184fc395da86b1 = []byte{ - // 552 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6a, 0xdb, 0x4c, - 0x14, 0x45, 0xb6, 0xe3, 0xd8, 0x57, 0x4e, 0x02, 0xc3, 0xc7, 0x87, 0x08, 0x14, 0x39, 0xda, 0xd4, - 0x29, 0x41, 0xc2, 0xea, 0xa6, 0x50, 0xba, 0x88, 0x53, 0x48, 0x45, 0xda, 0xa0, 0x0e, 0xcd, 0xa6, - 0x1b, 0x33, 0x91, 0x06, 0x67, 0x1a, 0x45, 0x33, 0x9d, 0x19, 0x3b, 0x08, 0x0a, 0x7d, 0xb3, 0x3e, - 0x46, 0x97, 0x5a, 0xe8, 0x49, 0x8a, 0xa4, 0xb1, 0x49, 0x16, 0x69, 0x5d, 0xe8, 0x6e, 0xee, 0xd1, - 0x39, 0x57, 0xe7, 0x9e, 0xf9, 0x81, 0x57, 0x0b, 0xa6, 0x6f, 0x96, 0xd7, 0x7e, 0xc2, 0xef, 0x02, - 0xa5, 0x69, 0x96, 0x11, 0x29, 0x24, 0xff, 0x42, 0x13, 0x1d, 0xdc, 0x50, 0x76, 0x97, 0x92, 0x2c, - 0x0b, 0x88, 0x60, 0xc1, 0x6a, 0xba, 0xa9, 0x7d, 0x21, 0xb9, 0xe6, 0xe8, 0x88, 0x71, 0xff, 0xb1, - 0xc2, 0xdf, 0x30, 0x88, 0x60, 0xfe, 0x6a, 0x7a, 0xf8, 0xdf, 0x82, 0x2f, 0x78, 0xc3, 0x0e, 0xea, - 0x55, 0x2b, 0xf4, 0xbe, 0x43, 0xff, 0x03, 0x51, 0x9a, 0x4a, 0xf4, 0x3f, 0x74, 0x58, 0xea, 0x58, - 0x63, 0x6b, 0x32, 0x9c, 0xf5, 0xab, 0xd2, 0xed, 0x44, 0x6f, 0x71, 0x87, 0xa5, 0x28, 0x84, 0xd1, - 0x42, 0x8a, 0x64, 0x4e, 0xd2, 0x54, 0x52, 0xa5, 0x9c, 0x4e, 0xc3, 0x38, 0xa8, 0x4a, 0xd7, 0x3e, - 0xc7, 0xf1, 0xd9, 0x69, 0x0b, 0x63, 0xbb, 0x26, 0x99, 0x02, 0x1d, 0xc3, 0x50, 0xd2, 0x94, 0xa9, - 0xf9, 0x52, 0x66, 0x4e, 0xb7, 0x11, 0x8c, 0xaa, 0xd2, 0x1d, 0xe0, 0x1a, 0xbc, 0xc2, 0xef, 0xf1, - 0xa0, 0xf9, 0x7c, 0x25, 0x33, 0x2f, 0x82, 0xfd, 0x33, 0x9e, 0xe7, 0x34, 0xd1, 0x98, 0x7e, 0x5d, - 0x52, 0xa5, 0x9f, 0x34, 0xe2, 0x82, 0x9d, 0x64, 0xcb, 0xda, 0xeb, 0xfc, 0x96, 0x16, 0xad, 0x0f, - 0x0c, 0x06, 0xba, 0xa0, 0x85, 0xf7, 0x09, 0x0e, 0x36, 0xad, 0x94, 0xe0, 0xb9, 0xa2, 0xe8, 0x14, - 0xfa, 0x77, 0xcd, 0x78, 0x4d, 0x3f, 0x3b, 0x3c, 0xf6, 0xff, 0x18, 0x94, 0xdf, 0xe6, 0x81, 0x8d, - 0xd0, 0x8b, 0x60, 0xf7, 0x82, 0x16, 0x31, 0x61, 0xb2, 0x76, 0x20, 0x24, 0x5b, 0x11, 0x4d, 0x1b, - 0x07, 0x56, 0xeb, 0xc0, 0x40, 0x17, 0xb4, 0x40, 0xcf, 0x00, 0xc4, 0xf2, 0x3a, 0x63, 0xc9, 0x03, - 0x87, 0xc3, 0x16, 0xa9, 0x0d, 0xfe, 0xb4, 0xa0, 0x77, 0xc9, 0x53, 0xfa, 0xe4, 0x88, 0x08, 0x7a, - 0x75, 0xcc, 0x46, 0xd9, 0xac, 0xd1, 0x47, 0xd8, 0xbd, 0xa5, 0x85, 0x20, 0x4c, 0x36, 0x49, 0xda, - 0xe1, 0x8b, 0x2d, 0x66, 0x30, 0x8e, 0x67, 0x76, 0x55, 0xba, 0x6b, 0xfb, 0x78, 0xdd, 0x07, 0x9d, - 0x00, 0x2c, 0x88, 0xa6, 0xf7, 0xa4, 0x98, 0x33, 0xe1, 0xf4, 0x1a, 0x1b, 0x7b, 0x55, 0xe9, 0x0e, - 0xcf, 0x5b, 0x34, 0x8a, 0xf1, 0xd0, 0x10, 0x22, 0x81, 0x8e, 0x60, 0xb4, 0x66, 0x0b, 0x2e, 0xb5, - 0xb3, 0x33, 0xb6, 0x26, 0x3d, 0x6c, 0x1b, 0x2c, 0xe6, 0x52, 0x7b, 0xfb, 0x30, 0xaa, 0xe7, 0x52, - 0x66, 0x0b, 0xbd, 0x4b, 0xd8, 0x33, 0xb5, 0xd9, 0x87, 0x37, 0xb0, 0x93, 0xd7, 0x80, 0x63, 0x8d, - 0xbb, 0x13, 0x3b, 0x7c, 0xbe, 0xc5, 0x08, 0x75, 0x03, 0xdc, 0xaa, 0xbc, 0x1f, 0x16, 0xf4, 0x62, - 0xfa, 0x9b, 0x43, 0xfa, 0x20, 0xa4, 0xce, 0x3f, 0x0a, 0x29, 0x00, 0x9b, 0x64, 0x19, 0xbf, 0xa7, - 0xe9, 0x9c, 0x09, 0xe5, 0x74, 0xc7, 0xdd, 0xc9, 0x70, 0xb6, 0x5f, 0x95, 0x2e, 0x9c, 0xb6, 0x70, - 0x14, 0x2b, 0x0c, 0x86, 0x12, 0x09, 0x85, 0x0e, 0x61, 0x40, 0xf3, 0x54, 0x70, 0x96, 0xeb, 0x36, - 0x53, 0xbc, 0xa9, 0xc3, 0x6f, 0x30, 0x78, 0x67, 0xfe, 0x8e, 0x04, 0xec, 0x9a, 0x63, 0x8a, 0xa6, - 0x5b, 0xb8, 0x7c, 0x7c, 0x3b, 0x0e, 0xc3, 0xbf, 0x91, 0xb4, 0xe9, 0xcf, 0xfc, 0xcf, 0x27, 0x5b, - 0xbf, 0x2c, 0xaf, 0x57, 0xd3, 0xeb, 0x7e, 0xf3, 0x36, 0xbc, 0xfc, 0x15, 0x00, 0x00, 0xff, 0xff, - 0x5f, 0xf4, 0xa8, 0x6a, 0x90, 0x04, 0x00, 0x00, + // 770 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x5d, 0x6b, 0xe3, 0x46, + 0x14, 0x45, 0xfe, 0x90, 0xed, 0x2b, 0xc7, 0x81, 0xa1, 0x04, 0xe1, 0x52, 0xe4, 0xa8, 0x0f, 0x75, + 0x4a, 0x90, 0x62, 0x97, 0x42, 0xa1, 0x14, 0x1a, 0x27, 0x6d, 0x2a, 0xd2, 0x06, 0x77, 0xda, 0xbc, + 0x94, 0x82, 0x91, 0xad, 0xa9, 0xa3, 0x44, 0xf6, 0x4c, 0x47, 0x63, 0x07, 0x3f, 0xf5, 0x9f, 0xf5, + 0x67, 0xec, 0xa3, 0x1f, 0xfc, 0x47, 0x76, 0x99, 0xd1, 0xc8, 0x6b, 0x6f, 0xc8, 0xae, 0xc2, 0xee, + 0x9b, 0xee, 0x99, 0x7b, 0xcf, 0x9c, 0x7b, 0xe6, 0x4b, 0xf0, 0xdd, 0x34, 0x16, 0x77, 0x8b, 0xb1, + 0x37, 0xa1, 0x33, 0x3f, 0x15, 0x24, 0x49, 0x42, 0xce, 0x38, 0xbd, 0x27, 0x13, 0xe1, 0xdf, 0x91, + 0x78, 0x16, 0x85, 0x49, 0xe2, 0x87, 0x2c, 0xf6, 0x97, 0xbd, 0x6d, 0xec, 0x31, 0x4e, 0x05, 0x45, + 0xc7, 0x31, 0xf5, 0xf6, 0x2b, 0xbc, 0x6d, 0x46, 0xc8, 0x62, 0x6f, 0xd9, 0x6b, 0x7f, 0x36, 0xa5, + 0x53, 0xaa, 0xb2, 0x7d, 0xf9, 0x95, 0x15, 0xb6, 0x3f, 0x9f, 0x52, 0x3a, 0x4d, 0x88, 0xaf, 0xa2, + 0xf1, 0xe2, 0x1f, 0x9f, 0xcc, 0x98, 0x58, 0x65, 0x83, 0xee, 0x7f, 0x60, 0xfe, 0x16, 0xa6, 0x82, + 0x70, 0x74, 0x04, 0xa5, 0x38, 0xb2, 0x8d, 0x8e, 0xd1, 0x6d, 0x0c, 0xcc, 0xcd, 0xda, 0x29, 0x05, + 0x97, 0xb8, 0x14, 0x47, 0xa8, 0x0f, 0xcd, 0x29, 0x67, 0x93, 0x51, 0x18, 0x45, 0x9c, 0xa4, 0xa9, + 0x5d, 0x52, 0x19, 0x87, 0x9b, 0xb5, 0x63, 0x5d, 0xe1, 0xe1, 0xc5, 0x79, 0x06, 0x63, 0x4b, 0x26, + 0xe9, 0x00, 0x9d, 0x40, 0x83, 0x93, 0x28, 0x4e, 0x47, 0x0b, 0x9e, 0xd8, 0x65, 0x55, 0xd0, 0xdc, + 0xac, 0x9d, 0x3a, 0x96, 0xe0, 0x2d, 0xfe, 0x15, 0xd7, 0xd5, 0xf0, 0x2d, 0x4f, 0xdc, 0x00, 0x5a, + 0x17, 0x74, 0x3e, 0x27, 0x13, 0x81, 0xc9, 0xbf, 0x0b, 0x92, 0x8a, 0x67, 0x85, 0x38, 0x60, 0x4d, + 0x92, 0x85, 0xd4, 0x3a, 0x7a, 0x20, 0xab, 0x4c, 0x07, 0x06, 0x0d, 0x5d, 0x93, 0x95, 0xfb, 0x27, + 0x1c, 0x6e, 0xa9, 0x52, 0x46, 0xe7, 0x29, 0x41, 0xe7, 0x60, 0xce, 0x54, 0x7b, 0x8a, 0xcf, 0xea, + 0x9f, 0x78, 0x1f, 0x74, 0xd1, 0xcb, 0xfc, 0xc0, 0xba, 0xd0, 0x0d, 0xa0, 0x76, 0x4d, 0x56, 0xc3, + 0x30, 0xe6, 0x52, 0x01, 0xe3, 0xf1, 0x32, 0x14, 0x44, 0x29, 0x30, 0x32, 0x05, 0x1a, 0xba, 0x26, + 0x2b, 0xf4, 0x05, 0x00, 0x5b, 0x8c, 0x93, 0x78, 0xb2, 0xa3, 0xb0, 0x91, 0x21, 0x52, 0xe0, 0x2b, + 0x03, 0x2a, 0x37, 0x34, 0x22, 0xcf, 0xb6, 0x88, 0xa0, 0x22, 0x6d, 0xd6, 0x95, 0xea, 0x1b, 0xfd, + 0x0e, 0xb5, 0x07, 0xb2, 0x62, 0x61, 0xcc, 0x95, 0x93, 0x56, 0xff, 0xeb, 0x02, 0x3d, 0x68, 0xc5, + 0x03, 0x6b, 0xb3, 0x76, 0x72, 0xf9, 0x38, 0xe7, 0x41, 0xa7, 0x00, 0xd3, 0x50, 0x90, 0xc7, 0x70, + 0x35, 0x8a, 0x99, 0x5d, 0x51, 0x32, 0x0e, 0x36, 0x6b, 0xa7, 0x71, 0x95, 0xa1, 0xc1, 0x10, 0x37, + 0x74, 0x42, 0xc0, 0xd0, 0x31, 0x34, 0xf3, 0x6c, 0x46, 0xb9, 0xb0, 0xab, 0x1d, 0xa3, 0x5b, 0xc1, + 0x96, 0xc6, 0x86, 0x94, 0x0b, 0xb7, 0x05, 0x4d, 0xd9, 0x57, 0xaa, 0x97, 0xd0, 0xbd, 0x81, 0x03, + 0x1d, 0xeb, 0x75, 0xf8, 0x01, 0xaa, 0x73, 0x09, 0xd8, 0x46, 0xa7, 0xdc, 0xb5, 0xfa, 0x5f, 0x15, + 0x68, 0x41, 0x12, 0xe0, 0xac, 0xca, 0xfd, 0xdf, 0x80, 0xca, 0x90, 0xbc, 0x67, 0x93, 0xee, 0x98, + 0x54, 0xfa, 0x44, 0x26, 0xf9, 0x60, 0x85, 0x49, 0x42, 0x1f, 0x49, 0x34, 0x8a, 0x59, 0x6a, 0x97, + 0x3b, 0xe5, 0x6e, 0x63, 0xd0, 0xda, 0xac, 0x1d, 0x38, 0xcf, 0xe0, 0x60, 0x98, 0x62, 0xd0, 0x29, + 0x01, 0x4b, 0x51, 0x1b, 0xea, 0x64, 0x1e, 0x31, 0x1a, 0xcf, 0x45, 0xe6, 0x29, 0xde, 0xc6, 0xd2, + 0x20, 0xa9, 0x7f, 0xd7, 0x20, 0x1d, 0xbf, 0x35, 0x88, 0x49, 0xe0, 0x05, 0x06, 0x49, 0x02, 0x9c, + 0x55, 0xb9, 0x3f, 0x43, 0x15, 0xd3, 0x85, 0x20, 0xe8, 0x4b, 0xa8, 0x49, 0xcb, 0x46, 0x5b, 0x97, + 0x60, 0xb3, 0x76, 0x4c, 0xe9, 0x65, 0x70, 0x89, 0x4d, 0x39, 0x14, 0x44, 0xc8, 0x86, 0xda, 0x9c, + 0x88, 0x47, 0xca, 0x1f, 0xf4, 0x4e, 0xcb, 0x43, 0xf7, 0x0f, 0x40, 0x17, 0x9c, 0x84, 0x82, 0x28, + 0xb6, 0xfc, 0x44, 0x7e, 0x24, 0xa9, 0x07, 0xe8, 0x92, 0x24, 0xe4, 0x1d, 0xd2, 0x9d, 0x7c, 0x63, + 0x3f, 0xff, 0x10, 0x0e, 0x54, 0xe6, 0xd6, 0x2d, 0x0c, 0xad, 0x1c, 0xd0, 0x76, 0xfd, 0x08, 0x26, + 0x57, 0x88, 0xf6, 0xab, 0x5b, 0xc0, 0xaf, 0x6c, 0x76, 0x5d, 0xd7, 0x7f, 0x5d, 0x81, 0xfa, 0x2f, + 0x3a, 0x03, 0x31, 0xa8, 0xe9, 0x9b, 0x03, 0xf5, 0x0a, 0x30, 0xed, 0x5f, 0x58, 0xed, 0xfe, 0x4b, + 0x4a, 0x74, 0x03, 0x33, 0x30, 0xb3, 0x96, 0xd0, 0x59, 0x51, 0xe9, 0xb9, 0x1d, 0xed, 0xde, 0x0b, + 0x2a, 0xf4, 0x74, 0x7f, 0x83, 0xb5, 0xb3, 0xae, 0xe8, 0xdb, 0x22, 0x8a, 0x9f, 0xec, 0x83, 0xf6, + 0x91, 0x97, 0x3d, 0x25, 0x5e, 0xfe, 0x94, 0x78, 0x3f, 0xc9, 0xa7, 0x44, 0xb2, 0xef, 0x2c, 0x70, + 0x21, 0xf6, 0xa7, 0x1b, 0xe2, 0x59, 0xf6, 0x7b, 0xa8, 0xaa, 0xcb, 0x04, 0xf9, 0x05, 0x6f, 0x8d, + 0xad, 0x51, 0x67, 0xc5, 0x0b, 0xb4, 0x4f, 0xf7, 0x50, 0x55, 0xe7, 0xb2, 0xd0, 0x5c, 0xbb, 0x27, + 0xba, 0xd0, 0x5c, 0x7b, 0x47, 0x7e, 0xe0, 0xfd, 0x75, 0x5a, 0xf8, 0x67, 0xe0, 0xfb, 0x65, 0x6f, + 0x6c, 0x2a, 0x5f, 0xbe, 0x79, 0x13, 0x00, 0x00, 0xff, 0xff, 0x30, 0x53, 0x36, 0x35, 0x43, 0x08, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -476,6 +764,11 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type HeimdallClient interface { Connect(ctx context.Context, in *ConnectRequest, opts ...grpc.CallOption) (*ConnectResponse, error) + Routes(ctx context.Context, in *RoutesRequest, opts ...grpc.CallOption) (*RoutesResponse, error) + CreateRoute(ctx context.Context, in *CreateRouteRequest, opts ...grpc.CallOption) (*types.Empty, error) + DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*types.Empty, error) + Nodes(ctx context.Context, in *NodesRequest, opts ...grpc.CallOption) (*NodesResponse, error) + Peers(ctx context.Context, in *PeersRequest, opts ...grpc.CallOption) (*PeersResponse, error) } type heimdallClient struct { @@ -495,9 +788,59 @@ func (c *heimdallClient) Connect(ctx context.Context, in *ConnectRequest, opts . return out, nil } +func (c *heimdallClient) Routes(ctx context.Context, in *RoutesRequest, opts ...grpc.CallOption) (*RoutesResponse, error) { + out := new(RoutesResponse) + err := c.cc.Invoke(ctx, "/io.stellarproject.heimdall.api.v1.Heimdall/Routes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *heimdallClient) CreateRoute(ctx context.Context, in *CreateRouteRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/io.stellarproject.heimdall.api.v1.Heimdall/CreateRoute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *heimdallClient) DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/io.stellarproject.heimdall.api.v1.Heimdall/DeleteRoute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *heimdallClient) Nodes(ctx context.Context, in *NodesRequest, opts ...grpc.CallOption) (*NodesResponse, error) { + out := new(NodesResponse) + err := c.cc.Invoke(ctx, "/io.stellarproject.heimdall.api.v1.Heimdall/Nodes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *heimdallClient) Peers(ctx context.Context, in *PeersRequest, opts ...grpc.CallOption) (*PeersResponse, error) { + out := new(PeersResponse) + err := c.cc.Invoke(ctx, "/io.stellarproject.heimdall.api.v1.Heimdall/Peers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // HeimdallServer is the server API for Heimdall service. type HeimdallServer interface { Connect(context.Context, *ConnectRequest) (*ConnectResponse, error) + Routes(context.Context, *RoutesRequest) (*RoutesResponse, error) + CreateRoute(context.Context, *CreateRouteRequest) (*types.Empty, error) + DeleteRoute(context.Context, *DeleteRouteRequest) (*types.Empty, error) + Nodes(context.Context, *NodesRequest) (*NodesResponse, error) + Peers(context.Context, *PeersRequest) (*PeersResponse, error) } // UnimplementedHeimdallServer can be embedded to have forward compatible implementations. @@ -507,6 +850,21 @@ type UnimplementedHeimdallServer struct { func (*UnimplementedHeimdallServer) Connect(ctx context.Context, req *ConnectRequest) (*ConnectResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Connect not implemented") } +func (*UnimplementedHeimdallServer) Routes(ctx context.Context, req *RoutesRequest) (*RoutesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Routes not implemented") +} +func (*UnimplementedHeimdallServer) CreateRoute(ctx context.Context, req *CreateRouteRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateRoute not implemented") +} +func (*UnimplementedHeimdallServer) DeleteRoute(ctx context.Context, req *DeleteRouteRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteRoute not implemented") +} +func (*UnimplementedHeimdallServer) Nodes(ctx context.Context, req *NodesRequest) (*NodesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Nodes not implemented") +} +func (*UnimplementedHeimdallServer) Peers(ctx context.Context, req *PeersRequest) (*PeersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Peers not implemented") +} func RegisterHeimdallServer(s *grpc.Server, srv HeimdallServer) { s.RegisterService(&_Heimdall_serviceDesc, srv) @@ -530,6 +888,96 @@ func _Heimdall_Connect_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Heimdall_Routes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RoutesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeimdallServer).Routes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/io.stellarproject.heimdall.api.v1.Heimdall/Routes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeimdallServer).Routes(ctx, req.(*RoutesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Heimdall_CreateRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateRouteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeimdallServer).CreateRoute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/io.stellarproject.heimdall.api.v1.Heimdall/CreateRoute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeimdallServer).CreateRoute(ctx, req.(*CreateRouteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Heimdall_DeleteRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRouteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeimdallServer).DeleteRoute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/io.stellarproject.heimdall.api.v1.Heimdall/DeleteRoute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeimdallServer).DeleteRoute(ctx, req.(*DeleteRouteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Heimdall_Nodes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NodesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeimdallServer).Nodes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/io.stellarproject.heimdall.api.v1.Heimdall/Nodes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeimdallServer).Nodes(ctx, req.(*NodesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Heimdall_Peers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PeersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeimdallServer).Peers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/io.stellarproject.heimdall.api.v1.Heimdall/Peers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeimdallServer).Peers(ctx, req.(*PeersRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Heimdall_serviceDesc = grpc.ServiceDesc{ ServiceName: "io.stellarproject.heimdall.api.v1.Heimdall", HandlerType: (*HeimdallServer)(nil), @@ -538,6 +986,26 @@ var _Heimdall_serviceDesc = grpc.ServiceDesc{ MethodName: "Connect", Handler: _Heimdall_Connect_Handler, }, + { + MethodName: "Routes", + Handler: _Heimdall_Routes_Handler, + }, + { + MethodName: "CreateRoute", + Handler: _Heimdall_CreateRoute_Handler, + }, + { + MethodName: "DeleteRoute", + Handler: _Heimdall_DeleteRoute_Handler, + }, + { + MethodName: "Nodes", + Handler: _Heimdall_Nodes_Handler, + }, + { + MethodName: "Peers", + Handler: _Heimdall_Peers_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "github.com/stellarproject/heimdall/api/v1/heimdall.proto", diff --git a/api/v1/heimdall.proto b/api/v1/heimdall.proto index 51aca5a..b14408e 100644 --- a/api/v1/heimdall.proto +++ b/api/v1/heimdall.proto @@ -3,15 +3,17 @@ syntax = "proto3"; package io.stellarproject.heimdall.api.v1; import "gogoproto/gogo.proto"; -//import "google/protobuf/empty.proto"; -//import "google/protobuf/any.proto"; +import "google/protobuf/empty.proto"; option go_package = "github.com/stellarproject/heimdall/api/v1;v1"; service Heimdall { rpc Connect(ConnectRequest) returns (ConnectResponse); - //rpc Nodes(NodesRequest) returns (NodesResponse); - //rpc Peers(PeersRequest) returns (PeersResponse); + rpc Routes(RoutesRequest) returns (RoutesResponse); + rpc CreateRoute(CreateRouteRequest) returns (google.protobuf.Empty); + rpc DeleteRoute(DeleteRouteRequest) returns (google.protobuf.Empty); + rpc Nodes(NodesRequest) returns (NodesResponse); + rpc Peers(PeersRequest) returns (PeersResponse); } message Master { @@ -54,3 +56,29 @@ message Peer { repeated string allowed_ips = 3 [(gogoproto.customname) = "AllowedIPs"]; string endpoint = 4; } + +message PeersRequest {} + +message PeersResponse { + repeated Peer peers = 1; +} + +message Route { + string node_id = 1 [(gogoproto.customname) = "NodeID"]; + string network = 2; +} + +message CreateRouteRequest { + string node_id = 1 [(gogoproto.customname) = "NodeID"]; + string network = 2; +} + +message DeleteRouteRequest { + string network = 1; +} + +message RoutesRequest {} + +message RoutesResponse { + repeated Route routes = 1; +} diff --git a/client/node.go b/client/node.go new file mode 100644 index 0000000..88b70b0 --- /dev/null +++ b/client/node.go @@ -0,0 +1,39 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "context" + + v1 "github.com/stellarproject/heimdall/api/v1" +) + +// Nodes returns the known nodes +func (c *Client) Nodes() ([]*v1.Node, error) { + ctx := context.Background() + resp, err := c.heimdallClient.Nodes(ctx, &v1.NodesRequest{}) + if err != nil { + return nil, err + } + + return resp.Nodes, nil +} diff --git a/client/peer.go b/client/peer.go new file mode 100644 index 0000000..d71518e --- /dev/null +++ b/client/peer.go @@ -0,0 +1,39 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "context" + + v1 "github.com/stellarproject/heimdall/api/v1" +) + +// Peers returns the known peers +func (c *Client) Peers() ([]*v1.Peer, error) { + ctx := context.Background() + resp, err := c.heimdallClient.Peers(ctx, &v1.PeersRequest{}) + if err != nil { + return nil, err + } + + return resp.Peers, nil +} diff --git a/client/route.go b/client/route.go new file mode 100644 index 0000000..a338ac2 --- /dev/null +++ b/client/route.go @@ -0,0 +1,64 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "context" + + v1 "github.com/stellarproject/heimdall/api/v1" +) + +// Routes returns the known routes +func (c *Client) Routes() ([]*v1.Route, error) { + ctx := context.Background() + resp, err := c.heimdallClient.Routes(ctx, &v1.RoutesRequest{}) + if err != nil { + return nil, err + } + + return resp.Routes, nil +} + +// CreateRoute creates a new route via the specified node ID +func (c *Client) CreateRoute(nodeID, network string) error { + ctx := context.Background() + if _, err := c.heimdallClient.CreateRoute(ctx, &v1.CreateRouteRequest{ + NodeID: nodeID, + Network: network, + }); err != nil { + return err + } + + return nil +} + +// DeleteRoute deletes a route +func (c *Client) DeleteRoute(network string) error { + ctx := context.Background() + if _, err := c.heimdallClient.DeleteRoute(ctx, &v1.DeleteRouteRequest{ + Network: network, + }); err != nil { + return err + } + + return nil +} diff --git a/cmd/hctl/main.go b/cmd/hctl/main.go index ac86cb7..ebcb348 100644 --- a/cmd/hctl/main.go +++ b/cmd/hctl/main.go @@ -35,7 +35,7 @@ import ( func main() { app := cli.NewApp() - app.Name = "actl" + app.Name = "hctl" app.Version = version.BuildVersion() app.Author = "@stellarproject" app.Email = "" @@ -49,7 +49,7 @@ func main() { Name: "addr, a", Usage: "heimdall grpc address", Value: "tcp://127.0.0.1:9000", - EnvVar: "ATLAS_ADDR", + EnvVar: "HEIMDALL_ADDR", }, cli.StringFlag{ Name: "cert, c", @@ -72,7 +72,11 @@ func main() { } return nil } - app.Commands = []cli.Command{} + app.Commands = []cli.Command{ + nodesCommand, + peersCommand, + routesCommand, + } if err := app.Run(os.Args); err != nil { logrus.Fatal(err) diff --git a/cmd/hctl/nodes.go b/cmd/hctl/nodes.go new file mode 100644 index 0000000..9120933 --- /dev/null +++ b/cmd/hctl/nodes.go @@ -0,0 +1,65 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "fmt" + "os" + "text/tabwriter" + + "github.com/urfave/cli" +) + +var nodesCommand = cli.Command{ + Name: "nodes", + Usage: "node management", + Subcommands: []cli.Command{ + listNodesCommand, + }, +} + +var listNodesCommand = cli.Command{ + Name: "list", + Usage: "list nodes", + Action: func(cx *cli.Context) error { + c, err := getClient(cx) + if err != nil { + return err + } + defer c.Close() + + nodes, err := c.Nodes() + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + fmt.Fprintf(w, "ID\tADDR\tGATEWAY\tPUBLIC KEY\n") + for _, n := range nodes { + gw := fmt.Sprintf("%s:%d", n.GatewayIP, n.GatewayPort) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", n.ID, n.Addr, gw, n.KeyPair.PublicKey) + } + w.Flush() + + return nil + }, +} diff --git a/cmd/hctl/peers.go b/cmd/hctl/peers.go new file mode 100644 index 0000000..a92fa5a --- /dev/null +++ b/cmd/hctl/peers.go @@ -0,0 +1,63 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "fmt" + "os" + "text/tabwriter" + + "github.com/urfave/cli" +) + +var peersCommand = cli.Command{ + Name: "peers", + Usage: "peer management", + Subcommands: []cli.Command{ + listPeersCommand, + }, +} +var listPeersCommand = cli.Command{ + Name: "list", + Usage: "list peers", + Action: func(cx *cli.Context) error { + c, err := getClient(cx) + if err != nil { + return err + } + defer c.Close() + + peers, err := c.Peers() + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + fmt.Fprintf(w, "ID\tPUBLIC KEY\tENDPOINT\tALLOWED\n") + for _, p := range peers { + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", p.ID, p.KeyPair.PublicKey, p.Endpoint, p.AllowedIPs) + } + w.Flush() + + return nil + }, +} diff --git a/cmd/hctl/routes.go b/cmd/hctl/routes.go new file mode 100644 index 0000000..1b44238 --- /dev/null +++ b/cmd/hctl/routes.go @@ -0,0 +1,111 @@ +/* + Copyright 2019 Stellar Project + + 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 ( + "fmt" + "os" + "text/tabwriter" + + "github.com/urfave/cli" +) + +var routesCommand = cli.Command{ + Name: "routes", + Usage: "route management", + Subcommands: []cli.Command{ + listRoutesCommand, + createRouteCommand, + deleteRouteCommand, + }, +} + +var listRoutesCommand = cli.Command{ + Name: "list", + Usage: "list routes", + Action: func(cx *cli.Context) error { + c, err := getClient(cx) + if err != nil { + return err + } + defer c.Close() + + routes, err := c.Routes() + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + fmt.Fprintf(w, "NODE\tNETWORK\n") + for _, r := range routes { + fmt.Fprintf(w, "%s\t%s\n", r.NodeID, r.Network) + } + w.Flush() + + return nil + }, +} + +var createRouteCommand = cli.Command{ + Name: "create", + Usage: "create a new route", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "node-id", + Usage: "node id for route", + }, + cli.StringFlag{ + Name: "network", + Usage: "network for route (i.e. 10.100.0.0/24)", + }, + }, + Action: func(cx *cli.Context) error { + c, err := getClient(cx) + if err != nil { + return err + } + defer c.Close() + + if err := c.CreateRoute(cx.String("node-id"), cx.String("network")); err != nil { + return err + } + return nil + }, +} + +var deleteRouteCommand = cli.Command{ + Name: "delete", + Usage: "delete a route", + Action: func(cx *cli.Context) error { + c, err := getClient(cx) + if err != nil { + return err + } + defer c.Close() + + network := cx.Args().First() + if err := c.DeleteRoute(network); err != nil { + return err + } + return nil + }, +} diff --git a/go.mod b/go.mod index fb485c9..307ae28 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.12 require ( github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 // indirect + github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067 // indirect github.com/getsentry/raven-go v0.2.0 // indirect github.com/gogo/googleapis v1.3.0 @@ -11,11 +12,9 @@ require ( github.com/gomodule/redigo v2.0.0+incompatible github.com/google/uuid v1.1.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/errors v0.8.1 - github.com/prometheus/client_golang v1.1.0 // indirect github.com/sirupsen/logrus v1.4.2 + github.com/stellarproject/atlas v0.1.0 github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067 github.com/urfave/cli v1.22.1 google.golang.org/grpc v1.24.0 diff --git a/go.sum b/go.sum index 6f00238..1dc2f8e 100644 --- a/go.sum +++ b/go.sum @@ -9,21 +9,27 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 h1:8k9FLYBLKT+9v2HQJ/a95ZemmTx+/ltJcAiRhVushG8= github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/containerd/typeurl v0.0.0-20190515163108-7312978f2987/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd h1:bRLyitWw3PT/2YuVaCKTPg0cA5dOFKFwKtkfcP2dLsA= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067 h1:jlV8Svz9lOwvxWBt2RN3uA1JUZ8AFj46boym2+Fx488= github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067/go.mod h1:+l2fIHwwiNb/sUw9RcsUH6wXnO07793PC4XjDWCuiHs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ehazlett/ttlcache v0.0.0-20190820213212-4400e3aef9f0/go.mod h1:D7IiYXsX2n2xixWvFTxGeZucCvvNtI14ikLj6L9Kp9E= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.3.0 h1:M695OaDJ5ipWvDPcoAg/YL9c3uORAegkEfBqTQF/fTQ= github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -44,18 +50,22 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/olebedev/emitter v0.0.0-20190110104742-e8d1457e6aee/go.mod h1:eT2/Pcsim3XBjbvldGiJBvvgiqZkAFyiOJJsDKXs/ts= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -81,14 +91,20 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stellarproject/atlas v0.1.0 h1:ZYRDbzERiu9hyBO1vTBaEro1ScZ8q874zVYdEASNNZQ= +github.com/stellarproject/atlas v0.1.0/go.mod h1:I6biE8fkkrchKwVASWzxyGVOson7ycZNjOGi2nWYUDA= github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067 h1:rXVdzLEX//pCEeoLSu5p61PktACUZY1pFXQ9dCsnMA4= github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067/go.mod h1:pJTo5Hd/Kb63HIoU6r3wfqWA7AMQWstyu7qvlOq+mqM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -108,18 +124,23 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/p golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/server/node.go b/server/node.go index a76e805..5df2e61 100644 --- a/server/node.go +++ b/server/node.go @@ -34,6 +34,51 @@ import ( v1 "github.com/stellarproject/heimdall/api/v1" ) +// Nodes returns a list of known nodes +func (s *Server) Nodes(ctx context.Context, req *v1.NodesRequest) (*v1.NodesResponse, error) { + nodes, err := s.getNodes(ctx) + if err != nil { + return nil, err + } + return &v1.NodesResponse{ + Nodes: nodes, + }, nil +} + +func (s *Server) getNodes(ctx context.Context) ([]*v1.Node, error) { + nodeKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getNodeKey("*"))) + if err != nil { + return nil, err + } + var nodes []*v1.Node + for _, nodeKey := range nodeKeys { + data, err := redis.Bytes(s.local(ctx, "GET", nodeKey)) + if err != nil { + return nil, err + } + + var node v1.Node + if err := proto.Unmarshal(data, &node); err != nil { + return nil, err + } + nodes = append(nodes, &node) + } + return nodes, nil +} + +func (s *Server) getNode(ctx context.Context, id string) (*v1.Node, error) { + data, err := redis.Bytes(s.local(ctx, "GET", s.getNodeKey(id))) + if err != nil { + return nil, err + } + + var node v1.Node + if err := proto.Unmarshal(data, &node); err != nil { + return nil, err + } + return &node, nil +} + func (s *Server) configureNode() error { ctx := context.Background() nodeKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getNodeKey("*"))) diff --git a/server/peer.go b/server/peer.go index c3ed9d2..984ceaf 100644 --- a/server/peer.go +++ b/server/peer.go @@ -35,6 +35,60 @@ import ( v1 "github.com/stellarproject/heimdall/api/v1" ) +// Peers returns a list of known peers +func (s *Server) Peers(ctx context.Context, req *v1.PeersRequest) (*v1.PeersResponse, error) { + peers, err := s.getPeers(ctx) + if err != nil { + return nil, err + } + return &v1.PeersResponse{ + Peers: peers, + }, nil +} + +func (s *Server) getPeers(ctx context.Context) ([]*v1.Peer, error) { + peerKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getPeerKey("*"))) + if err != nil { + return nil, err + } + var peers []*v1.Peer + for _, peerKey := range peerKeys { + data, err := redis.Bytes(s.local(ctx, "GET", peerKey)) + if err != nil { + return nil, err + } + + var peer v1.Peer + if err := proto.Unmarshal(data, &peer); err != nil { + return nil, err + } + peers = append(peers, &peer) + } + return peers, nil +} + +func (s *Server) peerUpdater(ctx context.Context) { + logrus.Debugf("starting peer config updater: ttl=%s", peerConfigUpdateInterval) + + t := time.NewTicker(peerConfigUpdateInterval) + + for range t.C { + uctx, cancel := context.WithTimeout(ctx, peerConfigUpdateInterval) + if err := s.updatePeerInfo(uctx); err != nil { + logrus.Errorf("updatePeerInfo: %s", err) + cancel() + continue + } + + if err := s.updatePeerConfig(uctx); err != nil { + logrus.Errorf("updatePeerConfig: %s", err) + cancel() + continue + } + cancel() + } +} + func (s *Server) updatePeerInfo(ctx context.Context) error { keypair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID) if err != nil { @@ -43,8 +97,23 @@ func (s *Server) updatePeerInfo(ctx context.Context) error { endpoint := fmt.Sprintf("%s:%d", s.cfg.GatewayIP, s.cfg.GatewayPort) - // TODO: build allowedIPs from routes and peer network + // build allowedIPs from routes and peer network allowedIPs := []string{s.cfg.PeerNetwork} + routes, err := s.getRoutes(ctx) + if err != nil { + return err + } + + for _, route := range routes { + // only add the route if a peer to prevent route duplicate + if route.NodeID != s.cfg.ID { + continue + } + + logrus.Debugf("adding route to allowed IPs: %s", route.Network) + + allowedIPs = append(allowedIPs, route.Network) + } n := &v1.Peer{ ID: s.cfg.ID, @@ -57,7 +126,23 @@ func (s *Server) updatePeerInfo(ctx context.Context) error { if err != nil { return err } + pHash := hashData(data) + key := s.getPeerKey(s.cfg.ID) + peerData, err := redis.Bytes(s.local(ctx, "GET", key)) + if err != nil { + if err != redis.ErrNil { + return err + } + } + + eHash := hashData(peerData) + + // skip update if same + if pHash == eHash { + return nil + } + if _, err := s.master(ctx, "SET", key, data); err != nil { return err } @@ -84,98 +169,86 @@ func (s *Server) getPeerInfo(ctx context.Context, id string) (*v1.Peer, error) { return &peer, nil } -func (s *Server) updatePeerConfig(ctx context.Context) { - logrus.Debugf("starting peer config updater: ttl=%s", peerConfigUpdateInterval) - t := time.NewTicker(peerConfigUpdateInterval) - - configHash := "" - - for range t.C { - uctx, cancel := context.WithTimeout(ctx, peerConfigUpdateInterval) - peerKeys, err := redis.Strings(s.local(uctx, "KEYS", s.getPeerKey("*"))) - if err != nil { - logrus.Error(err) - cancel() - continue - } - var peers []*v1.Peer - for _, peerKey := range peerKeys { - peerData, err := redis.Bytes(s.local(uctx, "GET", peerKey)) - if err != nil { - logrus.Error(err) - cancel() - continue - } - var p v1.Peer - if err := proto.Unmarshal(peerData, &p); err != nil { - logrus.Error(err) - cancel() - continue - } - - // do not add self as a peer - if p.ID == s.cfg.ID { - continue - } - - peers = append(peers, &p) - } - - keyPair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID) - if err != nil { - logrus.Error(err) - cancel() - continue - } - - gatewayIP, _, err := s.getOrAllocateIP(ctx, s.cfg.ID) - if err != nil { - logrus.Error(err) - cancel() - continue - } - wireguardCfg := &wireguardConfig{ - Iface: defaultWireguardInterface, - PrivateKey: keyPair.PrivateKey, - ListenPort: s.cfg.GatewayPort, - Address: gatewayIP.String() + "/32", - Peers: peers, - } - - tmpCfg, err := generateNodeWireguardConfig(wireguardCfg) - if err != nil { - logrus.Error(err) - cancel() - continue - } - - h, err := hashConfig(tmpCfg) - if err != nil { - logrus.Error(err) - cancel() - continue - } - - // if config has not change skip update - if h == configHash { - continue - } - - logrus.Debugf("updating peer config to version %s", h) - // update wireguard config - if err := os.Rename(tmpCfg, wireguardConfigPath); err != nil { - logrus.Error(err) - cancel() - continue - } - // reload wireguard - if err := restartWireguardTunnel(ctx); err != nil { - logrus.Error(err) - cancel() - continue - } - configHash = h +func (s *Server) updatePeerConfig(ctx context.Context) error { + peerKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getPeerKey("*"))) + if err != nil { + return err } + var peers []*v1.Peer + for _, peerKey := range peerKeys { + peerData, err := redis.Bytes(s.local(ctx, "GET", peerKey)) + if err != nil { + return err + } + var p v1.Peer + if err := proto.Unmarshal(peerData, &p); err != nil { + return err + } + + // do not add self as a peer + if p.ID == s.cfg.ID { + continue + } + + peers = append(peers, &p) + } + + keyPair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID) + if err != nil { + return err + } + + gatewayIP, _, err := s.getOrAllocateIP(ctx, s.cfg.ID) + if err != nil { + return err + } + wireguardCfg := &wireguardConfig{ + Iface: defaultWireguardInterface, + PrivateKey: keyPair.PrivateKey, + ListenPort: s.cfg.GatewayPort, + Address: gatewayIP.String() + "/32", + Peers: peers, + } + + tmpCfg, err := generateNodeWireguardConfig(wireguardCfg) + if err != nil { + return err + } + + h, err := hashConfig(tmpCfg) + if err != nil { + return err + } + + e, err := hashConfig(wireguardConfigPath) + if err != nil { + return err + } + + // if config has not change skip update + if h == e { + logrus.Debugf("config not changed: hash=%s", e) + return nil + } + + logrus.Debugf("updating peer config to version %s", h) + // update wireguard config + if err := os.Rename(tmpCfg, wireguardConfigPath); err != nil { + return err + } + + // reload wireguard + if err := restartWireguardTunnel(ctx); err != nil { + return err + } + + return nil +} + +func hashData(data []byte) string { + h := sha256.New() + h.Write(data) + return fmt.Sprintf("%x", h.Sum(nil)) } func hashConfig(cfgPath string) (string, error) { @@ -184,7 +257,5 @@ func hashConfig(cfgPath string) (string, error) { return "", err } - h := sha256.New() - h.Write(peerData) - return fmt.Sprintf("%x", h.Sum(nil)), nil + return hashData(peerData), nil } diff --git a/server/route.go b/server/route.go new file mode 100644 index 0000000..b08e8f7 --- /dev/null +++ b/server/route.go @@ -0,0 +1,113 @@ +/* + Copyright 2019 Stellar Project + + 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" + + "github.com/gogo/protobuf/proto" + ptypes "github.com/gogo/protobuf/types" + "github.com/gomodule/redigo/redis" + "github.com/pkg/errors" + v1 "github.com/stellarproject/heimdall/api/v1" +) + +// CreateRoute reserves a new route +func (s *Server) CreateRoute(ctx context.Context, req *v1.CreateRouteRequest) (*ptypes.Empty, error) { + // check for existing route + routeKey := s.getRouteKey(req.Network) + routeData, err := redis.Bytes(s.local(ctx, "GET", routeKey)) + if err != nil { + if err != redis.ErrNil { + return nil, err + } + } + if routeData != nil { + return nil, errors.Wrap(ErrRouteExists, req.Network) + } + + // check for node id + if _, err := redis.Bytes(s.local(ctx, "GET", s.getNodeKey(req.NodeID))); err != nil { + if err == redis.ErrNil { + return nil, errors.Wrap(ErrNodeDoesNotExist, req.NodeID) + } + return nil, err + } + + // save route + route := &v1.Route{ + NodeID: req.NodeID, + Network: req.Network, + } + + data, err := proto.Marshal(route) + if err != nil { + return nil, err + } + if _, err := s.master(ctx, "SET", routeKey, data); err != nil { + return nil, err + } + + return empty, nil +} + +// Delete deletes a new route +func (s *Server) DeleteRoute(ctx context.Context, req *v1.DeleteRouteRequest) (*ptypes.Empty, error) { + routeKey := s.getRouteKey(req.Network) + if _, err := s.master(ctx, "DEL", routeKey); err != nil { + return nil, err + } + return empty, nil +} + +// Routes returns a list of known routes +func (s *Server) Routes(ctx context.Context, req *v1.RoutesRequest) (*v1.RoutesResponse, error) { + routes, err := s.getRoutes(ctx) + if err != nil { + return nil, err + } + return &v1.RoutesResponse{ + Routes: routes, + }, nil +} + +func (s *Server) getRoutes(ctx context.Context) ([]*v1.Route, error) { + routeKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getRouteKey("*"))) + if err != nil { + return nil, err + } + var routes []*v1.Route + for _, routeKey := range routeKeys { + data, err := redis.Bytes(s.local(ctx, "GET", routeKey)) + if err != nil { + return nil, err + } + + var route v1.Route + if err := proto.Unmarshal(data, &route); err != nil { + return nil, err + } + routes = append(routes, &route) + } + + return routes, nil +} diff --git a/server/server.go b/server/server.go index 4af1468..5a1a1a5 100644 --- a/server/server.go +++ b/server/server.go @@ -47,6 +47,7 @@ const ( nodesKey = "heimdall:nodes" nodeJoinKey = "heimdall:join" peersKey = "heimdall:peers" + routesKey = "heimdall:routes" ipsKey = "heimdall:ips" wireguardConfigPath = "/etc/wireguard/darknet.conf" @@ -58,8 +59,14 @@ var ( nodeHeartbeatInterval = time.Second * 60 nodeHeartbeatExpiry = 86400 peerConfigUpdateInterval = time.Second * 10 + + // ErrRouteExists is returned when a requested route is already reserved + ErrRouteExists = errors.New("route already reserved") + // ErrNodeDoesNotExist is returned when an invalid node is requested + ErrNodeDoesNotExist = errors.New("node does not exist") ) +// Server represents the Heimdall server type Server struct { cfg *heimdall.Config rpool *redis.Pool @@ -67,6 +74,7 @@ type Server struct { replicaCh chan struct{} } +// NewServer returns a new Heimdall server func NewServer(cfg *heimdall.Config) (*Server, error) { pool := getPool(cfg.RedisURL) return &Server{ @@ -130,6 +138,9 @@ func (s *Server) Run() error { return err } + // ensure wireguard is started + _, _ = wgquick(ctx, "up", getTunnelName()) + if err := s.updatePeerInfo(ctx); err != nil { return err } @@ -138,7 +149,7 @@ func (s *Server) Run() error { go s.nodeHeartbeat(ctx) // start peer config updater to configure wireguard as peers join - go s.updatePeerConfig(ctx) + go s.peerUpdater(ctx) // start listener for pub/sub errCh := make(chan error, 1) @@ -219,6 +230,10 @@ func (s *Server) getNodeKey(id string) string { return fmt.Sprintf("%s:%s", nodesKey, id) } +func (s *Server) getRouteKey(network string) string { + return fmt.Sprintf("%s:%s", routesKey, network) +} + func (s *Server) getPeerKey(id string) string { return fmt.Sprintf("%s:%s", peersKey, id) } diff --git a/server/wireguard.go b/server/wireguard.go index e87e252..1bd75c8 100644 --- a/server/wireguard.go +++ b/server/wireguard.go @@ -107,8 +107,12 @@ func generateWireguardKeys(ctx context.Context) (string, string, error) { return privateKey, publicKey, nil } +func getTunnelName() string { + return strings.Replace(filepath.Base(wireguardConfigPath), filepath.Ext(filepath.Base(wireguardConfigPath)), "", 1) +} + func restartWireguardTunnel(ctx context.Context) error { - tunnelName := strings.Replace(filepath.Base(wireguardConfigPath), filepath.Ext(filepath.Base(wireguardConfigPath)), "", 1) + tunnelName := getTunnelName() logrus.Infof("restarting tunnel %s", tunnelName) d, err := wgquick(ctx, "down", tunnelName) if err != nil {