Skip to content

Commit

Permalink
Label Templates: rework collection of 'hostinfo' data and collected v…
Browse files Browse the repository at this point in the history
…ariables (#843)

* Label Templates: rework collection of 'System Data' info
Allow automatic conversion of data to map[string]interface{} (Template
Labels format) using reflection where all data can be useful.
Still do manual collection of data in the map[string]interface{} when
dropping of part of the data is needed.

Use the original hostinfo field names, drop spaces in the keys.
Import also the SMBIOS data from hostinfo, since are there (so also
without dmidecode tool some SMBIOS info will be available).

Keep support of old HARDWARE variable (to be deprecated sooner or
later).

* register/dumpdata: rework initial version adding more options
notably the "label" output format, which is now the default

* register: send both legacy and new Label Templates variables
we don't want to break possible setups using the older Label Templates
variables: send both.

* tests: check new hostinfo Label Templates format

---------

Signed-off-by: Francesco Giudici <[email protected]>
  • Loading branch information
fgiudici authored Sep 13, 2024
1 parent 9e42b19 commit 723d7c3
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 31 deletions.
110 changes: 87 additions & 23 deletions cmd/register/showdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,86 +19,150 @@ package main
import (
"encoding/json"
"fmt"
"sort"

"github.com/rancher/elemental-operator/pkg/dmidecode"
"github.com/rancher/elemental-operator/pkg/hostinfo"
"github.com/rancher/elemental-operator/pkg/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"sigs.k8s.io/yaml"
)

const (
DUMPHW = "hardware"
DUMPSMBIOS = "smbios"
DUMPLEGACY = "legacy"
DUMPSMBIOS = "smbios"
DUMPHOSTINFO = "hostinfo"
FORMATLABELS = "labels"
FORMATJSON = "json"
FORMATJSONCOMPACT = "json-compact"
FORMATYAML = "yaml"
)

func newDumpDataCommand() *cobra.Command {
var raw bool
var format string

cmd := &cobra.Command{
Use: "dumpdata",
Aliases: []string{"dump"},
Short: "Show host data sent during the registration phase",
Long: "Prints to stdout the data sent by the registering client " +
"to the Elemental Operator.\nTakes the type of host data to dump " +
"as argument, be it '" + DUMPHW + "' or '" + DUMPSMBIOS + "'.",
"as argument, be it '" + DUMPHOSTINFO + "' (default), " + DUMPLEGACY +
"' or '" + DUMPSMBIOS + "'.",
Args: cobra.MatchAll(cobra.MaximumNArgs(1), cobra.OnlyValidArgs),
ValidArgs: []string{DUMPHW, DUMPSMBIOS},
ValidArgs: []string{DUMPHOSTINFO, DUMPLEGACY, DUMPSMBIOS},
RunE: func(_ *cobra.Command, args []string) error {
return dumpdata(args, raw)
return dumpdata(args, format, raw)
},
}

viper.AutomaticEnv()
cmd.Flags().BoolVarP(&raw, "raw", "r", false, "dump raw data before conversion to label templates' variables")
cmd.Flags().BoolVarP(&raw, "raw", "r", false, "dump all collected raw data before postprocessing to refine available label templates variables")
_ = viper.BindPFlag("raw", cmd.Flags().Lookup("raw"))

cmd.Flags().StringVarP(&format, "format", "f", FORMATLABELS, "ouput format ['"+FORMATLABELS+"', '"+FORMATYAML+"', '"+FORMATJSON+"', '"+FORMATJSONCOMPACT+"']")
_ = viper.BindPFlag("format", cmd.Flags().Lookup("format"))
return cmd
}

func dumpdata(args []string, raw bool) error {
dataType := "hardware"
func dumpdata(args []string, format string, raw bool) error {
dataType := "hostinfo"
if len(args) > 0 {
dataType = args[0]
}

var hostData interface{}
var mapData map[string]interface{}

switch dataType {
case DUMPHW:
hwData, err := hostinfo.Host()
case DUMPHOSTINFO:
hostData, err := hostinfo.Host()
if err != nil {
log.Fatalf("Cannot retrieve host data: %s", err)
}

if raw {
hostData = hwData
mapData = hostinfo.ExtractFullData(hostData)
} else {
dataMap, err := hostinfo.ExtractLabels(hwData)
if err != nil {
log.Fatalf("Cannot convert host data to labels: %s", err)
}
hostData = dataMap
mapData = hostinfo.ExtractLabels(hostData)
}
case DUMPLEGACY:
hwData, err := hostinfo.Host()
if err != nil {
log.Fatalf("Cannot retrieve host data: %s", err)
}

if raw {
mapData = hostinfo.ExtractFullData(hwData)
} else {
mapData = hostinfo.ExtractLabelsLegacy(hwData)
}
case DUMPSMBIOS:
smbiosData, err := dmidecode.Decode()
if err != nil {
log.Fatalf("Cannot retrieve SMBIOS data: %s", err)
}

hostData = smbiosData

mapData = smbiosData
default:
// Should never happen but manage it anyway
log.Fatalf("Unsupported data type: %s", dataType)
}

jsonData, err := json.MarshalIndent(hostData, "", " ")
var serializedData []byte
var err error

switch format {
case FORMATLABELS:
labels := map2Labels("", mapData)
keys := make([]string, 0, len(labels))
for k := range labels {
keys = append(keys, k)
}
sort.Strings(keys)

for _, k := range keys {
fmt.Printf("%-52s: %q\n", k, labels[k])
}
return nil
case FORMATJSON:
serializedData, err = json.MarshalIndent(mapData, "", " ")
case FORMATJSONCOMPACT:
serializedData, err = json.Marshal(mapData)
case FORMATYAML:
serializedData, err = yaml.Marshal(mapData)
default:
// Should never happen but manage it anyway
log.Fatalf("Unsupported output type: %s", format)
}

if err != nil {
log.Fatalf("Cannot convert host data to json: %s", err)
log.Fatalf("Cannot convert host data to %s: %s", format, err)
}
fmt.Printf("%s\n", string(jsonData))
fmt.Printf("%s\n", string(serializedData))

return nil
}

func map2Labels(rootKey string, data map[string]interface{}) map[string]string {
ret := map[string]string{}

for key, val := range data {
lbl := key
if len(rootKey) > 0 {
lbl = rootKey + "/" + lbl
}
if _, ok := val.(string); ok {
lbl = "${" + lbl + "}"
ret[lbl] = fmt.Sprintf("%s", val)
continue
}
if _, ok := val.(map[string]interface{}); !ok {
continue
}
for k, v := range map2Labels(lbl, val.(map[string]interface{})) {
ret[k] = v
}
}
return ret
}
Loading

0 comments on commit 723d7c3

Please sign in to comment.