-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🤖 auto-generate resources for Mondoo integrations #195
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,5 +79,6 @@ ignore$ | |
\.xpm$ | ||
\.xz$ | ||
\.zip$ | ||
\.tmpl$ | ||
^\.github/actions/spelling/ | ||
^\Q.github/workflows/spelling.yml\E$ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ bin/ | |
dist/ | ||
modules-dev/ | ||
/pkg/ | ||
gen/generated | ||
website/.vagrant | ||
website/.bundle | ||
website/build | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,154 @@ | ||||||
// Copyright (c) Mondoo, Inc. | ||||||
// SPDX-License-Identifier: BUSL-1.1 | ||||||
|
||||||
package main | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
"log" | ||||||
"os" | ||||||
"path/filepath" | ||||||
"regexp" | ||||||
"strings" | ||||||
"text/template" | ||||||
|
||||||
"github.com/fatih/structs" | ||||||
mondoov1 "go.mondoo.com/mondoo-go" | ||||||
) | ||||||
|
||||||
func main() { | ||||||
// Generate resources for Mondoo integrations only | ||||||
err := generateIntegrationResources() | ||||||
if err != nil { | ||||||
log.Fatalln(err) | ||||||
} | ||||||
} | ||||||
|
||||||
type IntegrationResource struct { | ||||||
ResourceClassName string | ||||||
TerraformResourceName string | ||||||
} | ||||||
|
||||||
// generateIntegrationResources generates Terraform resources for Mondoo's integrations. | ||||||
func generateIntegrationResources() error { | ||||||
// Read the template file | ||||||
resourceTemplateFile := filepath.Join("gen", "templates", "integration_resource.go.tmpl") | ||||||
resourceTmpl, err := template.ParseFiles(resourceTemplateFile) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
testTemplateFile := filepath.Join("gen", "templates", "integration_resource_test.go.tmpl") | ||||||
testTmpl, err := template.ParseFiles(testTemplateFile) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
resourceDotTFTemplateFile := filepath.Join("gen", "templates", "resource.tf.tmpl") | ||||||
resourceTFTmpl, err := template.ParseFiles(resourceDotTFTemplateFile) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
// Ensure the output directory exists | ||||||
outputDirPath := filepath.Join("gen", "generated") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't we create this directly in the directory the other integrations are in? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not yet. still need some more work but we will ultimately write it in the right directory. |
||||||
if err := os.MkdirAll(outputDirPath, 0755); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
i := mondoov1.ClientIntegrationConfigurationInput{} | ||||||
m := structs.Map(i) | ||||||
|
||||||
for k := range m { | ||||||
// TODO we know the type and the struct associated to the type, we need | ||||||
// to look it (the struct) and use the same `structs.Map(v)` to list all | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something reads strange to me.
Suggested change
|
||||||
// fields per integration and auto generate the terraform schema and more | ||||||
// details, for now, we only leave a comment where we need to add specific | ||||||
// integration options | ||||||
|
||||||
var ( | ||||||
className, _ = strings.CutSuffix(k, "ConfigurationOptions") | ||||||
terraformResourceName = strings.ToLower(toSnakeCase(className)) | ||||||
resource = IntegrationResource{ | ||||||
ResourceClassName: className, | ||||||
TerraformResourceName: terraformResourceName, | ||||||
} | ||||||
) | ||||||
|
||||||
fmt.Printf("> Generating code for %s integration\n", className) | ||||||
|
||||||
// Create the resource file | ||||||
resourceOutputFilePath := filepath.Join(outputDirPath, | ||||||
fmt.Sprintf("integration_%s_resource.go", terraformResourceName), | ||||||
) | ||||||
resourceFile, err := os.Create(resourceOutputFilePath) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
defer resourceFile.Close() | ||||||
|
||||||
if err := resourceTmpl.Execute(resourceFile, resource); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
// Create test file | ||||||
testOutputFilePath := filepath.Join(outputDirPath, | ||||||
fmt.Sprintf("integration_%s_resource_test.go", terraformResourceName), | ||||||
) | ||||||
testFile, err := os.Create(testOutputFilePath) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
defer testFile.Close() | ||||||
|
||||||
if err := testTmpl.Execute(testFile, resource); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
// Create examples/ files | ||||||
examplesDirPath := filepath.Join(outputDirPath, "examples", fmt.Sprintf("mondoo_integration_%s", terraformResourceName)) | ||||||
// Ensure the output directory exists | ||||||
if err := os.MkdirAll(examplesDirPath, 0755); err != nil { | ||||||
return err | ||||||
} | ||||||
// Create example main.tf | ||||||
err = os.WriteFile(filepath.Join(examplesDirPath, "main.tf"), mainDotTFTestFile(), 0644) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here: Could we generate this directly in the final directory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not yet. still need some more work but we will ultimately write it in the right directory. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this something for a follow-up or do you want to include it in this PR? |
||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
// Create example resource.tf | ||||||
resourceTFOutputFilePath := filepath.Join(examplesDirPath, "resource.tf") | ||||||
resourceTFFile, err := os.Create(resourceTFOutputFilePath) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
defer testFile.Close() | ||||||
|
||||||
if err := resourceTFTmpl.Execute(resourceTFFile, resource); err != nil { | ||||||
return err | ||||||
} | ||||||
} | ||||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this works as expected. Wouldn't the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think, I'm missing something here. |
||||||
var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") | ||||||
|
||||||
func toSnakeCase(str string) string { | ||||||
snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") | ||||||
snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") | ||||||
return strings.ToLower(snake) | ||||||
} | ||||||
|
||||||
func mainDotTFTestFile() []byte { | ||||||
return []byte(`terraform { | ||||||
required_providers { | ||||||
mondoo = { | ||||||
source = "mondoohq/mondoo" | ||||||
version = ">= 0.19" | ||||||
} | ||||||
} | ||||||
} | ||||||
`) | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not include unmaintained go modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find any other go module that does this. I we ok copying the code and NOT use the import?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the alternative solution not to use mapstructure? github.com/go-viper/mapstructure/v2. In case we need to change the tags for mondoo-go, we need touch the templates here https://github.com/mondoohq/mondoo-go/blob/main/gen/gen.go#L260
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call! 🌟