go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/extensible_schema.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package providers
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/rs/zerolog/log"
    10  	"go.mondoo.com/cnquery/providers-sdk/v1/resources"
    11  )
    12  
    13  type extensibleSchema struct {
    14  	resources.Schema
    15  
    16  	loaded    map[string]struct{}
    17  	runtime   *Runtime
    18  	allLoaded bool
    19  	lockAll   sync.Mutex // only used in getting all schemas
    20  	lockAdd   sync.Mutex // only used when adding a schema
    21  }
    22  
    23  func (x *extensibleSchema) loadAllSchemas() {
    24  	x.lockAll.Lock()
    25  	defer x.lockAll.Unlock()
    26  
    27  	// If another goroutine started to load this before us, it will be locked until
    28  	// we complete to load everything and then it will be dumped into this
    29  	// position. At this point, if it has been loaded we can return safely, since
    30  	// we don't unlock until we are finished loading.
    31  	if x.allLoaded {
    32  		return
    33  	}
    34  	x.allLoaded = true
    35  
    36  	providers, err := ListActive()
    37  	if err != nil {
    38  		log.Error().Err(err).Msg("failed to list all providers, can't load additional schemas")
    39  		return
    40  	}
    41  
    42  	for name := range providers {
    43  		schema, err := x.runtime.coordinator.LoadSchema(name)
    44  		if err != nil {
    45  			log.Error().Err(err).Msg("load schema failed")
    46  		} else {
    47  			x.Add(name, schema)
    48  		}
    49  	}
    50  }
    51  
    52  func (x *extensibleSchema) Close() {
    53  	x.loaded = map[string]struct{}{}
    54  	x.Schema.Resources = nil
    55  }
    56  
    57  func (x *extensibleSchema) Lookup(name string) *resources.ResourceInfo {
    58  	if found, ok := x.Resources[name]; ok {
    59  		return found
    60  	}
    61  	if x.allLoaded {
    62  		return nil
    63  	}
    64  
    65  	x.loadAllSchemas()
    66  	return x.Resources[name]
    67  }
    68  
    69  func (x *extensibleSchema) LookupField(resource string, field string) (*resources.ResourceInfo, *resources.Field) {
    70  	found, ok := x.Resources[resource]
    71  	if !ok {
    72  		if x.allLoaded {
    73  			return nil, nil
    74  		}
    75  
    76  		x.loadAllSchemas()
    77  
    78  		found, ok = x.Resources[resource]
    79  		if !ok {
    80  			return nil, nil
    81  		}
    82  		return found, found.Fields[field]
    83  	}
    84  
    85  	fieldObj, ok := found.Fields[field]
    86  	if ok {
    87  		return found, fieldObj
    88  	}
    89  	if x.allLoaded {
    90  		return found, nil
    91  	}
    92  
    93  	x.loadAllSchemas()
    94  	return found, found.Fields[field]
    95  }
    96  
    97  func (x *extensibleSchema) Add(name string, schema *resources.Schema) {
    98  	if schema == nil {
    99  		return
   100  	}
   101  	if name == "" {
   102  		log.Error().Msg("tried to add a schema with no name")
   103  		return
   104  	}
   105  
   106  	x.lockAdd.Lock()
   107  	defer x.lockAdd.Unlock()
   108  
   109  	if _, ok := x.loaded[name]; ok {
   110  		return
   111  	}
   112  
   113  	x.loaded[name] = struct{}{}
   114  	x.Schema.Add(schema)
   115  }
   116  
   117  func (x *extensibleSchema) AllResources() map[string]*resources.ResourceInfo {
   118  	if !x.allLoaded {
   119  		x.loadAllSchemas()
   120  	}
   121  
   122  	return x.Resources
   123  }