Skip to content

Commit d54e952

Browse files
authored
🐛 Add dependencies to ResourceSchema interface (#5580)
We use the `ResourcesSchema` interface to interact with the `resources` package. However, when we introduced provider dependencies into `resource.Schema`, we didn't update or extend this interface accordingly. A few additional issues were observed: * When loading providers, we only read the `{provider}.json` file, but not the corresponding `{provider}.resources.json` metadata file. * For built-in providers, we intentionally skip loading files—but we also forgot to pass the schema. This omission results in errors like: ``` x provider without schema, unable to look up dependencies provider=core ``` * While `ResourcesSchema` is used consistently throughout the codebase, it’s not used within `providers.Provider.Schema`. This change addresses all of the issues mentioned above. Signed-off-by: Salim Afiune Maya <afiune@mondoo.com>
1 parent e1319bf commit d54e952

4 files changed

Lines changed: 87 additions & 6 deletions

File tree

providers-sdk/v1/resources/schema.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type ResourcesSchema interface {
1212
LookupField(resource string, field string) (*ResourceInfo, *Field)
1313
FindField(resource *ResourceInfo, field string) (FieldPath, []*Field, bool)
1414
AllResources() map[string]*ResourceInfo
15+
AllDependencies() map[string]*ProviderInfo
1516
}
1617

1718
// Add another schema and return yourself. other may be nil.
@@ -101,6 +102,20 @@ func (s *Schema) Add(other ResourcesSchema) ResourcesSchema {
101102
}
102103
}
103104

105+
for k, v := range other.AllDependencies() {
106+
if existing, ok := s.Dependencies[k]; ok {
107+
if v.Name != "" {
108+
existing.Name = v.Name
109+
}
110+
} else {
111+
pi := &ProviderInfo{
112+
Id: v.Id,
113+
Name: v.Name,
114+
}
115+
s.Dependencies[k] = pi
116+
}
117+
}
118+
104119
return s
105120
}
106121

@@ -163,3 +178,7 @@ func (s *Schema) FindField(resource *ResourceInfo, field string) (FieldPath, []*
163178
func (s *Schema) AllResources() map[string]*ResourceInfo {
164179
return s.Resources
165180
}
181+
182+
func (s *Schema) AllDependencies() map[string]*ProviderInfo {
183+
return s.Dependencies
184+
}

providers/extensible_schema.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ func (x *extensibleSchema) AllResources() map[string]*resources.ResourceInfo {
7070
return x.roAggregate.Resources
7171
}
7272

73+
func (x *extensibleSchema) AllDependencies() map[string]*resources.ProviderInfo {
74+
x.sync.Lock()
75+
defer x.sync.Unlock()
76+
77+
if x.lastRefreshed < LastProviderInstall {
78+
x.unsafeLoadAll()
79+
x.unsafeRefresh()
80+
}
81+
82+
return x.roAggregate.Dependencies
83+
}
84+
7385
func (x *extensibleSchema) Close() {
7486
x.sync.Lock()
7587
x.loaded = map[string]resources.ResourcesSchema{}
@@ -189,7 +201,8 @@ func (x *extensibleSchema) unsafeAdd(name string, schema resources.ResourcesSche
189201

190202
func (x *extensibleSchema) unsafeRefresh() {
191203
res := resources.Schema{
192-
Resources: map[string]*resources.ResourceInfo{},
204+
Resources: map[string]*resources.ResourceInfo{},
205+
Dependencies: map[string]*resources.ProviderInfo{},
193206
}
194207

195208
for _, schema := range x.loaded {
@@ -199,6 +212,7 @@ func (x *extensibleSchema) unsafeRefresh() {
199212
// Note: This object is read-only and thus must be re-created to
200213
// prevent concurrency issues with access outside this struct
201214
x.roAggregate = resources.Schema{
202-
Resources: res.Resources,
215+
Resources: res.Resources,
216+
Dependencies: res.Dependencies,
203217
}
204218
}

providers/extensible_schema_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,37 @@ func TestExtensibleSchema(t *testing.T) {
6464
require.Equal(t, resources.FieldPath{"v"}, filePath)
6565
require.Len(t, fieldinfos, 1)
6666
require.Equal(t, "first", fieldinfos[0].Provider)
67+
68+
// Check no dependencies
69+
require.Lenf(t, s.AllDependencies(), 0, "should not have dependencies")
70+
71+
t.Run("with dependencies", func(t *testing.T) {
72+
s.Add("third", &resources.Schema{
73+
Resources: map[string]*resources.ResourceInfo{
74+
"eternity": {
75+
Fields: map[string]*resources.Field{
76+
"iii": {Provider: "third"},
77+
"x": {Provider: "third"},
78+
},
79+
Provider: "third",
80+
},
81+
},
82+
Dependencies: map[string]*resources.ProviderInfo{
83+
"core": {
84+
Id: "go.mondoo.com/cnquery/v9/providers/core",
85+
Name: "core",
86+
},
87+
},
88+
})
89+
info := s.Lookup("eternity")
90+
require.NotNil(t, info)
91+
require.Len(t, info.Others, 2)
92+
providers := []string{info.Provider, info.Others[0].Provider, info.Others[1].Provider}
93+
assert.ElementsMatch(t, []string{"first", "second", "third"}, providers)
94+
95+
// Check dependencies
96+
deps := s.AllDependencies()
97+
require.Len(t, deps, 1)
98+
assert.Equal(t, "go.mondoo.com/cnquery/v9/providers/core", deps["core"].Id)
99+
})
67100
}

providers/providers.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func (p Providers) Add(nu *Provider) {
166166

167167
type Provider struct {
168168
*plugin.Provider
169-
Schema *resources.Schema
169+
Schema resources.ResourcesSchema
170170
Path string
171171
HasBinary bool
172172
}
@@ -289,6 +289,7 @@ func ListAll() ([]*Provider, error) {
289289
for _, x := range builtinProviders {
290290
all = append(all, &Provider{
291291
Provider: x.Config,
292+
Schema: x.Runtime.Schema,
292293
})
293294
}
294295

@@ -309,9 +310,18 @@ func ListAll() ([]*Provider, error) {
309310
Str("provider", provider.Name).
310311
Str("path", provider.Path).
311312
Msg("failed to load provider")
312-
} else {
313-
res = append(res, provider)
313+
continue
314+
}
315+
316+
if err := provider.LoadResources(); err != nil {
317+
log.Error().Err(err).
318+
Str("provider", provider.Name).
319+
Str("path", provider.Path).
320+
Msg("failed to load provider resources")
321+
continue
314322
}
323+
324+
res = append(res, provider)
315325
}
316326

317327
CachedProviders = res
@@ -485,7 +495,7 @@ func installDependencies(provider *Provider, existing Providers) error {
485495
return nil
486496
}
487497

488-
for _, dependency := range provider.Schema.Dependencies {
498+
for _, dependency := range provider.Schema.AllDependencies() {
489499
dependencyLookup := ProviderLookup{
490500
ID: dependency.Id,
491501
ProviderName: dependency.Name,
@@ -748,6 +758,11 @@ func InstallIO(reader io.ReadCloser, conf InstallConf) ([]*Provider, error) {
748758
continue
749759
}
750760

761+
if err := provider.LoadResources(); err != nil {
762+
log.Error().Err(err).Str("path", pdir).Msg("failed to read provider resources, please remove or fix it")
763+
continue
764+
}
765+
751766
res = append(res, provider)
752767
}
753768

0 commit comments

Comments
 (0)