Skip to content

Commit 9d001d4

Browse files
committed
✨ Add Prometheus instance support to sample external plugin: implement init and edit commands, update manifests, and enhance test scripts
1 parent 5395def commit 9d001d4

File tree

13 files changed

+286
-121
lines changed

13 files changed

+286
-121
lines changed

docs/book/src/plugins/extending/external-plugins.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ structures.
3030

3131
`PluginRequest` contains the data collected from the CLI and any previously executed plugins. Kubebuilder sends this data as a JSON object to the external plugin via `stdin`.
3232

33+
**Example `PluginRequest` (triggered by `kubebuilder init --plugins sampleexternalplugin/v1`):**
34+
35+
```json
36+
{
37+
"apiVersion": "v1alpha1",
38+
"args": [],
39+
"command": "init",
40+
"universe": {}
41+
}
42+
```
43+
3344
**Example `PluginRequest` (triggered by `kubebuilder edit --plugins sampleexternalplugin/v1`):**
3445

3546
```json
@@ -51,12 +62,12 @@ structures.
5162
"apiVersion": "v1alpha1",
5263
"command": "edit",
5364
"metadata": {
54-
"description": "The `edit` subcommand adds Prometheus ServiceMonitor configuration for monitoring your operator.",
65+
"description": "The `edit` subcommand adds Prometheus instance configuration for monitoring your operator.",
5566
"examples": "kubebuilder edit --plugins sampleexternalplugin/v1"
5667
},
5768
"universe": {
58-
"config/prometheus/monitor.yaml": "# Prometheus ServiceMonitor manifest...",
59-
"config/prometheus/kustomization.yaml": "resources:\n - monitor.yaml\n"
69+
"config/prometheus/prometheus.yaml": "# Prometheus instance manifest...",
70+
"config/prometheus/kustomization.yaml": "resources:\n - prometheus.yaml\n"
6071
},
6172
"error": false,
6273
"errorMsgs": []
@@ -121,10 +132,15 @@ Otherwise, Kubebuilder would search for the plugins in a default path based on y
121132
You can now use it by calling the CLI commands:
122133

123134
```sh
124-
# Update the project configuration with the sample external plugin
125-
# The sampleexternalplugin adds Prometheus ServiceMonitor configuration
135+
# Initialize a new project with Prometheus monitoring
136+
kubebuilder init --plugins sampleexternalplugin/v1
137+
138+
# Update an existing project with Prometheus monitoring
126139
kubebuilder edit --plugins sampleexternalplugin/v1
127140

141+
# Display help information for the init subcommand
142+
kubebuilder init --plugins sampleexternalplugin/v1 --help
143+
128144
# Display help information for the edit subcommand
129145
kubebuilder edit --plugins sampleexternalplugin/v1 --help
130146

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
sampleexternalplugin
8+
bin/
9+
10+
# Test binary, built with `go test -c`
11+
*.test
12+
13+
# Output of the go coverage tool, specifically when used with LiteIDE
14+
*.out
15+
16+
# Go workspace file
17+
go.work
18+
19+
# Temporary test directories
20+
testdata/testplugin/

docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,7 @@ install: build ## Build and install the binary with the current source code. Use
6363
.PHONY: test-plugin
6464
test-plugin: ## Run the plugin test.
6565
./test/test.sh
66+
67+
.PHONY: clean
68+
clean: ## Clean build artifacts.
69+
rm -rf ./bin

docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1/cmd/cmd.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ func Run() {
5959

6060
// Run logic depending on the command that is requested by Kubebuilder
6161
switch pluginRequest.Command {
62+
// the `init` subcommand is used to add features during project initialization
63+
case "init":
64+
response = scaffolds.InitCmd(pluginRequest)
6265
// the `edit` subcommand is used to add optional features to an existing project
6366
// This is a realistic use case for external plugins - adding optional monitoring
6467
case "edit":

docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1/cmd/flags.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,27 @@ func flagsCmd(pr *external.PluginRequest) external.PluginResponse {
3636
Flags: []external.Flag{},
3737
}
3838

39-
switch pr.Command {
39+
// Parse args to determine which subcommand flags are being requested
40+
var subcommand string
41+
for _, arg := range pr.Args {
42+
if arg == "--init" {
43+
subcommand = "init"
44+
break
45+
} else if arg == "--edit" {
46+
subcommand = "edit"
47+
break
48+
}
49+
}
50+
51+
switch subcommand {
52+
case "init":
53+
pluginResponse.Flags = scaffolds.InitFlags
4054
case "edit":
4155
pluginResponse.Flags = scaffolds.EditFlags
4256
default:
4357
pluginResponse.Error = true
4458
pluginResponse.ErrorMsgs = []string{
45-
"unrecognized command: " + pr.Command,
59+
"unrecognized subcommand flag in args: " + string(rune(len(pr.Args))),
4660
}
4761
}
4862

docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1/cmd/metadata.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func metadataCmd(pr *external.PluginRequest) external.PluginResponse {
3939

4040
// Here is an example of parsing multiple flags from a Kubebuilder external plugin request
4141
flagsToParse := pflag.NewFlagSet("flagsFlags", pflag.ContinueOnError)
42+
flagsToParse.Bool("init", false, "sets the init flag to true")
4243
flagsToParse.Bool("edit", false, "sets the edit flag to true")
4344

4445
if err := flagsToParse.Parse(pr.Args); err != nil {
@@ -49,11 +50,16 @@ func metadataCmd(pr *external.PluginRequest) external.PluginResponse {
4950
return pluginResponse
5051
}
5152

53+
initFlag, _ := flagsToParse.GetBool("init")
5254
editFlag, _ := flagsToParse.GetBool("edit")
5355

5456
// The Phase 2 Plugins implementation will only ever pass a single boolean flag
55-
// argument in the JSON request `args` field. The flag will be `--edit` for `edit`
56-
if editFlag {
57+
// argument in the JSON request `args` field.
58+
if initFlag {
59+
// Populate the JSON response `metadata` field with a description
60+
// and examples for the `init` subcommand
61+
pluginResponse.Metadata = scaffolds.InitMeta
62+
} else if editFlag {
5763
// Populate the JSON response `metadata` field with a description
5864
// and examples for the `edit` subcommand
5965
pluginResponse.Metadata = scaffolds.EditMeta

docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1/internal/test/plugins/prometheus/kustomization.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func NewPrometheusKustomization() *PrometheusKustomization {
3030
}
3131

3232
const prometheusKustomizationTemplate = `resources:
33-
- monitor.yaml
33+
- prometheus.yaml
3434
`
3535

3636
// DefaultKustomizationPatch represents a patch to config/default/kustomization.yaml
@@ -47,12 +47,12 @@ func NewDefaultKustomizationPatch() *DefaultKustomizationPatch {
4747
}
4848
}
4949

50-
const defaultKustomizationPatchTemplate = `# [PROMETHEUS] To enable prometheus monitor, uncomment the following line in config/default/kustomization.yaml:
50+
const defaultKustomizationPatchTemplate = `# [PROMETHEUS] To enable prometheus monitoring, uncomment the following line in config/default/kustomization.yaml:
5151
#
5252
# In the resources section, add:
5353
# - ../prometheus
5454
#
55-
# This will include the Prometheus ServiceMonitor in your deployment.
55+
# This will include the Prometheus instance in your deployment.
5656
# Make sure you have the Prometheus Operator installed in your cluster.
5757
#
5858
# For more information, see: https://github.com/prometheus-operator/prometheus-operator
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package prometheus
17+
18+
import "fmt"
19+
20+
// PrometheusInstance represents a Prometheus instance manifest
21+
type PrometheusInstance struct {
22+
Path string
23+
Content string
24+
}
25+
26+
// PrometheusOptions allows configuration of the Prometheus instance
27+
type PrometheusOptions func(*PrometheusInstance)
28+
29+
// WithDomain sets the domain for the Prometheus instance
30+
func WithDomain(domain string) PrometheusOptions {
31+
return func(p *PrometheusInstance) {
32+
p.Content = fmt.Sprintf(prometheusTemplate, domain, domain, domain, domain)
33+
}
34+
}
35+
36+
// WithProjectName sets the project name for the Prometheus instance
37+
func WithProjectName(projectName string) PrometheusOptions {
38+
return func(p *PrometheusInstance) {
39+
// Project name can be used for labels or naming
40+
// For now, we'll use it in a future iteration if needed
41+
}
42+
}
43+
44+
// NewPrometheusInstance creates a new Prometheus instance manifest
45+
func NewPrometheusInstance(opts ...PrometheusOptions) *PrometheusInstance {
46+
p := &PrometheusInstance{
47+
Path: "config/prometheus/prometheus.yaml",
48+
}
49+
50+
for _, opt := range opts {
51+
opt(p)
52+
}
53+
54+
// Set default content if not set by options
55+
if p.Content == "" {
56+
p.Content = fmt.Sprintf(prometheusTemplate, "example.com", "example.com", "example.com", "example.com")
57+
}
58+
59+
return p
60+
}
61+
62+
const prometheusTemplate = `# Prometheus ServiceAccount
63+
apiVersion: v1
64+
kind: ServiceAccount
65+
metadata:
66+
name: prometheus
67+
namespace: system
68+
labels:
69+
app.kubernetes.io/name: %s
70+
app.kubernetes.io/managed-by: kustomize
71+
72+
---
73+
# Prometheus ClusterRole
74+
apiVersion: rbac.authorization.k8s.io/v1
75+
kind: ClusterRole
76+
metadata:
77+
name: prometheus
78+
labels:
79+
app.kubernetes.io/name: %s
80+
app.kubernetes.io/managed-by: kustomize
81+
rules:
82+
- apiGroups: [""]
83+
resources: ["nodes", "nodes/metrics", "services", "endpoints", "pods"]
84+
verbs: ["get", "list", "watch"]
85+
- apiGroups: [""]
86+
resources: ["configmaps"]
87+
verbs: ["get"]
88+
- nonResourceURLs: ["/metrics"]
89+
verbs: ["get"]
90+
91+
---
92+
# Prometheus ClusterRoleBinding
93+
apiVersion: rbac.authorization.k8s.io/v1
94+
kind: ClusterRoleBinding
95+
metadata:
96+
name: prometheus
97+
labels:
98+
app.kubernetes.io/name: %s
99+
app.kubernetes.io/managed-by: kustomize
100+
roleRef:
101+
apiGroup: rbac.authorization.k8s.io
102+
kind: ClusterRole
103+
name: prometheus
104+
subjects:
105+
- kind: ServiceAccount
106+
name: prometheus
107+
namespace: system
108+
109+
---
110+
# Prometheus Instance
111+
apiVersion: monitoring.coreos.com/v1
112+
kind: Prometheus
113+
metadata:
114+
name: prometheus
115+
namespace: system
116+
labels:
117+
app.kubernetes.io/name: %s
118+
app.kubernetes.io/managed-by: kustomize
119+
spec:
120+
logLevel: debug
121+
ruleSelector: {}
122+
scrapeInterval: 1m
123+
scrapeTimeout: 30s
124+
securityContext:
125+
runAsNonRoot: true
126+
runAsUser: 65534
127+
seccompProfile:
128+
type: RuntimeDefault
129+
serviceAccountName: prometheus
130+
serviceDiscoveryRole: EndpointSlice
131+
serviceMonitorSelector: {}
132+
`

0 commit comments

Comments
 (0)