diff --git a/providers-sdk/v1/plugin/grpc.go b/providers-sdk/v1/plugin/grpc.go index b174863f81..2a77c3b7c6 100644 --- a/providers-sdk/v1/plugin/grpc.go +++ b/providers-sdk/v1/plugin/grpc.go @@ -54,6 +54,10 @@ func (m *GRPCClient) Connect(req *ConnectReq, callback ProviderCallback) (*Conne return m.client.Connect(context.Background(), req) } +func (m *GRPCClient) Disconnect(req *DisconnectReq) (*DisconnectRes, error) { + return m.client.Disconnect(context.Background(), req) +} + func (m *GRPCClient) MockConnect(req *ConnectReq, callback ProviderCallback) (*ConnectRes, error) { m.connect(req, callback) return m.client.MockConnect(context.Background(), req) @@ -100,6 +104,10 @@ func (m *GRPCServer) Connect(ctx context.Context, req *ConnectReq) (*ConnectRes, return m.Impl.Connect(req, a) } +func (m *GRPCServer) Disconnect(ctx context.Context, req *DisconnectReq) (*DisconnectRes, error) { + return m.Impl.Disconnect(req) +} + func (m *GRPCServer) MockConnect(ctx context.Context, req *ConnectReq) (*ConnectRes, error) { conn, err := m.broker.Dial(req.CallbackServer) if err != nil { diff --git a/providers-sdk/v1/plugin/interface.go b/providers-sdk/v1/plugin/interface.go index 23948b5257..b5e58aa758 100644 --- a/providers-sdk/v1/plugin/interface.go +++ b/providers-sdk/v1/plugin/interface.go @@ -22,6 +22,10 @@ var PluginMap = map[string]plugin.Plugin{ "provider": &ProviderPluginImpl{}, } +type Closer interface { + Close() +} + type ProviderCallback interface { Collect(req *DataRes) error GetRecording(req *DataReq) (*ResourceData, error) @@ -33,6 +37,7 @@ type ProviderPlugin interface { Heartbeat(req *HeartbeatReq) (*HeartbeatRes, error) ParseCLI(req *ParseCLIReq) (*ParseCLIRes, error) Connect(req *ConnectReq, callback ProviderCallback) (*ConnectRes, error) + Disconnect(req *DisconnectReq) (*DisconnectRes, error) MockConnect(req *ConnectReq, callback ProviderCallback) (*ConnectRes, error) Shutdown(req *ShutdownReq) (*ShutdownRes, error) GetData(req *DataReq) (*DataRes, error) diff --git a/providers-sdk/v1/plugin/plugin.pb.go b/providers-sdk/v1/plugin/plugin.pb.go index 179a891c8c..3a250ba7b7 100644 --- a/providers-sdk/v1/plugin/plugin.pb.go +++ b/providers-sdk/v1/plugin/plugin.pb.go @@ -789,6 +789,91 @@ func (*HeartbeatRes) Descriptor() ([]byte, []int) { return file_plugin_proto_rawDescGZIP(), []int{13} } +type DisconnectReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Connection uint32 `protobuf:"varint,1,opt,name=connection,proto3" json:"connection,omitempty"` +} + +func (x *DisconnectReq) Reset() { + *x = DisconnectReq{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DisconnectReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisconnectReq) ProtoMessage() {} + +func (x *DisconnectReq) ProtoReflect() protoreflect.Message { + mi := &file_plugin_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DisconnectReq.ProtoReflect.Descriptor instead. +func (*DisconnectReq) Descriptor() ([]byte, []int) { + return file_plugin_proto_rawDescGZIP(), []int{14} +} + +func (x *DisconnectReq) GetConnection() uint32 { + if x != nil { + return x.Connection + } + return 0 +} + +type DisconnectRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DisconnectRes) Reset() { + *x = DisconnectRes{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DisconnectRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisconnectRes) ProtoMessage() {} + +func (x *DisconnectRes) ProtoReflect() protoreflect.Message { + mi := &file_plugin_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DisconnectRes.ProtoReflect.Descriptor instead. +func (*DisconnectRes) Descriptor() ([]byte, []int) { + return file_plugin_proto_rawDescGZIP(), []int{15} +} + var File_plugin_proto protoreflect.FileDescriptor var file_plugin_proto_rawDesc = []byte{ @@ -893,63 +978,72 @@ var file_plugin_proto_rawDesc = []byte{ 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, - 0x61, 0x74, 0x52, 0x65, 0x73, 0x32, 0xc1, 0x04, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x53, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, - 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x63, 0x6e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x12, 0x50, 0x0a, - 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x12, 0x21, 0x2e, 0x63, 0x6e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x63, - 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x52, 0x65, 0x73, 0x12, - 0x4d, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6e, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x63, + 0x61, 0x74, 0x52, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x32, 0x99, 0x05, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x53, 0x0a, 0x09, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x63, 0x6e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x12, + 0x50, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x12, 0x21, 0x2e, 0x63, 0x6e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x52, 0x65, 0x71, 0x1a, 0x21, + 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x4c, 0x49, 0x52, 0x65, + 0x73, 0x12, 0x4d, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x12, 0x51, - 0x0a, 0x0b, 0x4d, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, - 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, - 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, - 0x73, 0x12, 0x50, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x21, 0x2e, - 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, - 0x1a, 0x21, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, - 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x09, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x2e, 0x63, 0x6e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x63, 0x6e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x32, 0xfa, 0x01, 0x0a, 0x10, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4a, - 0x0a, 0x07, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, + 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, + 0x12, 0x56, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x23, + 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x0b, 0x4d, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x1a, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x0c, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, + 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x12, 0x50, 0x0a, 0x08, 0x53, + 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x21, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x63, 0x6e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x47, 0x0a, + 0x31, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x6f, 0x2e, 0x6d, 0x6f, 0x6e, - 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, - 0x76, 0x31, 0x30, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2d, 0x73, 0x64, - 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x1e, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x32, 0xfa, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x07, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x65, 0x73, 0x1a, 0x20, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x47, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, + 0x71, 0x1a, 0x1d, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, + 0x42, 0x33, 0x5a, 0x31, 0x67, 0x6f, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x30, 0x2f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -964,7 +1058,7 @@ func file_plugin_proto_rawDescGZIP() []byte { return file_plugin_proto_rawDescData } -var file_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_plugin_proto_goTypes = []interface{}{ (*ParseCLIReq)(nil), // 0: cnquery.providers.v1.ParseCLIReq (*ParseCLIRes)(nil), // 1: cnquery.providers.v1.ParseCLIRes @@ -980,51 +1074,55 @@ var file_plugin_proto_goTypes = []interface{}{ (*StoreRes)(nil), // 11: cnquery.providers.v1.StoreRes (*HeartbeatReq)(nil), // 12: cnquery.providers.v1.HeartbeatReq (*HeartbeatRes)(nil), // 13: cnquery.providers.v1.HeartbeatRes - nil, // 14: cnquery.providers.v1.ParseCLIReq.FlagsEntry - nil, // 15: cnquery.providers.v1.DataReq.ArgsEntry - nil, // 16: cnquery.providers.v1.ResourceData.FieldsEntry - (*inventory.Asset)(nil), // 17: cnquery.providers.v1.Asset - (*upstream.UpstreamConfig)(nil), // 18: mondoo.cnquery.upstream.v1.UpstreamConfig - (*inventory.Inventory)(nil), // 19: cnquery.providers.v1.Inventory - (*llx.Primitive)(nil), // 20: cnquery.llx.Primitive - (*llx.Result)(nil), // 21: cnquery.llx.Result + (*DisconnectReq)(nil), // 14: cnquery.providers.v1.DisconnectReq + (*DisconnectRes)(nil), // 15: cnquery.providers.v1.DisconnectRes + nil, // 16: cnquery.providers.v1.ParseCLIReq.FlagsEntry + nil, // 17: cnquery.providers.v1.DataReq.ArgsEntry + nil, // 18: cnquery.providers.v1.ResourceData.FieldsEntry + (*inventory.Asset)(nil), // 19: cnquery.providers.v1.Asset + (*upstream.UpstreamConfig)(nil), // 20: mondoo.cnquery.upstream.v1.UpstreamConfig + (*inventory.Inventory)(nil), // 21: cnquery.providers.v1.Inventory + (*llx.Primitive)(nil), // 22: cnquery.llx.Primitive + (*llx.Result)(nil), // 23: cnquery.llx.Result } var file_plugin_proto_depIdxs = []int32{ - 14, // 0: cnquery.providers.v1.ParseCLIReq.flags:type_name -> cnquery.providers.v1.ParseCLIReq.FlagsEntry - 17, // 1: cnquery.providers.v1.ParseCLIRes.asset:type_name -> cnquery.providers.v1.Asset - 17, // 2: cnquery.providers.v1.ConnectReq.asset:type_name -> cnquery.providers.v1.Asset - 18, // 3: cnquery.providers.v1.ConnectReq.upstream:type_name -> mondoo.cnquery.upstream.v1.UpstreamConfig - 17, // 4: cnquery.providers.v1.ConnectRes.asset:type_name -> cnquery.providers.v1.Asset - 19, // 5: cnquery.providers.v1.ConnectRes.inventory:type_name -> cnquery.providers.v1.Inventory - 15, // 6: cnquery.providers.v1.DataReq.args:type_name -> cnquery.providers.v1.DataReq.ArgsEntry - 20, // 7: cnquery.providers.v1.DataRes.data:type_name -> cnquery.llx.Primitive + 16, // 0: cnquery.providers.v1.ParseCLIReq.flags:type_name -> cnquery.providers.v1.ParseCLIReq.FlagsEntry + 19, // 1: cnquery.providers.v1.ParseCLIRes.asset:type_name -> cnquery.providers.v1.Asset + 19, // 2: cnquery.providers.v1.ConnectReq.asset:type_name -> cnquery.providers.v1.Asset + 20, // 3: cnquery.providers.v1.ConnectReq.upstream:type_name -> mondoo.cnquery.upstream.v1.UpstreamConfig + 19, // 4: cnquery.providers.v1.ConnectRes.asset:type_name -> cnquery.providers.v1.Asset + 21, // 5: cnquery.providers.v1.ConnectRes.inventory:type_name -> cnquery.providers.v1.Inventory + 17, // 6: cnquery.providers.v1.DataReq.args:type_name -> cnquery.providers.v1.DataReq.ArgsEntry + 22, // 7: cnquery.providers.v1.DataRes.data:type_name -> cnquery.llx.Primitive 10, // 8: cnquery.providers.v1.StoreReq.resources:type_name -> cnquery.providers.v1.ResourceData - 16, // 9: cnquery.providers.v1.ResourceData.fields:type_name -> cnquery.providers.v1.ResourceData.FieldsEntry - 20, // 10: cnquery.providers.v1.ParseCLIReq.FlagsEntry.value:type_name -> cnquery.llx.Primitive - 20, // 11: cnquery.providers.v1.DataReq.ArgsEntry.value:type_name -> cnquery.llx.Primitive - 21, // 12: cnquery.providers.v1.ResourceData.FieldsEntry.value:type_name -> cnquery.llx.Result + 18, // 9: cnquery.providers.v1.ResourceData.fields:type_name -> cnquery.providers.v1.ResourceData.FieldsEntry + 22, // 10: cnquery.providers.v1.ParseCLIReq.FlagsEntry.value:type_name -> cnquery.llx.Primitive + 22, // 11: cnquery.providers.v1.DataReq.ArgsEntry.value:type_name -> cnquery.llx.Primitive + 23, // 12: cnquery.providers.v1.ResourceData.FieldsEntry.value:type_name -> cnquery.llx.Result 12, // 13: cnquery.providers.v1.ProviderPlugin.Heartbeat:input_type -> cnquery.providers.v1.HeartbeatReq 0, // 14: cnquery.providers.v1.ProviderPlugin.ParseCLI:input_type -> cnquery.providers.v1.ParseCLIReq 2, // 15: cnquery.providers.v1.ProviderPlugin.Connect:input_type -> cnquery.providers.v1.ConnectReq - 2, // 16: cnquery.providers.v1.ProviderPlugin.MockConnect:input_type -> cnquery.providers.v1.ConnectReq - 4, // 17: cnquery.providers.v1.ProviderPlugin.Shutdown:input_type -> cnquery.providers.v1.ShutdownReq - 6, // 18: cnquery.providers.v1.ProviderPlugin.GetData:input_type -> cnquery.providers.v1.DataReq - 9, // 19: cnquery.providers.v1.ProviderPlugin.StoreData:input_type -> cnquery.providers.v1.StoreReq - 7, // 20: cnquery.providers.v1.ProviderCallback.Collect:input_type -> cnquery.providers.v1.DataRes - 6, // 21: cnquery.providers.v1.ProviderCallback.GetRecording:input_type -> cnquery.providers.v1.DataReq - 6, // 22: cnquery.providers.v1.ProviderCallback.GetData:input_type -> cnquery.providers.v1.DataReq - 13, // 23: cnquery.providers.v1.ProviderPlugin.Heartbeat:output_type -> cnquery.providers.v1.HeartbeatRes - 1, // 24: cnquery.providers.v1.ProviderPlugin.ParseCLI:output_type -> cnquery.providers.v1.ParseCLIRes - 3, // 25: cnquery.providers.v1.ProviderPlugin.Connect:output_type -> cnquery.providers.v1.ConnectRes - 3, // 26: cnquery.providers.v1.ProviderPlugin.MockConnect:output_type -> cnquery.providers.v1.ConnectRes - 5, // 27: cnquery.providers.v1.ProviderPlugin.Shutdown:output_type -> cnquery.providers.v1.ShutdownRes - 7, // 28: cnquery.providers.v1.ProviderPlugin.GetData:output_type -> cnquery.providers.v1.DataRes - 11, // 29: cnquery.providers.v1.ProviderPlugin.StoreData:output_type -> cnquery.providers.v1.StoreRes - 8, // 30: cnquery.providers.v1.ProviderCallback.Collect:output_type -> cnquery.providers.v1.CollectRes - 10, // 31: cnquery.providers.v1.ProviderCallback.GetRecording:output_type -> cnquery.providers.v1.ResourceData - 7, // 32: cnquery.providers.v1.ProviderCallback.GetData:output_type -> cnquery.providers.v1.DataRes - 23, // [23:33] is the sub-list for method output_type - 13, // [13:23] is the sub-list for method input_type + 14, // 16: cnquery.providers.v1.ProviderPlugin.Disconnect:input_type -> cnquery.providers.v1.DisconnectReq + 2, // 17: cnquery.providers.v1.ProviderPlugin.MockConnect:input_type -> cnquery.providers.v1.ConnectReq + 4, // 18: cnquery.providers.v1.ProviderPlugin.Shutdown:input_type -> cnquery.providers.v1.ShutdownReq + 6, // 19: cnquery.providers.v1.ProviderPlugin.GetData:input_type -> cnquery.providers.v1.DataReq + 9, // 20: cnquery.providers.v1.ProviderPlugin.StoreData:input_type -> cnquery.providers.v1.StoreReq + 7, // 21: cnquery.providers.v1.ProviderCallback.Collect:input_type -> cnquery.providers.v1.DataRes + 6, // 22: cnquery.providers.v1.ProviderCallback.GetRecording:input_type -> cnquery.providers.v1.DataReq + 6, // 23: cnquery.providers.v1.ProviderCallback.GetData:input_type -> cnquery.providers.v1.DataReq + 13, // 24: cnquery.providers.v1.ProviderPlugin.Heartbeat:output_type -> cnquery.providers.v1.HeartbeatRes + 1, // 25: cnquery.providers.v1.ProviderPlugin.ParseCLI:output_type -> cnquery.providers.v1.ParseCLIRes + 3, // 26: cnquery.providers.v1.ProviderPlugin.Connect:output_type -> cnquery.providers.v1.ConnectRes + 15, // 27: cnquery.providers.v1.ProviderPlugin.Disconnect:output_type -> cnquery.providers.v1.DisconnectRes + 3, // 28: cnquery.providers.v1.ProviderPlugin.MockConnect:output_type -> cnquery.providers.v1.ConnectRes + 5, // 29: cnquery.providers.v1.ProviderPlugin.Shutdown:output_type -> cnquery.providers.v1.ShutdownRes + 7, // 30: cnquery.providers.v1.ProviderPlugin.GetData:output_type -> cnquery.providers.v1.DataRes + 11, // 31: cnquery.providers.v1.ProviderPlugin.StoreData:output_type -> cnquery.providers.v1.StoreRes + 8, // 32: cnquery.providers.v1.ProviderCallback.Collect:output_type -> cnquery.providers.v1.CollectRes + 10, // 33: cnquery.providers.v1.ProviderCallback.GetRecording:output_type -> cnquery.providers.v1.ResourceData + 7, // 34: cnquery.providers.v1.ProviderCallback.GetData:output_type -> cnquery.providers.v1.DataRes + 24, // [24:35] is the sub-list for method output_type + 13, // [13:24] is the sub-list for method input_type 13, // [13:13] is the sub-list for extension type_name 13, // [13:13] is the sub-list for extension extendee 0, // [0:13] is the sub-list for field type_name @@ -1204,6 +1302,30 @@ func file_plugin_proto_init() { return nil } } + file_plugin_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DisconnectReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DisconnectRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1211,7 +1333,7 @@ func file_plugin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_plugin_proto_rawDesc, NumEnums: 0, - NumMessages: 17, + NumMessages: 19, NumExtensions: 0, NumServices: 2, }, diff --git a/providers-sdk/v1/plugin/plugin.proto b/providers-sdk/v1/plugin/plugin.proto index c59cf45158..97f6349cc7 100644 --- a/providers-sdk/v1/plugin/plugin.proto +++ b/providers-sdk/v1/plugin/plugin.proto @@ -87,10 +87,19 @@ message HeartbeatRes { } +message DisconnectReq { + uint32 connection = 1; +} + +message DisconnectRes { + +} + service ProviderPlugin { rpc Heartbeat(HeartbeatReq) returns (HeartbeatRes); rpc ParseCLI(ParseCLIReq) returns (ParseCLIRes); rpc Connect(ConnectReq) returns (ConnectRes); + rpc Disconnect(DisconnectReq) returns (DisconnectRes); rpc MockConnect(ConnectReq) returns (ConnectRes); rpc Shutdown(ShutdownReq) returns (ShutdownRes); rpc GetData(DataReq) returns (DataRes); diff --git a/providers-sdk/v1/plugin/plugin_grpc.pb.go b/providers-sdk/v1/plugin/plugin_grpc.pb.go index 1a73f61341..3cd6f3c580 100644 --- a/providers-sdk/v1/plugin/plugin_grpc.pb.go +++ b/providers-sdk/v1/plugin/plugin_grpc.pb.go @@ -25,6 +25,7 @@ const ( ProviderPlugin_Heartbeat_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/Heartbeat" ProviderPlugin_ParseCLI_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/ParseCLI" ProviderPlugin_Connect_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/Connect" + ProviderPlugin_Disconnect_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/Disconnect" ProviderPlugin_MockConnect_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/MockConnect" ProviderPlugin_Shutdown_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/Shutdown" ProviderPlugin_GetData_FullMethodName = "/cnquery.providers.v1.ProviderPlugin/GetData" @@ -38,6 +39,7 @@ type ProviderPluginClient interface { Heartbeat(ctx context.Context, in *HeartbeatReq, opts ...grpc.CallOption) (*HeartbeatRes, error) ParseCLI(ctx context.Context, in *ParseCLIReq, opts ...grpc.CallOption) (*ParseCLIRes, error) Connect(ctx context.Context, in *ConnectReq, opts ...grpc.CallOption) (*ConnectRes, error) + Disconnect(ctx context.Context, in *DisconnectReq, opts ...grpc.CallOption) (*DisconnectRes, error) MockConnect(ctx context.Context, in *ConnectReq, opts ...grpc.CallOption) (*ConnectRes, error) Shutdown(ctx context.Context, in *ShutdownReq, opts ...grpc.CallOption) (*ShutdownRes, error) GetData(ctx context.Context, in *DataReq, opts ...grpc.CallOption) (*DataRes, error) @@ -79,6 +81,15 @@ func (c *providerPluginClient) Connect(ctx context.Context, in *ConnectReq, opts return out, nil } +func (c *providerPluginClient) Disconnect(ctx context.Context, in *DisconnectReq, opts ...grpc.CallOption) (*DisconnectRes, error) { + out := new(DisconnectRes) + err := c.cc.Invoke(ctx, ProviderPlugin_Disconnect_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *providerPluginClient) MockConnect(ctx context.Context, in *ConnectReq, opts ...grpc.CallOption) (*ConnectRes, error) { out := new(ConnectRes) err := c.cc.Invoke(ctx, ProviderPlugin_MockConnect_FullMethodName, in, out, opts...) @@ -122,6 +133,7 @@ type ProviderPluginServer interface { Heartbeat(context.Context, *HeartbeatReq) (*HeartbeatRes, error) ParseCLI(context.Context, *ParseCLIReq) (*ParseCLIRes, error) Connect(context.Context, *ConnectReq) (*ConnectRes, error) + Disconnect(context.Context, *DisconnectReq) (*DisconnectRes, error) MockConnect(context.Context, *ConnectReq) (*ConnectRes, error) Shutdown(context.Context, *ShutdownReq) (*ShutdownRes, error) GetData(context.Context, *DataReq) (*DataRes, error) @@ -142,6 +154,9 @@ func (UnimplementedProviderPluginServer) ParseCLI(context.Context, *ParseCLIReq) func (UnimplementedProviderPluginServer) Connect(context.Context, *ConnectReq) (*ConnectRes, error) { return nil, status.Errorf(codes.Unimplemented, "method Connect not implemented") } +func (UnimplementedProviderPluginServer) Disconnect(context.Context, *DisconnectReq) (*DisconnectRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method Disconnect not implemented") +} func (UnimplementedProviderPluginServer) MockConnect(context.Context, *ConnectReq) (*ConnectRes, error) { return nil, status.Errorf(codes.Unimplemented, "method MockConnect not implemented") } @@ -221,6 +236,24 @@ func _ProviderPlugin_Connect_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _ProviderPlugin_Disconnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DisconnectReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderPluginServer).Disconnect(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ProviderPlugin_Disconnect_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderPluginServer).Disconnect(ctx, req.(*DisconnectReq)) + } + return interceptor(ctx, in, info, handler) +} + func _ProviderPlugin_MockConnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ConnectReq) if err := dec(in); err != nil { @@ -312,6 +345,10 @@ var ProviderPlugin_ServiceDesc = grpc.ServiceDesc{ MethodName: "Connect", Handler: _ProviderPlugin_Connect_Handler, }, + { + MethodName: "Disconnect", + Handler: _ProviderPlugin_Disconnect_Handler, + }, { MethodName: "MockConnect", Handler: _ProviderPlugin_MockConnect_Handler, diff --git a/providers-sdk/v1/plugin/runtime.go b/providers-sdk/v1/plugin/runtime.go index f44a7741c1..e4b926a497 100644 --- a/providers-sdk/v1/plugin/runtime.go +++ b/providers-sdk/v1/plugin/runtime.go @@ -18,12 +18,22 @@ type Runtime struct { Callback ProviderCallback HasRecording bool CreateResource CreateNamedResource + NewResource NewResource + GetData GetData + SetData SetData Upstream *upstream.UpstreamClient } -type Connection interface{} +type Connection interface { + ID() uint32 +} -type CreateNamedResource func(runtime *Runtime, name string, args map[string]*llx.RawData) (Resource, error) +type ( + CreateNamedResource func(runtime *Runtime, name string, args map[string]*llx.RawData) (Resource, error) + NewResource func(runtime *Runtime, name string, args map[string]*llx.RawData) (Resource, error) + GetData func(resource Resource, field string, args map[string]*llx.RawData) *DataRes + SetData func(resource Resource, field string, val *llx.RawData) error +) type Resource interface { MqlID() string diff --git a/providers-sdk/v1/plugin/service.go b/providers-sdk/v1/plugin/service.go index ee2fda3e65..96f02f176a 100644 --- a/providers-sdk/v1/plugin/service.go +++ b/providers-sdk/v1/plugin/service.go @@ -6,33 +6,178 @@ package plugin import ( "errors" "os" + "strconv" + "strings" sync "sync" "time" + + llx "go.mondoo.com/cnquery/v10/llx" ) type Service struct { + runtimes map[uint32]*Runtime + lastConnectionID uint32 + runtimesLock sync.Mutex + lastHeartbeat int64 - lock sync.Mutex + heartbeatLock sync.Mutex +} + +func NewService() *Service { + return &Service{ + runtimes: make(map[uint32]*Runtime), + } } var heartbeatRes HeartbeatRes +func (s *Service) AddRuntime(createRuntime func(connId uint32) (*Runtime, error)) (*Runtime, error) { + s.runtimesLock.Lock() + defer s.runtimesLock.Unlock() + + s.lastConnectionID++ + runtime, err := createRuntime(s.lastConnectionID) + if err != nil { + // If the runtime creation fails, revert the lastConnectionID + s.lastConnectionID-- + return nil, err + } + s.runtimes[s.lastConnectionID] = runtime + return runtime, nil +} + +func (s *Service) GetRuntime(id uint32) (*Runtime, error) { + s.runtimesLock.Lock() + defer s.runtimesLock.Unlock() + if runtime, ok := s.runtimes[id]; ok { + return runtime, nil + } + return nil, errors.New("connection " + strconv.FormatUint(uint64(id), 10) + " not found") +} + +func (s *Service) Disconnect(req *DisconnectReq) (*DisconnectRes, error) { + s.runtimesLock.Lock() + defer s.runtimesLock.Unlock() + s.doDisconnect(req.Connection) + return &DisconnectRes{}, nil +} + +// doDisconnect is a helper function to disconnect a runtime by its ID. It MUST be called +// with a lock on s.runtimesLock. +func (s *Service) doDisconnect(id uint32) { + if runtime, ok := s.runtimes[id]; ok { + // If the runtime implements the Closer interface, we need to call the + // Close function + if closer, ok := runtime.Connection.(Closer); ok { + closer.Close() + } + delete(s.runtimes, id) + } +} + +func (s *Service) GetData(req *DataReq) (*DataRes, error) { + runtime, err := s.GetRuntime(req.Connection) + if err != nil { + return nil, err + } + + args := PrimitiveArgsToRawDataArgs(req.Args, runtime) + + if req.ResourceId == "" && req.Field == "" { + res, err := runtime.NewResource(runtime, req.Resource, args) + if err != nil { + return nil, err + } + + rd := llx.ResourceData(res, res.MqlName()).Result() + return &DataRes{ + Data: rd.Data, + }, nil + } + + resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) + if !ok { + // Note: Since resources are internally always created, there are only very + // few cases where we arrive here: + // 1. The caller is wrong. Possibly a mixup with IDs + // 2. The resource was loaded from a recording, but the field is not + // in the recording. Thus the resource was never created inside the + // plugin. We will attempt to create the resource and see if the field + // can be computed. + if !runtime.HasRecording { + return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") + } + + args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) + if err != nil { + return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) + } + + resource, err = runtime.CreateResource(runtime, req.Resource, args) + if err != nil { + return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) + } + } + + return runtime.GetData(resource, req.Field, args), nil +} + +func (s *Service) StoreData(req *StoreReq) (*StoreRes, error) { + runtime, err := s.GetRuntime(req.Connection) + if err != nil { + return nil, err + } + + var errs []string + for i := range req.Resources { + info := req.Resources[i] + + args, err := ProtoArgsToRawDataArgs(info.Fields) + if err != nil { + errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") + continue + } + + resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) + if !ok { + resource, err = runtime.CreateResource(runtime, info.Name, args) + if err != nil { + errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) + continue + } + + runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) + } + + for k, v := range args { + if err := runtime.SetData(resource, k, v); err != nil { + errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) + } + } + } + + if len(errs) != 0 { + return nil, errors.New(strings.Join(errs, ", ")) + } + return &StoreRes{}, nil +} + func (s *Service) Heartbeat(req *HeartbeatReq) (*HeartbeatRes, error) { if req.Interval == 0 { return nil, errors.New("heartbeat failed, requested interval is 0") } now := time.Now().UnixNano() - s.lock.Lock() + s.heartbeatLock.Lock() s.lastHeartbeat = now - s.lock.Unlock() + s.heartbeatLock.Unlock() go func() { time.Sleep(time.Duration(req.Interval)) - s.lock.Lock() + s.heartbeatLock.Lock() isDead := s.lastHeartbeat == now - s.lock.Unlock() + s.heartbeatLock.Unlock() if isDead { os.Exit(1) @@ -41,3 +186,13 @@ func (s *Service) Heartbeat(req *HeartbeatReq) (*HeartbeatRes, error) { return &heartbeatRes, nil } + +func (s *Service) Shutdown(req *ShutdownReq) (*ShutdownRes, error) { + s.runtimesLock.Lock() + defer s.runtimesLock.Unlock() + + for id := range s.runtimes { + s.doDisconnect(id) + } + return &ShutdownRes{}, nil +} diff --git a/providers-sdk/v1/plugin/service_test.go b/providers-sdk/v1/plugin/service_test.go new file mode 100644 index 0000000000..2129218aa2 --- /dev/null +++ b/providers-sdk/v1/plugin/service_test.go @@ -0,0 +1,187 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package plugin + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type TestConnection struct { + id uint32 +} + +func newTestConnection(id uint32) *TestConnection { + return &TestConnection{id: id} +} + +func (c *TestConnection) ID() uint32 { + return c.id +} + +type TestConnectionWithClose struct { + *TestConnection + closed bool +} + +func newTestConnectionWithClose(id uint32) *TestConnectionWithClose { + return &TestConnectionWithClose{TestConnection: newTestConnection(id)} +} + +func (c *TestConnectionWithClose) Close() { + c.closed = true +} + +func TestAddRuntime(t *testing.T) { + s := NewService() + wg := sync.WaitGroup{} + wg.Add(4) + addRuntimes := func() { + defer wg.Done() + for i := 0; i < 50; i++ { + _, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{}, nil + }) + require.NoError(t, err) + } + } + + // Add runtimes concurrently + for i := 0; i < 4; i++ { + go addRuntimes() + } + + // Wait until all runtimes are added + wg.Wait() + + // Vertify that all runtimes are added and the last connectiod ID is correct + assert.Len(t, s.runtimes, 200) + assert.Equal(t, s.lastConnectionID, uint32(200)) +} + +func TestGetRuntime(t *testing.T) { + s := NewService() + + runtime, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnection(connId), + }, nil + }) + require.NoError(t, err) + + // Add some more runtimes + for i := 0; i < 5; i++ { + _, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnection(connId), + }, nil + }) + require.NoError(t, err) + } + + // Retrieve the first runtime + retrievedRuntime, err := s.GetRuntime(runtime.Connection.ID()) + require.NoError(t, err) + assert.Equal(t, runtime, retrievedRuntime) +} + +func TestGetRuntime_DoesNotExist(t *testing.T) { + s := NewService() + + _, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnection(connId), + }, nil + }) + require.NoError(t, err) + + _, err = s.GetRuntime(10) + assert.Error(t, err) + assert.Equal(t, "connection 10 not found", err.Error()) +} + +func TestDisconnect(t *testing.T) { + s := NewService() + + runtime, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnection(connId), + }, nil + }) + require.NoError(t, err) + + assert.Len(t, s.runtimes, 1) + + _, err = s.Disconnect(&DisconnectReq{Connection: runtime.Connection.ID()}) + require.NoError(t, err) + assert.Empty(t, s.runtimes) +} + +func TestDisconnect_Closer(t *testing.T) { + s := NewService() + + runtime, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnectionWithClose(connId), + }, nil + }) + require.NoError(t, err) + + assert.False(t, runtime.Connection.(*TestConnectionWithClose).closed) + assert.Len(t, s.runtimes, 1) + + _, err = s.Disconnect(&DisconnectReq{Connection: runtime.Connection.ID()}) + require.NoError(t, err) + assert.Empty(t, s.runtimes) + + assert.True(t, runtime.Connection.(*TestConnectionWithClose).closed) +} + +func TestShutdown(t *testing.T) { + s := NewService() + + // Add some more runtimes + for i := 0; i < 50; i++ { + _, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnection(connId), + }, nil + }) + require.NoError(t, err) + } + + // Shutdown and verify all runtimes are gone + _, err := s.Shutdown(&ShutdownReq{}) + require.NoError(t, err) + assert.Empty(t, s.runtimes) +} + +func TestShutdown_Closer(t *testing.T) { + s := NewService() + + // Add some more runtimes + runtimes := []*Runtime{} + for i := 0; i < 50; i++ { + runtime, err := s.AddRuntime(func(connId uint32) (*Runtime, error) { + return &Runtime{ + Connection: newTestConnectionWithClose(connId), + }, nil + }) + require.NoError(t, err) + runtimes = append(runtimes, runtime) + } + + // Shutdown and verify all runtimes are gone + _, err := s.Shutdown(&ShutdownReq{}) + require.NoError(t, err) + assert.Empty(t, s.runtimes) + + // Verify that all runtimes are closed + for _, runtime := range runtimes { + assert.True(t, runtime.Connection.(*TestConnectionWithClose).closed) + } +} diff --git a/providers/arista/provider/provider.go b/providers/arista/provider/provider.go index b50b62eddc..4f6b109078 100644 --- a/providers/arista/provider/provider.go +++ b/providers/arista/provider/provider.go @@ -24,15 +24,12 @@ const ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -89,9 +86,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) // Shutdown is automatically called when the shell closes. // It is not necessary to implement this method. // If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") @@ -129,37 +123,38 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.AristaConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewAristaConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewAristaConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + asset.Connections[0].Id = connId + + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.AristaConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.AristaConnection) error { @@ -194,90 +189,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.AristaConnecti asset.PlatformIds = []string{id} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/atlassian/provider/provider.go b/providers/atlassian/provider/provider.go index 23e0c3c1b0..cd486c729e 100644 --- a/providers/atlassian/provider/provider.go +++ b/providers/atlassian/provider/provider.go @@ -5,7 +5,6 @@ package provider import ( "errors" - "strconv" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -22,15 +21,12 @@ const ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -134,13 +130,6 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba }, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (shared.Connection, error) { if len(req.Asset.Connections) == 0 { return nil, errors.New("no connection options for asset") @@ -148,33 +137,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn shared.Connection - var err error - - conn, err = connection.NewConnection(s.lastConnectionID, asset, conf) - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + asset.Connections[0].Id = conn.ID() + + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(shared.Connection), nil } func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error { @@ -186,58 +179,6 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error { return nil } -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - // resource, ok := runtime.Resources[req.Resource+"\x00"+req.ResourceId] - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - return nil, errors.New("not yet implemented") -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } diff --git a/providers/aws/provider/provider.go b/providers/aws/provider/provider.go index 78c9a22f6c..94af458a8a 100644 --- a/providers/aws/provider/provider.go +++ b/providers/aws/provider/provider.go @@ -5,7 +5,6 @@ package provider import ( "errors" - "strconv" "strings" "go.mondoo.com/cnquery/v10/llx" @@ -19,20 +18,16 @@ import ( ) const ( - defaultConnection uint32 = 1 - DefaultConnectionType = "aws" + DefaultConnectionType = "aws" ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -114,22 +109,6 @@ func parseFlagsToOptions(m map[string]*llx.Primitive) map[string]string { return o } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - for i := range s.runtimes { - runtime := s.runtimes[i] - if conn, ok := runtime.Connection.(shared.Connection); ok { - if conn.Type() == awsec2ebsconn.EBSConnectionType { - conn := runtime.Connection.(*awsec2ebsconn.AwsEbsConnection) - conn.Close() - } - } - } - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { if req == nil || req.Asset == nil { return nil, errors.New("no connection data provided") @@ -153,8 +132,8 @@ func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCa } return &plugin.ConnectRes{ - Id: uint32(conn.(shared.Connection).ID()), - Name: conn.(shared.Connection).Name(), + Id: uint32(conn.ID()), + Name: conn.Name(), Asset: asset, Inventory: nil, }, nil @@ -200,58 +179,64 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba }, nil } -func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (plugin.Connection, error) { +func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (shared.Connection, error) { if len(req.Asset.Connections) == 0 { return nil, errors.New("no connection options for asset") } asset := req.Asset conf := asset.Connections[0] - var conn shared.Connection - var err error - - switch conf.Type { - case "mock": - s.lastConnectionID++ - conn = connection.NewMockConnection(s.lastConnectionID, asset, conf) - - case string(awsec2ebsconn.EBSConnectionType): - s.lastConnectionID++ - conn, err = awsec2ebsconn.NewAwsEbsConnection(s.lastConnectionID, conf, asset) - if conn.Asset() != nil && len(conn.Asset().Connections) > 0 && conn.Asset().Connections[0].Options["mounted"] != "" { - // if we've already done all the mounting work, then reassign the connection - // to be the filesystem connection so we use the right connection down the line - fsconn := conn.(*awsec2ebsconn.AwsEbsConnection).FsProvider - conn = fsconn - req.Asset = fsconn.Asset() - req.Asset.Connections[0] = fsconn.Conf - asset = req.Asset - } - default: - s.lastConnectionID++ - conn, err = connection.NewAwsConnection(s.lastConnectionID, asset, conf) - } - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn shared.Connection + var err error + + switch conf.Type { + case "mock": + conn = connection.NewMockConnection(connId, asset, conf) + + case string(awsec2ebsconn.EBSConnectionType): + conn, err = awsec2ebsconn.NewAwsEbsConnection(connId, conf, asset) + if conn.Asset() != nil && len(conn.Asset().Connections) > 0 && conn.Asset().Connections[0].Options["mounted"] != "" { + // if we've already done all the mounting work, then reassign the connection + // to be the filesystem connection so we use the right connection down the line + fsconn := conn.(*awsec2ebsconn.AwsEbsConnection).FsProvider + conn = fsconn + req.Asset = fsconn.Asset() + req.Asset.Connections[0] = fsconn.Conf + asset = req.Asset + } + default: + conn, err = connection.NewAwsConnection(connId, asset, conf) + } if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(shared.Connection), nil } func (s *Service) detect(asset *inventory.Asset, conn plugin.Connection) error { @@ -269,65 +254,14 @@ func (s *Service) detect(asset *inventory.Asset, conn plugin.Connection) error { return nil } -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - return nil, errors.New("not yet implemented") -} - func (s *Service) discover(conn *connection.AwsConnection) (*inventory.Inventory, error) { if conn.Conf.Discover == nil { return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime, conn.Filters) diff --git a/providers/azure/provider/provider.go b/providers/azure/provider/provider.go index 78cde9b016..61fcd1879c 100644 --- a/providers/azure/provider/provider.go +++ b/providers/azure/provider/provider.go @@ -5,8 +5,6 @@ package provider import ( "errors" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -20,19 +18,16 @@ import ( ) const ( - defaultConnection uint32 = 1 - ConnectionType = "azure" + ConnectionType = "azure" ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, + Service: plugin.NewService(), } } @@ -136,21 +131,6 @@ func handleAzureComputeSubcommands(args []string, config *inventory.Config) erro } } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - for i := range s.runtimes { - runtime := s.runtimes[i] - sharedConn := runtime.Connection.(shared.AzureConnection) - if sharedConn.Type() == azureinstancesnapshot.SnapshotConnectionType { - conn := runtime.Connection.(*azureinstancesnapshot.AzureSnapshotConnection) - conn.Close() - } - } - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -193,135 +173,54 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - s.lastConnectionID++ - var conn shared.AzureConnection - var err error - - switch conf.Type { - case string(azureinstancesnapshot.SnapshotConnectionType): - // An AzureSnapshotConnection is a wrapper around a FilesystemConnection - // To make sure the connection is later handled by the os provider, override the type - conf.Type = "filesystem" - s.lastConnectionID++ - conn, err = azureinstancesnapshot.NewAzureSnapshotConnection(s.lastConnectionID, conf, asset) - default: - s.lastConnectionID++ - conn, err = connection.NewAzureConnection(s.lastConnectionID, asset, conf) - } - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn shared.AzureConnection + var err error + + switch conf.Type { + case string(azureinstancesnapshot.SnapshotConnectionType): + // An AzureSnapshotConnection is a wrapper around a FilesystemConnection + // To make sure the connection is later handled by the os provider, override the type + conf.Type = "filesystem" + conn, err = azureinstancesnapshot.NewAzureSnapshotConnection(connId, conf, asset) + default: + conn, err = connection.NewAzureConnection(connId, asset, conf) } - } - - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, - } - - return conn, err -} - -func (s *Service) detect(asset *inventory.Asset, conn shared.AzureConnection) error { - // TODO: what do i put here - return nil -} - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) if err != nil { return nil, err } - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue + return nil, err } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) } - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil + return runtime.Connection.(shared.AzureConnection), nil +} + +func (s *Service) detect(asset *inventory.Asset, conn shared.AzureConnection) error { + // TODO: what do i put here + return nil } func (s *Service) discover(conn shared.AzureConnection) (*inventory.Inventory, error) { @@ -329,10 +228,9 @@ func (s *Service) discover(conn shared.AzureConnection) (*inventory.Inventory, e return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime, conn.Config()) diff --git a/providers/core/provider/provider.go b/providers/core/provider/provider.go index 3938d26681..22dd18ec96 100644 --- a/providers/core/provider/provider.go +++ b/providers/core/provider/provider.go @@ -5,8 +5,6 @@ package provider import ( "errors" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" @@ -18,14 +16,12 @@ import ( const defaultConnection uint32 = 1 type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, + Service: plugin.NewService(), } } @@ -38,23 +34,31 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba return nil, errors.New("no connection data provided") } - var upstream *upstream.UpstreamClient - var err error - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err + connectionId := defaultConnection + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + connectionId = connId + var upstream *upstream.UpstreamClient + var err error + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } } - } - s.lastConnectionID++ - connID := s.lastConnectionID - runtime := &plugin.Runtime{ - Callback: callback, - Upstream: upstream, - HasRecording: req.HasRecording, + return &plugin.Runtime{ + Callback: callback, + Upstream: upstream, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + }, nil + }) + if err != nil { + return nil, err } - s.runtimes[connID] = runtime asset := req.Asset _, err = resources.CreateResource(runtime, "asset", map[string]*llx.RawData{ @@ -85,7 +89,7 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba } return &plugin.ConnectRes{ - Id: connID, + Id: connectionId, Name: "core", }, nil } @@ -93,78 +97,3 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return s.Connect(req, callback) } - -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, req.Resource).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/equinix/provider/provider.go b/providers/equinix/provider/provider.go index 983e4b9325..513ce0f0c4 100644 --- a/providers/equinix/provider/provider.go +++ b/providers/equinix/provider/provider.go @@ -6,8 +6,6 @@ package provider import ( "errors" "os" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -21,15 +19,12 @@ import ( const ConnectionType = "equinix" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -77,13 +72,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -120,37 +108,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.EquinixConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewEquinixConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewEquinixConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.EquinixConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.EquinixConnection) error { @@ -169,90 +157,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.EquinixConnect asset.PlatformIds = []string{id} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/gcp/provider/provider.go b/providers/gcp/provider/provider.go index d16431d128..2e5f784d74 100644 --- a/providers/gcp/provider/provider.go +++ b/providers/gcp/provider/provider.go @@ -6,8 +6,6 @@ package provider import ( "errors" "os" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/providers-sdk/v1/vault" @@ -26,15 +24,12 @@ const ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -174,22 +169,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - for i := range s.runtimes { - runtime := s.runtimes[i] - // FIXME: I think, we might need the asset here to cleanup the correct connection - sharedConn := runtime.Connection.(shared.GcpConnection) - if sharedConn.Type() == gcpinstancesnapshot.SnapshotConnectionType { - conn := runtime.Connection.(*gcpinstancesnapshot.GcpSnapshotConnection) - conn.Close() - } - } - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -229,43 +208,50 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn shared.GcpConnection - var err error - - switch conf.Type { - case string(gcpinstancesnapshot.SnapshotConnectionType): - // A GcpSnapshotConnection is a wrapper around a FilesystemConnection - // To make sure the connection is later handled by the os provider, override the type - conf.Type = "filesystem" - s.lastConnectionID++ - conn, err = gcpinstancesnapshot.NewGcpSnapshotConnection(s.lastConnectionID, conf, asset) - default: - s.lastConnectionID++ - conn, err = connection.NewGcpConnection(s.lastConnectionID, asset, conf) - } - if err != nil { - return nil, err - } + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn shared.GcpConnection + var err error + + switch conf.Type { + case string(gcpinstancesnapshot.SnapshotConnectionType): + // A GcpSnapshotConnection is a wrapper around a FilesystemConnection + // To make sure the connection is later handled by the os provider, override the type + conf.Type = "filesystem" + conn, err = gcpinstancesnapshot.NewGcpSnapshotConnection(connId, conf, asset) + default: + conn, err = connection.NewGcpConnection(connId, asset, conf) + } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(shared.GcpConnection), nil } func (s *Service) discover(conn shared.GcpConnection) (*inventory.Inventory, error) { @@ -273,98 +259,10 @@ func (s *Service) discover(conn shared.GcpConnection) (*inventory.Inventory, err return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime) } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/github/provider/provider.go b/providers/github/provider/provider.go index 19511ff90a..6dfa3078c6 100644 --- a/providers/github/provider/provider.go +++ b/providers/github/provider/provider.go @@ -6,7 +6,6 @@ package provider import ( "errors" "os" - "strconv" "strings" "go.mondoo.com/cnquery/v10/llx" @@ -21,15 +20,12 @@ import ( const ConnectionType = "github" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -92,13 +88,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -139,37 +128,38 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.GithubConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewGithubConnection(s.lastConnectionID, asset, conf) - } - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewGithubConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.GithubConnection), err } func (s *Service) detect(asset *inventory.Asset, conn *connection.GithubConnection) error { @@ -201,102 +191,14 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.GithubConnecti return nil } -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} - func (s *Service) discover(conn *connection.GithubConnection) (*inventory.Inventory, error) { if conn.Conf.Discover == nil { return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime, conn.Conf.Options) diff --git a/providers/gitlab/provider/provider.go b/providers/gitlab/provider/provider.go index 18e6bc0f3b..75930f81a5 100644 --- a/providers/gitlab/provider/provider.go +++ b/providers/gitlab/provider/provider.go @@ -7,7 +7,6 @@ import ( "errors" "os" "strconv" - "strings" "github.com/xanzy/go-gitlab" "go.mondoo.com/cnquery/v10/llx" @@ -34,15 +33,12 @@ const ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -104,13 +100,6 @@ func parseDiscover(flags map[string]*llx.Primitive) *inventory.Discovery { return &inventory.Discovery{Targets: targets} } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -152,37 +141,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.GitLabConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewGitLabConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewGitLabConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.GitLabConnection), nil } var ( @@ -261,90 +250,3 @@ func (s *Service) detectAsGroup(asset *inventory.Asset, group *gitlab.Group) err } return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/google-workspace/provider/provider.go b/providers/google-workspace/provider/provider.go index 94324ddbf2..3ddc3a8ea0 100644 --- a/providers/google-workspace/provider/provider.go +++ b/providers/google-workspace/provider/provider.go @@ -6,8 +6,6 @@ package provider import ( "errors" "os" - "strconv" - "strings" "github.com/rs/zerolog/log" "go.mondoo.com/cnquery/v10/llx" @@ -22,15 +20,12 @@ import ( const ConnectionType = "google-workspace" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -128,13 +123,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -171,36 +159,36 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.GoogleWorkspaceConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewGoogleWorkspaceConnection(s.lastConnectionID, asset, conf) - } - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewGoogleWorkspaceConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, - } + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } - return conn, err + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err + } + return runtime.Connection.(*connection.GoogleWorkspaceConnection), err } func (s *Service) detect(asset *inventory.Asset, conn *connection.GoogleWorkspaceConnection) error { @@ -217,90 +205,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.GoogleWorkspac asset.PlatformIds = []string{"//platformid.api.mondoo.app/runtime/googleworkspace/customer/" + conn.CustomerID()} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/ipmi/provider/provider.go b/providers/ipmi/provider/provider.go index 63edf44b9c..0bf0bd7b6a 100644 --- a/providers/ipmi/provider/provider.go +++ b/providers/ipmi/provider/provider.go @@ -22,15 +22,12 @@ import ( const ConnectionType = "ipmi" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -85,13 +82,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -128,37 +118,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.IpmiConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewIpmiConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewIpmiConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.IpmiConnection), err } func (s *Service) detect(asset *inventory.Asset, conn *connection.IpmiConnection) error { @@ -178,90 +168,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.IpmiConnection asset.PlatformIds = []string{conn.Identifier()} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/k8s/connection/admission/connection.go b/providers/k8s/connection/admission/connection.go index 18de451884..1a16f03907 100644 --- a/providers/k8s/connection/admission/connection.go +++ b/providers/k8s/connection/admission/connection.go @@ -26,6 +26,7 @@ type Connection struct { // func newManifestProvider(selectedResourceID string, objectKind string, opts ...Option) (KubernetesProvider, error) { func NewConnection(id uint32, asset *inventory.Asset, data string) (shared.Connection, error) { c := &Connection{ + id: id, asset: asset, namespace: asset.Connections[0].Options[shared.OPTION_NAMESPACE], } diff --git a/providers/k8s/connection/api/connection.go b/providers/k8s/connection/api/connection.go index 51e2d92c4c..8936e9297b 100644 --- a/providers/k8s/connection/api/connection.go +++ b/providers/k8s/connection/api/connection.go @@ -125,6 +125,10 @@ func buildConfigFromFlags(masterUrl, kubeconfigPath string, context string) (*re &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}, CurrentContext: context}).ClientConfig() } +func (c *Connection) SetID(id uint32) { + c.id = id +} + func (c *Connection) ID() uint32 { return c.id } diff --git a/providers/k8s/connection/manifest/connection.go b/providers/k8s/connection/manifest/connection.go index 7631c06043..e9dce2dc7b 100644 --- a/providers/k8s/connection/manifest/connection.go +++ b/providers/k8s/connection/manifest/connection.go @@ -51,6 +51,7 @@ type Connection struct { // func newManifestProvider(selectedResourceID string, objectKind string, opts ...Option) (KubernetesProvider, error) { func NewConnection(id uint32, asset *inventory.Asset, opts ...Option) (shared.Connection, error) { c := &Connection{ + id: id, asset: asset, namespace: asset.Connections[0].Options[shared.OPTION_NAMESPACE], } diff --git a/providers/k8s/connection/shared/connection.go b/providers/k8s/connection/shared/connection.go index 87cfd981fd..6f0e705ebc 100644 --- a/providers/k8s/connection/shared/connection.go +++ b/providers/k8s/connection/shared/connection.go @@ -8,6 +8,7 @@ import ( "strings" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v10/providers/k8s/connection/shared/resources" admissionv1 "k8s.io/api/admission/v1" v1 "k8s.io/api/core/v1" @@ -29,6 +30,7 @@ const ( type ConnectionType string type Connection interface { + plugin.Connection ID() uint32 Name() string Runtime() string diff --git a/providers/k8s/provider/provider.go b/providers/k8s/provider/provider.go index 0bf06278a8..5560b62a72 100644 --- a/providers/k8s/provider/provider.go +++ b/providers/k8s/provider/provider.go @@ -5,8 +5,6 @@ package provider import ( "errors" - "strconv" - "strings" "go.mondoo.com/cnquery/v10" "go.mondoo.com/cnquery/v10/llx" @@ -24,17 +22,15 @@ import ( const ConnectionType = "k8s" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 - discoveryCache *connectionResources.DiscoveryCache + *plugin.Service + + discoveryCache *connectionResources.DiscoveryCache } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, - discoveryCache: connectionResources.NewDiscoveryCache(), + Service: plugin.NewService(), + discoveryCache: connectionResources.NewDiscoveryCache(), } } @@ -99,13 +95,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &res, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -147,53 +136,57 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn shared.Connection - var err error - if manifestContent, ok := conf.Options[shared.OPTION_IMMEMORY_CONTENT]; ok { - s.lastConnectionID++ - conn, err = manifest.NewConnection(s.lastConnectionID, asset, manifest.WithManifestContent([]byte(manifestContent))) - if err != nil { - return nil, err - } - } else if manifestFile, ok := conf.Options[shared.OPTION_MANIFEST]; ok { - s.lastConnectionID++ - conn, err = manifest.NewConnection(s.lastConnectionID, asset, manifest.WithManifestFile(manifestFile)) - if err != nil { - return nil, err - } - } else if data, ok := conf.Options[shared.OPTION_ADMISSION]; ok { - s.lastConnectionID++ - conn, err = admission.NewConnection(s.lastConnectionID, asset, data) - if err != nil { - return nil, err - } - } else { - s.lastConnectionID++ - conn, err = api.NewConnection(s.lastConnectionID, asset, s.discoveryCache) - if err != nil { - return nil, err + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn shared.Connection + var err error + if manifestContent, ok := conf.Options[shared.OPTION_IMMEMORY_CONTENT]; ok { + conn, err = manifest.NewConnection(connId, asset, manifest.WithManifestContent([]byte(manifestContent))) + if err != nil { + return nil, err + } + } else if manifestFile, ok := conf.Options[shared.OPTION_MANIFEST]; ok { + conn, err = manifest.NewConnection(connId, asset, manifest.WithManifestFile(manifestFile)) + if err != nil { + return nil, err + } + } else if data, ok := conf.Options[shared.OPTION_ADMISSION]; ok { + conn, err = admission.NewConnection(connId, asset, data) + if err != nil { + return nil, err + } + } else { + conn, err = api.NewConnection(connId, asset, s.discoveryCache) + if err != nil { + return nil, err + } } - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } } + asset.Connections[0].Id = connId + + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, - } - - return conn, err + return runtime.Connection.(shared.Connection), nil } func (s *Service) discover(conn shared.Connection, features cnquery.Features) (*inventory.Inventory, error) { @@ -201,98 +194,10 @@ func (s *Service) discover(conn shared.Connection, features cnquery.Features) (* return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime, features) } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/k8s/provider/provider_test.go b/providers/k8s/provider/provider_test.go index a590cac25c..290aabe70b 100644 --- a/providers/k8s/provider/provider_test.go +++ b/providers/k8s/provider/provider_test.go @@ -16,13 +16,10 @@ import ( func newTestService(t *testing.T, path string) (*Service, *plugin.ConnectRes) { srv := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } - callbacks := &providerCallbacks{ - runtime: srv.runtimes[0], - } + callbacks := &providerCallbacks{} resp, err := srv.Connect(&plugin.ConnectReq{ Asset: &inventory.Asset{ diff --git a/providers/mock.go b/providers/mock.go index 10fb847ec0..79a5819518 100644 --- a/providers/mock.go +++ b/providers/mock.go @@ -97,6 +97,11 @@ func (s *mockProviderService) MockConnect(req *plugin.ConnectReq, callback plugi return nil, errors.New("the mock provider does not support the mock connect call, this is an internal error") } +func (s *mockProviderService) Disconnect(req *plugin.DisconnectReq) (*plugin.DisconnectRes, error) { + // Nothing to do yet... + return nil, nil +} + func (s *mockProviderService) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { // Nothing to do yet... return nil, nil diff --git a/providers/ms365/provider/provider.go b/providers/ms365/provider/provider.go index 9768dbfd03..164a22c987 100644 --- a/providers/ms365/provider/provider.go +++ b/providers/ms365/provider/provider.go @@ -5,10 +5,7 @@ package provider import ( "errors" - "strconv" - "strings" - "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v10/providers-sdk/v1/upstream" @@ -18,19 +15,16 @@ import ( ) const ( - defaultConnection uint32 = 1 - ConnectionType = "ms365" + ConnectionType = "ms365" ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, + Service: plugin.NewService(), } } @@ -78,13 +72,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -128,30 +115,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - s.lastConnectionID++ - conn, err := connection.NewMs365Connection(s.lastConnectionID, asset, conf) - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewMs365Connection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.Ms365Connection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.Ms365Connection) error { @@ -167,100 +161,14 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.Ms365Connectio return nil } -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } else { - if err := resources.SetAllData(resource, args); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} - func (s *Service) discover(conn *connection.Ms365Connection, conf *inventory.Config) (*inventory.Inventory, error) { if conn.Conf.Discover == nil { return nil, nil } - _, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + _, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } identifier := conn.PlatformId() diff --git a/providers/network/provider/provider.go b/providers/network/provider/provider.go index 2e2f2bd569..4109d81b49 100644 --- a/providers/network/provider/provider.go +++ b/providers/network/provider/provider.go @@ -6,10 +6,8 @@ package provider import ( "errors" "net/url" - "strconv" "strings" - "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v10/providers-sdk/v1/upstream" @@ -19,19 +17,16 @@ import ( ) const ( - defaultConnection uint32 = 1 - HostConnectionType = "host" + HostConnectionType = "host" ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, + Service: plugin.NewService(), } } @@ -103,13 +98,6 @@ func parseTarget(target string) (string, int, string, string, error) { return host, port, scheme, path, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -148,57 +136,60 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.HostConnection - var err error - - switch conf.Type { - case HostConnectionType: - s.lastConnectionID++ - conn = connection.NewHostConnection(s.lastConnectionID, asset, conf) - - default: - // generic host connection, without anything else - s.lastConnectionID++ - conn = connection.NewHostConnection(s.lastConnectionID, asset, conf) - } - if conn.Conf.Options != nil && conn.Conf.Options["host"] != "" { - target := conn.Conf.Options["host"] - host, port, scheme, path, err := parseTarget(target) - if err != nil { - return nil, err + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn *connection.HostConnection + + switch conf.Type { + case HostConnectionType: + conn = connection.NewHostConnection(connId, asset, conf) + + default: + // generic host connection, without anything else + conn = connection.NewHostConnection(connId, asset, conf) } - conn.Conf.Host = host - conn.Conf.Path = path - conn.Conf.Port = int32(port) - conn.Conf.Runtime = scheme - } - if err != nil { - return nil, err - } + if conn.Conf.Options != nil && conn.Conf.Options["host"] != "" { + target := conn.Conf.Options["host"] + host, port, scheme, path, err := parseTarget(target) + if err != nil { + return nil, err + } + conn.Conf.Host = host + conn.Conf.Path = path + conn.Conf.Port = int32(port) + conn.Conf.Runtime = scheme + } - conf.Backend = inventory.ProviderType_HOST - conf.Kind = inventory.DeprecatedV8_Kind_KIND_NETWORK + conf.Backend = inventory.ProviderType_HOST + conf.Kind = inventory.DeprecatedV8_Kind_KIND_NETWORK - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err + var upstream *upstream.UpstreamClient + var err error + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.HostConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.HostConnection) error { @@ -220,90 +211,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.HostConnection return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/oci/provider/provider.go b/providers/oci/provider/provider.go index ff46daa0ed..d2ebe411a0 100644 --- a/providers/oci/provider/provider.go +++ b/providers/oci/provider/provider.go @@ -7,8 +7,6 @@ import ( "context" "errors" "fmt" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/providers-sdk/v1/vault" @@ -23,15 +21,12 @@ import ( const ConnectionType = "oci" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -105,13 +100,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -148,37 +136,38 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.OciConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewOciConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewOciConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.OciConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.OciConnection) error { @@ -204,90 +193,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.OciConnection) asset.PlatformIds = []string{platformID} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/okta/provider/provider.go b/providers/okta/provider/provider.go index e5885e8ba6..36c1832c77 100644 --- a/providers/okta/provider/provider.go +++ b/providers/okta/provider/provider.go @@ -6,7 +6,6 @@ package provider import ( "errors" "os" - "strconv" "strings" "go.mondoo.com/cnquery/v10/llx" @@ -21,15 +20,12 @@ import ( const ConnectionType = "okta" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -85,13 +81,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -128,37 +117,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.OktaConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewOktaConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewOktaConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.OktaConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.OktaConnection) error { @@ -178,90 +167,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.OktaConnection asset.PlatformIds = []string{"//platformid.api.mondoo.app/runtime/okta/organization/" + id} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/opcua/provider/provider.go b/providers/opcua/provider/provider.go index c12f22a2f8..ab2450caca 100644 --- a/providers/opcua/provider/provider.go +++ b/providers/opcua/provider/provider.go @@ -5,8 +5,6 @@ package provider import ( "errors" - "strconv" - "strings" "github.com/mozillazg/go-slugify" "go.mondoo.com/cnquery/v10/llx" @@ -20,15 +18,12 @@ import ( const ConnectionType = "opcua" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -60,13 +55,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -103,37 +91,37 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.OpcuaConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewOpcuaConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewOpcuaConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.OpcuaConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.OpcuaConnection) error { @@ -151,90 +139,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.OpcuaConnectio asset.PlatformIds = []string{"//platformid.api.mondoo.app/runtime/opcua/" + slugify.Slugify(endpoint)} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/os/connection/docker_container.go b/providers/os/connection/docker_container.go index c8d434ad08..9966dfcbdd 100644 --- a/providers/os/connection/docker_container.go +++ b/providers/os/connection/docker_container.go @@ -70,6 +70,7 @@ func NewDockerContainerConnection(id uint32, conf *inventory.Config, asset *inve } conn := &DockerContainerConnection{ + id: id, asset: asset, Client: dockerClient, container: conf.Host, diff --git a/providers/os/connection/local/statutil/stat_test.go b/providers/os/connection/local/statutil/stat_test.go index 391113eaf2..c06a4522ba 100644 --- a/providers/os/connection/local/statutil/stat_test.go +++ b/providers/os/connection/local/statutil/stat_test.go @@ -18,7 +18,7 @@ import ( func TestLinuxStatCmd(t *testing.T) { filepath, _ := filepath.Abs("./testdata/linux.toml") - p, err := mock.New(filepath, nil) + p, err := mock.New(0, filepath, nil) require.NoError(t, err) statHelper := New(p) @@ -45,7 +45,7 @@ func TestLinuxStatCmd(t *testing.T) { func TestOpenbsdStatCmd(t *testing.T) { filepath, _ := filepath.Abs("./testdata/openbsd.toml") - p, err := mock.New(filepath, nil) + p, err := mock.New(0, filepath, nil) require.NoError(t, err) statHelper := New(p) @@ -65,7 +65,7 @@ func TestOpenbsdStatCmd(t *testing.T) { func TestAixStatCmd(t *testing.T) { filepath, _ := filepath.Abs("./testdata/aix.toml") - p, err := mock.New(filepath, nil) + p, err := mock.New(0, filepath, nil) require.NoError(t, err) statHelper := New(p) diff --git a/providers/os/connection/mock/mock.go b/providers/os/connection/mock/mock.go index ab21c61364..d746e83e05 100644 --- a/providers/os/connection/mock/mock.go +++ b/providers/os/connection/mock/mock.go @@ -70,8 +70,9 @@ type Connection struct { missing map[string]map[string]bool } -func New(path string, asset *inventory.Asset) (*Connection, error) { +func New(id uint32, path string, asset *inventory.Asset) (*Connection, error) { res := &Connection{ + uid: id, data: &TomlData{}, asset: asset, missing: map[string]map[string]bool{ diff --git a/providers/os/connection/ssh/cat/cat_test.go b/providers/os/connection/ssh/cat/cat_test.go index 9f7a6e1b72..92c0348dcc 100644 --- a/providers/os/connection/ssh/cat/cat_test.go +++ b/providers/os/connection/ssh/cat/cat_test.go @@ -22,7 +22,7 @@ import ( func TestCatFs(t *testing.T) { filepath, _ := filepath.Abs("./testdata/cat.toml") - p, err := mock.New(filepath, nil) + p, err := mock.New(0, filepath, nil) require.NoError(t, err) flags := map[string]*llx.Primitive{ diff --git a/providers/os/connection/vagrant/cli_test.go b/providers/os/connection/vagrant/cli_test.go index d40f0449fd..fe953bf81c 100644 --- a/providers/os/connection/vagrant/cli_test.go +++ b/providers/os/connection/vagrant/cli_test.go @@ -13,7 +13,7 @@ import ( ) func TestVagrantSshConfigParsing(t *testing.T) { - mock, err := mock.New("./testdata/vagrant.toml", nil) + mock, err := mock.New(0, "./testdata/vagrant.toml", nil) require.NoError(t, err) cmd, err := mock.RunCommand("vagrant ssh-config debian10") @@ -30,7 +30,7 @@ func TestVagrantSshConfigParsing(t *testing.T) { } func TestVagrantStatusParsing(t *testing.T) { - mock, err := mock.New("./testdata/vagrant.toml", nil) + mock, err := mock.New(0, "./testdata/vagrant.toml", nil) require.NoError(t, err) cmd, err := mock.RunCommand("vagrant status") diff --git a/providers/os/connection/winrm/cat/cat_test.go b/providers/os/connection/winrm/cat/cat_test.go index 120014e995..9f37e95459 100644 --- a/providers/os/connection/winrm/cat/cat_test.go +++ b/providers/os/connection/winrm/cat/cat_test.go @@ -16,7 +16,7 @@ import ( func TestCatFs(t *testing.T) { filepath, _ := filepath.Abs("./testdata/winrm.toml") - p, err := mock.New(filepath, nil) + p, err := mock.New(0, filepath, nil) require.NoError(t, err) catfs := cat.New(p) diff --git a/providers/os/detector/detector_platform_test.go b/providers/os/detector/detector_platform_test.go index 8499f98ad6..54847e1e7c 100644 --- a/providers/os/detector/detector_platform_test.go +++ b/providers/os/detector/detector_platform_test.go @@ -5,15 +5,16 @@ package detector import ( "errors" - "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "testing" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" + "github.com/stretchr/testify/assert" "go.mondoo.com/cnquery/v10/providers/os/connection/mock" ) func detectPlatformFromMock(filepath string) (*inventory.Platform, error) { - mockConn, err := mock.New(filepath, nil) + mockConn, err := mock.New(0, filepath, nil) if err != nil { return nil, err } diff --git a/providers/os/id/aws/aws_test.go b/providers/os/id/aws/aws_test.go index defbb4c310..8e46ef3a59 100644 --- a/providers/os/id/aws/aws_test.go +++ b/providers/os/id/aws/aws_test.go @@ -13,7 +13,7 @@ import ( ) func TestDetectInstance(t *testing.T) { - conn, err := mock.New("./testdata/instance.toml", nil) + conn, err := mock.New(0, "./testdata/instance.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -27,7 +27,7 @@ func TestDetectInstance(t *testing.T) { } func TestDetectInstanceArm(t *testing.T) { - conn, err := mock.New("./testdata/instancearm.toml", nil) + conn, err := mock.New(0, "./testdata/instancearm.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -41,7 +41,7 @@ func TestDetectInstanceArm(t *testing.T) { } func TestDetectNotInstance(t *testing.T) { - conn, err := mock.New("./testdata/notinstance.toml", nil) + conn, err := mock.New(0, "./testdata/notinstance.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -55,7 +55,7 @@ func TestDetectNotInstance(t *testing.T) { } func TestDetectConainer(t *testing.T) { - conn, err := mock.New("./testdata/container.toml", nil) + conn, err := mock.New(0, "./testdata/container.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/awsec2/metadata_cmd_test.go b/providers/os/id/awsec2/metadata_cmd_test.go index c2675f4902..fe8d87478f 100644 --- a/providers/os/id/awsec2/metadata_cmd_test.go +++ b/providers/os/id/awsec2/metadata_cmd_test.go @@ -13,7 +13,7 @@ import ( ) func TestEC2RoleProviderInstanceIdentityUnix(t *testing.T) { - conn, err := mock.New("./testdata/instance-identity_document_linux.toml", nil) + conn, err := mock.New(0, "./testdata/instance-identity_document_linux.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -28,7 +28,7 @@ func TestEC2RoleProviderInstanceIdentityUnix(t *testing.T) { } func TestEC2RoleProviderInstanceIdentityUnixNoName(t *testing.T) { - conn, err := mock.New("./testdata/instance-identity_document_linux_no_tags.toml", nil) + conn, err := mock.New(0, "./testdata/instance-identity_document_linux_no_tags.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -43,7 +43,7 @@ func TestEC2RoleProviderInstanceIdentityUnixNoName(t *testing.T) { } func TestEC2RoleProviderInstanceIdentityWindows(t *testing.T) { - conn, err := mock.New("./testdata/instance-identity_document_windows.toml", nil) + conn, err := mock.New(0, "./testdata/instance-identity_document_windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -58,7 +58,7 @@ func TestEC2RoleProviderInstanceIdentityWindows(t *testing.T) { } func TestEC2RoleProviderInstanceIdentityWindowsNoName(t *testing.T) { - conn, err := mock.New("./testdata/instance-identity_document_windows_no_tags.toml", nil) + conn, err := mock.New(0, "./testdata/instance-identity_document_windows_no_tags.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/awsecs/awsecs_test.go b/providers/os/id/awsecs/awsecs_test.go index c86a459a17..099c3e8a16 100644 --- a/providers/os/id/awsecs/awsecs_test.go +++ b/providers/os/id/awsecs/awsecs_test.go @@ -22,7 +22,7 @@ func TestParseECSContainerId(t *testing.T) { } func TestEC2RoleProviderInstanceIdentityUnix(t *testing.T) { - conn, err := mock.New("./testdata/container-identity.toml", nil) + conn, err := mock.New(0, "./testdata/container-identity.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/azcompute/azcompute_test.go b/providers/os/id/azcompute/azcompute_test.go index d3ccb76be3..0c6c91ca37 100644 --- a/providers/os/id/azcompute/azcompute_test.go +++ b/providers/os/id/azcompute/azcompute_test.go @@ -13,7 +13,7 @@ import ( ) func TestCommandProviderLinux(t *testing.T) { - conn, err := mock.New("./testdata/metadata_linux.toml", nil) + conn, err := mock.New(0, "./testdata/metadata_linux.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -27,7 +27,7 @@ func TestCommandProviderLinux(t *testing.T) { } func TestCommandProviderWindows(t *testing.T) { - conn, err := mock.New("./testdata/metadata_windows.toml", nil) + conn, err := mock.New(0, "./testdata/metadata_windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/gce/gce_test.go b/providers/os/id/gce/gce_test.go index 1c1a8ba6bc..ebec7a9d52 100644 --- a/providers/os/id/gce/gce_test.go +++ b/providers/os/id/gce/gce_test.go @@ -14,7 +14,7 @@ import ( ) func TestCommandProviderLinux(t *testing.T) { - conn, err := mock.New("./testdata/metadata_linux.toml", nil) + conn, err := mock.New(0, "./testdata/metadata_linux.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -29,7 +29,7 @@ func TestCommandProviderLinux(t *testing.T) { } func TestCommandProviderWindows(t *testing.T) { - conn, err := mock.New("./testdata/metadata_windows.toml", nil) + conn, err := mock.New(0, "./testdata/metadata_windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/gcp/gcp_test.go b/providers/os/id/gcp/gcp_test.go index 3cf4e06527..475c52f287 100644 --- a/providers/os/id/gcp/gcp_test.go +++ b/providers/os/id/gcp/gcp_test.go @@ -13,7 +13,7 @@ import ( ) func TestDetectLinuxInstance(t *testing.T) { - conn, err := mock.New("./testdata/instance_linux.toml", nil) + conn, err := mock.New(0, "./testdata/instance_linux.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -27,7 +27,7 @@ func TestDetectLinuxInstance(t *testing.T) { } func TestDetectWindowsInstance(t *testing.T) { - conn, err := mock.New("./testdata/instance_windows.toml", nil) + conn, err := mock.New(0, "./testdata/instance_windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -41,7 +41,7 @@ func TestDetectWindowsInstance(t *testing.T) { } func TestNoMatch(t *testing.T) { - conn, err := mock.New("./testdata/aws_instance.toml", nil) + conn, err := mock.New(0, "./testdata/aws_instance.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/hostname/hostname_test.go b/providers/os/id/hostname/hostname_test.go index f1933110f6..9fc77c48d8 100644 --- a/providers/os/id/hostname/hostname_test.go +++ b/providers/os/id/hostname/hostname_test.go @@ -14,7 +14,7 @@ import ( ) func TestHostnameLinuxEtcHostname(t *testing.T) { - conn, err := mock.New("./testdata/hostname_arch.toml", nil) + conn, err := mock.New(0, "./testdata/hostname_arch.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -26,7 +26,7 @@ func TestHostnameLinuxEtcHostname(t *testing.T) { } func TestHostnameLinux(t *testing.T) { - conn, err := mock.New("./testdata/hostname_linux.toml", nil) + conn, err := mock.New(0, "./testdata/hostname_linux.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -38,7 +38,7 @@ func TestHostnameLinux(t *testing.T) { } func TestHostnameLinuxFqdn(t *testing.T) { - conn, err := mock.New("./testdata/hostname_fqdn.toml", nil) + conn, err := mock.New(0, "./testdata/hostname_fqdn.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -50,7 +50,7 @@ func TestHostnameLinuxFqdn(t *testing.T) { } func TestHostnameWindows(t *testing.T) { - conn, err := mock.New("./testdata/hostname_windows.toml", nil) + conn, err := mock.New(0, "./testdata/hostname_windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -62,7 +62,7 @@ func TestHostnameWindows(t *testing.T) { } func TestHostnameMacos(t *testing.T) { - conn, err := mock.New("./testdata/hostname_macos.toml", nil) + conn, err := mock.New(0, "./testdata/hostname_macos.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/id/platformid/linux_test.go b/providers/os/id/platformid/linux_test.go index 0b98f0227b..a7cb3dbde1 100644 --- a/providers/os/id/platformid/linux_test.go +++ b/providers/os/id/platformid/linux_test.go @@ -14,7 +14,7 @@ import ( func TestLinuxMachineId(t *testing.T) { filepath, _ := filepath.Abs("./testdata/linux_test.toml") - provider, err := mock.New(filepath, nil) + provider, err := mock.New(0, filepath, nil) require.NoError(t, err) lid := LinuxIdProvider{connection: provider} diff --git a/providers/os/id/platformid/osx_test.go b/providers/os/id/platformid/osx_test.go index 83f74cd48d..433db78486 100644 --- a/providers/os/id/platformid/osx_test.go +++ b/providers/os/id/platformid/osx_test.go @@ -14,7 +14,7 @@ import ( func TestMacOSMachineId(t *testing.T) { filepath, _ := filepath.Abs("./testdata/osx_test.toml") - provider, err := mock.New(filepath, nil) + provider, err := mock.New(0, filepath, nil) require.NoError(t, err) lid := MacOSIdProvider{connection: provider} diff --git a/providers/os/id/platformid/win_test.go b/providers/os/id/platformid/win_test.go index 53c7bcad52..309a367f21 100644 --- a/providers/os/id/platformid/win_test.go +++ b/providers/os/id/platformid/win_test.go @@ -12,7 +12,7 @@ import ( ) func TestGuidWindows(t *testing.T) { - provider, err := mock.New("./testdata/guid_windows.toml", nil) + provider, err := mock.New(0, "./testdata/guid_windows.toml", nil) require.NoError(t, err) lid := WinIdProvider{connection: provider} diff --git a/providers/os/provider/provider.go b/providers/os/provider/provider.go index 3ad2e0b340..6130d94bde 100644 --- a/providers/os/provider/provider.go +++ b/providers/os/provider/provider.go @@ -29,15 +29,12 @@ import ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -282,19 +279,6 @@ func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCa }, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - for i := range s.runtimes { - runtime := s.runtimes[i] - if x, ok := runtime.Connection.(*connection.TarConnection); ok { - x.CloseFN() - } - } - return &plugin.ShutdownRes{}, nil -} - func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (shared.Connection, error) { if len(req.Asset.Connections) == 0 { return nil, errors.New("no connection options for asset") @@ -302,246 +286,158 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn shared.Connection - var err error - - switch conf.Type { - case shared.Type_Local.String(): - s.lastConnectionID++ - conn = local.NewConnection(s.lastConnectionID, conf, asset) - - fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) - if err == nil { - asset.Name = fingerprint.Name - asset.PlatformIds = fingerprint.PlatformIDs - asset.IdDetector = fingerprint.ActiveIdDetectors - } - case shared.Type_SSH.String(): - s.lastConnectionID++ - conn, err = connection.NewSshConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn shared.Connection + var err error - fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) - if err == nil { - if conn.Asset().Connections[0].Runtime != "vagrant" { + switch conf.Type { + case shared.Type_Local.String(): + conn = local.NewConnection(connId, conf, asset) + + fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + if err == nil { asset.Name = fingerprint.Name + asset.PlatformIds = fingerprint.PlatformIDs + asset.IdDetector = fingerprint.ActiveIdDetectors } - asset.PlatformIds = fingerprint.PlatformIDs - asset.IdDetector = fingerprint.ActiveIdDetectors - } - - case shared.Type_Winrm.String(): - s.lastConnectionID++ - conn, err = connection.NewWinrmConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } - - fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) - if err == nil { - asset.Name = fingerprint.Name - asset.PlatformIds = fingerprint.PlatformIDs - asset.IdDetector = fingerprint.ActiveIdDetectors - } - - case shared.Type_Tar.String(): - s.lastConnectionID++ - conn, err = connection.NewTarConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } - - fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) - if err == nil { - asset.Name = fingerprint.Name - asset.PlatformIds = fingerprint.PlatformIDs - asset.IdDetector = fingerprint.ActiveIdDetectors - } - - case shared.Type_DockerSnapshot.String(): - s.lastConnectionID++ - conn, err = connection.NewDockerSnapshotConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } - - fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) - if err == nil { - asset.Name = fingerprint.Name - asset.PlatformIds = fingerprint.PlatformIDs - asset.IdDetector = fingerprint.ActiveIdDetectors - } - case shared.Type_Vagrant.String(): - s.lastConnectionID++ - conn, err = connection.NewVagrantConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } - // We need to detect the platform for the connection asset here, because - // this platform information will be used to determine the package manager - err := s.detect(conn.Asset(), conn) - if err != nil { - return nil, err - } - - case shared.Type_DockerImage.String(): - s.lastConnectionID++ - conn, err = connection.NewDockerContainerImageConnection(s.lastConnectionID, conf, asset) - - case shared.Type_DockerContainer.String(): - s.lastConnectionID++ - conn, err = connection.NewDockerEngineContainer(s.lastConnectionID, conf, asset) + case shared.Type_SSH.String(): + conn, err = connection.NewSshConnection(connId, conf, asset) + if err != nil { + return nil, err + } - case shared.Type_DockerRegistry.String(), shared.Type_ContainerRegistry.String(): - s.lastConnectionID++ - conn, err = connection.NewContainerRegistryImage(s.lastConnectionID, conf, asset) + fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + if err == nil { + if conn.Asset().Connections[0].Runtime != "vagrant" { + asset.Name = fingerprint.Name + } + asset.PlatformIds = fingerprint.PlatformIDs + asset.IdDetector = fingerprint.ActiveIdDetectors + } - case shared.Type_RegistryImage.String(): - s.lastConnectionID++ - conn, err = connection.NewContainerRegistryImage(s.lastConnectionID, conf, asset) + case shared.Type_Winrm.String(): + conn, err = connection.NewWinrmConnection(connId, conf, asset) + if err != nil { + return nil, err + } - case shared.Type_FileSystem.String(): - s.lastConnectionID++ - conn, err = fs.NewConnection(s.lastConnectionID, conf, asset) - if err != nil { - return nil, err - } - // This is a workaround to set Google COS platform IDs when scanned from inside k8s - pID, err := conn.(*fs.FileSystemConnection).Identifier() - if err != nil { fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) if err == nil { asset.Name = fingerprint.Name asset.PlatformIds = fingerprint.PlatformIDs asset.IdDetector = fingerprint.ActiveIdDetectors } - } else { - // In this case asset.Name should already be set via the inventory - asset.PlatformIds = []string{pID} - } - - // Do not expose mock connection as a supported type - case "mock": - s.lastConnectionID++ - conn, err = mock.New("", asset) - - default: - return nil, errors.New("cannot find connection type " + conf.Type) - } - if err != nil { - return nil, err - } + case shared.Type_Tar.String(): + conn, err = connection.NewTarConnection(connId, conf, asset) + if err != nil { + return nil, err + } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err - } - } + fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + if err == nil { + asset.Name = fingerprint.Name + asset.PlatformIds = fingerprint.PlatformIDs + asset.IdDetector = fingerprint.ActiveIdDetectors + } - conf.Id = conn.ID() - conf.Capabilities = conn.Capabilities().String() + case shared.Type_DockerSnapshot.String(): + conn, err = connection.NewDockerSnapshotConnection(connId, conf, asset) + if err != nil { + return nil, err + } - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, - } + fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + if err == nil { + asset.Name = fingerprint.Name + asset.PlatformIds = fingerprint.PlatformIDs + asset.IdDetector = fingerprint.ActiveIdDetectors + } - return conn, err -} + case shared.Type_Vagrant.String(): + conn, err = connection.NewVagrantConnection(connId, conf, asset) + if err != nil { + return nil, err + } + // We need to detect the platform for the connection asset here, because + // this platform information will be used to determine the package manager + err := s.detect(conn.Asset(), conn) + if err != nil { + return nil, err + } -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } + case shared.Type_DockerImage.String(): + conn, err = connection.NewDockerContainerImageConnection(connId, conf, asset) - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) + case shared.Type_DockerContainer.String(): + conn, err = connection.NewDockerEngineContainer(connId, conf, asset) - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } + case shared.Type_DockerRegistry.String(), shared.Type_ContainerRegistry.String(): + conn, err = connection.NewContainerRegistryImage(connId, conf, asset) - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } + case shared.Type_RegistryImage.String(): + conn, err = connection.NewContainerRegistryImage(connId, conf, asset) - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } + case shared.Type_FileSystem.String(): + conn, err = fs.NewConnection(connId, conf, asset) + if err != nil { + return nil, err + } + // This is a workaround to set Google COS platform IDs when scanned from inside k8s + pID, err := conn.(*fs.FileSystemConnection).Identifier() + if err != nil { + fingerprint, err := id.IdentifyPlatform(conn, asset.Platform, asset.IdDetector) + if err == nil { + asset.Name = fingerprint.Name + asset.PlatformIds = fingerprint.PlatformIDs + asset.IdDetector = fingerprint.ActiveIdDetectors + } + } else { + // In this case asset.Name should already be set via the inventory + asset.PlatformIds = []string{pID} + } - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } + // Do not expose mock connection as a supported type + case "mock": + conn, err = mock.New(connId, "", asset) - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) + default: + return nil, errors.New("cannot find connection type " + conf.Type) } - } - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue + return nil, err } - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } else { - if err := resources.SetAllData(resource, args); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) + return nil, err } } - } - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) + conf.Id = connId + conf.Capabilities = conn.Capabilities().String() + + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return &plugin.StoreRes{}, nil + + return runtime.Connection.(shared.Connection), nil } func (s *Service) discoverRegistry(conn *connection.TarConnection) (*inventory.Inventory, error) { diff --git a/providers/os/provider/provider_test.go b/providers/os/provider/provider_test.go index 8676492134..380a9a5b96 100644 --- a/providers/os/provider/provider_test.go +++ b/providers/os/provider/provider_test.go @@ -20,8 +20,7 @@ import ( func TestLocalConnectionIdDetectors(t *testing.T) { srv := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } connectResp, err := srv.Connect(&plugin.ConnectReq{ @@ -50,8 +49,7 @@ func TestLocalConnectionIdDetectors(t *testing.T) { require.NotNil(t, shutdownconnectResp) srv = &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } connectResp, err = srv.Connect(&plugin.ConnectReq{ Asset: connectResp.Asset, @@ -99,8 +97,7 @@ func TestService_ParseCLI(t *testing.T) { defer os.Remove(file.Name()) s := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } req := &plugin.ParseCLIReq{ diff --git a/providers/os/resources/groups/dscache_test.go b/providers/os/resources/groups/dscache_test.go index 8cc634484f..94530056ae 100644 --- a/providers/os/resources/groups/dscache_test.go +++ b/providers/os/resources/groups/dscache_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseDscacheutilResult(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", nil) + mock, err := mock.New(0, "./testdata/osx.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/groups/etcgroups_test.go b/providers/os/resources/groups/etcgroups_test.go index 0e64d589ac..beb5288fe7 100644 --- a/providers/os/resources/groups/etcgroups_test.go +++ b/providers/os/resources/groups/etcgroups_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseLinuxEtcGroups(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) if err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ func TestParseLinuxEtcGroups(t *testing.T) { } func TestParseFreebsd12EtcGroups(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", nil) + mock, err := mock.New(0, "./testdata/freebsd12.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/groups/manager_test.go b/providers/os/resources/groups/manager_test.go index 8d6250fdf1..c39a13a6c8 100644 --- a/providers/os/resources/groups/manager_test.go +++ b/providers/os/resources/groups/manager_test.go @@ -14,7 +14,7 @@ import ( ) func TestManagerDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "linux", "debian"}, }, @@ -36,7 +36,7 @@ func TestManagerDebian(t *testing.T) { } func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"darwin"}, }, @@ -58,7 +58,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "bsd"}, }, @@ -80,7 +80,7 @@ func TestManagerFreebsd(t *testing.T) { } func TestManagerWindows(t *testing.T) { - mock, err := mock.New("./testdata/windows.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"windows"}, }, diff --git a/providers/os/resources/groups/ps1getlocalgroup_test.go b/providers/os/resources/groups/ps1getlocalgroup_test.go index 0ad58f0ed4..42b6a755b4 100644 --- a/providers/os/resources/groups/ps1getlocalgroup_test.go +++ b/providers/os/resources/groups/ps1getlocalgroup_test.go @@ -13,7 +13,7 @@ import ( ) func TestWindowsGroupsParserFromMock(t *testing.T) { - mock, err := mock.New("./testdata/windows.toml", nil) + mock, err := mock.New(0, "./testdata/windows.toml", nil) require.NoError(t, err) f, err := mock.RunCommand("powershell -c \"Get-LocalGroup | ConvertTo-Json\"") diff --git a/providers/os/resources/kernel/manager_test.go b/providers/os/resources/kernel/manager_test.go index e212cfb421..1a3b33001c 100644 --- a/providers/os/resources/kernel/manager_test.go +++ b/providers/os/resources/kernel/manager_test.go @@ -13,7 +13,7 @@ import ( ) func TestManagerDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "debian", Version: "8.0", @@ -31,7 +31,7 @@ func TestManagerDebian(t *testing.T) { } func TestManagerCentos(t *testing.T) { - mock, err := mock.New("./testdata/centos7.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/centos7.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "centos", Version: "6.10", @@ -57,7 +57,7 @@ func TestManagerCentos(t *testing.T) { } func TestManagerAmazonLinux1(t *testing.T) { - mock, err := mock.New("./testdata/amznlinux1.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/amznlinux1.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Version: "2018.03", @@ -83,7 +83,7 @@ func TestManagerAmazonLinux1(t *testing.T) { } func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", Family: []string{"unix", "darwin"}, @@ -108,7 +108,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "freebsd", Family: []string{"unix"}, diff --git a/providers/os/resources/kernel/modules_test.go b/providers/os/resources/kernel/modules_test.go index e7fe095c79..34a1ae5653 100644 --- a/providers/os/resources/kernel/modules_test.go +++ b/providers/os/resources/kernel/modules_test.go @@ -12,7 +12,7 @@ import ( ) func TestLsmodParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) require.NoError(t, err) f, err := mock.RunCommand("/sbin/lsmod") @@ -31,7 +31,7 @@ func TestLsmodParser(t *testing.T) { } func TestLinuxProcModulesParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/proc/modules") @@ -51,7 +51,7 @@ func TestLinuxProcModulesParser(t *testing.T) { } func TestKldstatParser(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", nil) + mock, err := mock.New(0, "./testdata/freebsd12.toml", nil) require.NoError(t, err) f, err := mock.RunCommand("kldstat") @@ -70,7 +70,7 @@ func TestKldstatParser(t *testing.T) { } func TestKextstatParser(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", nil) + mock, err := mock.New(0, "./testdata/osx.toml", nil) require.NoError(t, err) f, err := mock.RunCommand("kextstat") diff --git a/providers/os/resources/kernel/sysctl_test.go b/providers/os/resources/kernel/sysctl_test.go index 0472b01c2b..bc3a430797 100644 --- a/providers/os/resources/kernel/sysctl_test.go +++ b/providers/os/resources/kernel/sysctl_test.go @@ -12,7 +12,7 @@ import ( ) func TestSysctlDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) require.NoError(t, err) c, err := mock.RunCommand("/sbin/sysctl -a") @@ -26,7 +26,7 @@ func TestSysctlDebian(t *testing.T) { } func TestSysctlMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", nil) + mock, err := mock.New(0, "./testdata/osx.toml", nil) require.NoError(t, err) c, err := mock.RunCommand("sysctl -a") @@ -40,7 +40,7 @@ func TestSysctlMacos(t *testing.T) { } func TestSysctlFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", nil) + mock, err := mock.New(0, "./testdata/freebsd12.toml", nil) require.NoError(t, err) c, err := mock.RunCommand("sysctl -a") diff --git a/providers/os/resources/logindefs/logindefs_test.go b/providers/os/resources/logindefs/logindefs_test.go index 9a768f21b2..6d86db02b3 100644 --- a/providers/os/resources/logindefs/logindefs_test.go +++ b/providers/os/resources/logindefs/logindefs_test.go @@ -13,7 +13,7 @@ import ( ) func TestLoginDefsParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/etc/login.defs") diff --git a/providers/os/resources/macos/preferences_test.go b/providers/os/resources/macos/preferences_test.go index 5c9b609b54..b3f9c91b15 100644 --- a/providers/os/resources/macos/preferences_test.go +++ b/providers/os/resources/macos/preferences_test.go @@ -13,7 +13,7 @@ import ( ) func TestPreferences(t *testing.T) { - mock, err := mock.New("./testdata/user_preferences.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/user_preferences.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", Version: "13.0", diff --git a/providers/os/resources/macos/systemsetup_test.go b/providers/os/resources/macos/systemsetup_test.go index 191fc55f02..b20ce3bf24 100644 --- a/providers/os/resources/macos/systemsetup_test.go +++ b/providers/os/resources/macos/systemsetup_test.go @@ -15,7 +15,7 @@ import ( ) func TestSystemSetup(t *testing.T) { - mock, err := mock.New("./testdata/systemsetup.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/systemsetup.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", Version: "13.0", diff --git a/providers/os/resources/mount/manager_test.go b/providers/os/resources/mount/manager_test.go index ccfa32457a..11c7659bc6 100644 --- a/providers/os/resources/mount/manager_test.go +++ b/providers/os/resources/mount/manager_test.go @@ -14,7 +14,7 @@ import ( ) func TestManagerDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"linux"}}, }) require.NoError(t, err) @@ -28,7 +28,7 @@ func TestManagerDebian(t *testing.T) { } func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"unix"}}, }) require.NoError(t, err) @@ -42,7 +42,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"unix"}}, }) require.NoError(t, err) diff --git a/providers/os/resources/mount/mount_test.go b/providers/os/resources/mount/mount_test.go index d6ecb29683..a9a8613743 100644 --- a/providers/os/resources/mount/mount_test.go +++ b/providers/os/resources/mount/mount_test.go @@ -16,7 +16,7 @@ import ( ) func TestMountLinuxParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"linux"}}, }) require.NoError(t, err) @@ -43,7 +43,7 @@ func TestMountLinuxParser(t *testing.T) { } func TestMountMacosParser(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"unix"}}, }) require.NoError(t, err) @@ -71,7 +71,7 @@ func TestMountMacosParser(t *testing.T) { } func TestMountFreeBsdParser(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"unix"}}, }) require.NoError(t, err) @@ -97,7 +97,7 @@ func TestMountFreeBsdParser(t *testing.T) { } func TestProcModulesParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{Family: []string{"linux"}}, }) require.NoError(t, err) diff --git a/providers/os/resources/networkinterface/interface_test.go b/providers/os/resources/networkinterface/interface_test.go index 411e94e203..8a41fb646c 100644 --- a/providers/os/resources/networkinterface/interface_test.go +++ b/providers/os/resources/networkinterface/interface_test.go @@ -15,7 +15,7 @@ import ( ) func TestWindowsRemoteInterface(t *testing.T) { - mock, err := mock.New("./testdata/windows.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "windows", }, @@ -54,7 +54,7 @@ func TestMacOsRegex(t *testing.T) { } func TestMacOSRemoteInterface(t *testing.T) { - mock, err := mock.New("./testdata/macos.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/macos.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", }, @@ -85,7 +85,7 @@ func TestMacOSRemoteInterface(t *testing.T) { } func TestLinuxRemoteInterface(t *testing.T) { - mock, err := mock.New("./testdata/linux_remote.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/linux_remote.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "linux", Family: []string{"linux"}, @@ -124,7 +124,7 @@ func TestLinuxRemoteInterface(t *testing.T) { } func TestLinuxRemoteInterfaceFlannel(t *testing.T) { - mock, err := mock.New("./testdata/linux_flannel.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/linux_flannel.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "linux", Family: []string{"linux"}, diff --git a/providers/os/resources/packages/apk_packages_test.go b/providers/os/resources/packages/apk_packages_test.go index 26e403a1f5..37600d9d2b 100644 --- a/providers/os/resources/packages/apk_packages_test.go +++ b/providers/os/resources/packages/apk_packages_test.go @@ -4,9 +4,10 @@ package packages_test import ( - "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "testing" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" + "github.com/stretchr/testify/assert" "go.mondoo.com/cnquery/v10/providers/os/connection/mock" "go.mondoo.com/cnquery/v10/providers/os/resources/packages" @@ -23,7 +24,7 @@ func TestAlpineApkdbParser(t *testing.T) { }, } - mock, err := mock.New("./testdata/packages_apk.toml", nil) + mock, err := mock.New(0, "./testdata/packages_apk.toml", nil) if err != nil { t.Fatal(err) } @@ -117,7 +118,7 @@ func TestAlpineApkdbParser(t *testing.T) { } func TestApkUpdateParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_apk.toml", nil) + mock, err := mock.New(0, "./testdata/updates_apk.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/packages/dpkg_packages_test.go b/providers/os/resources/packages/dpkg_packages_test.go index 0e9fe9db8f..0294a532fa 100644 --- a/providers/os/resources/packages/dpkg_packages_test.go +++ b/providers/os/resources/packages/dpkg_packages_test.go @@ -4,9 +4,10 @@ package packages_test import ( - "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "testing" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mondoo.com/cnquery/v10/providers/os/connection/mock" @@ -24,7 +25,7 @@ func TestDpkgParser(t *testing.T) { }, } - mock, err := mock.New("./testdata/packages_dpkg.toml", nil) + mock, err := mock.New(0, "./testdata/packages_dpkg.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/var/lib/dpkg/status") require.NoError(t, err) @@ -86,7 +87,7 @@ func TestDpkgParserStatusD(t *testing.T) { }, } - mock, err := mock.New("./testdata/packages_dpkg_statusd.toml", nil) + mock, err := mock.New(0, "./testdata/packages_dpkg_statusd.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/var/lib/dpkg/status.d/base") require.NoError(t, err) @@ -114,7 +115,7 @@ and the text of several common licenses in use on Debian systems.`, } func TestDpkgUpdateParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_dpkg.toml", nil) + mock, err := mock.New(0, "./testdata/updates_dpkg.toml", nil) require.NoError(t, err) c, err := mock.RunCommand("DEBIAN_FRONTEND=noninteractive apt-get upgrade --dry-run") require.NoError(t, err) diff --git a/providers/os/resources/packages/macos_packages_test.go b/providers/os/resources/packages/macos_packages_test.go index d6c4d6baea..e7475a80b5 100644 --- a/providers/os/resources/packages/macos_packages_test.go +++ b/providers/os/resources/packages/macos_packages_test.go @@ -12,7 +12,7 @@ import ( ) func TestMacOsXPackageParser(t *testing.T) { - mock, err := mock.New("./testdata/packages_macos.toml", nil) + mock, err := mock.New(0, "./testdata/packages_macos.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/packages/opkg_packages_test.go b/providers/os/resources/packages/opkg_packages_test.go index 439c795be0..6b37aac819 100644 --- a/providers/os/resources/packages/opkg_packages_test.go +++ b/providers/os/resources/packages/opkg_packages_test.go @@ -49,7 +49,7 @@ firewall - 2016-11-29-1` } func TestOpkgStatusParser(t *testing.T) { - mock, err := mock.New("./testdata/packages_opkg_statusfile.toml", nil) + mock, err := mock.New(0, "./testdata/packages_opkg_statusfile.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/usr/lib/opkg/status") require.NoError(t, err) @@ -73,7 +73,7 @@ func TestOpkgStatusParser(t *testing.T) { func TestOpkgManager(t *testing.T) { filepath, _ := filepath.Abs("./testdata/packages_opkg.toml") - conn, err := mock.New(filepath, &inventory.Asset{ + conn, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "openwrt", }, diff --git a/providers/os/resources/packages/rpm_packages_test.go b/providers/os/resources/packages/rpm_packages_test.go index 0bbdc66071..a38f7bf986 100644 --- a/providers/os/resources/packages/rpm_packages_test.go +++ b/providers/os/resources/packages/rpm_packages_test.go @@ -6,12 +6,13 @@ package packages_test import ( "bytes" "fmt" - "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" "io" "os" "path/filepath" "testing" + "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" + rpmdb "github.com/knqyf263/go-rpmdb/pkg" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -20,7 +21,7 @@ import ( ) func TestRedhat7Parser(t *testing.T) { - mock, err := mock.New("./testdata/packages_redhat7.toml", nil) + mock, err := mock.New(0, "./testdata/packages_redhat7.toml", nil) if err != nil { t.Fatal(err) } @@ -103,7 +104,7 @@ func TestRedhat7Parser(t *testing.T) { } func TestRedhat6Parser(t *testing.T) { - mock, err := mock.New("./testdata/packages_redhat6.toml", nil) + mock, err := mock.New(0, "./testdata/packages_redhat6.toml", nil) if err != nil { t.Fatal(err) } @@ -177,7 +178,7 @@ func TestRedhat6Parser(t *testing.T) { func TestPhoton4ImageParser(t *testing.T) { // to create this test file, run the following command: // mondoo scan docker image photon:4.0 --record - mock, err := mock.New("./testdata/packages_photon_image.toml", nil) + mock, err := mock.New(0, "./testdata/packages_photon_image.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/packages/rpm_updates_test.go b/providers/os/resources/packages/rpm_updates_test.go index d798ca3c24..a66460f58a 100644 --- a/providers/os/resources/packages/rpm_updates_test.go +++ b/providers/os/resources/packages/rpm_updates_test.go @@ -11,7 +11,7 @@ import ( ) func TestRpmUpdateParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_rpm.toml", nil) + mock, err := mock.New(0, "./testdata/updates_rpm.toml", nil) if err != nil { t.Fatal(err) } @@ -37,7 +37,7 @@ func TestRpmUpdateParser(t *testing.T) { } func TestZypperUpdateParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_zypper.toml", nil) + mock, err := mock.New(0, "./testdata/updates_zypper.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/packages/solaris_packages_test.go b/providers/os/resources/packages/solaris_packages_test.go index e70b81f785..ebe8d28d0e 100644 --- a/providers/os/resources/packages/solaris_packages_test.go +++ b/providers/os/resources/packages/solaris_packages_test.go @@ -88,7 +88,7 @@ pkg://solaris/compress/p7zip@9.20.1,5.11-0.175.1.0.0.24.0:20120904T170605Z i-- func TestSolarisManager(t *testing.T) { filepath, _ := filepath.Abs("./testdata/packages_solaris11.toml") - conn, err := mock.New(filepath, &inventory.Asset{ + conn, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "solaris", }, diff --git a/providers/os/resources/packages/windows_packages_test.go b/providers/os/resources/packages/windows_packages_test.go index 92e3e6ceff..29d6e80962 100644 --- a/providers/os/resources/packages/windows_packages_test.go +++ b/providers/os/resources/packages/windows_packages_test.go @@ -39,7 +39,7 @@ func TestWindowsAppPackagesParser(t *testing.T) { } func TestWindowsAppxPackagesParser(t *testing.T) { - mock, err := mock.New("./testdata/windows_2019.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows_2019.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"windows"}, }, @@ -72,7 +72,7 @@ func TestWindowsAppxPackagesParser(t *testing.T) { } func TestWindowsHotFixParser(t *testing.T) { - mock, err := mock.New("./testdata/windows_2019.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows_2019.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"windows"}, }, diff --git a/providers/os/resources/processes/manager_test.go b/providers/os/resources/processes/manager_test.go index 58648498c6..d334e46c84 100644 --- a/providers/os/resources/processes/manager_test.go +++ b/providers/os/resources/processes/manager_test.go @@ -14,7 +14,7 @@ import ( ) func TestManagerDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"linux", "unix"}, }, @@ -30,7 +30,7 @@ func TestManagerDebian(t *testing.T) { } func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "darwin"}, }, @@ -46,7 +46,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "freebsd"}, }, @@ -62,7 +62,7 @@ func TestManagerFreebsd(t *testing.T) { } // func TestManagerWindows(t *testing.T) { -// mock, err := mock.New("./testdata/windows.toml") +// mock, err := mock.New(0, "./testdata/windows.toml") // require.NoError(t, err) // m, err := motor.New(mock) // require.NoError(t, err) diff --git a/providers/os/resources/processes/unixps_test.go b/providers/os/resources/processes/unixps_test.go index 15ba3b0ddc..d47aa9e8a6 100644 --- a/providers/os/resources/processes/unixps_test.go +++ b/providers/os/resources/processes/unixps_test.go @@ -17,7 +17,7 @@ import ( ) func TestLinuxPSProcessParser(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"linux"}, }, @@ -49,7 +49,7 @@ func TestLinuxPSProcessParser(t *testing.T) { } func TestOSxPSProcessParser(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix"}, }, @@ -77,7 +77,7 @@ func TestOSxPSProcessParser(t *testing.T) { } func TestUnixPSProcessParser(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix"}, }, @@ -105,7 +105,7 @@ func TestUnixPSProcessParser(t *testing.T) { } func TestAixPSProcessParser(t *testing.T) { - mock, err := mock.New("./testdata/aix72.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/aix72.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "aix", Family: []string{"unix"}, diff --git a/providers/os/resources/procfs/cpu_info_test.go b/providers/os/resources/procfs/cpu_info_test.go index 4457dba52f..d8231498dd 100644 --- a/providers/os/resources/procfs/cpu_info_test.go +++ b/providers/os/resources/procfs/cpu_info_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseProcCpuX64(t *testing.T) { - trans, err := mock.New("./testdata/cpu-info-x64.toml", nil) + trans, err := mock.New(0, "./testdata/cpu-info-x64.toml", nil) require.NoError(t, err) f, err := trans.FileSystem().Open("/proc/cpuinfo") @@ -70,7 +70,7 @@ func TestParseProcCpuX64(t *testing.T) { } func TestParseProcCpuArm(t *testing.T) { - trans, err := mock.New("./testdata/cpu-info-aarch64.toml", nil) + trans, err := mock.New(0, "./testdata/cpu-info-aarch64.toml", nil) require.NoError(t, err) f, err := trans.FileSystem().Open("/proc/cpuinfo") diff --git a/providers/os/resources/procfs/processes_test.go b/providers/os/resources/procfs/processes_test.go index 181809ded2..2763943722 100644 --- a/providers/os/resources/procfs/processes_test.go +++ b/providers/os/resources/procfs/processes_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseProcessStatus(t *testing.T) { - trans, err := mock.New("./testdata/process-pid1.toml", nil) + trans, err := mock.New(0, "./testdata/process-pid1.toml", nil) require.NoError(t, err) f, err := trans.FileSystem().Open("/proc/1/status") @@ -27,7 +27,7 @@ func TestParseProcessStatus(t *testing.T) { } func TestParseProcessCmdline(t *testing.T) { - trans, err := mock.New("./testdata/process-pid1.toml", nil) + trans, err := mock.New(0, "./testdata/process-pid1.toml", nil) require.NoError(t, err) f, err := trans.FileSystem().Open("/proc/1/cmdline") diff --git a/providers/os/resources/reboot/debian_test.go b/providers/os/resources/reboot/debian_test.go index 74174b435d..7036d6d6eb 100644 --- a/providers/os/resources/reboot/debian_test.go +++ b/providers/os/resources/reboot/debian_test.go @@ -15,7 +15,7 @@ import ( func TestRebootLinux(t *testing.T) { filepath, _ := filepath.Abs("./testdata/ubuntu_reboot.toml") - provider, err := mock.New(filepath, &inventory.Asset{ + provider, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Family: []string{"linux", "debian", "ubuntu"}, @@ -31,7 +31,7 @@ func TestRebootLinux(t *testing.T) { func TestNoRebootLinux(t *testing.T) { filepath, _ := filepath.Abs("./testdata/ubuntu_noreboot.toml") - provider, err := mock.New(filepath, &inventory.Asset{ + provider, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Family: []string{"linux", "debian", "ubuntu"}, diff --git a/providers/os/resources/reboot/reboot_test.go b/providers/os/resources/reboot/reboot_test.go index 71c0269f4c..e92974aba1 100644 --- a/providers/os/resources/reboot/reboot_test.go +++ b/providers/os/resources/reboot/reboot_test.go @@ -15,7 +15,7 @@ import ( func TestRebootOnUbuntu(t *testing.T) { filepath, _ := filepath.Abs("./testdata/ubuntu_reboot.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Family: []string{"linux", "debian", "ubuntu"}, @@ -33,7 +33,7 @@ func TestRebootOnUbuntu(t *testing.T) { func TestRebootOnRhel(t *testing.T) { filepath, _ := filepath.Abs("./testdata/redhat_kernel_reboot.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "redhat", Family: []string{"linux", "redhat"}, @@ -52,7 +52,7 @@ func TestRebootOnRhel(t *testing.T) { func TestRebootOnWindows(t *testing.T) { filepath, _ := filepath.Abs("./testdata/windows_reboot.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "windows", Family: []string{"windows"}, diff --git a/providers/os/resources/reboot/rhel_test.go b/providers/os/resources/reboot/rhel_test.go index 416b963050..7105b0196f 100644 --- a/providers/os/resources/reboot/rhel_test.go +++ b/providers/os/resources/reboot/rhel_test.go @@ -15,7 +15,7 @@ import ( func TestRhelKernelLatest(t *testing.T) { filepath, _ := filepath.Abs("./testdata/redhat_kernel_reboot.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "redhat", Family: []string{"linux", "redhat"}, @@ -31,7 +31,7 @@ func TestRhelKernelLatest(t *testing.T) { func TestAmznContainerWithoutKernel(t *testing.T) { filepath, _ := filepath.Abs("./testdata/amzn_kernel_container.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Version: "2018.03", @@ -49,7 +49,7 @@ func TestAmznContainerWithoutKernel(t *testing.T) { func TestAmznEc2Kernel(t *testing.T) { filepath, _ := filepath.Abs("./testdata/amzn_kernel_ec2.toml") - mock, err := mock.New(filepath, &inventory.Asset{ + mock, err := mock.New(0, filepath, &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Version: "2018.03", diff --git a/providers/os/resources/services/alpine_openrc_test.go b/providers/os/resources/services/alpine_openrc_test.go index 7f68f8a9fe..43dc847682 100644 --- a/providers/os/resources/services/alpine_openrc_test.go +++ b/providers/os/resources/services/alpine_openrc_test.go @@ -13,7 +13,7 @@ import ( ) func TestManagerAlpineImage(t *testing.T) { - mock, err := mock.New("./testdata/alpine-image.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/alpine-image.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "alpine", }, @@ -45,7 +45,7 @@ func TestManagerAlpineImage(t *testing.T) { } func TestManagerAlpineContainer(t *testing.T) { - mock, err := mock.New("./testdata/alpine-container.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/alpine-container.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "alpine", }, diff --git a/providers/os/resources/services/bsdinit_test.go b/providers/os/resources/services/bsdinit_test.go index f502d3dd43..b890610c17 100644 --- a/providers/os/resources/services/bsdinit_test.go +++ b/providers/os/resources/services/bsdinit_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseBsdInit(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "freebsd", Family: []string{"unix"}, diff --git a/providers/os/resources/services/launchd_test.go b/providers/os/resources/services/launchd_test.go index ea8c46038b..0ee35869a8 100644 --- a/providers/os/resources/services/launchd_test.go +++ b/providers/os/resources/services/launchd_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseServiceLaunchD(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", Family: []string{"unix", "darwin"}, diff --git a/providers/os/resources/services/manager_test.go b/providers/os/resources/services/manager_test.go index 1a26d543c7..bcef7cc426 100644 --- a/providers/os/resources/services/manager_test.go +++ b/providers/os/resources/services/manager_test.go @@ -13,7 +13,7 @@ import ( ) func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "macos", Family: []string{"unix", "darwin"}, @@ -30,7 +30,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "freebsd", Family: []string{"unix"}, @@ -47,7 +47,7 @@ func TestManagerFreebsd(t *testing.T) { } func TestManagerDragonflybsd5(t *testing.T) { - mock, err := mock.New("./testdata/dragonfly5.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/dragonfly5.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "dragonflybsd", Family: []string{"unix"}, @@ -64,7 +64,7 @@ func TestManagerDragonflybsd5(t *testing.T) { } func TestManagerOpenBsd6(t *testing.T) { - mock, err := mock.New("./testdata/openbsd6.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/openbsd6.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "openbsd", Family: []string{"unix"}, @@ -81,7 +81,7 @@ func TestManagerOpenBsd6(t *testing.T) { } func TestManagerWindows(t *testing.T) { - mock, err := mock.New("./testdata/windows2019.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows2019.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "windows", Family: []string{"windows"}, @@ -98,7 +98,7 @@ func TestManagerWindows(t *testing.T) { } func TestManagerUbuntu2204(t *testing.T) { - mock, err := mock.New("./testdata/ubuntu2204.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/ubuntu2204.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Version: "22.04", @@ -116,7 +116,7 @@ func TestManagerUbuntu2204(t *testing.T) { } func TestManagerPhoton(t *testing.T) { - mock, err := mock.New("./testdata/photon.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/photon.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "photon", Version: "8.1.10", diff --git a/providers/os/resources/services/openbsdrcctl_test.go b/providers/os/resources/services/openbsdrcctl_test.go index 17844deb38..9e1e7624fe 100644 --- a/providers/os/resources/services/openbsdrcctl_test.go +++ b/providers/os/resources/services/openbsdrcctl_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseOpenbsdServicesRunning(t *testing.T) { - mock, err := mock.New("./testdata/openbsd6.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/openbsd6.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "openbsd", }, diff --git a/providers/os/resources/services/systemd_test.go b/providers/os/resources/services/systemd_test.go index 1701c9037b..af103313dd 100644 --- a/providers/os/resources/services/systemd_test.go +++ b/providers/os/resources/services/systemd_test.go @@ -45,7 +45,7 @@ Nov 03 06:51:44 mondoopad avahi-daemon[1219]: Registering new address record for } func TestParseServiceSystemDUnitFiles(t *testing.T) { - mock, err := mock.New("./testdata/ubuntu2204.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/ubuntu2204.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Family: []string{"ubuntu", "linux"}, @@ -76,8 +76,9 @@ func TestParseServiceSystemDUnitFiles(t *testing.T) { assert.Equal(t, "cryptdisks", m[30].Name, "service name detected") assert.Equal(t, true, m[30].Masked, "service is masked") } + func TestParseServiceSystemDUnitFilesPhoton(t *testing.T) { - mock, err := mock.New("./testdata/photon.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/photon.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "photon", Family: []string{"redhat", "linux"}, diff --git a/providers/os/resources/services/sysv_test.go b/providers/os/resources/services/sysv_test.go index 92dc8dea08..634b9f3403 100644 --- a/providers/os/resources/services/sysv_test.go +++ b/providers/os/resources/services/sysv_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseSysvServices(t *testing.T) { - mock, err := mock.New("./testdata/amzn1.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/amzn1.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Family: []string{"linux"}, @@ -28,7 +28,7 @@ func TestParseSysvServices(t *testing.T) { } func TestParseSysvServicesRunlevel(t *testing.T) { - mock, err := mock.New("./testdata/amzn1.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/amzn1.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Family: []string{"linux"}, @@ -44,7 +44,7 @@ func TestParseSysvServicesRunlevel(t *testing.T) { } func TestParseSysvServicesRunning(t *testing.T) { - mock, err := mock.New("./testdata/amzn1.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/amzn1.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "amazonlinux", Family: []string{"linux"}, diff --git a/providers/os/resources/services/upstart_test.go b/providers/os/resources/services/upstart_test.go index c7ab7aafd4..05b6dca0df 100644 --- a/providers/os/resources/services/upstart_test.go +++ b/providers/os/resources/services/upstart_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseUpstartServicesRunning(t *testing.T) { - mock, err := mock.New("./testdata/ubuntu1404.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/ubuntu1404.toml", &inventory.Asset{ Platform: &inventory.Platform{ Name: "ubuntu", Family: []string{"linux", "ubuntu"}, diff --git a/providers/os/resources/shadow/shadow_test.go b/providers/os/resources/shadow/shadow_test.go index 88d472cc4c..982efcb51f 100644 --- a/providers/os/resources/shadow/shadow_test.go +++ b/providers/os/resources/shadow/shadow_test.go @@ -14,7 +14,7 @@ import ( ) func TestParseShadow(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) require.NoError(t, err) f, err := mock.FileSystem().Open("/etc/shadow") diff --git a/providers/os/resources/smbios/smbios_test.go b/providers/os/resources/smbios/smbios_test.go index ab11b0986f..9311ca1d85 100644 --- a/providers/os/resources/smbios/smbios_test.go +++ b/providers/os/resources/smbios/smbios_test.go @@ -13,7 +13,7 @@ import ( ) func TestManagerCentos(t *testing.T) { - conn, err := mock.New("./testdata/centos.toml", nil) + conn, err := mock.New(0, "./testdata/centos.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -56,7 +56,7 @@ func TestManagerCentos(t *testing.T) { } func TestManagerMacos(t *testing.T) { - conn, err := mock.New("./testdata/macos.toml", nil) + conn, err := mock.New(0, "./testdata/macos.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) @@ -99,7 +99,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerWindows(t *testing.T) { - conn, err := mock.New("./testdata/windows.toml", nil) + conn, err := mock.New(0, "./testdata/windows.toml", nil) require.NoError(t, err) platform, ok := detector.DetectOS(conn) require.True(t, ok) diff --git a/providers/os/resources/updates/suse_updates_test.go b/providers/os/resources/updates/suse_updates_test.go index 0822dd4066..45f4747c9a 100644 --- a/providers/os/resources/updates/suse_updates_test.go +++ b/providers/os/resources/updates/suse_updates_test.go @@ -13,7 +13,7 @@ import ( // SUSE OS updates func TestZypperPatchParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_zypper.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/updates_zypper.toml", &inventory.Asset{ Platform: &inventory.Platform{Name: "suse"}, }) if err != nil { diff --git a/providers/os/resources/updates/win_updates_test.go b/providers/os/resources/updates/win_updates_test.go index 7e889a8cab..5c01a4b22f 100644 --- a/providers/os/resources/updates/win_updates_test.go +++ b/providers/os/resources/updates/win_updates_test.go @@ -16,7 +16,7 @@ import ( ) func TestWinOSUpdatesParser(t *testing.T) { - mock, err := mock.New("./testdata/updates_win.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/updates_win.toml", &inventory.Asset{ Platform: &inventory.Platform{Name: "windows"}, }) if err != nil { diff --git a/providers/os/resources/uptime/uptime_test.go b/providers/os/resources/uptime/uptime_test.go index 24e06c7499..e9baed41ad 100644 --- a/providers/os/resources/uptime/uptime_test.go +++ b/providers/os/resources/uptime/uptime_test.go @@ -14,7 +14,7 @@ import ( ) func TestUptimeOnLinux(t *testing.T) { - mock, err := mock.New("./testdata/linux.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/linux.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix"}, }, @@ -31,7 +31,7 @@ func TestUptimeOnLinux(t *testing.T) { func TestUptimeOnLinuxLcDecimalDe(t *testing.T) { // LC_NUMERIC=de_DE.UTF-8 on Ubuntu 22.04 - mock, err := mock.New("./testdata/linux_de.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/linux_de.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix"}, }, @@ -47,7 +47,7 @@ func TestUptimeOnLinuxLcDecimalDe(t *testing.T) { } func TestUptimeOnFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix"}, }, @@ -64,7 +64,7 @@ func TestUptimeOnFreebsd(t *testing.T) { } func TestUptimeOnWindows(t *testing.T) { - mock, err := mock.New("./testdata/windows.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"windows"}, }, diff --git a/providers/os/resources/users/dscl_test.go b/providers/os/resources/users/dscl_test.go index d118858978..02c85ce555 100644 --- a/providers/os/resources/users/dscl_test.go +++ b/providers/os/resources/users/dscl_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseDsclListResult(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", nil) + mock, err := mock.New(0, "./testdata/osx.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/users/etcpasswd_test.go b/providers/os/resources/users/etcpasswd_test.go index 980cbeebcb..21f227c06c 100644 --- a/providers/os/resources/users/etcpasswd_test.go +++ b/providers/os/resources/users/etcpasswd_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseLinuxEtcPasswd(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", nil) + mock, err := mock.New(0, "./testdata/debian.toml", nil) if err != nil { t.Fatal(err) } @@ -36,7 +36,7 @@ func TestParseLinuxEtcPasswd(t *testing.T) { } func TestParseFreebsdLinuxEtcPasswd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", nil) + mock, err := mock.New(0, "./testdata/freebsd12.toml", nil) if err != nil { t.Fatal(err) } diff --git a/providers/os/resources/users/manager_test.go b/providers/os/resources/users/manager_test.go index a5e3ee9ded..0689a0cead 100644 --- a/providers/os/resources/users/manager_test.go +++ b/providers/os/resources/users/manager_test.go @@ -14,7 +14,7 @@ import ( ) func TestManagerDebian(t *testing.T) { - mock, err := mock.New("./testdata/debian.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/debian.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "linux", "debian"}, }, @@ -38,7 +38,7 @@ func TestManagerDebian(t *testing.T) { } func TestManagerMacos(t *testing.T) { - mock, err := mock.New("./testdata/osx.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/osx.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"darwin"}, }, @@ -62,7 +62,7 @@ func TestManagerMacos(t *testing.T) { } func TestManagerFreebsd(t *testing.T) { - mock, err := mock.New("./testdata/freebsd12.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/freebsd12.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"unix", "bsd"}, }, @@ -86,7 +86,7 @@ func TestManagerFreebsd(t *testing.T) { } func TestManagerWindows(t *testing.T) { - mock, err := mock.New("./testdata/windows.toml", &inventory.Asset{ + mock, err := mock.New(0, "./testdata/windows.toml", &inventory.Asset{ Platform: &inventory.Platform{ Family: []string{"windows"}, }, diff --git a/providers/os/resources/windows/auditpol_test.go b/providers/os/resources/windows/auditpol_test.go index 3631a09a2c..c70b371449 100644 --- a/providers/os/resources/windows/auditpol_test.go +++ b/providers/os/resources/windows/auditpol_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseAuditpol(t *testing.T) { - mock, err := mock.New("./testdata/auditpol.toml", nil) + mock, err := mock.New(0, "./testdata/auditpol.toml", nil) require.NoError(t, err) f, err := mock.RunCommand("auditpol /get /category:* /r") diff --git a/providers/os/resources/windows/secpol_test.go b/providers/os/resources/windows/secpol_test.go index c3e75a11b3..2f8274ef90 100644 --- a/providers/os/resources/windows/secpol_test.go +++ b/providers/os/resources/windows/secpol_test.go @@ -13,7 +13,7 @@ import ( ) func TestParseSecpol(t *testing.T) { - mock, err := mock.New("./testdata/secpol.toml", nil) + mock, err := mock.New(0, "./testdata/secpol.toml", nil) require.NoError(t, err) encoded := powershell.Encode(SecpolScript) diff --git a/providers/os/resources/yum/yum_test.go b/providers/os/resources/yum/yum_test.go index 7869f036ca..34f0bce00c 100644 --- a/providers/os/resources/yum/yum_test.go +++ b/providers/os/resources/yum/yum_test.go @@ -62,7 +62,7 @@ Repo-filename: /etc/yum.repos.d/CentOS-Media.repo } func TestYumRepoRhel7(t *testing.T) { - mock, err := mock.New("./testdata/yum_rhel7.toml", nil) + mock, err := mock.New(0, "./testdata/yum_rhel7.toml", nil) require.NoError(t, err) cmd, err := mock.RunCommand(RhelYumRepoListCommand) @@ -79,7 +79,7 @@ func TestYumRepoRhel7(t *testing.T) { } func TestYumRepoRhel8(t *testing.T) { - mock, err := mock.New("./testdata/yum_rhel8.toml", nil) + mock, err := mock.New(0, "./testdata/yum_rhel8.toml", nil) require.NoError(t, err) cmd, err := mock.RunCommand(RhelYumRepoListCommand) diff --git a/providers/runtime.go b/providers/runtime.go index 2997581526..928099327c 100644 --- a/providers/runtime.go +++ b/providers/runtime.go @@ -62,13 +62,28 @@ type shutdownResult struct { } func (r *Runtime) tryShutdown() shutdownResult { + for _, provider := range r.providers { + if provider.Connection == nil { + continue + } + _, err := provider.Instance.Plugin.Disconnect(&plugin.DisconnectReq{Connection: provider.Connection.Id}) + if err != nil { + if status, ok := status.FromError(err); ok { + if status.Code() == 12 { + log.Warn().Msg("please update the provider plugin for " + provider.Instance.Name) + continue + } + } + log.Error().Msg("failed to disconnect from provider " + provider.Instance.Name) + } + } + // Ephemeral runtimes have their primary provider be ephemeral, i.e. non-shared. // All other providers are shared and will not be shut down from within the provider. if r.isEphemeral { err := r.coordinator.Stop(r.Provider.Instance, true) return shutdownResult{Error: err} } - return shutdownResult{} } diff --git a/providers/slack/provider/provider.go b/providers/slack/provider/provider.go index f2fd68dba8..7a673c72d1 100644 --- a/providers/slack/provider/provider.go +++ b/providers/slack/provider/provider.go @@ -6,8 +6,6 @@ package provider import ( "errors" "os" - "strconv" - "strings" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -21,15 +19,12 @@ import ( const ConnectionType = "slack" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -62,13 +57,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { if req == nil || req.Asset == nil { return nil, errors.New("no connection data provided") @@ -131,40 +119,46 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.SlackConnection - var err error - - switch conf.Type { - case "mock": - s.lastConnectionID++ - conn = connection.NewMockConnection(s.lastConnectionID, asset, conf) - default: - s.lastConnectionID++ - conn, err = connection.NewSlackConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn *connection.SlackConnection + var err error + + switch conf.Type { + case "mock": + conn = connection.NewMockConnection(connId, asset, conf) + default: + conn, err = connection.NewSlackConnection(connId, asset, conf) + } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.SlackConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.SlackConnection) error { @@ -179,90 +173,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.SlackConnectio asset.PlatformIds = []string{"//platformid.api.mondoo.app/runtime/slack/team/" + conn.TeamID()} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/terraform/connection/hcl_manifest.go b/providers/terraform/connection/hcl_manifest.go index 8a19e580d4..36c59fd818 100644 --- a/providers/terraform/connection/hcl_manifest.go +++ b/providers/terraform/connection/hcl_manifest.go @@ -46,10 +46,10 @@ var MODULE_EXAMPLES = regexp.MustCompile(`^.*/modules/.+/examples/.+`) func NewHclConnection(id uint32, asset *inventory.Asset) (*Connection, error) { cc := asset.Connections[0] path := cc.Options["path"] - return newHclConnection(path, asset) + return newHclConnection(id, path, asset) } -func newHclConnection(path string, asset *inventory.Asset) (*Connection, error) { +func newHclConnection(id uint32, path string, asset *inventory.Asset) (*Connection, error) { // NOTE: right now we are only supporting to load either state, plan or hcl files but not at the same time if len(asset.Connections) != 1 { return nil, errors.New("only one connection is supported") @@ -133,6 +133,7 @@ func newHclConnection(path string, asset *inventory.Asset) (*Connection, error) } return &Connection{ + id: id, asset: asset, assetType: assetType, @@ -190,7 +191,7 @@ func NewHclGitConnection(id uint32, asset *inventory.Asset) (*Connection, error) if err != nil { return nil, err } - conn, err := newHclConnection(path, asset) + conn, err := newHclConnection(id, path, asset) if err != nil { return nil, err } diff --git a/providers/terraform/connection/tfplan.go b/providers/terraform/connection/tfplan.go index 3b27ac09d7..0be7ade6bb 100644 --- a/providers/terraform/connection/tfplan.go +++ b/providers/terraform/connection/tfplan.go @@ -214,6 +214,7 @@ func NewPlanConnection(id uint32, asset *inventory.Asset) (*Connection, error) { } return &Connection{ + id: id, asset: asset, assetType: assetType, diff --git a/providers/terraform/connection/tfstate.go b/providers/terraform/connection/tfstate.go index 0085a9c279..4c3b4fcf81 100644 --- a/providers/terraform/connection/tfstate.go +++ b/providers/terraform/connection/tfstate.go @@ -101,6 +101,7 @@ func NewStateConnection(id uint32, asset *inventory.Asset) (*Connection, error) } return &Connection{ + id: id, asset: asset, assetType: assetType, diff --git a/providers/terraform/provider/provider.go b/providers/terraform/provider/provider.go index 62172d7ad9..e8c50c1f7f 100644 --- a/providers/terraform/provider/provider.go +++ b/providers/terraform/provider/provider.go @@ -5,9 +5,9 @@ package provider import ( "errors" - "github.com/rs/zerolog/log" "strconv" - "strings" + + "github.com/rs/zerolog/log" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -30,15 +30,12 @@ const ( ) type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -101,18 +98,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &res, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - for _, runtime := range s.runtimes { - if conn, ok := runtime.Connection.(*connection.Connection); ok { - conn.Close() - } - } - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -149,145 +134,63 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.Connection - var err error - - switch conf.Type { - case HclConnectionType: - s.lastConnectionID++ - conn, err = connection.NewHclConnection(s.lastConnectionID, asset) - if err != nil { - return nil, err - } - - case StateConnectionType: - s.lastConnectionID++ - conn, err = connection.NewStateConnection(s.lastConnectionID, asset) - if err != nil { - return nil, err - } - - case PlanConnectionType: - s.lastConnectionID++ - conn, err = connection.NewPlanConnection(s.lastConnectionID, asset) - if err != nil { - return nil, err - } - - case HclGitConnectionType: - s.lastConnectionID++ - conn, err = connection.NewHclGitConnection(s.lastConnectionID, asset) - if err != nil { - return nil, err - } - - default: - return nil, errors.New("cannot find connection type " + conf.Type) - } - - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() - if err != nil { - return nil, err - } - } - - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, - } - - return conn, err -} - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - return resources.GetData(resource, req.Field, args), nil -} + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + var conn *connection.Connection + var err error -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } + switch conf.Type { + case HclConnectionType: + conn, err = connection.NewHclConnection(connId, asset) + if err != nil { + return nil, err + } - var errs []string - for i := range req.Resources { - info := req.Resources[i] + case StateConnectionType: + conn, err = connection.NewStateConnection(connId, asset) + if err != nil { + return nil, err + } - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } + case PlanConnectionType: + conn, err = connection.NewPlanConnection(connId, asset) + if err != nil { + return nil, err + } - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) + case HclGitConnectionType: + conn, err = connection.NewHclGitConnection(connId, asset) if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue + return nil, err } - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) + default: + return nil, errors.New("cannot find connection type " + conf.Type) } - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err } } - } - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return &plugin.StoreRes{}, nil + + return runtime.Connection.(*connection.Connection), nil } diff --git a/providers/terraform/provider/terraform_test.go b/providers/terraform/provider/terraform_test.go index 0316521c94..dba7cde5c1 100644 --- a/providers/terraform/provider/terraform_test.go +++ b/providers/terraform/provider/terraform_test.go @@ -10,8 +10,7 @@ import ( func newTestService(connType string, path string) (*Service, *plugin.ConnectRes) { srv := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } if path == "" { diff --git a/providers/vcd/provider/provider.go b/providers/vcd/provider/provider.go index aafd340c1a..fdaa94920d 100644 --- a/providers/vcd/provider/provider.go +++ b/providers/vcd/provider/provider.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "strconv" - "strings" "go.mondoo.com/cnquery/v10/llx" "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory" @@ -21,15 +20,12 @@ import ( const ConnectionType = "vcd" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -76,13 +72,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -119,37 +108,38 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.VcdConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewVcdConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewVcdConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = conn.ID() + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.VcdConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.VcdConnection) error { @@ -178,90 +168,3 @@ func (s *Service) detect(asset *inventory.Asset, conn *connection.VcdConnection) asset.PlatformIds = []string{"//platformid.api.mondoo.app/runtime/vcd/host/" + conn.Conf.Host} return nil } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/vsphere/provider/provider.go b/providers/vsphere/provider/provider.go index 0d8af9569c..72f135990c 100644 --- a/providers/vsphere/provider/provider.go +++ b/providers/vsphere/provider/provider.go @@ -21,15 +21,12 @@ import ( const ConnectionType = "vsphere" type Service struct { - plugin.Service - runtimes map[uint32]*plugin.Runtime - lastConnectionID uint32 + *plugin.Service } func Init() *Service { return &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } } @@ -100,13 +97,6 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) return &plugin.ParseCLIRes{Asset: &asset}, nil } -// Shutdown is automatically called when the shell closes. -// It is not necessary to implement this method. -// If you want to do some cleanup, you can do it here. -func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { - return &plugin.ShutdownRes{}, nil -} - func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { return nil, errors.New("mock connect not yet implemented") } @@ -148,37 +138,38 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba asset := req.Asset conf := asset.Connections[0] - var conn *connection.VsphereConnection - var err error - - switch conf.Type { - default: - s.lastConnectionID++ - conn, err = connection.NewVsphereConnection(s.lastConnectionID, asset, conf) - } - - if err != nil { - return nil, err - } - var upstream *upstream.UpstreamClient - if req.Upstream != nil && !req.Upstream.Incognito { - upstream, err = req.Upstream.InitClient() + runtime, err := s.AddRuntime(func(connId uint32) (*plugin.Runtime, error) { + conn, err := connection.NewVsphereConnection(connId, asset, conf) if err != nil { return nil, err } - } - asset.Connections[0].Id = conn.ID() - s.runtimes[conn.ID()] = &plugin.Runtime{ - Connection: conn, - Callback: callback, - HasRecording: req.HasRecording, - CreateResource: resources.CreateResource, - Upstream: upstream, + var upstream *upstream.UpstreamClient + if req.Upstream != nil && !req.Upstream.Incognito { + upstream, err = req.Upstream.InitClient() + if err != nil { + return nil, err + } + } + + asset.Connections[0].Id = connId + return &plugin.Runtime{ + Connection: conn, + Callback: callback, + HasRecording: req.HasRecording, + CreateResource: resources.CreateResource, + NewResource: resources.NewResource, + GetData: resources.GetData, + SetData: resources.SetData, + Upstream: upstream, + }, nil + }) + if err != nil { + return nil, err } - return conn, err + return runtime.Connection.(*connection.VsphereConnection), nil } func (s *Service) detect(asset *inventory.Asset, conn *connection.VsphereConnection) error { @@ -208,98 +199,10 @@ func (s *Service) discover(conn *connection.VsphereConnection) (*inventory.Inven return nil, nil } - runtime, ok := s.runtimes[conn.ID()] - if !ok { - // no connection found, this should never happen - return nil, errors.New("connection " + strconv.FormatUint(uint64(conn.ID()), 10) + " not found") + runtime, err := s.GetRuntime(conn.ID()) + if err != nil { + return nil, err } return resources.Discover(runtime) } - -func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) - - if req.ResourceId == "" && req.Field == "" { - res, err := resources.NewResource(runtime, req.Resource, args) - if err != nil { - return nil, err - } - - rd := llx.ResourceData(res, res.MqlName()).Result() - return &plugin.DataRes{ - Data: rd.Data, - }, nil - } - - resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) - if !ok { - // Note: Since resources are internally always created, there are only very - // few cases where we arrive here: - // 1. The caller is wrong. Possibly a mixup with IDs - // 2. The resource was loaded from a recording, but the field is not - // in the recording. Thus the resource was never created inside the - // plugin. We will attempt to create the resource and see if the field - // can be computed. - if !runtime.HasRecording { - return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") - } - - args, err := runtime.ResourceFromRecording(req.Resource, req.ResourceId) - if err != nil { - return nil, errors.New("attempted to load resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - - resource, err = resources.CreateResource(runtime, req.Resource, args) - if err != nil { - return nil, errors.New("attempted to create resource '" + req.Resource + "' (id: " + req.ResourceId + ") from recording failed: " + err.Error()) - } - } - - return resources.GetData(resource, req.Field, args), nil -} - -func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { - runtime, ok := s.runtimes[req.Connection] - if !ok { - return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") - } - - var errs []string - for i := range req.Resources { - info := req.Resources[i] - - args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") - continue - } - - resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) - if !ok { - resource, err = resources.CreateResource(runtime, info.Name, args) - if err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) - continue - } - - runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) - } - - for k, v := range args { - if err := resources.SetData(resource, k, v); err != nil { - errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) - } - } - } - - if len(errs) != 0 { - return nil, errors.New(strings.Join(errs, ", ")) - } - return &plugin.StoreRes{}, nil -} diff --git a/providers/vsphere/provider/provider_test.go b/providers/vsphere/provider/provider_test.go index 951bbb0107..4bcc7cea2e 100644 --- a/providers/vsphere/provider/provider_test.go +++ b/providers/vsphere/provider/provider_test.go @@ -28,8 +28,7 @@ func newTestService() (*vsimulator.VsphereSimulator, *Service, *plugin.ConnectRe } srv := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } resp, err := srv.Connect(&plugin.ConnectReq{ @@ -138,8 +137,7 @@ func TestVsphereDiscovery(t *testing.T) { } srv := &Service{ - runtimes: map[uint32]*plugin.Runtime{}, - lastConnectionID: 0, + Service: plugin.NewService(), } resp, err := srv.Connect(&plugin.ConnectReq{