Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⭐️ support re-using MQL cache between provider connections #3274

Merged
merged 36 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b10c115
⭐️ support re-using MQL cache between provider connections
imilchev Feb 12, 2024
3596bbb
remove go-memoize from k8s provider
imilchev Feb 12, 2024
73ecda3
make k8s discovery reuses mql cache
imilchev Feb 12, 2024
f32a859
migrate arista provider
imilchev Feb 12, 2024
aa35de8
migrate atlassian provider
imilchev Feb 12, 2024
0e8e0c7
migrate aws provider
imilchev Feb 12, 2024
d66c150
migrate os provider
imilchev Feb 12, 2024
6532052
migrate azure provider
imilchev Feb 12, 2024
b428d41
migrate equinix provider
imilchev Feb 12, 2024
e75987c
re-use plugin.Connection instead of copying functions
imilchev Feb 12, 2024
deb6744
migrate gcp provider
imilchev Feb 12, 2024
6ee0502
migrate github provider
imilchev Feb 12, 2024
41937e6
migrate gitlab provider
imilchev Feb 12, 2024
f6d02e1
make sure cache is reused for discovered gcp assets
imilchev Feb 12, 2024
275b56a
migrate google-workspace provider
imilchev Feb 12, 2024
347c33b
migrate ipmi provider
imilchev Feb 12, 2024
bcd6f6e
migrate ms365 provider
imilchev Feb 12, 2024
9255b3b
migrate network provider
imilchev Feb 12, 2024
bd9a82f
define plugin.Connection and reuse in all providers
imilchev Feb 12, 2024
8f553b3
migrate okta provider
imilchev Feb 12, 2024
5a9d9b8
migrate opcua provider
imilchev Feb 12, 2024
49f867e
migrate slack provider
imilchev Feb 12, 2024
b0a0cd8
migrate terraform provider
imilchev Feb 12, 2024
3aef285
migrate vcd provider
imilchev Feb 12, 2024
c24bfb6
migrate vsphere provider
imilchev Feb 12, 2024
f53e507
fix test build
imilchev Feb 12, 2024
4524924
fix linter error
imilchev Feb 12, 2024
b3cc660
fix mock provider
imilchev Feb 12, 2024
a000f08
fix dns tests for network provider
imilchev Feb 12, 2024
ca64032
fix more tests
imilchev Feb 12, 2024
9335513
re-use plugin.Connection in os provider
imilchev Feb 13, 2024
e129a40
fix tests
imilchev Feb 13, 2024
5320102
add tests for connection sharing
imilchev Feb 13, 2024
9baa375
do not use pointer for ParentID
imilchev Feb 14, 2024
390f266
use plugin.Connection in winrm
imilchev Feb 14, 2024
a40301a
fix tests
imilchev Feb 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion providers-sdk/v1/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ func (p *Platform) PrettyTitle() string {
}

type cloneSettings struct {
noDiscovery bool
noDiscovery bool
parentConnectionId *uint32
}

type CloneOption interface {
Expand All @@ -394,6 +395,17 @@ type withoutDiscovery struct{}

func (w withoutDiscovery) Apply(o *cloneSettings) { o.noDiscovery = true }

// WithoutDiscovery removes the discovery flags in the opts to ensure the same discovery does not run again
func WithParentConnectionId(parentId uint32) CloneOption {
return withParentConnectionId{parentId: parentId}
}

type withParentConnectionId struct {
parentId uint32
}

func (w withParentConnectionId) Apply(o *cloneSettings) { o.parentConnectionId = &w.parentId }

func (cfg *Config) Clone(opts ...CloneOption) *Config {
if cfg == nil {
return nil
Expand All @@ -409,6 +421,9 @@ func (cfg *Config) Clone(opts ...CloneOption) *Config {
if cloneSettings.noDiscovery {
clonedObject.Discover = &Discovery{}
}
if cloneSettings.parentConnectionId != nil {
clonedObject.ParentConnectionId = *cloneSettings.parentConnectionId
}

return clonedObject
}
Expand Down
476 changes: 244 additions & 232 deletions providers-sdk/v1/inventory/inventory.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions providers-sdk/v1/inventory/inventory.proto
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ message Config {
int32 port = 3;
string path = 4;
uint32 id = 5;
uint32 parent_connection_id = 30;
string type = 12;

// credentials available for this provider configuration
Expand Down
37 changes: 37 additions & 0 deletions providers-sdk/v1/plugin/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package plugin

import inventory "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory"

type Connection interface {
ID() uint32

// ParentID returns the ID of the parent connection. If this returns >0,
// the connection with that ID will be used to store and get data.
ParentID() uint32
}

type connection struct {
id uint32
parentId uint32
}

func NewConnection(id uint32, asset *inventory.Asset) Connection {
conn := &connection{
id: id,
}
if len(asset.Connections) > 0 && asset.Connections[0].ParentConnectionId > 0 {
conn.parentId = asset.Connections[0].ParentConnectionId
}
return conn
}

func (c *connection) ID() uint32 {
return c.id
}

func (c *connection) ParentID() uint32 {
return c.parentId
}
48 changes: 48 additions & 0 deletions providers-sdk/v1/plugin/connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package plugin

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
inventory "go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory"
)

func TestConnection_ID(t *testing.T) {
c := NewConnection(1, &inventory.Asset{})
require.NotNil(t, c)
assert.Equal(t, uint32(1), c.ID())
}

func TestConnection_ParentID_Nil(t *testing.T) {
c := NewConnection(1, &inventory.Asset{})
require.NotNil(t, c)
assert.Equal(t, uint32(0), c.ParentID())
}

func TestConnection_ParentID(t *testing.T) {
c := NewConnection(1, &inventory.Asset{
Connections: []*inventory.Config{
{
ParentConnectionId: 2,
},
},
})
require.NotNil(t, c)
assert.Equal(t, uint32(2), c.ParentID())
}

func TestConnection_ParentID_0(t *testing.T) {
c := NewConnection(1, &inventory.Asset{
Connections: []*inventory.Config{
{
ParentConnectionId: 0,
},
},
})
require.NotNil(t, c)
assert.Equal(t, uint32(0), c.ParentID())
}
25 changes: 22 additions & 3 deletions providers-sdk/v1/plugin/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

type Runtime struct {
Connection Connection
Resources syncx.Map[Resource]
Resources *syncx.Map[Resource]
Callback ProviderCallback
HasRecording bool
CreateResource CreateNamedResource
Expand All @@ -24,8 +24,27 @@ type Runtime struct {
Upstream *upstream.UpstreamClient
}

type Connection interface {
ID() uint32
func NewRuntime(
conn Connection,
callback ProviderCallback,
hasRecording bool,
createResource CreateNamedResource,
newResource NewResource,
getData GetData,
setData SetData,
upstream *upstream.UpstreamClient,
) *Runtime {
return &Runtime{
Connection: conn,
Resources: &syncx.Map[Resource]{},
Callback: callback,
HasRecording: hasRecording,
CreateResource: createResource,
NewResource: newResource,
GetData: getData,
SetData: setData,
Upstream: upstream,
}
}

type (
Expand Down
17 changes: 17 additions & 0 deletions providers-sdk/v1/plugin/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,30 @@ func (s *Service) AddRuntime(createRuntime func(connId uint32) (*Runtime, error)
s.lastConnectionID--
return nil, err
}

if runtime.Connection != nil {
if parentId := runtime.Connection.ParentID(); parentId > 0 {
parentRuntime, err := s.doGetRuntime(parentId)
if err != nil {
return nil, errors.New("parent connection " + strconv.FormatUint(uint64(parentId), 10) + " not found")
}
runtime.Resources = parentRuntime.Resources

}
}
s.runtimes[s.lastConnectionID] = runtime
return runtime, nil
}

func (s *Service) GetRuntime(id uint32) (*Runtime, error) {
s.runtimesLock.Lock()
defer s.runtimesLock.Unlock()
return s.doGetRuntime(id)
}

// doGetRuntime is a helper function to get a runtime by its ID. It MUST be called
// with a lock on s.runtimesLock.
func (s *Service) doGetRuntime(id uint32) (*Runtime, error) {
if runtime, ok := s.runtimes[id]; ok {
return runtime, nil
}
Expand Down
64 changes: 63 additions & 1 deletion providers-sdk/v1/plugin/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mondoo.com/cnquery/v10/utils/syncx"
)

type TestConnection struct {
id uint32
id uint32
parentId uint32
}

func newTestConnection(id uint32) *TestConnection {
Expand All @@ -23,6 +25,10 @@ func (c *TestConnection) ID() uint32 {
return c.id
}

func (c *TestConnection) ParentID() uint32 {
return c.parentId
}

type TestConnectionWithClose struct {
*TestConnection
closed bool
Expand All @@ -36,6 +42,16 @@ func (c *TestConnectionWithClose) Close() {
c.closed = true
}

type TestResource struct{}

func (r *TestResource) MqlID() string {
return "test.resource"
}

func (r *TestResource) MqlName() string {
return "Test Resource"
}

func TestAddRuntime(t *testing.T) {
s := NewService()
wg := sync.WaitGroup{}
Expand Down Expand Up @@ -63,6 +79,52 @@ func TestAddRuntime(t *testing.T) {
assert.Equal(t, s.lastConnectionID, uint32(200))
}

func TestAddRuntime_ParentNotExist(t *testing.T) {
s := NewService()
parentId := uint32(10)
_, err := s.AddRuntime(func(connId uint32) (*Runtime, error) {
c := newTestConnection(connId)
c.parentId = parentId
return &Runtime{
Connection: c,
}, nil
})
require.Error(t, err)
assert.Equal(t, "parent connection 10 not found", err.Error())
}

func TestAddRuntime_Parent(t *testing.T) {
s := NewService()

parent, err := s.AddRuntime(func(connId uint32) (*Runtime, error) {
resMap := &syncx.Map[Resource]{}
resMap.Set("test.resource", &TestResource{})

return &Runtime{
Resources: resMap,
Connection: newTestConnection(connId),
}, nil
})
require.NoError(t, err)

parentId := parent.Connection.ID()
child, err := s.AddRuntime(func(connId uint32) (*Runtime, error) {
c := newTestConnection(connId)
c.parentId = parentId
return &Runtime{
Connection: c,
}, nil
})
require.NoError(t, err)

// Check that the resources for the parent and the child are the same
assert.Equal(t, parent.Resources, child.Resources)

// Add another resource and check that it appears in the child runtime
parent.Resources.Set("test.resource2", &TestResource{})
assert.Equal(t, parent.Resources, child.Resources)
}

func TestGetRuntime(t *testing.T) {
s := NewService()

Expand Down
2 changes: 2 additions & 0 deletions providers-sdk/v1/testutils/mockprovider/mockprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/testutils/mockprovider/resources"
"go.mondoo.com/cnquery/v10/utils/syncx"
)

var Config = plugin.Provider{
Expand Down Expand Up @@ -44,6 +45,7 @@ func (s *Service) Connect(req *plugin.ConnectReq, callback plugin.ProviderCallba
s.lastConnectionID++
connID := s.lastConnectionID
runtime := &plugin.Runtime{
Resources: &syncx.Map[plugin.Resource]{},
Callback: callback,
HasRecording: req.HasRecording,
}
Expand Down
13 changes: 5 additions & 8 deletions providers/arista/connection/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (

"github.com/aristanetworks/goeapi"
"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/vault"
)

type AristaConnection struct {
id uint32
plugin.Connection
Conf *inventory.Config
asset *inventory.Asset
// custom connection fields
Expand All @@ -21,9 +22,9 @@ type AristaConnection struct {

func NewAristaConnection(id uint32, asset *inventory.Asset, conf *inventory.Config) (*AristaConnection, error) {
conn := &AristaConnection{
Conf: conf,
id: id,
asset: asset,
Connection: plugin.NewConnection(id, asset),
Conf: conf,
asset: asset,
}

// initialize connection
Expand Down Expand Up @@ -59,10 +60,6 @@ func (c *AristaConnection) Name() string {
return "arista"
}

func (c *AristaConnection) ID() uint32 {
return c.id
}

func (c *AristaConnection) Asset() *inventory.Asset {
return c.asset
}
Expand Down
19 changes: 9 additions & 10 deletions providers/arista/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,15 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba
}
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
return plugin.NewRuntime(
conn,
callback,
req.HasRecording,
resources.CreateResource,
resources.NewResource,
resources.GetData,
resources.SetData,
upstream), nil
})
if err != nil {
return nil, err
Expand Down
Loading
Loading