go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/core/provider/provider.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package provider 5 6 import ( 7 "errors" 8 "strconv" 9 "strings" 10 11 "go.mondoo.com/cnquery/llx" 12 "go.mondoo.com/cnquery/providers-sdk/v1/plugin" 13 "go.mondoo.com/cnquery/providers/core/resources" 14 "go.mondoo.com/cnquery/types" 15 ) 16 17 const defaultConnection uint32 = 1 18 19 type Service struct { 20 runtimes map[uint32]*plugin.Runtime 21 lastConnectionID uint32 22 } 23 24 func Init() *Service { 25 return &Service{ 26 runtimes: map[uint32]*plugin.Runtime{}, 27 } 28 } 29 30 func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) { 31 return nil, errors.New("core doesn't offer any connectors") 32 } 33 34 func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { 35 if req == nil || req.Asset == nil { 36 return nil, errors.New("no connection data provided") 37 } 38 39 s.lastConnectionID++ 40 connID := s.lastConnectionID 41 runtime := &plugin.Runtime{ 42 Callback: callback, 43 HasRecording: req.HasRecording, 44 } 45 s.runtimes[connID] = runtime 46 47 asset := req.Asset 48 _, err := resources.CreateResource(runtime, "asset", map[string]*llx.RawData{ 49 "ids": llx.ArrayData(llx.TArr2Raw(asset.PlatformIds), types.String), 50 "platform": llx.StringData(asset.Platform.Name), 51 "name": llx.StringData(asset.Name), 52 "kind": llx.StringData(asset.Platform.Kind), 53 "runtime": llx.StringData(asset.Platform.Runtime), 54 "version": llx.StringData(asset.Platform.Version), 55 "arch": llx.StringData(asset.Platform.Arch), 56 "title": llx.StringData(asset.Platform.PrettyTitle()), 57 "family": llx.ArrayData(llx.TArr2Raw(asset.Platform.Family), types.String), 58 "build": llx.StringData(asset.Platform.Build), 59 "labels": llx.MapData(llx.TMap2Raw(asset.Platform.Labels), types.String), 60 "fqdn": llx.StringData(""), 61 }) 62 if err != nil { 63 return nil, errors.New("failed to init core, cannot set asset metadata") 64 } 65 66 if len(asset.Connections) > 0 { 67 _, err = resources.CreateResource(runtime, "mondoo", map[string]*llx.RawData{ 68 "capabilities": llx.ArrayData(llx.TArr2Raw(asset.Connections[0].Capabilities), types.String), 69 }) 70 if err != nil { 71 return nil, errors.New("failed to init core, cannot set connection metadata") 72 } 73 } 74 75 return &plugin.ConnectRes{ 76 Id: connID, 77 Name: "core", 78 }, nil 79 } 80 81 func (s *Service) MockConnect(req *plugin.ConnectReq, callback plugin.ProviderCallback) (*plugin.ConnectRes, error) { 82 return s.Connect(req, callback) 83 } 84 85 // Shutdown is automatically called when the shell closes. 86 // It is not necessary to implement this method. 87 // If you want to do some cleanup, you can do it here. 88 func (s *Service) Shutdown(req *plugin.ShutdownReq) (*plugin.ShutdownRes, error) { 89 return &plugin.ShutdownRes{}, nil 90 } 91 92 func (s *Service) GetData(req *plugin.DataReq) (*plugin.DataRes, error) { 93 runtime, ok := s.runtimes[req.Connection] 94 if !ok { 95 return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") 96 } 97 98 args := plugin.PrimitiveArgsToRawDataArgs(req.Args, runtime) 99 100 if req.ResourceId == "" && req.Field == "" { 101 res, err := resources.CreateResource(runtime, req.Resource, args) 102 if err != nil { 103 return nil, err 104 } 105 106 rd := llx.ResourceData(res, req.Resource).Result() 107 return &plugin.DataRes{ 108 Data: rd.Data, 109 }, nil 110 } 111 112 resource, ok := runtime.Resources.Get(req.Resource + "\x00" + req.ResourceId) 113 if !ok { 114 return nil, errors.New("resource '" + req.Resource + "' (id: " + req.ResourceId + ") doesn't exist") 115 } 116 117 return resources.GetData(resource, req.Field, args), nil 118 } 119 120 func (s *Service) StoreData(req *plugin.StoreReq) (*plugin.StoreRes, error) { 121 runtime, ok := s.runtimes[req.Connection] 122 if !ok { 123 return nil, errors.New("connection " + strconv.FormatUint(uint64(req.Connection), 10) + " not found") 124 } 125 126 var errs []string 127 for i := range req.Resources { 128 info := req.Resources[i] 129 130 args, err := plugin.ProtoArgsToRawDataArgs(info.Fields) 131 if err != nil { 132 errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), failed to parse arguments") 133 continue 134 } 135 136 resource, ok := runtime.Resources.Get(info.Name + "\x00" + info.Id) 137 if !ok { 138 resource, err = resources.CreateResource(runtime, info.Name, args) 139 if err != nil { 140 errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), creation failed: "+err.Error()) 141 continue 142 } 143 144 runtime.Resources.Set(info.Name+"\x00"+info.Id, resource) 145 } 146 147 for k, v := range args { 148 if err := resources.SetData(resource, k, v); err != nil { 149 errs = append(errs, "failed to add cached "+info.Name+" (id: "+info.Id+"), field error: "+err.Error()) 150 } 151 } 152 } 153 154 if len(errs) != 0 { 155 return nil, errors.New(strings.Join(errs, ", ")) 156 } 157 return &plugin.StoreRes{}, nil 158 }