go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/platform/detector/platform_resolver.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package detector
     5  
     6  import (
     7  	"github.com/rs/zerolog/log"
     8  	"go.mondoo.com/cnquery/motor/platform"
     9  	"go.mondoo.com/cnquery/motor/providers/container/docker_engine"
    10  	"go.mondoo.com/cnquery/motor/providers/os"
    11  	"go.mondoo.com/cnquery/motor/providers/tar"
    12  )
    13  
    14  type detect func(r *PlatformResolver, pf *platform.Platform, p os.OperatingSystemProvider) (bool, error)
    15  
    16  type PlatformResolver struct {
    17  	Name     string
    18  	IsFamily bool
    19  	Children []*PlatformResolver
    20  	Detect   detect
    21  }
    22  
    23  func (r *PlatformResolver) Resolve(p os.OperatingSystemProvider) (*platform.Platform, bool) {
    24  	// prepare detect info object
    25  	di := &platform.Platform{}
    26  	di.Family = make([]string, 0)
    27  
    28  	// start recursive platform resolution
    29  	pi, resolved := r.resolvePlatform(di, p)
    30  
    31  	// if we have a container image use the architecture specified in the transport as it is resolved
    32  	// using the container image properties
    33  	tarTransport, ok := p.(*tar.Provider)
    34  	if resolved && ok {
    35  		pi.Arch = tarTransport.PlatformArchitecture
    36  
    37  		// if the platform name is not set, we should fallback to the scratch operating system
    38  		if len(pi.Name) == 0 {
    39  			di.Name = "scratch"
    40  			di.Arch = tarTransport.PlatformArchitecture
    41  			return di, true
    42  		}
    43  	}
    44  
    45  	_, ok = p.(*docker_engine.Provider)
    46  	if resolved && ok {
    47  		pi.Arch = p.(*docker_engine.Provider).PlatformArchitecture
    48  		// if the platform name is not set, we should fallback to the scratch operating system
    49  		if len(pi.Name) == 0 {
    50  			di.Name = "scratch"
    51  			di.Arch = pi.Arch
    52  			return di, true
    53  		}
    54  	}
    55  
    56  	log.Debug().Str("platform", pi.Name).Strs("family", pi.Family).Msg("platform> detected os")
    57  	return pi, resolved
    58  }
    59  
    60  // Resolve tries to find recursively all
    61  // platforms until a leaf (operating systems) detect
    62  // mechanism is returning true
    63  func (r *PlatformResolver) resolvePlatform(pf *platform.Platform, p os.OperatingSystemProvider) (*platform.Platform, bool) {
    64  	detected, err := r.Detect(r, pf, p)
    65  	if err != nil {
    66  		return pf, false
    67  	}
    68  
    69  	// if detection is true but we have a family
    70  	if detected == true && r.IsFamily == true {
    71  		// we are a family and we may have children to try
    72  		for _, c := range r.Children {
    73  			detected, resolved := c.resolvePlatform(pf, p)
    74  			if resolved {
    75  				// add family hierarchy
    76  				detected.Family = append(pf.Family, r.Name)
    77  				return detected, resolved
    78  			}
    79  		}
    80  
    81  		// we reached this point, we know it is the platform but we could not
    82  		// identify the system
    83  		// TODO: add generic platform instance
    84  		// TODO: should we return an error?
    85  	}
    86  
    87  	// return if the detect is true and we have a leaf
    88  	if detected && r.IsFamily == false {
    89  		return pf, true
    90  	}
    91  
    92  	// could not find it
    93  	return pf, false
    94  }