Skip to content

Commit

Permalink
make sure resource overriding and extension works
Browse files Browse the repository at this point in the history
Signed-off-by: Ivan Milchev <[email protected]>
  • Loading branch information
imilchev committed Feb 16, 2024
1 parent 072607d commit 0e4462f
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 74 deletions.
101 changes: 63 additions & 38 deletions providers-sdk/v1/resources/resources.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions providers-sdk/v1/resources/resources.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ message ResourceInfo {
string min_mondoo_version = 25;
string defaults = 26;
string provider = 27;
repeated ResourceInfo others = 29;
}

message Field {
Expand All @@ -54,4 +55,5 @@ message Field {
bool is_implicit_resource = 24;
bool is_embedded = 25;
string provider = 27;
repeated Field others = 29;
}
26 changes: 23 additions & 3 deletions providers-sdk/v1/resources/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ type ResourcesSchema interface {
// Add another schema and return yourself. other may be nil.
// The other schema overrides specifications in this schema, unless
// it is trying to extend a resource whose base is already defined.
func (s *Schema) Add(other ResourcesSchema) *Schema {
func (s *Schema) Add(other ResourcesSchema) ResourcesSchema {
if other == nil {
return s
}

for k, v := range other.AllResources() {
if existing, ok := s.Resources[k]; ok {
// If neither resource is an extension, we can't merge them. We store both references.
if !v.IsExtension && !existing.IsExtension {
existing.Others = append(existing.Others, v)
continue
}

// We will merge resources into it until we find one that is not extending.
// Technically, this should only happen with one resource and one only,
// i.e. the root resource. In case they are incorrectly specified, the
Expand Down Expand Up @@ -56,7 +62,11 @@ func (s *Schema) Add(other ResourcesSchema) *Schema {
existing.Fields = map[string]*Field{}
}
for fk, fv := range v.Fields {
existing.Fields[fk] = fv
if fExisting, ok := existing.Fields[fk]; ok {
fExisting.Others = append(fExisting.Others, fv)
} else {
existing.Fields[fk] = fv
}
}
} else {
ri := &ResourceInfo{
Expand Down Expand Up @@ -89,9 +99,19 @@ func (s *Schema) Lookup(name string) *ResourceInfo {

func (s *Schema) LookupField(resource string, field string) (*ResourceInfo, *Field) {
res := s.Lookup(resource)
if res == nil || res.Fields == nil {
if res == nil {
return res, nil
}

// If the fields don't exist in the current resource, check the other instances of it
if res.Fields == nil {
for _, o := range res.Others {
if o.Fields != nil && o.Fields[field] != nil {
res = o
break
}
}
}
return res, res.Fields[field]
}

Expand Down
8 changes: 4 additions & 4 deletions providers/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ type ProvidersCoordinator interface {

var BuiltinCoreID = coreconf.Config.ID

var Coordinator ProvidersCoordinator = newCoordinator()
var Coordinator ProvidersCoordinator

func newCoordinator() ProvidersCoordinator {
func newCoordinator() *coordinator {
c := &coordinator{
runningByID: map[string]*RunningProvider{},
runtimes: map[string]*Runtime{},
Expand Down Expand Up @@ -306,6 +306,7 @@ func (c *coordinator) unsafeStartProvider(id string, update UpdateProvidersConfi
mp := x.Runtime.Plugin.(*mockProviderService)
mp.Init(x.Runtime)
}
c.schema.Add(id, x.Runtime.Schema)
return x.Runtime, nil
}

Expand Down Expand Up @@ -385,8 +386,7 @@ func (c *coordinator) unsafeStartProvider(id string, update UpdateProvidersConfi
gracePeriod: 3 * time.Second,
}

c.schema.Add(provider.Name, provider.Schema)
c.schema.prioritizeIDs(BuiltinCoreID)
c.schema.Add(provider.ID, provider.Schema)

if err := res.heartbeat(); err != nil {
return nil, err
Expand Down
43 changes: 14 additions & 29 deletions providers/extensible_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
"golang.org/x/exp/slices"
)

type ExtensibleSchema interface {
Expand Down Expand Up @@ -39,7 +38,7 @@ func newExtensibleSchema() extensibleSchema {
}
}

func (x *extensibleSchema) Add(name string, schema *resources.Schema) {
func (x *extensibleSchema) Add(name string, schema resources.ResourcesSchema) {
x.sync.Lock()
x.unsafeAdd(name, schema)
x.unsafeRefresh()
Expand Down Expand Up @@ -101,31 +100,19 @@ func (x *extensibleSchema) LookupField(resource string, field string) (*resource
x.sync.Lock()
defer x.sync.Unlock()

found, ok := x.roAggregate.Resources[resource]
if !ok {
if x.lastRefreshed >= LastProviderInstall {
return nil, nil
}

found, ok = x.roAggregate.Resources[resource]
if !ok {
return nil, nil
}
return found, found.Fields[field]
res, f := x.roAggregate.LookupField(resource, field)
if res != nil && f != nil {
return res, f
}

fieldObj, ok := found.Fields[field]
if ok {
return found, fieldObj
}
if x.lastRefreshed >= LastProviderInstall {
return found, nil
return nil, nil
}

x.unsafeLoadAll()
x.unsafeRefresh()

return found, found.Fields[field]
return x.roAggregate.LookupField(resource, field)
}

// Prioritize the provider IDs in the order that is provided. Any other
Expand Down Expand Up @@ -185,18 +172,16 @@ func (x *extensibleSchema) unsafeRefresh() {
res := resources.Schema{
Resources: map[string]*resources.ResourceInfo{},
}
for id, schema := range x.loaded {
if !slices.Contains(x.prioritization, id) {
res.Add(schema)
}
for _, schema := range x.loaded {
res.Add(schema)
}

for i := len(x.prioritization) - 1; i >= 0; i-- {
id := x.prioritization[i]
if s := x.loaded[id]; s != nil {
res.Add(s)
}
}
// for i := len(x.prioritization) - 1; i >= 0; i-- {
// id := x.prioritization[i]
// if s := x.loaded[id]; s != nil {
// res.Add(s)
// }
// }

// Note: This object is read-only and thus must be re-created to
// prevent concurrency issues with access outside this struct
Expand Down
20 changes: 20 additions & 0 deletions providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ func init() {
}

LastProviderInstall = time.Now().Unix()

// Initialize the global coordinator instance
coordinator := newCoordinator()
Coordinator = coordinator

// Load the schema for all the active providers
providers, err := ListActive()
if err != nil {
log.Error().Err(err).Msg("failed to list active providers")
return
}

for name := range providers {
schema, err := Coordinator.LoadSchema(name)
if err != nil {
log.Error().Err(err).Str("provider", name).Msg("failed to load schema")
continue
}
coordinator.schema.Add(name, schema)
}
}

type ProviderLookup struct {
Expand Down
24 changes: 24 additions & 0 deletions providers/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,22 @@ func (r *Runtime) lookupResourceProvider(resource string) (*ConnectedProvider, *
return nil, nil, errors.New("cannot find resource '" + resource + "' in schema")
}

// prioritize ids
resourcesPerProvider := map[string]*resources.ResourceInfo{
info.Provider: info,
}
for _, other := range info.Others {
resourcesPerProvider[other.Provider] = other
}

priority := []string{BuiltinCoreID, r.Provider.Instance.ID}
for i := len(priority) - 1; i >= 0; i-- {
id := priority[i]
if s := resourcesPerProvider[id]; s != nil {
info = s
}
}

if info.Provider == "" {
// This case happens when the resource is only bridging a resource chain,
// i.e. it is extending in nature (which we only test for the warning).
Expand Down Expand Up @@ -597,6 +613,14 @@ func (r *Runtime) lookupFieldProvider(resource string, field string) (*Connected
return nil, nil, nil, errors.New("cannot find field '" + field + "' in resource '" + resource + "'")
}

// Make sure we grab the field that matches the provider of this runtime (if possible).
for _, f := range fieldInfo.Others {
if f.Provider == r.Provider.Instance.ID {
fieldInfo = f
break
}
}

if provider := r.providers[fieldInfo.Provider]; provider != nil {
return provider, resourceInfo, fieldInfo, provider.ConnectionError
}
Expand Down

0 comments on commit 0e4462f

Please sign in to comment.