github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/generator/helper/resources.go (about)

     1  package helper
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"text/template"
     7  
     8  	"github.com/SAP/jenkins-library/pkg/piperutils"
     9  )
    10  
    11  // PiperEnvironmentResource defines a piper environement resource which stores data across multiple pipeline steps
    12  type PiperEnvironmentResource struct {
    13  	Name       string
    14  	StepName   string
    15  	Parameters []PiperEnvironmentParameter
    16  	Categories []string
    17  }
    18  
    19  // PiperEnvironmentParameter defines a parameter within the Piper environment
    20  type PiperEnvironmentParameter struct {
    21  	Category string
    22  	Name     string
    23  	Type     string
    24  }
    25  
    26  const piperEnvStructTemplate = `type {{ .StepName }}{{ .Name | title}} struct {
    27  	{{- range $notused, $param := .Parameters }}
    28  	{{- if not $param.Category}}
    29  	{{ $param.Name | golangName }} {{ $param.Type | resourceFieldType }}
    30  	{{- end }}
    31  	{{- end }}
    32  	{{- range $notused, $category := .Categories }}
    33  	{{ $category }} struct {
    34  		{{- range $notused, $param := $.Parameters }}
    35  		{{- if eq $category $param.Category }}
    36  		{{ $param.Name | golangName }} {{ $param.Type | resourceFieldType }}
    37  		{{- end }}
    38  		{{- end }}
    39  	}
    40  	{{- end }}
    41  }
    42  
    43  func (p *{{ .StepName }}{{ .Name | title}}) persist(path, resourceName string) {
    44  	content := []struct{
    45  		category string
    46  		name string
    47  		value interface{}
    48  	}{
    49  		{{- range $notused, $param := .Parameters }}
    50  		{{- if not $param.Category}}
    51  		{category: "", name: "{{ $param.Name }}", value: p.{{ $param.Name | golangName}}},
    52  		{{- else }}
    53  		{category: "{{ $param.Category }}", name: "{{ $param.Name }}", value: p.{{ $param.Category }}.{{ $param.Name | golangName}}},
    54  		{{- end }}
    55  		{{- end }}
    56  	}
    57  
    58  	errCount := 0
    59  	for _, param := range content {
    60  		err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
    61  		if err != nil {
    62  			log.Entry().WithError(err).Error("Error persisting piper environment.")
    63  			errCount++
    64  		}
    65  	}
    66  	if errCount > 0 {
    67  		log.Entry().Error("failed to persist Piper environment")
    68  	}
    69  }`
    70  
    71  // StructName returns the name of the environment resource struct
    72  func (p *PiperEnvironmentResource) StructName() string {
    73  	return fmt.Sprintf("%v%v", p.StepName, piperutils.Title(p.Name))
    74  }
    75  
    76  // StructString returns the golang coding for the struct definition of the environment resource
    77  func (p *PiperEnvironmentResource) StructString() (string, error) {
    78  	funcMap := template.FuncMap{
    79  		"title":             piperutils.Title,
    80  		"golangName":        golangName,
    81  		"resourceFieldType": resourceFieldType,
    82  	}
    83  
    84  	tmpl, err := template.New("resources").Funcs(funcMap).Parse(piperEnvStructTemplate)
    85  	if err != nil {
    86  		return "", err
    87  	}
    88  
    89  	var generatedCode bytes.Buffer
    90  	err = tmpl.Execute(&generatedCode, &p)
    91  	if err != nil {
    92  		return "", err
    93  	}
    94  
    95  	return string(generatedCode.Bytes()), nil
    96  }
    97  
    98  // InfluxResource defines an Influx resouece that holds measurement information for a pipeline run
    99  type InfluxResource struct {
   100  	Name         string
   101  	StepName     string
   102  	Measurements []InfluxMeasurement
   103  }
   104  
   105  // InfluxMeasurement defines a measurement for Influx reporting which is defined via a step resource
   106  type InfluxMeasurement struct {
   107  	Name   string
   108  	Fields []InfluxMetric
   109  	Tags   []InfluxMetric
   110  }
   111  
   112  // InfluxMetric defines a metric (column) in an influx measurement
   113  type InfluxMetric struct {
   114  	Name string
   115  	Type string
   116  }
   117  
   118  // InfluxMetricContent defines the content of an Inflx metric
   119  type InfluxMetricContent struct {
   120  	Measurement string
   121  	ValType     string
   122  	Name        string
   123  	Value       *string
   124  }
   125  
   126  const influxStructTemplate = `type {{ .StepName }}{{ .Name | title}} struct {
   127  	{{- range $notused, $measurement := .Measurements }}
   128  	{{ $measurement.Name }} struct {
   129  		fields struct {
   130  			{{- range $notused, $field := $measurement.Fields }}
   131  			{{ $field.Name | golangName }} {{ $field.Type | resourceFieldType }}
   132  			{{- end }}
   133  		}
   134  		tags struct {
   135  			{{- range $notused, $tag := $measurement.Tags }}
   136  			{{ $tag.Name | golangName }} {{ $tag.Type | resourceFieldType }}
   137  			{{- end }}
   138  		}
   139  	}
   140  	{{- end }}
   141  }
   142  
   143  func (i *{{ .StepName }}{{ .Name | title}}) persist(path, resourceName string) {
   144  	measurementContent := []struct{
   145  		measurement string
   146  		valType     string
   147  		name        string
   148  		value       interface{}
   149  	}{
   150  		{{- range $notused, $measurement := .Measurements }}
   151  		{{- range $notused, $field := $measurement.Fields }}
   152  		{valType: config.InfluxField, measurement: "{{ $measurement.Name }}" , name: "{{ $field.Name }}", value: i.{{ $measurement.Name }}.fields.{{ $field.Name | golangName }}},
   153  		{{- end }}
   154  		{{- range $notused, $tag := $measurement.Tags }}
   155  		{valType: config.InfluxTag, measurement: "{{ $measurement.Name }}" , name: "{{  $tag.Name }}", value: i.{{ $measurement.Name }}.tags.{{  $tag.Name | golangName }}},
   156  		{{- end }}
   157  		{{- end }}
   158  	}
   159  
   160  	errCount := 0
   161  	for _, metric := range measurementContent {
   162  		err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
   163  		if err != nil {
   164  			log.Entry().WithError(err).Error("Error persisting influx environment.")
   165  			errCount++
   166  		}
   167  	}
   168  	if errCount > 0 {
   169  		log.Entry().Error("failed to persist Influx environment")
   170  	}
   171  }`
   172  
   173  // StructString returns the golang coding for the struct definition of the InfluxResource
   174  func (i *InfluxResource) StructString() (string, error) {
   175  	funcMap := template.FuncMap{
   176  		"title":             piperutils.Title,
   177  		"golangName":        golangName,
   178  		"resourceFieldType": resourceFieldType,
   179  	}
   180  
   181  	tmpl, err := template.New("resources").Funcs(funcMap).Parse(influxStructTemplate)
   182  	if err != nil {
   183  		return "", err
   184  	}
   185  
   186  	var generatedCode bytes.Buffer
   187  	err = tmpl.Execute(&generatedCode, &i)
   188  	if err != nil {
   189  		return "", err
   190  	}
   191  
   192  	return string(generatedCode.Bytes()), nil
   193  }
   194  
   195  // StructName returns the name of the influx resource struct
   196  func (i *InfluxResource) StructName() string {
   197  	return fmt.Sprintf("%v%v", i.StepName, piperutils.Title(i.Name))
   198  }
   199  
   200  // PiperEnvironmentResource defines a piper environement resource which stores data across multiple pipeline steps
   201  type ReportsResource struct {
   202  	Name       string
   203  	StepName   string
   204  	Parameters []ReportsParameter
   205  }
   206  
   207  // PiperEnvironmentParameter defines a parameter within the Piper environment
   208  type ReportsParameter struct {
   209  	FilePattern string
   210  	ParamRef    string
   211  	Type        string
   212  }
   213  
   214  const reportsStructTemplate = `type {{ .StepName }}{{ .Name | title}} struct {
   215  }
   216  
   217  func (p *{{ .StepName }}{{ .Name | title}}) persist(stepConfig {{ .StepName }}Options, gcpJsonKeyFilePath string, gcsBucketId string, gcsFolderPath string, gcsSubFolder string) {
   218  	if gcsBucketId == "" {
   219  		log.Entry().Info("persisting reports to GCS is disabled, because gcsBucketId is empty")
   220  		return
   221  	}
   222  	log.Entry().Info("Uploading reports to Google Cloud Storage...")
   223  	content := []gcs.ReportOutputParam{
   224  		{{- range $notused, $param := .Parameters }}
   225  		{FilePattern: "{{ $param.FilePattern }}", ParamRef: "{{ $param.ParamRef }}", StepResultType: "{{ $param.Type }}"},
   226  		{{- end }}
   227  	}
   228  	envVars := []gcs.EnvVar{
   229  		{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false},
   230  	}
   231  	gcsClient, err := gcs.NewClient(gcs.WithEnvVars(envVars))
   232  	if err != nil {
   233  		log.Entry().Errorf("creation of GCS client failed: %v", err)
   234          	return
   235  	}
   236  	defer gcsClient.Close()
   237  	structVal := reflect.ValueOf(&stepConfig).Elem()
   238  	inputParameters := map[string]string{}
   239  	for i := 0; i < structVal.NumField(); i++ {
   240  		field := structVal.Type().Field(i)
   241  		if field.Type.String() == "string" {
   242  			paramName := strings.Split(field.Tag.Get("json"), ",")
   243  			paramValue, _ := structVal.Field(i).Interface().(string)
   244  			inputParameters[paramName[0]] = paramValue
   245  		}
   246  	}
   247  	if err := gcs.PersistReportsToGCS(gcsClient, content, inputParameters, gcsFolderPath, gcsBucketId, gcsSubFolder, doublestar.Glob, os.Stat); err != nil {
   248  		log.Entry().Errorf("failed to persist reports: %v", err)
   249  	}
   250  }`
   251  
   252  // StructName returns the name of the environment resource struct
   253  func (p *ReportsResource) StructName() string {
   254  	return fmt.Sprintf("%v%v", p.StepName, piperutils.Title(p.Name))
   255  }
   256  
   257  // StructString returns the golang coding for the struct definition of the environment resource
   258  func (p *ReportsResource) StructString() (string, error) {
   259  	funcMap := template.FuncMap{
   260  		"title":             piperutils.Title,
   261  		"golangName":        golangName,
   262  		"resourceFieldType": resourceFieldType,
   263  	}
   264  
   265  	tmpl, err := template.New("resources").Funcs(funcMap).Parse(reportsStructTemplate)
   266  	if err != nil {
   267  		return "", err
   268  	}
   269  
   270  	var generatedCode bytes.Buffer
   271  	err = tmpl.Execute(&generatedCode, &p)
   272  	if err != nil {
   273  		return "", err
   274  	}
   275  
   276  	return string(generatedCode.String()), nil
   277  }