github.com/grafana/pyroscope@v1.18.0/tools/monitoring-chart-extractor/main.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	"go.yaml.in/yaml/v3"
    15  )
    16  
    17  func main() {
    18  	outputPath := flag.CommandLine.String("output.path", "./operations/monitoring/", "Provide the output path for the code generation. Warning: All existing files will be overwritten.")
    19  	flag.Parse()
    20  
    21  	if err := run(*outputPath); err != nil {
    22  		log.Fatal(err)
    23  	}
    24  }
    25  
    26  func outputRules(outputPath string, fileName string, body []byte) error {
    27  	if fileName == "prometheus.yaml" {
    28  		return nil
    29  	}
    30  	path := filepath.Join(outputPath, "rules", fileName)
    31  
    32  	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
    33  		return err
    34  	}
    35  
    36  	return os.WriteFile(path, body, 0644)
    37  }
    38  
    39  func outputDashboards(outputPath string, fileName string, body []byte) error {
    40  	path := filepath.Join(outputPath, "dashboards", fileName)
    41  
    42  	if !strings.HasSuffix(path, ".json") {
    43  		return nil
    44  	}
    45  
    46  	data := map[string]any{}
    47  	if err := json.Unmarshal(body, &data); err != nil {
    48  		return fmt.Errorf("error Unmarshalling body of '%s': %w", fileName, err)
    49  	}
    50  
    51  	bodyFormatted, err := json.MarshalIndent(data, "", "  ")
    52  	if err != nil {
    53  		return fmt.Errorf("error marshalling body of '%s': %w", fileName, err)
    54  	}
    55  
    56  	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
    57  		return err
    58  	}
    59  
    60  	return os.WriteFile(path, bodyFormatted, 0644)
    61  }
    62  
    63  func run(outputPath string) error {
    64  	d := yaml.NewDecoder(os.Stdin)
    65  	obj := map[string]any{}
    66  
    67  	for {
    68  		err := d.Decode(&obj)
    69  		if err != nil {
    70  			if err == io.EOF {
    71  				return nil
    72  			}
    73  			return err
    74  		}
    75  
    76  		metaIntf, ok := obj["metadata"]
    77  		if !ok {
    78  			return errors.New("metadata not found")
    79  		}
    80  
    81  		meta, ok := metaIntf.(map[string]any)
    82  		if !ok {
    83  			return fmt.Errorf("metadata not object: %T", metaIntf)
    84  		}
    85  
    86  		nameIntf, ok := meta["name"]
    87  		if !ok {
    88  			return errors.New("name not found")
    89  		}
    90  
    91  		name, ok := nameIntf.(string)
    92  		if !ok {
    93  			return errors.New("name not string")
    94  		}
    95  
    96  		var handle func(string, string, []byte) error
    97  
    98  		switch name {
    99  		case "pyroscope-monitoring-dashboards":
   100  			handle = outputDashboards
   101  		case "pyroscope-monitoring-rules":
   102  			handle = outputRules
   103  		default:
   104  			continue
   105  		}
   106  
   107  		dataIntf, ok := obj["data"]
   108  		if !ok {
   109  			return errors.New("data not found")
   110  		}
   111  
   112  		data, ok := dataIntf.(map[string]any)
   113  		if !ok {
   114  			return fmt.Errorf("data not object: %T", dataIntf)
   115  		}
   116  
   117  		for key, bodyIntf := range data {
   118  			body, ok := bodyIntf.(string)
   119  			if !ok {
   120  				continue
   121  			}
   122  			if err := handle(outputPath, key, []byte(body)); err != nil {
   123  				return err
   124  			}
   125  		}
   126  	}
   127  }