From e3e80d555c09c661c32f526d4e4c2d05f1fe7350 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:07:02 +0700 Subject: [PATCH 01/20] initialize instance db --- sdk/sdk_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 2ff7a859e..e5390089f 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -18,12 +18,14 @@ import ( const ( servicedbname = "service.db.test" + instancedbname = "instance.db.test" execdbname = "exec.db.test" ) type apiTesting struct { *testing.T serviceDB *database.LevelDBServiceDB + instanceDB *database.LevelDBInstanceDB executionDB *database.LevelDBExecutionDB containerMock *mocks.Container } @@ -44,6 +46,9 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { db, err := database.NewServiceDB(servicedbname) require.NoError(t, err) + instanceDB, err := database.NewInstanceDB(instancedbname) + require.NoError(t, err) + execDB, err := database.NewExecutionDB(execdbname) require.NoError(t, err) @@ -52,6 +57,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From cc3f4360798a5069f967efba9877c3f0bbae5c2b Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:14:35 +0700 Subject: [PATCH 02/20] go fmt --- sdk/sdk_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index e5390089f..9a4c58425 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -17,9 +17,9 @@ import ( ) const ( - servicedbname = "service.db.test" + servicedbname = "service.db.test" instancedbname = "instance.db.test" - execdbname = "exec.db.test" + execdbname = "exec.db.test" ) type apiTesting struct { @@ -57,7 +57,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, - instanceDB: instanceDB, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From 5ae93f1dac98f04dadeb834c25d286a562a5c1a5 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 16:58:28 +0700 Subject: [PATCH 03/20] add api to delete instance --- database/instance_db.go | 13 ++++ protobuf/api/instance.pb.go | 131 +++++++++++++++++++++++++++++++++--- protobuf/api/instance.proto | 9 +++ sdk/instance/instance.go | 12 ++++ server/grpc/instance.go | 11 +++ 5 files changed, 167 insertions(+), 9 deletions(-) diff --git a/database/instance_db.go b/database/instance_db.go index bc9b1e77c..0eed7d228 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -102,3 +102,16 @@ func (d *LevelDBInstanceDB) Save(i *instance.Instance) error { func (d *LevelDBInstanceDB) Close() error { return d.db.Close() } + +// Delete deletes service from database. +func (d *LevelDBInstanceDB) Delete(hash string) error { + tx, err := d.db.OpenTransaction() + if err != nil { + return err + } + if err := tx.Delete([]byte(hash), nil); err != nil { + tx.Discard() + return err + } + return tx.Commit() +} diff --git a/protobuf/api/instance.pb.go b/protobuf/api/instance.pb.go index 7e3c2b4e8..7f0b0c328 100644 --- a/protobuf/api/instance.pb.go +++ b/protobuf/api/instance.pb.go @@ -35,7 +35,7 @@ func (m *CreateInstanceRequest) Reset() { *m = CreateInstanceRequest{} } func (m *CreateInstanceRequest) String() string { return proto.CompactTextString(m) } func (*CreateInstanceRequest) ProtoMessage() {} func (*CreateInstanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_instance_2c5546442411f429, []int{0} + return fileDescriptor_instance_7f0accdedd09f197, []int{0} } func (m *CreateInstanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateInstanceRequest.Unmarshal(m, b) @@ -81,7 +81,7 @@ func (m *CreateInstanceResponse) Reset() { *m = CreateInstanceResponse{} func (m *CreateInstanceResponse) String() string { return proto.CompactTextString(m) } func (*CreateInstanceResponse) ProtoMessage() {} func (*CreateInstanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_instance_2c5546442411f429, []int{1} + return fileDescriptor_instance_7f0accdedd09f197, []int{1} } func (m *CreateInstanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateInstanceResponse.Unmarshal(m, b) @@ -115,9 +115,87 @@ func (m *CreateInstanceResponse) GetServiceHash() string { return "" } +type DeleteInstanceRequest struct { + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteInstanceRequest) Reset() { *m = DeleteInstanceRequest{} } +func (m *DeleteInstanceRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteInstanceRequest) ProtoMessage() {} +func (*DeleteInstanceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_7f0accdedd09f197, []int{2} +} +func (m *DeleteInstanceRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteInstanceRequest.Unmarshal(m, b) +} +func (m *DeleteInstanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteInstanceRequest.Marshal(b, m, deterministic) +} +func (dst *DeleteInstanceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteInstanceRequest.Merge(dst, src) +} +func (m *DeleteInstanceRequest) XXX_Size() int { + return xxx_messageInfo_DeleteInstanceRequest.Size(m) +} +func (m *DeleteInstanceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteInstanceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteInstanceRequest proto.InternalMessageInfo + +func (m *DeleteInstanceRequest) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +type DeleteInstanceResponse struct { + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteInstanceResponse) Reset() { *m = DeleteInstanceResponse{} } +func (m *DeleteInstanceResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteInstanceResponse) ProtoMessage() {} +func (*DeleteInstanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_7f0accdedd09f197, []int{3} +} +func (m *DeleteInstanceResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteInstanceResponse.Unmarshal(m, b) +} +func (m *DeleteInstanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteInstanceResponse.Marshal(b, m, deterministic) +} +func (dst *DeleteInstanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteInstanceResponse.Merge(dst, src) +} +func (m *DeleteInstanceResponse) XXX_Size() int { + return xxx_messageInfo_DeleteInstanceResponse.Size(m) +} +func (m *DeleteInstanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteInstanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteInstanceResponse proto.InternalMessageInfo + +func (m *DeleteInstanceResponse) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + func init() { proto.RegisterType((*CreateInstanceRequest)(nil), "api.CreateInstanceRequest") proto.RegisterType((*CreateInstanceResponse)(nil), "api.CreateInstanceResponse") + proto.RegisterType((*DeleteInstanceRequest)(nil), "api.DeleteInstanceRequest") + proto.RegisterType((*DeleteInstanceResponse)(nil), "api.DeleteInstanceResponse") } // Reference imports to suppress errors if they are not otherwise used. @@ -133,6 +211,7 @@ 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 InstanceClient interface { Create(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error) + Delete(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error) } type instanceClient struct { @@ -152,9 +231,19 @@ func (c *instanceClient) Create(ctx context.Context, in *CreateInstanceRequest, return out, nil } +func (c *instanceClient) Delete(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error) { + out := new(DeleteInstanceResponse) + err := c.cc.Invoke(ctx, "/api.Instance/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // InstanceServer is the server API for Instance service. type InstanceServer interface { Create(context.Context, *CreateInstanceRequest) (*CreateInstanceResponse, error) + Delete(context.Context, *DeleteInstanceRequest) (*DeleteInstanceResponse, error) } func RegisterInstanceServer(s *grpc.Server, srv InstanceServer) { @@ -179,6 +268,24 @@ func _Instance_Create_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Instance_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInstanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InstanceServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.Instance/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InstanceServer).Delete(ctx, req.(*DeleteInstanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Instance_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.Instance", HandlerType: (*InstanceServer)(nil), @@ -187,17 +294,21 @@ var _Instance_serviceDesc = grpc.ServiceDesc{ MethodName: "Create", Handler: _Instance_Create_Handler, }, + { + MethodName: "Delete", + Handler: _Instance_Delete_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "protobuf/api/instance.proto", } func init() { - proto.RegisterFile("protobuf/api/instance.proto", fileDescriptor_instance_2c5546442411f429) + proto.RegisterFile("protobuf/api/instance.proto", fileDescriptor_instance_7f0accdedd09f197) } -var fileDescriptor_instance_2c5546442411f429 = []byte{ - // 180 bytes of a gzipped FileDescriptorProto +var fileDescriptor_instance_7f0accdedd09f197 = []byte{ + // 223 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x2c, 0xc8, 0xd4, 0xcf, 0xcc, 0x2b, 0x2e, 0x49, 0xcc, 0x4b, 0x4e, 0xd5, 0x03, 0x8b, 0x0a, 0x31, 0x27, 0x16, 0x64, 0x2a, 0x79, 0x73, 0x89, 0x3a, 0x17, 0xa5, @@ -206,8 +317,10 @@ var fileDescriptor_instance_2c5546442411f429 = []byte{ 0x35, 0x38, 0x83, 0x90, 0x85, 0x84, 0x04, 0xb8, 0x98, 0x53, 0xf3, 0xca, 0x24, 0x98, 0x14, 0x98, 0x35, 0x38, 0x83, 0x40, 0x4c, 0x25, 0x3f, 0x2e, 0x31, 0x74, 0xc3, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0x84, 0xb8, 0x58, 0x32, 0x40, 0xc6, 0x30, 0x81, 0x8d, 0x01, 0xb3, 0xd1, 0x6d, 0x60, - 0xc6, 0xb0, 0xc1, 0xc8, 0x9f, 0x8b, 0x03, 0x66, 0x92, 0x90, 0x33, 0x17, 0x1b, 0xc4, 0x6c, 0x21, - 0x29, 0xbd, 0xc4, 0x82, 0x4c, 0x3d, 0xac, 0xae, 0x96, 0x92, 0xc6, 0x2a, 0x07, 0x71, 0x84, 0x12, - 0x43, 0x12, 0x1b, 0xd8, 0xe7, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x11, 0x07, 0xe2, - 0x18, 0x01, 0x00, 0x00, + 0xc6, 0xb0, 0x41, 0x49, 0x9b, 0x4b, 0xd4, 0x25, 0x35, 0x27, 0x15, 0xd3, 0x71, 0x30, 0xe3, 0x18, + 0x11, 0xc6, 0x29, 0xe9, 0x70, 0x89, 0xa1, 0x2b, 0x46, 0xb3, 0x1c, 0x49, 0xb5, 0xd1, 0x14, 0x46, + 0x2e, 0x0e, 0x98, 0x42, 0x21, 0x67, 0x2e, 0x36, 0x88, 0xbb, 0x85, 0xa4, 0xf4, 0x12, 0x0b, 0x32, + 0xf5, 0xb0, 0x86, 0x88, 0x94, 0x34, 0x56, 0x39, 0x88, 0x1d, 0x4a, 0x0c, 0x20, 0x43, 0x20, 0xf6, + 0x43, 0x0d, 0xc1, 0xea, 0x72, 0xa8, 0x21, 0xd8, 0x1d, 0xaa, 0xc4, 0x90, 0xc4, 0x06, 0x8e, 0x1a, + 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x62, 0x32, 0x6b, 0x6c, 0xb9, 0x01, 0x00, 0x00, } diff --git a/protobuf/api/instance.proto b/protobuf/api/instance.proto index a8620988a..c4bc24b70 100644 --- a/protobuf/api/instance.proto +++ b/protobuf/api/instance.proto @@ -4,6 +4,7 @@ package api; service Instance { rpc Create (CreateInstanceRequest) returns (CreateInstanceResponse) {} + rpc Delete (DeleteInstanceRequest) returns (DeleteInstanceResponse) {} } message CreateInstanceRequest { @@ -15,3 +16,11 @@ message CreateInstanceResponse { string hash = 2; // Service's instance hash. string serviceHash = 3; // Service's bare hash. } + +message DeleteInstanceRequest { + string hash = 1; // Instance hash +} + +message DeleteInstanceResponse { + string hash = 1; // Instance hash +} diff --git a/sdk/instance/instance.go b/sdk/instance/instance.go index 7869419d3..d8ccd602f 100644 --- a/sdk/instance/instance.go +++ b/sdk/instance/instance.go @@ -95,3 +95,15 @@ func (i *Instance) Create(id string, env []string) (*instance.Instance, error) { _, err = i.start(o) return o, err } + +// Delete an instance +func (i *Instance) Delete(hash string) error { + inst, err := i.instanceDB.Get(hash) + if err != nil { + return err + } + if err := i.stop(inst); err != nil { + return err + } + return i.instanceDB.Delete(hash) +} diff --git a/server/grpc/instance.go b/server/grpc/instance.go index cd8342ca0..5b6f2fc6e 100644 --- a/server/grpc/instance.go +++ b/server/grpc/instance.go @@ -28,3 +28,14 @@ func (s *InstanceServer) Create(ctx context.Context, request *protobuf_api.Creat ServiceHash: i.ServiceHash, }, nil } + +// Delete an instance +func (s *InstanceServer) Delete(ctx context.Context, request *protobuf_api.DeleteInstanceRequest) (*protobuf_api.DeleteInstanceResponse, error) { + i, err := s.sdk.Instance.Delete(request.Hash) + if err != nil { + return nil, err + } + return &protobuf_api.DeleteInstanceResponse{ + Hash: i.Hash, + }, nil +} From 03679e38ddf2887c791fb7ad66c30aa3d0c2069e Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 18:11:23 +0700 Subject: [PATCH 04/20] fix delete --- database/instance_db.go | 3 +++ server/grpc/instance.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/database/instance_db.go b/database/instance_db.go index 0eed7d228..7e6e87c8e 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -14,6 +14,9 @@ type InstanceDB interface { // Save saves instance to database. Save(i *instance.Instance) error + + // Delete an instance by instance hash. + Delete(hash string) error // Close closes underlying database connection. Close() error diff --git a/server/grpc/instance.go b/server/grpc/instance.go index 5b6f2fc6e..7dc6662bb 100644 --- a/server/grpc/instance.go +++ b/server/grpc/instance.go @@ -31,11 +31,11 @@ func (s *InstanceServer) Create(ctx context.Context, request *protobuf_api.Creat // Delete an instance func (s *InstanceServer) Delete(ctx context.Context, request *protobuf_api.DeleteInstanceRequest) (*protobuf_api.DeleteInstanceResponse, error) { - i, err := s.sdk.Instance.Delete(request.Hash) + err := s.sdk.Instance.Delete(request.Hash) if err != nil { return nil, err } return &protobuf_api.DeleteInstanceResponse{ - Hash: i.Hash, + Hash: request.Hash, }, nil } From eaa1873940f9e904ceb6f96f50099e497c2ccab6 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 18:12:47 +0700 Subject: [PATCH 05/20] gofmt --- database/instance_db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/instance_db.go b/database/instance_db.go index 7e6e87c8e..ee43985d5 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -14,7 +14,7 @@ type InstanceDB interface { // Save saves instance to database. Save(i *instance.Instance) error - + // Delete an instance by instance hash. Delete(hash string) error From 25257647c81aaf8a569cdeec532933431b1d3161 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:07:02 +0700 Subject: [PATCH 06/20] initialize instance db --- sdk/sdk_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 9e9331e62..532bb1073 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -18,12 +18,14 @@ import ( const ( servicedbname = "service.db.test" + instancedbname = "instance.db.test" execdbname = "exec.db.test" ) type apiTesting struct { *testing.T serviceDB *database.LevelDBServiceDB + instanceDB *database.LevelDBInstanceDB executionDB *database.LevelDBExecutionDB containerMock *mocks.Container } @@ -42,14 +44,18 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { db, err := database.NewServiceDB(servicedbname) require.NoError(t, err) + instanceDB, err := database.NewInstanceDB(instancedbname) + require.NoError(t, err) + execDB, err := database.NewExecutionDB(execdbname) require.NoError(t, err) - a := New(m, containerMock, db, nil, execDB) + a := New(m, containerMock, db, instanceDB, execDB) return a, &apiTesting{ T: t, serviceDB: db, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From 0d52fc7a6db905bedf9d54cce5aaf824fb2e8c72 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:14:35 +0700 Subject: [PATCH 07/20] go fmt --- sdk/sdk_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 532bb1073..f638d6834 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -17,9 +17,9 @@ import ( ) const ( - servicedbname = "service.db.test" + servicedbname = "service.db.test" instancedbname = "instance.db.test" - execdbname = "exec.db.test" + execdbname = "exec.db.test" ) type apiTesting struct { @@ -55,7 +55,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, - instanceDB: instanceDB, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From 5a36e8547881c8bd1feb417d40adcf5e0fd9662c Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 14:42:18 +0700 Subject: [PATCH 08/20] initialize sdk and create function --- sdk/instance/instance.go | 98 ++++++++++++++++++++++++++++++++++++++++ sdk/sdk.go | 5 +- 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 sdk/instance/instance.go diff --git a/sdk/instance/instance.go b/sdk/instance/instance.go new file mode 100644 index 000000000..287b24d53 --- /dev/null +++ b/sdk/instance/instance.go @@ -0,0 +1,98 @@ +package instancesdk + +import ( + "crypto/sha256" + "errors" + "io/ioutil" + "net/http" + "os" + + "github.com/docker/docker/pkg/archive" + "github.com/mesg-foundation/core/container" + "github.com/mesg-foundation/core/database" + "github.com/mesg-foundation/core/instance" + "github.com/mesg-foundation/core/x/xos" + "github.com/mr-tron/base58" +) + +// Instance exposes service instance APIs of MESG. +type Instance struct { + container container.Container + serviceDB database.ServiceDB + instanceDB database.InstanceDB +} + +// New creates a new Instance SDK with given options. +func New(c container.Container, serviceDB database.ServiceDB, instanceDB database.InstanceDB) *Instance { + return &Instance{ + container: c, + serviceDB: serviceDB, + instanceDB: instanceDB, + } +} + +// Create creates a new service instance for service with id(sid/hash) and applies given env vars. +func (i *Instance) Create(id string, env []string) (*instance.Instance, error) { + // get the service from service db. + srv, err := i.serviceDB.Get(id) + if err != nil { + return nil, err + } + + // download and untar service context into path. + path, err := ioutil.TempDir("", "mesg") + if err != nil { + return nil, err + } + defer os.RemoveAll(path) + + resp, err := http.Get("http://ipfs.app.mesg.com:8080/ipfs/" + srv.Source) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New("service's source code is not reachable") + } + defer resp.Body.Close() + + if err := archive.Untar(resp.Body, path, nil); err != nil { + return nil, err + } + + // build service's Docker image and apply to service. + _, err = i.container.Build(path) + if err != nil { + return nil, err + } + + // overwrite default env vars with user defined ones. + instanceEnv := xos.EnvMergeMaps(xos.EnvSliceToMap(srv.Configuration.Env), xos.EnvSliceToMap(env)) + + // calculate instance's hash. + h := sha256.New() + h.Write([]byte(srv.Hash)) + h.Write([]byte(xos.EnvMapToString(instanceEnv))) + instanceHash := base58.Encode(h.Sum(nil)) + + // check if instance is already running. + _, err = i.instanceDB.Get(instanceHash) + if err == nil { + return nil, errors.New("service's instance is already running") + } + if !database.IsErrNotFound(err) { + return nil, err + } + + // save & start instance. + o := &instance.Instance{ + Hash: instanceHash, + ServiceHash: srv.Hash, + } + if err := i.instanceDB.Save(o); err != nil { + return nil, err + } + + // TODO: Start the container + + return o, nil +} diff --git a/sdk/sdk.go b/sdk/sdk.go index fdb0dd573..09cf66b55 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -9,6 +9,7 @@ import ( "github.com/mesg-foundation/core/database" "github.com/mesg-foundation/core/event" "github.com/mesg-foundation/core/execution" + instancesdk "github.com/mesg-foundation/core/sdk/instance" servicesdk "github.com/mesg-foundation/core/sdk/service" "github.com/mesg-foundation/core/service" "github.com/mesg-foundation/core/service/manager" @@ -21,7 +22,8 @@ const executionStreamTopic = "execution-stream" // SDK exposes all functionalities of MESG core. type SDK struct { - Service *servicesdk.Service + Service *servicesdk.Service + Instance *instancesdk.Instance ps *pubsub.PubSub @@ -35,6 +37,7 @@ type SDK struct { func New(m manager.Manager, c container.Container, db database.ServiceDB, instanceDB database.InstanceDB, execDB database.ExecutionDB) *SDK { return &SDK{ Service: servicesdk.New(m, c, db, execDB), + Instance: instancesdk.New(c, db, instanceDB), ps: pubsub.New(0), m: m, container: c, From 5721167349a3acf2dafeffb19cced83fb03397fb Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 17:39:06 +0700 Subject: [PATCH 09/20] add start instance --- sdk/instance/helpers.go | 83 ++++++++++++++++++++++++++++++++++++++++ sdk/instance/instance.go | 5 +-- sdk/instance/start.go | 78 +++++++++++++++++++++++++++++++++++++ sdk/instance/stop.go | 10 +++++ 4 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 sdk/instance/helpers.go create mode 100644 sdk/instance/start.go create mode 100644 sdk/instance/stop.go diff --git a/sdk/instance/helpers.go b/sdk/instance/helpers.go new file mode 100644 index 000000000..dcd8b0930 --- /dev/null +++ b/sdk/instance/helpers.go @@ -0,0 +1,83 @@ +package instancesdk + +import ( + "crypto/sha1" + "encoding/hex" + "strconv" + "strings" + + "github.com/mesg-foundation/core/container" + "github.com/mesg-foundation/core/service" + "github.com/mesg-foundation/core/x/xstructhash" +) + +// instanceNamespace returns the namespace of the service. +func instanceNamespace(hash string) []string { + sum := sha1.Sum([]byte(hash)) + return []string{hex.EncodeToString(sum[:])} +} + +// dependencyNamespace builds the namespace of a dependency. +func dependencyNamespace(instanceNamespace []string, dependencyKey string) []string { + return append(instanceNamespace, dependencyKey) +} + +func extractPorts(d *service.Dependency) []container.Port { + ports := make([]container.Port, len(d.Ports)) + for i, p := range d.Ports { + split := strings.Split(p, ":") + from, _ := strconv.ParseUint(split[0], 10, 64) + to := from + if len(split) > 1 { + to, _ = strconv.ParseUint(split[1], 10, 64) + } + ports[i] = container.Port{ + Target: uint32(to), + Published: uint32(from), + } + } + return ports +} + +// TODO: add test and hack for MkDir in CircleCI +func extractVolumes(s *service.Service, d *service.Dependency) []container.Mount { + volumes := make([]container.Mount, 0) + for _, volume := range d.Volumes { + volumes = append(volumes, container.Mount{ + Source: volumeKey(s, d.Key, volume), + Target: volume, + }) + } + return volumes +} + +func extractVolumesFrom(s *service.Service, d *service.Dependency) ([]container.Mount, error) { + volumesFrom := make([]container.Mount, 0) + for _, depName := range d.VolumesFrom { + dep, err := s.GetDependency(depName) + if err != nil { + if depName == service.MainServiceKey { + dep = s.Configuration + } else { + return nil, err + } + } + for _, volume := range dep.Volumes { + volumesFrom = append(volumesFrom, container.Mount{ + Source: volumeKey(s, depName, volume), + Target: volume, + }) + } + } + return volumesFrom, nil +} + +// volumeKey creates a key for service's volume based on the sid to make sure that the volume +// will stay the same for different versions of the service. +func volumeKey(s *service.Service, dependency string, volume string) string { + return hex.EncodeToString(xstructhash.Hash([]string{ + s.Sid, + dependency, + volume, + }, 1)) +} diff --git a/sdk/instance/instance.go b/sdk/instance/instance.go index 287b24d53..7869419d3 100644 --- a/sdk/instance/instance.go +++ b/sdk/instance/instance.go @@ -92,7 +92,6 @@ func (i *Instance) Create(id string, env []string) (*instance.Instance, error) { return nil, err } - // TODO: Start the container - - return o, nil + _, err = i.start(o) + return o, err } diff --git a/sdk/instance/start.go b/sdk/instance/start.go new file mode 100644 index 000000000..5416daf4b --- /dev/null +++ b/sdk/instance/start.go @@ -0,0 +1,78 @@ +package instancesdk + +import ( + "strconv" + + "github.com/mesg-foundation/core/config" + "github.com/mesg-foundation/core/container" + "github.com/mesg-foundation/core/instance" + "github.com/mesg-foundation/core/x/xnet" + "github.com/mesg-foundation/core/x/xos" +) + +// Start starts the service. +func (i *Instance) start(inst *instance.Instance) (serviceIDs []string, err error) { + srv, err := i.serviceDB.Get(inst.ServiceHash) + if err != nil { + return nil, err + } + sNamespace := instanceNamespace(inst.Hash) + networkID, err := i.container.CreateNetwork(sNamespace) + if err != nil { + return nil, err + } + sharedNetworkID, err := i.container.SharedNetworkID() + if err != nil { + return nil, err + } + conf, err := config.Global() + if err != nil { + return nil, err + } + _, port, _ := xnet.SplitHostPort(conf.Server.Address) + endpoint := conf.Name + ":" + strconv.Itoa(port) + // BUG: https://github.com/mesg-foundation/core/issues/382 + // After solving this by docker, switch back to deploy in parallel + serviceIDs = make([]string, 0) + for _, d := range append(srv.Dependencies, srv.Configuration) { + // Service.Configuration can be nil so, here is a check for it. + if d == nil { + continue + } + volumes := extractVolumes(srv, d) + volumesFrom, err := extractVolumesFrom(srv, d) + if err != nil { + return nil, err + } + serviceID, err := i.container.StartService(container.ServiceOptions{ + Namespace: dependencyNamespace(sNamespace, d.Key), + Labels: map[string]string{ + "mesg.service": srv.Name, + "mesg.hash": inst.Hash, + "mesg.sid": srv.Sid, + "mesg.core": conf.Name, + }, + Image: d.Image, + Args: d.Args, + Command: d.Command, + Env: xos.EnvMergeSlices(d.Env, []string{ + "MESG_TOKEN=" + inst.Hash, + "MESG_ENDPOINT=" + endpoint, + "MESG_ENDPOINT_TCP=" + endpoint, + }), + Mounts: append(volumes, volumesFrom...), + Ports: extractPorts(d), + Networks: []container.Network{ + {ID: networkID, Alias: d.Key}, + {ID: sharedNetworkID}, + }, + }) + if err != nil { + + i.stop(inst) + return nil, err + } + serviceIDs = append(serviceIDs, serviceID) + } + return serviceIDs, nil +} diff --git a/sdk/instance/stop.go b/sdk/instance/stop.go new file mode 100644 index 000000000..8355324a1 --- /dev/null +++ b/sdk/instance/stop.go @@ -0,0 +1,10 @@ +package instancesdk + +import ( + "github.com/mesg-foundation/core/instance" +) + +// Stop stops an instance. +func (i *Instance) stop(inst *instance.Instance) error { + return nil +} From 0862e34aba641b50d00a8e31119db84a65749699 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Sun, 9 Jun 2019 21:45:20 +0700 Subject: [PATCH 10/20] fix tests --- sdk/sdk_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index f638d6834..9a4c58425 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -33,8 +33,10 @@ type apiTesting struct { func (t *apiTesting) close() { require.NoError(t, t.serviceDB.Close()) require.NoError(t, t.executionDB.Close()) + require.NoError(t, t.instanceDB.Close()) require.NoError(t, os.RemoveAll(servicedbname)) require.NoError(t, os.RemoveAll(execdbname)) + require.NoError(t, os.RemoveAll(instancedbname)) } func newTesting(t *testing.T) (*SDK, *apiTesting) { @@ -50,7 +52,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { execDB, err := database.NewExecutionDB(execdbname) require.NoError(t, err) - a := New(m, containerMock, db, instanceDB, execDB) + a := New(m, containerMock, db, nil, execDB) return a, &apiTesting{ T: t, From dc3317ba4746e0fc500ab99e0e9bc58eda214461 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 15:36:37 +0700 Subject: [PATCH 11/20] add start instance --- sdk/instance/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/instance/start.go b/sdk/instance/start.go index 5416daf4b..4d2caa80d 100644 --- a/sdk/instance/start.go +++ b/sdk/instance/start.go @@ -50,7 +50,7 @@ func (i *Instance) start(inst *instance.Instance) (serviceIDs []string, err erro "mesg.service": srv.Name, "mesg.hash": inst.Hash, "mesg.sid": srv.Sid, - "mesg.core": conf.Name, + "mesg.engine": conf.Name, }, Image: d.Image, Args: d.Args, From 58f0247552c14ab31ed19d50f0ebf51c0006434a Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 15:42:53 +0700 Subject: [PATCH 12/20] add stop for the instance --- sdk/instance/stop.go | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/sdk/instance/stop.go b/sdk/instance/stop.go index 8355324a1..0c72198aa 100644 --- a/sdk/instance/stop.go +++ b/sdk/instance/stop.go @@ -1,10 +1,42 @@ package instancesdk import ( + "sync" + "github.com/mesg-foundation/core/instance" + "github.com/mesg-foundation/core/service" + "github.com/mesg-foundation/core/x/xerrors" ) // Stop stops an instance. func (i *Instance) stop(inst *instance.Instance) error { - return nil + srv, err := i.serviceDB.Get(inst.ServiceHash) + if err != nil { + return err + } + + var ( + wg sync.WaitGroup + errs xerrors.SyncErrors + sNamespace = instanceNamespace(inst.Hash) + ) + for _, d := range append([]*service.Dependency{srv.Configuration}, srv.Dependencies...) { + // Service.Configuration can be nil so, here is a check for it. + if d == nil { + continue + } + wg.Add(1) + go func(namespace []string) { + defer wg.Done() + if err := i.container.StopService(namespace); err != nil { + errs.Append(err) + } + }(dependencyNamespace(sNamespace, d.Key)) + } + wg.Wait() + if err := errs.ErrorOrNil(); err != nil { + return err + } + + return i.container.DeleteNetwork(sNamespace) } From 2f77f5b9ab94aa82fb6e076104b626a6ebd7a0ef Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:34:07 +0700 Subject: [PATCH 13/20] fix test --- sdk/sdk_test.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 9a4c58425..2ff7a859e 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -17,15 +17,13 @@ import ( ) const ( - servicedbname = "service.db.test" - instancedbname = "instance.db.test" - execdbname = "exec.db.test" + servicedbname = "service.db.test" + execdbname = "exec.db.test" ) type apiTesting struct { *testing.T serviceDB *database.LevelDBServiceDB - instanceDB *database.LevelDBInstanceDB executionDB *database.LevelDBExecutionDB containerMock *mocks.Container } @@ -46,9 +44,6 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { db, err := database.NewServiceDB(servicedbname) require.NoError(t, err) - instanceDB, err := database.NewInstanceDB(instancedbname) - require.NoError(t, err) - execDB, err := database.NewExecutionDB(execdbname) require.NoError(t, err) @@ -57,7 +52,6 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, - instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From cc074ed6a2416e527a9a3032c90d931df69a9bb0 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 16:07:25 +0700 Subject: [PATCH 14/20] add instance server and create api --- protobuf/api/instance.pb.go | 213 ++++++++++++++++++++++++++++++++++++ protobuf/api/instance.proto | 17 +++ scripts/build-proto.sh | 1 + server/grpc/instance.go | 30 +++++ server/grpc/server.go | 2 + 5 files changed, 263 insertions(+) create mode 100644 protobuf/api/instance.pb.go create mode 100644 protobuf/api/instance.proto create mode 100644 server/grpc/instance.go diff --git a/protobuf/api/instance.pb.go b/protobuf/api/instance.pb.go new file mode 100644 index 000000000..7e3c2b4e8 --- /dev/null +++ b/protobuf/api/instance.pb.go @@ -0,0 +1,213 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: protobuf/api/instance.proto + +package api + +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 CreateInstanceRequest struct { + ServiceHash string `protobuf:"bytes,1,opt,name=serviceHash,proto3" json:"serviceHash,omitempty"` + Env []string `protobuf:"bytes,2,rep,name=env,proto3" json:"env,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateInstanceRequest) Reset() { *m = CreateInstanceRequest{} } +func (m *CreateInstanceRequest) String() string { return proto.CompactTextString(m) } +func (*CreateInstanceRequest) ProtoMessage() {} +func (*CreateInstanceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_2c5546442411f429, []int{0} +} +func (m *CreateInstanceRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateInstanceRequest.Unmarshal(m, b) +} +func (m *CreateInstanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateInstanceRequest.Marshal(b, m, deterministic) +} +func (dst *CreateInstanceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateInstanceRequest.Merge(dst, src) +} +func (m *CreateInstanceRequest) XXX_Size() int { + return xxx_messageInfo_CreateInstanceRequest.Size(m) +} +func (m *CreateInstanceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateInstanceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateInstanceRequest proto.InternalMessageInfo + +func (m *CreateInstanceRequest) GetServiceHash() string { + if m != nil { + return m.ServiceHash + } + return "" +} + +func (m *CreateInstanceRequest) GetEnv() []string { + if m != nil { + return m.Env + } + return nil +} + +type CreateInstanceResponse struct { + Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` + ServiceHash string `protobuf:"bytes,3,opt,name=serviceHash,proto3" json:"serviceHash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateInstanceResponse) Reset() { *m = CreateInstanceResponse{} } +func (m *CreateInstanceResponse) String() string { return proto.CompactTextString(m) } +func (*CreateInstanceResponse) ProtoMessage() {} +func (*CreateInstanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_2c5546442411f429, []int{1} +} +func (m *CreateInstanceResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateInstanceResponse.Unmarshal(m, b) +} +func (m *CreateInstanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateInstanceResponse.Marshal(b, m, deterministic) +} +func (dst *CreateInstanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateInstanceResponse.Merge(dst, src) +} +func (m *CreateInstanceResponse) XXX_Size() int { + return xxx_messageInfo_CreateInstanceResponse.Size(m) +} +func (m *CreateInstanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateInstanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateInstanceResponse proto.InternalMessageInfo + +func (m *CreateInstanceResponse) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +func (m *CreateInstanceResponse) GetServiceHash() string { + if m != nil { + return m.ServiceHash + } + return "" +} + +func init() { + proto.RegisterType((*CreateInstanceRequest)(nil), "api.CreateInstanceRequest") + proto.RegisterType((*CreateInstanceResponse)(nil), "api.CreateInstanceResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// InstanceClient is the client API for Instance service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type InstanceClient interface { + Create(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error) +} + +type instanceClient struct { + cc *grpc.ClientConn +} + +func NewInstanceClient(cc *grpc.ClientConn) InstanceClient { + return &instanceClient{cc} +} + +func (c *instanceClient) Create(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error) { + out := new(CreateInstanceResponse) + err := c.cc.Invoke(ctx, "/api.Instance/Create", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// InstanceServer is the server API for Instance service. +type InstanceServer interface { + Create(context.Context, *CreateInstanceRequest) (*CreateInstanceResponse, error) +} + +func RegisterInstanceServer(s *grpc.Server, srv InstanceServer) { + s.RegisterService(&_Instance_serviceDesc, srv) +} + +func _Instance_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateInstanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InstanceServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.Instance/Create", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InstanceServer).Create(ctx, req.(*CreateInstanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Instance_serviceDesc = grpc.ServiceDesc{ + ServiceName: "api.Instance", + HandlerType: (*InstanceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Create", + Handler: _Instance_Create_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "protobuf/api/instance.proto", +} + +func init() { + proto.RegisterFile("protobuf/api/instance.proto", fileDescriptor_instance_2c5546442411f429) +} + +var fileDescriptor_instance_2c5546442411f429 = []byte{ + // 180 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x28, 0xca, 0x2f, + 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x2c, 0xc8, 0xd4, 0xcf, 0xcc, 0x2b, 0x2e, 0x49, 0xcc, 0x4b, + 0x4e, 0xd5, 0x03, 0x8b, 0x0a, 0x31, 0x27, 0x16, 0x64, 0x2a, 0x79, 0x73, 0x89, 0x3a, 0x17, 0xa5, + 0x26, 0x96, 0xa4, 0x7a, 0x42, 0x25, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x14, 0xb8, + 0xb8, 0x8b, 0x53, 0x8b, 0xca, 0x32, 0x93, 0x53, 0x3d, 0x12, 0x8b, 0x33, 0x24, 0x18, 0x15, 0x18, + 0x35, 0x38, 0x83, 0x90, 0x85, 0x84, 0x04, 0xb8, 0x98, 0x53, 0xf3, 0xca, 0x24, 0x98, 0x14, 0x98, + 0x35, 0x38, 0x83, 0x40, 0x4c, 0x25, 0x3f, 0x2e, 0x31, 0x74, 0xc3, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, + 0x53, 0x85, 0x84, 0xb8, 0x58, 0x32, 0x40, 0xc6, 0x30, 0x81, 0x8d, 0x01, 0xb3, 0xd1, 0x6d, 0x60, + 0xc6, 0xb0, 0xc1, 0xc8, 0x9f, 0x8b, 0x03, 0x66, 0x92, 0x90, 0x33, 0x17, 0x1b, 0xc4, 0x6c, 0x21, + 0x29, 0xbd, 0xc4, 0x82, 0x4c, 0x3d, 0xac, 0xae, 0x96, 0x92, 0xc6, 0x2a, 0x07, 0x71, 0x84, 0x12, + 0x43, 0x12, 0x1b, 0xd8, 0xe7, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x11, 0x07, 0xe2, + 0x18, 0x01, 0x00, 0x00, +} diff --git a/protobuf/api/instance.proto b/protobuf/api/instance.proto new file mode 100644 index 000000000..a8620988a --- /dev/null +++ b/protobuf/api/instance.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package api; + +service Instance { + rpc Create (CreateInstanceRequest) returns (CreateInstanceResponse) {} +} + +message CreateInstanceRequest { + string serviceHash = 1; // Service's sid or hash. + repeated string env = 2; // Env vars to apply to service's instance on runtime. +} + +message CreateInstanceResponse { + string hash = 2; // Service's instance hash. + string serviceHash = 3; // Service's bare hash. +} diff --git a/scripts/build-proto.sh b/scripts/build-proto.sh index 7d0752c40..4dd1e11df 100755 --- a/scripts/build-proto.sh +++ b/scripts/build-proto.sh @@ -9,6 +9,7 @@ GRPC_PLUGIN="--go_out=plugins=grpc,paths=source_relative:." protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/definition/execution.proto protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/definition/service.proto protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/api/service.proto +protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/api/instance.proto protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/coreapi/api.proto protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/api/execution.proto protoc $GRPC_PLUGIN --proto_path=$PROJECT $GRPC/serviceapi/api.proto diff --git a/server/grpc/instance.go b/server/grpc/instance.go new file mode 100644 index 000000000..cd8342ca0 --- /dev/null +++ b/server/grpc/instance.go @@ -0,0 +1,30 @@ +package grpc + +import ( + "context" + + protobuf_api "github.com/mesg-foundation/core/protobuf/api" + "github.com/mesg-foundation/core/sdk" +) + +// InstanceServer is the type to aggregate all Instance APIs. +type InstanceServer struct { + sdk *sdk.SDK +} + +// NewInstanceServer creates a new ServiceServer. +func NewInstanceServer(sdk *sdk.SDK) *InstanceServer { + return &InstanceServer{sdk: sdk} +} + +// Create creates a new instance from service. +func (s *InstanceServer) Create(ctx context.Context, request *protobuf_api.CreateInstanceRequest) (*protobuf_api.CreateInstanceResponse, error) { + i, err := s.sdk.Instance.Create(request.ServiceHash, request.Env) + if err != nil { + return nil, err + } + return &protobuf_api.CreateInstanceResponse{ + Hash: i.Hash, + ServiceHash: i.ServiceHash, + }, nil +} diff --git a/server/grpc/server.go b/server/grpc/server.go index 0be0376f8..717c25a23 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -104,11 +104,13 @@ func (s *Server) Close() { func (s *Server) register() error { coreServer := core.NewServer(s.sdk) coreServiceServer := NewServiceServer(s.sdk) + instanceServer := NewInstanceServer(s.sdk) serviceServer := service.NewServer(s.sdk) serviceapi.RegisterServiceServer(s.instance, serviceServer) coreapi.RegisterCoreServer(s.instance, coreServer) protobuf_api.RegisterServiceXServer(s.instance, coreServiceServer) + protobuf_api.RegisterInstanceServer(s.instance, instanceServer) reflection.Register(s.instance) return nil From 29482befd6c9991d7bd8a2e9556bd6cdf6d65663 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:07:02 +0700 Subject: [PATCH 15/20] initialize instance db --- sdk/sdk_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 2ff7a859e..e5390089f 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -18,12 +18,14 @@ import ( const ( servicedbname = "service.db.test" + instancedbname = "instance.db.test" execdbname = "exec.db.test" ) type apiTesting struct { *testing.T serviceDB *database.LevelDBServiceDB + instanceDB *database.LevelDBInstanceDB executionDB *database.LevelDBExecutionDB containerMock *mocks.Container } @@ -44,6 +46,9 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { db, err := database.NewServiceDB(servicedbname) require.NoError(t, err) + instanceDB, err := database.NewInstanceDB(instancedbname) + require.NoError(t, err) + execDB, err := database.NewExecutionDB(execdbname) require.NoError(t, err) @@ -52,6 +57,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From bd3765442c72ddab9e0c6b22e77f5301ec8cda3a Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 12:14:35 +0700 Subject: [PATCH 16/20] go fmt --- sdk/sdk_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index e5390089f..9a4c58425 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -17,9 +17,9 @@ import ( ) const ( - servicedbname = "service.db.test" + servicedbname = "service.db.test" instancedbname = "instance.db.test" - execdbname = "exec.db.test" + execdbname = "exec.db.test" ) type apiTesting struct { @@ -57,7 +57,7 @@ func newTesting(t *testing.T) (*SDK, *apiTesting) { return a, &apiTesting{ T: t, serviceDB: db, - instanceDB: instanceDB, + instanceDB: instanceDB, executionDB: execDB, containerMock: containerMock, } From a48f2e0e804abc657746e2b7dbc657d4adebf7b0 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 16:58:28 +0700 Subject: [PATCH 17/20] add api to delete instance --- database/instance_db.go | 13 ++++ protobuf/api/instance.pb.go | 131 +++++++++++++++++++++++++++++++++--- protobuf/api/instance.proto | 9 +++ sdk/instance/instance.go | 12 ++++ server/grpc/instance.go | 11 +++ 5 files changed, 167 insertions(+), 9 deletions(-) diff --git a/database/instance_db.go b/database/instance_db.go index c939b66ca..11879b124 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -80,3 +80,16 @@ func (d *LevelDBInstanceDB) Save(i *instance.Instance) error { func (d *LevelDBInstanceDB) Close() error { return d.db.Close() } + +// Delete deletes service from database. +func (d *LevelDBInstanceDB) Delete(hash string) error { + tx, err := d.db.OpenTransaction() + if err != nil { + return err + } + if err := tx.Delete([]byte(hash), nil); err != nil { + tx.Discard() + return err + } + return tx.Commit() +} diff --git a/protobuf/api/instance.pb.go b/protobuf/api/instance.pb.go index 7e3c2b4e8..7f0b0c328 100644 --- a/protobuf/api/instance.pb.go +++ b/protobuf/api/instance.pb.go @@ -35,7 +35,7 @@ func (m *CreateInstanceRequest) Reset() { *m = CreateInstanceRequest{} } func (m *CreateInstanceRequest) String() string { return proto.CompactTextString(m) } func (*CreateInstanceRequest) ProtoMessage() {} func (*CreateInstanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_instance_2c5546442411f429, []int{0} + return fileDescriptor_instance_7f0accdedd09f197, []int{0} } func (m *CreateInstanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateInstanceRequest.Unmarshal(m, b) @@ -81,7 +81,7 @@ func (m *CreateInstanceResponse) Reset() { *m = CreateInstanceResponse{} func (m *CreateInstanceResponse) String() string { return proto.CompactTextString(m) } func (*CreateInstanceResponse) ProtoMessage() {} func (*CreateInstanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_instance_2c5546442411f429, []int{1} + return fileDescriptor_instance_7f0accdedd09f197, []int{1} } func (m *CreateInstanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateInstanceResponse.Unmarshal(m, b) @@ -115,9 +115,87 @@ func (m *CreateInstanceResponse) GetServiceHash() string { return "" } +type DeleteInstanceRequest struct { + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteInstanceRequest) Reset() { *m = DeleteInstanceRequest{} } +func (m *DeleteInstanceRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteInstanceRequest) ProtoMessage() {} +func (*DeleteInstanceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_7f0accdedd09f197, []int{2} +} +func (m *DeleteInstanceRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteInstanceRequest.Unmarshal(m, b) +} +func (m *DeleteInstanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteInstanceRequest.Marshal(b, m, deterministic) +} +func (dst *DeleteInstanceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteInstanceRequest.Merge(dst, src) +} +func (m *DeleteInstanceRequest) XXX_Size() int { + return xxx_messageInfo_DeleteInstanceRequest.Size(m) +} +func (m *DeleteInstanceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteInstanceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteInstanceRequest proto.InternalMessageInfo + +func (m *DeleteInstanceRequest) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +type DeleteInstanceResponse struct { + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteInstanceResponse) Reset() { *m = DeleteInstanceResponse{} } +func (m *DeleteInstanceResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteInstanceResponse) ProtoMessage() {} +func (*DeleteInstanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_instance_7f0accdedd09f197, []int{3} +} +func (m *DeleteInstanceResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteInstanceResponse.Unmarshal(m, b) +} +func (m *DeleteInstanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteInstanceResponse.Marshal(b, m, deterministic) +} +func (dst *DeleteInstanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteInstanceResponse.Merge(dst, src) +} +func (m *DeleteInstanceResponse) XXX_Size() int { + return xxx_messageInfo_DeleteInstanceResponse.Size(m) +} +func (m *DeleteInstanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteInstanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteInstanceResponse proto.InternalMessageInfo + +func (m *DeleteInstanceResponse) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + func init() { proto.RegisterType((*CreateInstanceRequest)(nil), "api.CreateInstanceRequest") proto.RegisterType((*CreateInstanceResponse)(nil), "api.CreateInstanceResponse") + proto.RegisterType((*DeleteInstanceRequest)(nil), "api.DeleteInstanceRequest") + proto.RegisterType((*DeleteInstanceResponse)(nil), "api.DeleteInstanceResponse") } // Reference imports to suppress errors if they are not otherwise used. @@ -133,6 +211,7 @@ 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 InstanceClient interface { Create(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error) + Delete(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error) } type instanceClient struct { @@ -152,9 +231,19 @@ func (c *instanceClient) Create(ctx context.Context, in *CreateInstanceRequest, return out, nil } +func (c *instanceClient) Delete(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error) { + out := new(DeleteInstanceResponse) + err := c.cc.Invoke(ctx, "/api.Instance/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // InstanceServer is the server API for Instance service. type InstanceServer interface { Create(context.Context, *CreateInstanceRequest) (*CreateInstanceResponse, error) + Delete(context.Context, *DeleteInstanceRequest) (*DeleteInstanceResponse, error) } func RegisterInstanceServer(s *grpc.Server, srv InstanceServer) { @@ -179,6 +268,24 @@ func _Instance_Create_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Instance_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInstanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InstanceServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.Instance/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InstanceServer).Delete(ctx, req.(*DeleteInstanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Instance_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.Instance", HandlerType: (*InstanceServer)(nil), @@ -187,17 +294,21 @@ var _Instance_serviceDesc = grpc.ServiceDesc{ MethodName: "Create", Handler: _Instance_Create_Handler, }, + { + MethodName: "Delete", + Handler: _Instance_Delete_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "protobuf/api/instance.proto", } func init() { - proto.RegisterFile("protobuf/api/instance.proto", fileDescriptor_instance_2c5546442411f429) + proto.RegisterFile("protobuf/api/instance.proto", fileDescriptor_instance_7f0accdedd09f197) } -var fileDescriptor_instance_2c5546442411f429 = []byte{ - // 180 bytes of a gzipped FileDescriptorProto +var fileDescriptor_instance_7f0accdedd09f197 = []byte{ + // 223 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x2c, 0xc8, 0xd4, 0xcf, 0xcc, 0x2b, 0x2e, 0x49, 0xcc, 0x4b, 0x4e, 0xd5, 0x03, 0x8b, 0x0a, 0x31, 0x27, 0x16, 0x64, 0x2a, 0x79, 0x73, 0x89, 0x3a, 0x17, 0xa5, @@ -206,8 +317,10 @@ var fileDescriptor_instance_2c5546442411f429 = []byte{ 0x35, 0x38, 0x83, 0x90, 0x85, 0x84, 0x04, 0xb8, 0x98, 0x53, 0xf3, 0xca, 0x24, 0x98, 0x14, 0x98, 0x35, 0x38, 0x83, 0x40, 0x4c, 0x25, 0x3f, 0x2e, 0x31, 0x74, 0xc3, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0x84, 0xb8, 0x58, 0x32, 0x40, 0xc6, 0x30, 0x81, 0x8d, 0x01, 0xb3, 0xd1, 0x6d, 0x60, - 0xc6, 0xb0, 0xc1, 0xc8, 0x9f, 0x8b, 0x03, 0x66, 0x92, 0x90, 0x33, 0x17, 0x1b, 0xc4, 0x6c, 0x21, - 0x29, 0xbd, 0xc4, 0x82, 0x4c, 0x3d, 0xac, 0xae, 0x96, 0x92, 0xc6, 0x2a, 0x07, 0x71, 0x84, 0x12, - 0x43, 0x12, 0x1b, 0xd8, 0xe7, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x11, 0x07, 0xe2, - 0x18, 0x01, 0x00, 0x00, + 0xc6, 0xb0, 0x41, 0x49, 0x9b, 0x4b, 0xd4, 0x25, 0x35, 0x27, 0x15, 0xd3, 0x71, 0x30, 0xe3, 0x18, + 0x11, 0xc6, 0x29, 0xe9, 0x70, 0x89, 0xa1, 0x2b, 0x46, 0xb3, 0x1c, 0x49, 0xb5, 0xd1, 0x14, 0x46, + 0x2e, 0x0e, 0x98, 0x42, 0x21, 0x67, 0x2e, 0x36, 0x88, 0xbb, 0x85, 0xa4, 0xf4, 0x12, 0x0b, 0x32, + 0xf5, 0xb0, 0x86, 0x88, 0x94, 0x34, 0x56, 0x39, 0x88, 0x1d, 0x4a, 0x0c, 0x20, 0x43, 0x20, 0xf6, + 0x43, 0x0d, 0xc1, 0xea, 0x72, 0xa8, 0x21, 0xd8, 0x1d, 0xaa, 0xc4, 0x90, 0xc4, 0x06, 0x8e, 0x1a, + 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x62, 0x32, 0x6b, 0x6c, 0xb9, 0x01, 0x00, 0x00, } diff --git a/protobuf/api/instance.proto b/protobuf/api/instance.proto index a8620988a..c4bc24b70 100644 --- a/protobuf/api/instance.proto +++ b/protobuf/api/instance.proto @@ -4,6 +4,7 @@ package api; service Instance { rpc Create (CreateInstanceRequest) returns (CreateInstanceResponse) {} + rpc Delete (DeleteInstanceRequest) returns (DeleteInstanceResponse) {} } message CreateInstanceRequest { @@ -15,3 +16,11 @@ message CreateInstanceResponse { string hash = 2; // Service's instance hash. string serviceHash = 3; // Service's bare hash. } + +message DeleteInstanceRequest { + string hash = 1; // Instance hash +} + +message DeleteInstanceResponse { + string hash = 1; // Instance hash +} diff --git a/sdk/instance/instance.go b/sdk/instance/instance.go index 7869419d3..d8ccd602f 100644 --- a/sdk/instance/instance.go +++ b/sdk/instance/instance.go @@ -95,3 +95,15 @@ func (i *Instance) Create(id string, env []string) (*instance.Instance, error) { _, err = i.start(o) return o, err } + +// Delete an instance +func (i *Instance) Delete(hash string) error { + inst, err := i.instanceDB.Get(hash) + if err != nil { + return err + } + if err := i.stop(inst); err != nil { + return err + } + return i.instanceDB.Delete(hash) +} diff --git a/server/grpc/instance.go b/server/grpc/instance.go index cd8342ca0..5b6f2fc6e 100644 --- a/server/grpc/instance.go +++ b/server/grpc/instance.go @@ -28,3 +28,14 @@ func (s *InstanceServer) Create(ctx context.Context, request *protobuf_api.Creat ServiceHash: i.ServiceHash, }, nil } + +// Delete an instance +func (s *InstanceServer) Delete(ctx context.Context, request *protobuf_api.DeleteInstanceRequest) (*protobuf_api.DeleteInstanceResponse, error) { + i, err := s.sdk.Instance.Delete(request.Hash) + if err != nil { + return nil, err + } + return &protobuf_api.DeleteInstanceResponse{ + Hash: i.Hash, + }, nil +} From 502c7238cb73eefda4b274ed487e6cec3acaeab9 Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 18:11:23 +0700 Subject: [PATCH 18/20] fix delete --- database/instance_db.go | 3 +++ server/grpc/instance.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/database/instance_db.go b/database/instance_db.go index 11879b124..7a3e53048 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -14,6 +14,9 @@ type InstanceDB interface { // Save saves instance to database. Save(i *instance.Instance) error + + // Delete an instance by instance hash. + Delete(hash string) error // Close closes underlying database connection. Close() error diff --git a/server/grpc/instance.go b/server/grpc/instance.go index 5b6f2fc6e..7dc6662bb 100644 --- a/server/grpc/instance.go +++ b/server/grpc/instance.go @@ -31,11 +31,11 @@ func (s *InstanceServer) Create(ctx context.Context, request *protobuf_api.Creat // Delete an instance func (s *InstanceServer) Delete(ctx context.Context, request *protobuf_api.DeleteInstanceRequest) (*protobuf_api.DeleteInstanceResponse, error) { - i, err := s.sdk.Instance.Delete(request.Hash) + err := s.sdk.Instance.Delete(request.Hash) if err != nil { return nil, err } return &protobuf_api.DeleteInstanceResponse{ - Hash: i.Hash, + Hash: request.Hash, }, nil } From abe82f99d3ad8eb196284b4608e15e0eef2c948d Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Fri, 7 Jun 2019 18:12:47 +0700 Subject: [PATCH 19/20] gofmt --- database/instance_db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/instance_db.go b/database/instance_db.go index 7a3e53048..a0f8506aa 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -14,7 +14,7 @@ type InstanceDB interface { // Save saves instance to database. Save(i *instance.Instance) error - + // Delete an instance by instance hash. Delete(hash string) error From ae6e377da3a82f6f51d4dbca4a26c099edd7c9af Mon Sep 17 00:00:00 2001 From: Anthony ESTEBE Date: Mon, 10 Jun 2019 22:41:06 +0700 Subject: [PATCH 20/20] remove useless transaction and add test --- database/instance_db.go | 10 +--------- database/instance_db_test.go | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/database/instance_db.go b/database/instance_db.go index a0f8506aa..f9aeb62b4 100644 --- a/database/instance_db.go +++ b/database/instance_db.go @@ -86,13 +86,5 @@ func (d *LevelDBInstanceDB) Close() error { // Delete deletes service from database. func (d *LevelDBInstanceDB) Delete(hash string) error { - tx, err := d.db.OpenTransaction() - if err != nil { - return err - } - if err := tx.Delete([]byte(hash), nil); err != nil { - tx.Discard() - return err - } - return tx.Commit() + return d.db.Delete([]byte(hash), nil) } diff --git a/database/instance_db_test.go b/database/instance_db_test.go index 8d387fb20..a3912a5b8 100644 --- a/database/instance_db_test.go +++ b/database/instance_db_test.go @@ -44,7 +44,7 @@ func TestFindInstance(t *testing.T) { } func TestSaveInstance(t *testing.T) { - dir, _ := ioutil.TempDir("", "TestSave") + dir, _ := ioutil.TempDir("", "TestSaveInstance") defer os.RemoveAll(dir) db := instancedb(t, dir) defer db.Close() @@ -64,3 +64,18 @@ func TestSaveInstance(t *testing.T) { require.NoError(t, err) } } + +func TestDeleteInstance(t *testing.T) { + dir, _ := ioutil.TempDir("", "TestDeleteInstance") + defer os.RemoveAll(dir) + db := instancedb(t, dir) + defer db.Close() + i := &instance.Instance{Hash: "xxx", ServiceHash: "yyy"} + db.Save(i) + require.NoError(t, db.Delete("xxx")) + inst, err := db.Get("xxx") + require.Nil(t, inst) + require.Error(t, err) + + require.NoError(t, db.Delete("yyy")) +}