go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers-sdk/v1/util/configure/configure.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package main 5 6 import ( 7 "errors" 8 "fmt" 9 "go/format" 10 "os" 11 "os/exec" 12 "regexp" 13 "strconv" 14 "strings" 15 16 "github.com/rs/zerolog" 17 "github.com/rs/zerolog/log" 18 "github.com/spf13/cobra" 19 "go.mondoo.com/cnquery/logger" 20 "sigs.k8s.io/yaml" 21 ) 22 23 type ProvidersConf struct { 24 Builtin []string `json:"builtin"` 25 } 26 27 var rootCmd = &cobra.Command{ 28 Use: "configure [-f config] [-o file]", 29 Short: "configure providers for cnquery", 30 Run: func(cmd *cobra.Command, args []string) { 31 confPath, err := cmd.Flags().GetString("file") 32 if err != nil { 33 log.Fatal().Err(err).Msg("Can't get --file") 34 } 35 outPath, err := cmd.Flags().GetString("output") 36 if err != nil { 37 log.Fatal().Err(err).Msg("Can't get --output") 38 } 39 40 raw, err := os.ReadFile(confPath) 41 if err != nil { 42 log.Fatal().Err(err).Str("path", confPath).Msg("failed to read config file") 43 } 44 45 var conf ProvidersConf 46 err = yaml.Unmarshal(raw, &conf) 47 if err != nil { 48 log.Fatal().Err(err).Str("path", confPath).Msg("failed to parse config file") 49 } 50 51 builtinGo, err := genBuiltinGo(conf) 52 if err != nil { 53 log.Fatal().Err(err).Str("path", confPath).Msg("failed to generate builtin go") 54 } 55 56 if err = os.WriteFile(outPath, builtinGo, 0o644); err != nil { 57 log.Fatal().Err(err).Str("path", outPath).Msg("failed to write output") 58 } 59 log.Info().Str("path", outPath).Strs("providers", conf.Builtin).Msg("(1/3) configured builtin providers") 60 61 buildProviders(conf.Builtin) 62 log.Info().Strs("providers", conf.Builtin).Msg("(2/3) built providers") 63 64 rewireDependencies(conf.Builtin) 65 log.Info().Str("path", outPath).Strs("providers", conf.Builtin).Msg("(3/3) rewired dependencies/files") 66 }, 67 } 68 69 func genBuiltinGo(conf ProvidersConf) ([]byte, error) { 70 var imports string 71 var infos string 72 var configs string 73 74 for _, provider := range conf.Builtin { 75 // imports cannot contain dashes 76 trimProvider := strings.Replace(provider, "-", "", -1) 77 imports += fmt.Sprintf("\t%sconf \"go.mondoo.com/cnquery/providers/%s/config\"\n", trimProvider, provider) 78 imports += fmt.Sprintf("\t%s \"go.mondoo.com/cnquery/providers/%s/provider\"\n", trimProvider, provider) 79 infos += fmt.Sprintf( 80 "//go:embed %s.resources.json\n"+ 81 "var %sInfo []byte\n", 82 provider, trimProvider) 83 configs += fmt.Sprintf(` 84 builtinProviders[%sconf.Config.ID] = &builtinProvider{ 85 Runtime: &RunningProvider{ 86 Name: %sconf.Config.Name, 87 ID: %sconf.Config.ID, 88 Plugin: %s.Init(), 89 Schema: MustLoadSchema("%s", %sInfo), 90 isClosed: false, 91 }, 92 Config: &%sconf.Config, 93 } 94 `, trimProvider, trimProvider, trimProvider, trimProvider, provider, trimProvider, trimProvider) 95 } 96 97 res := fmt.Sprintf(template, imports, infos, configs) 98 return format.Source([]byte(res)) 99 } 100 101 const template = `// Copyright (c) Mondoo, Inc. 102 // SPDX-License-Identifier: BUSL-1.1 103 // 104 // This file is auto-generated by 'make providers/config' 105 // and configured via 'providers.yaml' 106 107 package providers 108 109 import ( 110 _ "embed" 111 // osconf "go.mondoo.com/cnquery/providers/os/config" 112 // os "go.mondoo.com/cnquery/providers/os/provider" 113 %s) 114 115 // //go:embed os/resources/os.resources.json 116 // var osInfo []byte 117 118 %s 119 120 func init() { 121 // builtinProviders[osconf.Config.ID] = &builtinProvider{ 122 // Runtime: &RunningProvider{ 123 // Name: osconf.Config.Name, 124 // ID: osconf.Config.ID, 125 // Plugin: os.Init(), 126 // Schema: MustLoadSchema("os", osInfo), 127 // isClosed: false, 128 // }, 129 // Config: &osconf.Config, 130 // } 131 %s 132 } 133 ` 134 135 func buildProviders(providers []string) { 136 for i, provider := range providers { 137 cmd := exec.Command("make", "providers/build/"+provider) 138 log.Debug().Str("provider", provider).Msg("build provider " + strconv.Itoa(i+1) + "/" + strconv.Itoa(len(providers))) 139 if err := cmd.Run(); err != nil { 140 log.Error().Err(err).Str("provider", provider).Msg("failed to build provider") 141 } 142 143 // inefficient copy... 144 src := "providers/" + provider + "/resources/" + provider + ".resources.json" 145 raw, err := os.ReadFile(src) 146 if err != nil { 147 log.Fatal().Err(err).Str("src", src).Msg("failed to read resources json") 148 } 149 150 dst := "providers/" + provider + ".resources.json" 151 err = os.WriteFile(dst, raw, 0o644) 152 if err != nil { 153 log.Fatal().Err(err).Str("dst", dst).Msg("failed to write resources json") 154 } 155 } 156 } 157 158 var ( 159 reBuiltinReplace = regexp.MustCompile(`replace go.mondoo.com/cnquery/providers/.* => ./providers/.*`) 160 reBuiltinDep = regexp.MustCompile(`go.mondoo.com/cnquery/providers/.*`) 161 ) 162 163 func rewireDependencies(providers []string) { 164 raw, err := os.ReadFile("go.mod") 165 if err != nil { 166 log.Fatal().Err(err).Msg("failed to read go.mod") 167 } 168 169 raws := string(raw) 170 raws = reBuiltinReplace.ReplaceAllString(raws, "") 171 raws = reBuiltinDep.ReplaceAllString(raws, "") 172 173 deps := "" 174 replace := "" 175 for _, provider := range providers { 176 _, err := os.Stat("providers/" + provider + "/go.mod") 177 if err != nil { 178 if errors.Is(err, os.ErrNotExist) { 179 log.Info().Str("provider", provider).Msg("skipping provider without go.mod") 180 continue 181 } else { 182 log.Fatal().Err(err).Str("provider", provider).Msg("failed to stat provider go.mod") 183 } 184 } 185 // we don't care about the specific version for dev 186 deps += "\n\tgo.mondoo.com/cnquery/providers/" + provider + " v0.0.0" 187 replace += "\nreplace go.mondoo.com/cnquery/providers/" + provider + " => ./providers/" + provider 188 } 189 if deps != "" { 190 raws = strings.Replace(raws, "require (", "require ("+deps, 1) 191 raws = strings.Replace(raws, "module go.mondoo.com/cnquery", "module go.mondoo.com/cnquery\n"+replace, 1) 192 } 193 194 err = os.WriteFile("go.mod", []byte(raws), 0o644) 195 if err != nil { 196 log.Fatal().Err(err).Msg("failed to write go.mod") 197 } 198 199 cmd := exec.Command("go", "mod", "tidy") 200 log.Debug().Msg("go mod tidy") 201 if err := cmd.Run(); err != nil { 202 log.Fatal().Err(err).Msg("failed to go mod tidy") 203 } 204 } 205 206 func init() { 207 rootCmd.Flags().StringP("file", "f", "providers.yaml", "config file for providers") 208 rootCmd.Flags().StringP("output", "o", "providers/builtin_dev.go", "output go-file for builtin dev providers") 209 } 210 211 func main() { 212 logger.CliCompactLogger(logger.LogOutputWriter) 213 zerolog.SetGlobalLevel(zerolog.DebugLevel) 214 215 if err := rootCmd.Execute(); err != nil { 216 fmt.Fprintln(os.Stderr, err) 217 os.Exit(1) 218 } 219 }