diff --git a/hack/generate/samples/internal/go/memcached-with-customization/memcached_with_customization.go b/hack/generate/samples/internal/go/memcached-with-customization/memcached_with_customization.go index 5c51dc445e7..5e81a0497c1 100644 --- a/hack/generate/samples/internal/go/memcached-with-customization/memcached_with_customization.go +++ b/hack/generate/samples/internal/go/memcached-with-customization/memcached_with_customization.go @@ -27,7 +27,7 @@ import ( "github.com/operator-framework/operator-sdk/hack/generate/samples/internal/pkg" ) -// Memcached defines the Memcached Sample in GO using webhooks and monitoring code +// Memcached defines the Memcached Sample in GO using webhooks or webhooks and monitoring code type Memcached struct { ctx *pkg.SampleContext } @@ -39,25 +39,40 @@ var prometheusAPIVersion = "v0.59.0" // GenerateSample will call all actions to create the directory and generate the sample // Note that it should NOT be called in the e2e tests. func GenerateSample(binaryPath, samplesPath string) { - log.Infof("starting to generate Go memcached sample with webhooks and metrics documentation") - ctx, err := pkg.NewSampleContext(binaryPath, filepath.Join(samplesPath, "memcached-operator"), "GO111MODULE=on") - pkg.CheckError("generating Go memcached with webhooks and metrics documentation context", err) - generateWithMonitoring = false if strings.HasSuffix(samplesPath, "monitoring") { generateWithMonitoring = true } + var logInfo, errorInfo string + if generateWithMonitoring { + logInfo = "starting to generate Go memcached sample with webhooks and monitoring" + errorInfo = "generating Go memcached with webhooks and monitoring context" + } else { + logInfo = "starting to generate Go memcached sample with webhooks" + errorInfo = "generating Go memcached with webhooks context" + } + + log.Infof(logInfo) + ctx, err := pkg.NewSampleContext(binaryPath, filepath.Join(samplesPath, "memcached-operator"), "GO111MODULE=on") + pkg.CheckError(errorInfo, err) + memcached := Memcached{&ctx} memcached.Prepare() memcached.Run() } -// Prepare the Context for the Memcached with webhooks and metrics documentation Go Sample +// Prepare the Context for the Memcached with webhooks or with webhooks and monitoring Go Sample // Note that sample directory will be re-created and the context data for the sample // will be set such as the domain and GVK. func (mh *Memcached) Prepare() { - log.Infof("destroying directory for Memcached with webhooks and metrics documentation Go samples") + var logInfo string + if generateWithMonitoring { + logInfo = "destroying directory for Go Memcached sample with webhooks and monitoring" + } else { + logInfo = "destroying directory for Go Memcached sample with webhooks" + } + log.Infof(logInfo) mh.ctx.Destroy() log.Infof("creating directory") @@ -71,7 +86,7 @@ func (mh *Memcached) Prepare() { mh.ctx.Kind = "Memcached" } -// Run the steps to create the Memcached with metrics and webhooks Go Sample +// Run the steps to create the Memcached with webhooks or with webhooks and monitoring Go Sample func (mh *Memcached) Run() { if !mh.isV3() { @@ -930,105 +945,45 @@ const metricsdocsFragment = ` package main import ( + "bytes" "fmt" "sort" + "text/template" "github.com/example/memcached-operator/monitoring" ) -// please run "make generate-metricsdocs" to run this tool and update metrics documentation -const ( - title = "# Operator Metrics\n" - background = "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + - "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" - - KVSpecificMetrics = "## Operator Metrics List\n" - - opening = title + - background + - KVSpecificMetrics - - // footer - footerHeading = "## Developing new metrics\n" - footerContent = "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + - "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.\n" - - footer = footerHeading + footerContent -) - -// TODO: scaffolding these helpers with operator-lib: https://github.com/operator-framework/operator-lib. - -// metricList contains the name, description, and type for each metric. func main() { - metricList := metricDescriptionListToMetricList(monitoring.ListMetrics()) - sort.Sort(metricList) - writeToStdOut(metricList) -} + metricDescriptions := monitoring.ListMetrics() + sort.Slice(metricDescriptions, func(i, j int) bool { + return metricDescriptions[i].Name < metricDescriptions[j].Name + }) + + tmpl, err := template.New("Operator metrics").Parse("# Operator Metrics\n" + + "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + + "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" + + "## Operator Metrics List" + + "{{range .}}\n" + + "### {{.Name}}\n" + + "{{.Help}} " + + "Type: {{.Type}}.\n" + + "{{end}}" + + "## Developing new metrics\n" + + "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + + "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.") -// writeToStdOut receives a list of metrics and prints them to STDOUT. -func writeToStdOut(metricsList metricList) { - fmt.Print(opening) - metricsList.writeOut() - fmt.Print(footer) -} - -// Metric is an exported struct that defines the metric -// name, description, and type as a new type named Metric. -type Metric struct { - name string - description string - metricType string -} - -func metricDescriptionToMetric(md monitoring.MetricDescription) Metric { - return Metric{ - name: md.Name, - description: md.Help, - metricType: md.Type, + if err != nil { + panic(err) } -} - -// writeOut receives a metric of type metric and prints -// the metric name, description, and type. -func (m Metric) writeOut() { - fmt.Println("###", m.name) - fmt.Println(m.description, "Type: "+m.metricType+".") -} - -// metricList is an array that contain metrics from type metric, -// as a new type named metricList. -type metricList []Metric -// metricDescriptionListToMetricList collects the metrics exposed by the -// operator, and inserts them into the metricList array. -func metricDescriptionListToMetricList(mdl []monitoring.MetricDescription) metricList { - res := make([]Metric, len(mdl)) - for i, md := range mdl { - res[i] = metricDescriptionToMetric(md) + // generate the template using the sorted list of metrics + var buf bytes.Buffer + if err := tmpl.Execute(&buf, metricDescriptions); err != nil { + panic(err) } - return res -} - -// Len implements sort.Interface.Len -func (m metricList) Len() int { - return len(m) -} - -// Less implements sort.Interface.Less -func (m metricList) Less(i, j int) bool { - return m[i].name < m[j].name -} - -// Swap implements sort.Interface.Swap -func (m metricList) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -func (m metricList) writeOut() { - for _, met := range m { - met.writeOut() - } + // print the generated metrics documentation + fmt.Println(buf.String()) } ` diff --git a/testdata/go/v3/monitoring/memcached-operator/README.md b/testdata/go/v3/monitoring/memcached-operator/README.md index 3194aa0789a..43bc2fc0e22 100644 --- a/testdata/go/v3/monitoring/memcached-operator/README.md +++ b/testdata/go/v3/monitoring/memcached-operator/README.md @@ -1,8 +1,8 @@ -# memcached-operator -// TODO(user): Add simple overview of use/purpose +# memcached-operator (with monitoring) +A Go-based Operator framework that has the goal to install, deploy, monitor and manage [Memcached](https://hub.docker.com/_/memcached) on the cluster. ## Description -// TODO(user): An in-depth paragraph about your project and overview of use +This project is based on the testdata operator and will deploy the operator with the recommended structure and tooling for metrics, alerts, runbooks and all that is needed for monitoring with Prometheus, in order to help developers start implementing monitoring and provide them with tooling, examples and best practices. ## Getting Started You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. @@ -41,6 +41,9 @@ UnDeploy the controller from the cluster: make undeploy ``` +## Monitoring +This operator follows the [Operator Observability Best Practices](https://sdk.operatorframework.io/docs/best-practices/observability-best-practices/). + ## Contributing // TODO(user): Add detailed information on how you would like others to contribute to this project diff --git a/testdata/go/v3/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go b/testdata/go/v3/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go index 08fb06f0804..84ae54faf4a 100644 --- a/testdata/go/v3/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go +++ b/testdata/go/v3/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go @@ -17,103 +17,43 @@ limitations under the License. package main import ( + "bytes" "fmt" "sort" + "text/template" "github.com/example/memcached-operator/monitoring" ) -// please run "make generate-metricsdocs" to run this tool and update metrics documentation -const ( - title = "# Operator Metrics\n" - background = "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + - "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" - - KVSpecificMetrics = "## Operator Metrics List\n" - - opening = title + - background + - KVSpecificMetrics - - // footer - footerHeading = "## Developing new metrics\n" - footerContent = "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + - "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.\n" - - footer = footerHeading + footerContent -) - -// TODO: scaffolding these helpers with operator-lib: https://github.com/operator-framework/operator-lib. - -// metricList contains the name, description, and type for each metric. func main() { - metricList := metricDescriptionListToMetricList(monitoring.ListMetrics()) - sort.Sort(metricList) - writeToStdOut(metricList) -} - -// writeToStdOut receives a list of metrics and prints them to STDOUT. -func writeToStdOut(metricsList metricList) { - fmt.Print(opening) - metricsList.writeOut() - fmt.Print(footer) -} - -// Metric is an exported struct that defines the metric -// name, description, and type as a new type named Metric. -type Metric struct { - name string - description string - metricType string -} - -func metricDescriptionToMetric(md monitoring.MetricDescription) Metric { - return Metric{ - name: md.Name, - description: md.Help, - metricType: md.Type, + metricDescriptions := monitoring.ListMetrics() + sort.Slice(metricDescriptions, func(i, j int) bool { + return metricDescriptions[i].Name < metricDescriptions[j].Name + }) + + tmpl, err := template.New("Operator metrics").Parse("# Operator Metrics\n" + + "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + + "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" + + "## Operator Metrics List" + + "{{range .}}\n" + + "### {{.Name}}\n" + + "{{.Help}} " + + "Type: {{.Type}}.\n" + + "{{end}}" + + "## Developing new metrics\n" + + "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + + "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.") + + if err != nil { + panic(err) } -} - -// writeOut receives a metric of type metric and prints -// the metric name, description, and type. -func (m Metric) writeOut() { - fmt.Println("###", m.name) - fmt.Println(m.description, "Type: "+m.metricType+".") -} - -// metricList is an array that contain metrics from type metric, -// as a new type named metricList. -type metricList []Metric -// metricDescriptionListToMetricList collects the metrics exposed by the -// operator, and inserts them into the metricList array. -func metricDescriptionListToMetricList(mdl []monitoring.MetricDescription) metricList { - res := make([]Metric, len(mdl)) - for i, md := range mdl { - res[i] = metricDescriptionToMetric(md) + // generate the template using the sorted list of metrics + var buf bytes.Buffer + if err := tmpl.Execute(&buf, metricDescriptions); err != nil { + panic(err) } - return res -} - -// Len implements sort.Interface.Len -func (m metricList) Len() int { - return len(m) -} - -// Less implements sort.Interface.Less -func (m metricList) Less(i, j int) bool { - return m[i].name < m[j].name -} - -// Swap implements sort.Interface.Swap -func (m metricList) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -func (m metricList) writeOut() { - for _, met := range m { - met.writeOut() - } + // print the generated metrics documentation + fmt.Println(buf.String()) } diff --git a/testdata/go/v4-alpha/monitoring/memcached-operator/README.md b/testdata/go/v4-alpha/monitoring/memcached-operator/README.md index 3194aa0789a..43bc2fc0e22 100644 --- a/testdata/go/v4-alpha/monitoring/memcached-operator/README.md +++ b/testdata/go/v4-alpha/monitoring/memcached-operator/README.md @@ -1,8 +1,8 @@ -# memcached-operator -// TODO(user): Add simple overview of use/purpose +# memcached-operator (with monitoring) +A Go-based Operator framework that has the goal to install, deploy, monitor and manage [Memcached](https://hub.docker.com/_/memcached) on the cluster. ## Description -// TODO(user): An in-depth paragraph about your project and overview of use +This project is based on the testdata operator and will deploy the operator with the recommended structure and tooling for metrics, alerts, runbooks and all that is needed for monitoring with Prometheus, in order to help developers start implementing monitoring and provide them with tooling, examples and best practices. ## Getting Started You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. @@ -41,6 +41,9 @@ UnDeploy the controller from the cluster: make undeploy ``` +## Monitoring +This operator follows the [Operator Observability Best Practices](https://sdk.operatorframework.io/docs/best-practices/observability-best-practices/). + ## Contributing // TODO(user): Add detailed information on how you would like others to contribute to this project diff --git a/testdata/go/v4-alpha/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go b/testdata/go/v4-alpha/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go index 08fb06f0804..84ae54faf4a 100644 --- a/testdata/go/v4-alpha/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go +++ b/testdata/go/v4-alpha/monitoring/memcached-operator/monitoring/metricsdocs/metricsdocs.go @@ -17,103 +17,43 @@ limitations under the License. package main import ( + "bytes" "fmt" "sort" + "text/template" "github.com/example/memcached-operator/monitoring" ) -// please run "make generate-metricsdocs" to run this tool and update metrics documentation -const ( - title = "# Operator Metrics\n" - background = "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + - "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" - - KVSpecificMetrics = "## Operator Metrics List\n" - - opening = title + - background + - KVSpecificMetrics - - // footer - footerHeading = "## Developing new metrics\n" - footerContent = "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + - "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.\n" - - footer = footerHeading + footerContent -) - -// TODO: scaffolding these helpers with operator-lib: https://github.com/operator-framework/operator-lib. - -// metricList contains the name, description, and type for each metric. func main() { - metricList := metricDescriptionListToMetricList(monitoring.ListMetrics()) - sort.Sort(metricList) - writeToStdOut(metricList) -} - -// writeToStdOut receives a list of metrics and prints them to STDOUT. -func writeToStdOut(metricsList metricList) { - fmt.Print(opening) - metricsList.writeOut() - fmt.Print(footer) -} - -// Metric is an exported struct that defines the metric -// name, description, and type as a new type named Metric. -type Metric struct { - name string - description string - metricType string -} - -func metricDescriptionToMetric(md monitoring.MetricDescription) Metric { - return Metric{ - name: md.Name, - description: md.Help, - metricType: md.Type, + metricDescriptions := monitoring.ListMetrics() + sort.Slice(metricDescriptions, func(i, j int) bool { + return metricDescriptions[i].Name < metricDescriptions[j].Name + }) + + tmpl, err := template.New("Operator metrics").Parse("# Operator Metrics\n" + + "This document aims to help users that are not familiar with metrics exposed by this operator.\n" + + "The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" + + "## Operator Metrics List" + + "{{range .}}\n" + + "### {{.Name}}\n" + + "{{.Help}} " + + "Type: {{.Type}}.\n" + + "{{end}}" + + "## Developing new metrics\n" + + "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" + + "If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.") + + if err != nil { + panic(err) } -} - -// writeOut receives a metric of type metric and prints -// the metric name, description, and type. -func (m Metric) writeOut() { - fmt.Println("###", m.name) - fmt.Println(m.description, "Type: "+m.metricType+".") -} - -// metricList is an array that contain metrics from type metric, -// as a new type named metricList. -type metricList []Metric -// metricDescriptionListToMetricList collects the metrics exposed by the -// operator, and inserts them into the metricList array. -func metricDescriptionListToMetricList(mdl []monitoring.MetricDescription) metricList { - res := make([]Metric, len(mdl)) - for i, md := range mdl { - res[i] = metricDescriptionToMetric(md) + // generate the template using the sorted list of metrics + var buf bytes.Buffer + if err := tmpl.Execute(&buf, metricDescriptions); err != nil { + panic(err) } - return res -} - -// Len implements sort.Interface.Len -func (m metricList) Len() int { - return len(m) -} - -// Less implements sort.Interface.Less -func (m metricList) Less(i, j int) bool { - return m[i].name < m[j].name -} - -// Swap implements sort.Interface.Swap -func (m metricList) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -func (m metricList) writeOut() { - for _, met := range m { - met.writeOut() - } + // print the generated metrics documentation + fmt.Println(buf.String()) }