Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/lr
mqlr
dist
alpine-container.tar
centos-container.tar
Expand Down
132 changes: 13 additions & 119 deletions providers-sdk/v1/mqlr/cmd/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os"
"path"
"path/filepath"
"sort"
"strings"
"text/template"

Expand Down Expand Up @@ -59,74 +58,6 @@ var docsYamlCmd = &cobra.Command{
},
}

// required to be before more detail platform to ensure the right mapping
var platformMappingKeys = []string{
"aws", "gcp", "k8s", "azure", "azurerm", "arista", "equinix", "ms365", "msgraph", "vsphere", "esxi", "terraform", "terraform.state", "terraform.plan",
}

var platformMapping = map[string][]string{
"aws": {"aws"},
"gcp": {"gcp"},
"k8s": {"kubernetes"},
"azure": {"azure"},
"azurerm": {"azure"},
"arista": {"arista-eos"},
"equinix": {"equinix"},
"ms365": {"microsoft365"},
"msgraph": {"microsoft365"},
"vsphere": {"vmware-esxi", "vmware-vsphere"},
"esxi": {"vmware-esxi", "vmware-vsphere"},
"terraform": {"terraform-hcl"},
"terraform.state": {"terraform-state"},
"terraform.plan": {"terraform-plan"},
}

func ensureDefaults(id string, entry *lrcore.LrDocsEntry, version string) *lrcore.LrDocsEntry {
for _, k := range platformMappingKeys {
if entry == nil {
entry = &lrcore.LrDocsEntry{}
}
if entry.MinMondooVersion == "" {
entry.MinMondooVersion = version
} else if entry.MinMondooVersion == defaultVersionField && version != defaultVersionField {
// Update to specified version if previously set to default
entry.MinMondooVersion = version
}
if strings.HasPrefix(id, k) {
entry.Platform = &lrcore.LrDocsPlatform{
Name: platformMapping[k],
}
}
}
return entry
}

func mergeFields(version string, entry *lrcore.LrDocsEntry, fields []*lrcore.BasicField) {
if entry == nil && len(fields) > 0 {
entry = &lrcore.LrDocsEntry{}
entry.Fields = map[string]*lrcore.LrDocsField{}
} else if entry == nil {
return
} else if entry.Fields == nil {
entry.Fields = map[string]*lrcore.LrDocsField{}
}
docFields := entry.Fields
for _, f := range fields {
if docFields[f.ID] == nil {
fDoc := &lrcore.LrDocsField{
MinMondooVersion: version,
}
entry.Fields[f.ID] = fDoc
} else if entry.Fields[f.ID].MinMondooVersion == defaultVersionField && version != defaultVersionField {
entry.Fields[f.ID].MinMondooVersion = version
}
// Scrub field version if same as resource
if entry.Fields[f.ID].MinMondooVersion == entry.MinMondooVersion {
entry.Fields[f.ID].MinMondooVersion = ""
}
}
}

var docsJsonCmd = &cobra.Command{
Use: "json",
Short: "convert yaml docs manifest into json",
Expand Down Expand Up @@ -157,43 +88,6 @@ func runDocsYamlCmd(lrFile string, headerFile string, version string, docsFilePa
return
}

// to ensure we generate the same markdown, we sort the resources first
sort.SliceStable(res.Resources, func(i, j int) bool {
return res.Resources[i].ID < res.Resources[j].ID
})

d := lrcore.LrDocs{
Resources: map[string]*lrcore.LrDocsEntry{},
}

fields := map[string][]*lrcore.BasicField{}
isPrivate := map[string]bool{}
for i := range res.Resources {
id := res.Resources[i].ID
isPrivate[id] = res.Resources[i].IsPrivate
d.Resources[id] = nil
if res.Resources[i].Body != nil {
basicFields := []*lrcore.BasicField{}
for _, f := range res.Resources[i].Body.Fields {
if f.BasicField != nil {
basicFields = append(basicFields, f.BasicField)
}
}
fields[id] = basicFields
}
}

// default behaviour is to output the result on cli
if docsFilePath == "" {
data, err := yaml.Marshal(d)
if err != nil {
log.Fatal().Err(err).Msg("could not marshal docs")
}

fmt.Println(string(data))
return
}

// if an file was provided, we check if the file exist and merge existing content with the new resources
// to ensure that existing documentation stays available
var existingData lrcore.LrDocs
Expand All @@ -208,28 +102,28 @@ func runDocsYamlCmd(lrFile string, headerFile string, version string, docsFilePa
if err != nil {
log.Fatal().Err(err).Msg("could not load yaml data")
}
}

log.Info().Msg("merge content")
for k := range existingData.Resources {
v := existingData.Resources[k]
d.Resources[k] = v
}
docs, err := res.GenerateDocs(version, defaultVersionField, existingData)
if err != nil {
log.Fatal().Err(err).Msg("could not generate docs")
}
// default behaviour is to output the result on cli
if docsFilePath == "" {
data, err := yaml.Marshal(docs)
if err != nil {
log.Fatal().Err(err).Msg("could not marshal docs")
}

// ensure default values and fields are set
for k := range d.Resources {
d.Resources[k] = ensureDefaults(k, d.Resources[k], version)
mergeFields(version, d.Resources[k], fields[k])
// Merge in other doc fields from core.lr
d.Resources[k].IsPrivate = isPrivate[k]
fmt.Println(string(data))
return
}

// generate content
data, err := yaml.Marshal(d)
data, err := yaml.Marshal(docs)
if err != nil {
log.Fatal().Err(err).Msg("could not marshal docs")
}

// add license header
var headerTpl *template.Template
if headerFile != "" {
Expand Down
30 changes: 0 additions & 30 deletions providers-sdk/v1/mqlr/cmd/docs_test.go

This file was deleted.

18 changes: 9 additions & 9 deletions providers-sdk/v1/mqlr/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ import (

var cfgFile string

func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Set config file path (default $HOME/.lr.yaml)")
}

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cli",
Expand All @@ -34,15 +43,6 @@ func Execute() {
}
}

func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Set config file path (default $HOME/.lr.yaml)")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
Expand Down
112 changes: 111 additions & 1 deletion providers-sdk/v1/mqlr/lrcore/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package lrcore

import (
"fmt"
"maps"
"sort"
"strconv"
"strings"

Expand All @@ -23,7 +25,7 @@ type LrDocsEntry struct {
Platform *LrDocsPlatform `json:"platform,omitempty"`
Docs *LrDocsDocumentation `json:"docs,omitempty"`
Resources []LrDocsRefs `json:"resources,omitempty"`
Fields map[string]*LrDocsField `json:"fields,omitEmpty"`
Fields map[string]*LrDocsField `json:"fields,omitempty"`
Refs []LrDocsRefs `json:"refs,omitempty"`
Snippets []LrDocsSnippet `json:"snippets,omitempty"`
IsPrivate bool `json:"is_private,omitempty"`
Expand Down Expand Up @@ -96,3 +98,111 @@ func InjectMetadata(schema *resources.Schema, docs *LrDocs) {
}
}
}

func (lr *LR) GenerateDocs(currentVersion, defaultVersion string, existingDocs LrDocs) (LrDocs, error) {
// to ensure we generate the same markdown, we sort the resources first
sort.SliceStable(lr.Resources, func(i, j int) bool {
return lr.Resources[i].ID < lr.Resources[j].ID
})

docs := LrDocs{Resources: map[string]*LrDocsEntry{}}

fields := map[string][]*BasicField{}
isPrivate := map[string]bool{}
for i := range lr.Resources {
id := lr.Resources[i].ID
isPrivate[id] = lr.Resources[i].IsPrivate
docs.Resources[id] = nil
if lr.Resources[i].Body != nil {
basicFields := []*BasicField{}
for _, f := range lr.Resources[i].Body.Fields {
if f.BasicField != nil {
basicFields = append(basicFields, f.BasicField)
}
}
fields[id] = basicFields
}
}

// if we have docs from existing manifest, merge them in
if existingDocs.Resources != nil {
maps.Copy(docs.Resources, existingDocs.Resources)
}
// ensure default values and fields are set
for k := range docs.Resources {
docs.Resources[k] = ensureDefaults(k, docs.Resources[k], currentVersion, defaultVersion)
mergeFields(docs.Resources[k], fields[k], currentVersion, defaultVersion)
// Merge in other doc fields from core.lr
docs.Resources[k].IsPrivate = isPrivate[k]
}

return docs, nil
}

func mergeFields(entry *LrDocsEntry, fields []*BasicField, currentVersion, defaultVersion string) {
if entry == nil && len(fields) > 0 {
entry = &LrDocsEntry{}
entry.Fields = map[string]*LrDocsField{}
} else if entry == nil {
return
} else if entry.Fields == nil {
entry.Fields = map[string]*LrDocsField{}
}
docFields := entry.Fields
for _, f := range fields {
if docFields[f.ID] == nil {
fDoc := &LrDocsField{
MinMondooVersion: currentVersion,
}
entry.Fields[f.ID] = fDoc
} else if entry.Fields[f.ID].MinMondooVersion == defaultVersion && currentVersion != defaultVersion {
entry.Fields[f.ID].MinMondooVersion = currentVersion
}
// Scrub field version if same as resource
if entry.Fields[f.ID].MinMondooVersion == entry.MinMondooVersion {
entry.Fields[f.ID].MinMondooVersion = ""
}
}
}

func ensureDefaults(id string, entry *LrDocsEntry, currentVersion, defaultVersion string) *LrDocsEntry {
for _, k := range platformMappingKeys {
if entry == nil {
entry = &LrDocsEntry{}
}
if entry.MinMondooVersion == "" {
entry.MinMondooVersion = currentVersion
} else if entry.MinMondooVersion == defaultVersion && currentVersion != defaultVersion {
// Update to specified version if previously set to default
entry.MinMondooVersion = currentVersion
}
if strings.HasPrefix(id, k) {
entry.Platform = &LrDocsPlatform{
Name: platformMapping[k],
}
}
}
return entry
}

// required to be before more detail platform to ensure the right mapping
var platformMappingKeys = []string{
"aws", "gcp", "k8s", "azure", "azurerm", "arista", "equinix", "ms365", "msgraph", "vsphere", "esxi", "terraform", "terraform.state", "terraform.plan",
}

var platformMapping = map[string][]string{
"aws": {"aws"},
"gcp": {"gcp"},
"k8s": {"kubernetes"},
"azure": {"azure"},
"azurerm": {"azure"},
"arista": {"arista-eos"},
"equinix": {"equinix"},
"ms365": {"microsoft365"},
"msgraph": {"microsoft365"},
"vsphere": {"vmware-esxi", "vmware-vsphere"},
"esxi": {"vmware-esxi", "vmware-vsphere"},
"terraform": {"terraform-hcl"},
"terraform.state": {"terraform-state"},
"terraform.plan": {"terraform-plan"},
}
Loading
Loading