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

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package resources
     5  
     6  import (
     7  	"errors"
     8  	"sync"
     9  
    10  	"github.com/rs/zerolog/log"
    11  	"go.mondoo.com/cnquery/llx"
    12  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  	"go.mondoo.com/cnquery/providers/os/resources/services"
    15  )
    16  
    17  func initService(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) {
    18  	if len(args) != 1 {
    19  		return args, nil, nil
    20  	}
    21  
    22  	x, ok := args["name"]
    23  	if !ok {
    24  		return nil, nil, errors.New("cannot initialize service, need at least a name to look it up")
    25  	}
    26  
    27  	name := x.Value.(string)
    28  	if name == "" {
    29  		return nil, nil, errors.New("cannot look for a service with an empty name")
    30  	}
    31  
    32  	raw, err := CreateResource(runtime, "services", nil)
    33  	if err != nil {
    34  		return nil, nil, err
    35  	}
    36  	services := raw.(*mqlServices)
    37  
    38  	if err := services.refreshCache(nil); err != nil {
    39  		return nil, nil, err
    40  	}
    41  
    42  	if srv, ok := services.namedServices[name]; ok {
    43  		return nil, srv, nil
    44  	}
    45  
    46  	res := &mqlService{}
    47  	res.Name = plugin.TValue[string]{Data: name, State: plugin.StateIsSet}
    48  	res.Description.State = plugin.StateIsSet | plugin.StateIsNull
    49  	res.Installed = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
    50  	res.Running = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
    51  	res.Enabled = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
    52  	res.Type.State = plugin.StateIsSet | plugin.StateIsNull
    53  	res.Enabled = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
    54  	res.Masked = plugin.TValue[bool]{Data: false, State: plugin.StateIsSet}
    55  	return nil, res, nil
    56  }
    57  
    58  func (x *mqlService) id() (string, error) {
    59  	return x.Name.Data, nil
    60  }
    61  
    62  type mqlServicesInternal struct {
    63  	lock          sync.Mutex
    64  	namedServices map[string]*mqlService
    65  }
    66  
    67  func (x *mqlServices) list() ([]interface{}, error) {
    68  	x.lock.Lock()
    69  	defer x.lock.Unlock()
    70  
    71  	// find suitable service manager
    72  	conn := x.MqlRuntime.Connection.(shared.Connection)
    73  	osm, err := services.ResolveManager(conn)
    74  	if osm == nil || err != nil {
    75  		// there are valid cases where this error is happening, eg. you run a service query in
    76  		// asset filters for non-supported providers
    77  		log.Debug().Err(err).Msg("mql[services]> could not retrieve services list")
    78  		return nil, errors.New("cannot find service manager")
    79  	}
    80  
    81  	// retrieve all system services
    82  	services, err := osm.List()
    83  	if err != nil {
    84  		log.Debug().Err(err).Msg("mql[services]> could not retrieve service list")
    85  		return nil, errors.New("could not retrieve service list")
    86  	}
    87  	log.Debug().Int("services", len(services)).Msg("mql[services]> running services")
    88  
    89  	// convert to interface{}{}
    90  	mqlSrvs := []interface{}{}
    91  
    92  	for i := range services {
    93  		srv := services[i]
    94  
    95  		mqlSrv, err := CreateResource(x.MqlRuntime, "service", map[string]*llx.RawData{
    96  			"name":        llx.StringData(srv.Name),
    97  			"description": llx.StringData(srv.Description),
    98  			"installed":   llx.BoolData(srv.Installed),
    99  			"enabled":     llx.BoolData(srv.Enabled),
   100  			"masked":      llx.BoolData(srv.Masked),
   101  			"running":     llx.BoolData(srv.Running),
   102  			"type":        llx.StringData(srv.Type),
   103  		})
   104  		if err != nil {
   105  			return nil, err
   106  		}
   107  
   108  		mqlSrvs = append(mqlSrvs, mqlSrv.(*mqlService))
   109  	}
   110  
   111  	return mqlSrvs, x.refreshCache(mqlSrvs)
   112  }
   113  
   114  func (x *mqlServices) refreshCache(all []interface{}) error {
   115  	if all == nil {
   116  		raw := x.GetList()
   117  		if raw.Error != nil {
   118  			return raw.Error
   119  		}
   120  		all = raw.Data
   121  	}
   122  
   123  	x.namedServices = map[string]*mqlService{}
   124  	for i := range all {
   125  		service := all[i].(*mqlService)
   126  		x.namedServices[service.Name.Data] = service
   127  	}
   128  
   129  	return nil
   130  }