Skip to content

Commit 61c6dcd

Browse files
committed
Create CLI using github.com/alecthomas/kong
api, filesystem, and kubernetes are now sub commands
1 parent e7f874f commit 61c6dcd

File tree

9 files changed

+60
-91
lines changed

9 files changed

+60
-91
lines changed

.github/workflows/go.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ jobs:
2222
go-version: ${{ env.golang-version }}
2323
- run: mkdir -p cmd/api/ui/build && touch cmd/api/ui/build/empty
2424
- run: make test
25-
- run: make api kubernetes filesystem
25+
- run: make api

Makefile

+4-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Image URL to use all building/pushing image targets
22
IMG_API ?= api:latest
3-
IMG_KUBERNETES ?= kubernetes:latest
43

54
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
65
CRD_OPTIONS ?= "crd:trivialVersions=true"
@@ -26,19 +25,11 @@ clean:
2625
test: generate fmt vet manifests
2726
go test -race ./... -coverprofile cover.out
2827

29-
build: kubernetes filesystem api
30-
31-
# Build kubernetes binary
32-
kubernetes: generate fmt vet
33-
CGO_ENABLED=0 go build -v -ldflags '-w -extldflags '-static'' -o bin/kubernetes ./cmd/kubernetes/main.go
34-
35-
# Build kubernetes binary
36-
filesystem: generate fmt vet
37-
CGO_ENABLED=0 go build -v -ldflags '-w -extldflags '-static'' -o bin/filesystem ./cmd/filesystem/main.go
28+
build: api
3829

3930
# Build api binary
4031
api: fmt vet
41-
CGO_ENABLED=0 go build -v -ldflags '-w -extldflags '-static'' -o bin/api ./cmd/api/main.go
32+
CGO_ENABLED=0 go build -v -ldflags '-w -extldflags '-static'' -o bin/api ./cmd/api
4233

4334
# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
4435
deploy: manifests config/api.yaml config/kubernetes.yaml
@@ -74,23 +65,17 @@ generate: controller-gen manifests
7465
$(CONTROLLER_GEN) object:headerFile="kubernetes/hack/boilerplate.go.txt" paths="./..."
7566

7667
# Build the docker image
77-
docker-build: docker-build-api docker-build-kubernetes
68+
docker-build: docker-build-api
7869

7970
docker-build-api:
8071
docker build . -t ${IMG_API} -f ./cmd/api/Dockerfile
8172

82-
docker-build-kubernetes:
83-
docker build . -t ${IMG_KUBERNETES} -f ./cmd/kubernetes/Dockerfile
84-
8573
# Push the docker image
86-
docker-push: docker-push-api docker-push-kubernetes
74+
docker-push: docker-push-api
8775

8876
docker-push-api:
8977
docker push ${IMG_API}
9078

91-
docker-push-kubernetes:
92-
docker push ${IMG_KUBERNETES}
93-
9479
# find or download controller-gen
9580
# download controller-gen if necessary
9681
controller-gen:

cmd/api/Dockerfile

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ COPY cmd/api/ cmd/api/
2020
COPY kubernetes/ kubernetes/
2121
COPY openapi/ openapi/
2222
COPY slo/ slo/
23-
COPY slo/ slo/
2423
COPY go.mod go.mod
2524
COPY go.sum go.sum
2625
COPY Makefile Makefile

cmd/filesystem/main.go renamed to cmd/api/filesystem.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020

2121
var objectives = map[string]slo.Objective{}
2222

23-
func main() {
23+
func cmdFilesystem(configFiles, prometheusFolder string) {
2424
var gr run.Group
2525

2626
ctx, cancel := context.WithCancel(context.Background())
@@ -29,7 +29,7 @@ func main() {
2929
{
3030
gr.Add(func() error {
3131
// Initially read all files and send them to be processed and added to the in memory store.
32-
filenames, err := filepath.Glob("/etc/pyrra/*.yaml")
32+
filenames, err := filepath.Glob(configFiles)
3333
if err != nil {
3434
return err
3535
}
@@ -43,12 +43,15 @@ func main() {
4343
})
4444
}
4545
{
46+
dir := filepath.Dir(configFiles)
47+
log.Println("watching directory for changes", dir)
48+
4649
watcher, err := fsnotify.NewWatcher()
4750
if err != nil {
4851
log.Fatal(err)
4952
}
5053

51-
err = watcher.Add("/etc/pyrra")
54+
err = watcher.Add(dir)
5255
if err != nil {
5356
log.Fatal(err)
5457
}
@@ -110,7 +113,7 @@ func main() {
110113
}
111114

112115
_, file := filepath.Split(f)
113-
if err := ioutil.WriteFile(filepath.Join("/etc/prometheus/pyrra/", file), bytes, 0644); err != nil {
116+
if err := ioutil.WriteFile(filepath.Join(prometheusFolder, file), bytes, 0644); err != nil {
114117
return err
115118
}
116119

cmd/kubernetes/main.go renamed to cmd/api/kubernetes.go

+2-11
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package main
1818

1919
import (
2020
"context"
21-
"flag"
2221
"fmt"
2322
"net/http"
2423
"os"
@@ -49,23 +48,15 @@ func init() {
4948
// +kubebuilder:scaffold:scheme
5049
}
5150

52-
func main() {
53-
var metricsAddr string
54-
var enableLeaderElection bool
55-
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
56-
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
57-
"Enable leader election for controller manager. "+
58-
"Enabling this will ensure there is only one active controller manager.")
59-
flag.Parse()
60-
51+
func cmdKubernetes(metricsAddr string) {
6152
setupLog := ctrl.Log.WithName("setup")
6253
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
6354

6455
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
6556
Scheme: scheme,
6657
MetricsBindAddress: metricsAddr,
6758
Port: 9443,
68-
LeaderElection: enableLeaderElection,
59+
LeaderElection: false,
6960
LeaderElectionID: "9d76195a.metalmatze.de",
7061
})
7162
if err != nil {

cmd/api/main.go

+39-21
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"context"
55
"embed"
6-
"flag"
76
"fmt"
87
"html/template"
98
"io/fs"
@@ -17,6 +16,7 @@ import (
1716
"sync"
1817
"time"
1918

19+
"github.com/alecthomas/kong"
2020
"github.com/cespare/xxhash/v2"
2121
"github.com/dgraph-io/ristretto"
2222
"github.com/go-chi/chi/v5"
@@ -32,26 +32,50 @@ import (
3232
//go:embed ui/build
3333
var ui embed.FS
3434

35+
var CLI struct {
36+
API struct {
37+
PrometheusURL *url.URL `default:"http://localhost:9090" help:"The URL to the Prometheus to query."`
38+
PrometheusExternalURL *url.URL `help:"The URL for the UI to redirect users to when opening Prometheus. If empty the same as prometheus.url"`
39+
ApiURL *url.URL `default:"http://localhost:9444" help:"The URL to the API service like a Kubernetes Operator."`
40+
} `cmd:"" help:"Runs Pyrra's API and UI."`
41+
Filesystem struct {
42+
ConfigFiles string `default:"/etc/pyrra/*.yaml" help:"The folder where Pyrra finds the config files to use."`
43+
PrometheusFolder string `default:"/etc/prometheus/pyrra/" help:"The folder where Pyrra writes the generates Prometheus rules and alerts."`
44+
} `cmd:"" help:"Runs Pyrra's filesystem operator and backend for the API."`
45+
Kubernetes struct {
46+
MetricsAddr string `default:":8080" help:"The address the metric endpoint binds to."`
47+
} `cmd:"" help:"Runs Pyrra's Kubernetes operator and backend for the API."`
48+
}
49+
3550
func main() {
51+
ctx := kong.Parse(&CLI)
52+
switch ctx.Command() {
53+
case "api":
54+
cmdAPI(CLI.API.PrometheusURL, CLI.API.PrometheusExternalURL, CLI.API.ApiURL)
55+
case "filesystem":
56+
cmdFilesystem(CLI.Filesystem.ConfigFiles, CLI.Filesystem.PrometheusFolder)
57+
case "kubernetes":
58+
cmdKubernetes(CLI.Kubernetes.MetricsAddr)
59+
}
60+
61+
return
62+
}
63+
64+
func cmdAPI(prometheusURL, prometheusExternal, apiURL *url.URL) {
3665
build, err := fs.Sub(ui, "ui/build")
3766
if err != nil {
3867
log.Fatal(err)
3968
}
4069

41-
prometheusURL := flag.String("prometheus.url", "http://localhost:9090", "The URL to the Prometheus to query.")
42-
prometheusExternal := flag.String("prometheus.external", "", "The URL for the UI to redirect users to when opening Prometheus. If empty the same as prometheus.url")
43-
apiURL := flag.String("api.url", "http://localhost:9444", "The URL to the API service like a Kubernetes Operator.")
44-
flag.Parse()
45-
46-
if *prometheusExternal == "" {
70+
if prometheusExternal == nil {
4771
prometheusExternal = prometheusURL
4872
}
4973

50-
log.Println("Using Prometheus at", *prometheusURL)
51-
log.Println("Using external Prometheus at", *prometheusExternal)
52-
log.Println("Using API at", *apiURL)
74+
log.Println("Using Prometheus at", prometheusURL.String())
75+
log.Println("Using external Prometheus at", prometheusExternal.String())
76+
log.Println("Using API at", apiURL.String())
5377

54-
client, err := api.NewClient(api.Config{Address: *prometheusURL})
78+
client, err := api.NewClient(api.Config{Address: prometheusURL.String()})
5579
if err != nil {
5680
log.Fatal(err)
5781
}
@@ -71,15 +95,9 @@ func main() {
7195
cache: cache,
7296
}
7397

74-
parsedAPIURL, err := url.Parse(*apiURL)
75-
if err != nil {
76-
log.Fatal(err)
77-
return
78-
}
79-
8098
apiConfig := openapiclient.NewConfiguration()
81-
apiConfig.Scheme = parsedAPIURL.Scheme
82-
apiConfig.Host = parsedAPIURL.Host
99+
apiConfig.Scheme = apiURL.Scheme
100+
apiConfig.Host = apiURL.Host
83101
apiClient := openapiclient.NewAPIClient(apiConfig)
84102

85103
router := openapiserver.NewRouter(
@@ -101,7 +119,7 @@ func main() {
101119
if err := tmpl.Execute(w, struct {
102120
PrometheusURL string
103121
}{
104-
PrometheusURL: *prometheusExternal,
122+
PrometheusURL: prometheusExternal.String(),
105123
}); err != nil {
106124
log.Println(err)
107125
return
@@ -112,7 +130,7 @@ func main() {
112130
if err := tmpl.Execute(w, struct {
113131
PrometheusURL string
114132
}{
115-
PrometheusURL: *prometheusExternal,
133+
PrometheusURL: prometheusExternal.String(),
116134
}); err != nil {
117135
log.Println(err)
118136
}

cmd/kubernetes/Dockerfile

-29
This file was deleted.

go.mod

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,23 @@ module github.com/pyrra-dev/pyrra
33
go 1.16
44

55
require (
6+
github.com/alecthomas/kong v0.2.17
67
github.com/cespare/xxhash/v2 v2.1.1
78
github.com/dgraph-io/ristretto v0.0.3
8-
github.com/fsnotify/fsnotify v1.4.9 // indirect
9+
github.com/fsnotify/fsnotify v1.4.9
910
github.com/go-chi/chi/v5 v5.0.3
1011
github.com/go-chi/cors v1.2.0
1112
github.com/go-logr/logr v0.4.0
12-
github.com/gorilla/mux v1.8.0 // indirect
13+
github.com/gorilla/mux v1.8.0
1314
github.com/oklog/run v1.1.0
1415
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.47.0
1516
github.com/prometheus/client_golang v1.10.0
1617
github.com/prometheus/common v0.21.0
1718
github.com/prometheus/prometheus v1.8.2-0.20210421143221-52df5ef7a3be
1819
github.com/stretchr/testify v1.7.0
19-
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 // indirect
20+
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1
2021
k8s.io/apimachinery v0.21.0
2122
k8s.io/client-go v0.21.0
2223
sigs.k8s.io/controller-runtime v0.9.0-beta.1.0.20210505224715-55a329c15d6b
23-
sigs.k8s.io/yaml v1.2.0 // indirect
24+
sigs.k8s.io/yaml v1.2.0
2425
)

go.sum

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/
8484
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
8585
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
8686
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
87+
github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0=
88+
github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
8789
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
8890
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
8991
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -997,7 +999,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
997999
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
9981000
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
9991001
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
1000-
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY=
10011002
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
10021003
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 h1:x622Z2o4hgCr/4CiKWc51jHVKaWdtVpBNmEI8wI9Qns=
10031004
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=

0 commit comments

Comments
 (0)