Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ helm install --create-namespace --namespace pvc-autoresizer pvc-autoresizer pvc-

See the Chart [README.md](./charts/pvc-autoresizer/README.md) for detailed documentation on the Helm Chart.

For instructions on installing on OpenShift refer to the doc [openshift_monitoring.md](./docs/openshift_monitoring.md).

### How to use

To allow auto volume expansion, the StorageClass of PVC need to allow volume expansion and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ spec:
- /pvc-autoresizer
args:
- --prometheus-url={{ .Values.controller.args.prometheusURL }}
- --bearer-token={{ .Values.controller.args.bearerToken }}
- --interval={{ .Values.controller.args.interval }}
{{- if .Values.controller.args.useK8sMetricsApi }}
- --use-k8s-metrics-api={{ .Values.controller.args.useK8sMetricsApi }}
Expand All @@ -48,7 +49,7 @@ spec:
{{- end }}
{{- if not .Values.webhook.pvcMutatingWebhook.enabled }}
- --pvc-mutating-webhook-enabled=false
{{- end}}
{{- end }}
image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}"
{{- with .Values.image.pullPolicy }}
imagePullPolicy: {{ . }}
Expand Down
3 changes: 3 additions & 0 deletions charts/pvc-autoresizer/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ controller:
# Used as "--prometheus-url" option
prometheusURL: http://prometheus-prometheus-oper-prometheus.prometheus.svc:9090

# controller.args.bearerToken -- Specify bearer token, useful for accessing OpenShift Monitoring Prometheus.
bearerToken: ""

# controller.args.namespaces -- Specify namespaces to control the pvcs of. Empty for all namespaces.
# Used as "--namespaces" option
namespaces: []
Expand Down
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var config struct {
namespaces []string
watchInterval time.Duration
prometheusURL string
bearerToken string
useK8sMetricsApi bool
skipAnnotation bool
development bool
Expand Down Expand Up @@ -56,6 +57,7 @@ func init() {
"Namespaces to resize PersistentVolumeClaims within. Empty for all namespaces.")
fs.DurationVar(&config.watchInterval, "interval", 1*time.Minute, "Interval to monitor pvc capacity.")
fs.StringVar(&config.prometheusURL, "prometheus-url", "", "Prometheus URL to query volume stats.")
fs.StringVar(&config.bearerToken, "bearer-token", "", "bearer token for Prometheus authentication.")
fs.BoolVar(&config.useK8sMetricsApi, "use-k8s-metrics-api", false, "Use Kubernetes metrics API instead of Prometheus")
fs.BoolVar(&config.skipAnnotation, "no-annotation-check", false, "Skip annotation check for StorageClass")
fs.BoolVar(&config.development, "development", false, "Use development logger config")
Expand Down
3 changes: 2 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ func subMain() error {
if config.useK8sMetricsApi {
metricsClient, err = runners.NewK8sMetricsApiClient()
} else if config.prometheusURL != "" {
metricsClient, err = runners.NewPrometheusClient(config.prometheusURL)
setupLog.Info("enable prometheus url", "url", config.prometheusURL)
metricsClient, err = runners.NewPrometheusClient(config.prometheusURL, config.bearerToken, ctrl.Log.WithName("prometheus-client"))
} else {
setupLog.Error(err, "enable use-k8s-metrics-api or provide prometheus-url")
return err
Expand Down
14 changes: 14 additions & 0 deletions docs/openshift_monitoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Integration with OpenShift Monitoring

https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/monitoring/accessing-metrics#about-accessing-monitoring-web-service-apis_accessing-monitoring-apis-by-using-the-cli

```
helm install --create-namespace --namespace pvc-autoresizer pvc-autoresizer pvc-autoresizer/pvc-autoresizer --set "controller.args.prometheusURL=https://prometheus-k8s-openshift-monitoring.apps.[clustername.domain]/" --set "controller.args.bearerToken=$(oc create token cluster-monitoring-operator --duration=8760h -n openshift-monitoring)

oc get pods -n pvc-autoresizer
```

## TODO
[ ] Support proper TLS not just `InsecureSkipVerify: true`
[ ] Add support for other authentication method than bearer token
[ ] Document how to configure the `controller-pvc-autoresizer` serviceAccount for [cluster-monitoring-view](https://www.redhat.com/en/blog/custom-grafana-dashboards-red-hat-openshift-container-platform-4)
3 changes: 2 additions & 1 deletion internal/runners/metrics_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http/httptest"
"sync"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -40,7 +41,7 @@ var _ = Describe("test prometheusClient", func() {
ts := httptest.NewServer(http.HandlerFunc(http.NotFound))
defer ts.Close()

c, err := NewPrometheusClient(ts.URL)
c, err := NewPrometheusClient(ts.URL, "", logr.Discard())
Expect(err).ToNot(HaveOccurred())
_, err = c.GetMetrics(context.TODO())
Expect(err).To(HaveOccurred())
Expand Down
43 changes: 39 additions & 4 deletions internal/runners/prometheus_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package runners

import (
"context"
"crypto/tls"
"fmt"
"net/http"
"strings"
"time"

"github.com/go-logr/logr"
"github.com/prometheus/client_golang/api"
prometheusv1 "github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/common/model"
Expand All @@ -13,20 +17,51 @@ import (
)

// NewPrometheusClient returns a new prometheusClient
func NewPrometheusClient(url string) (MetricsClient, error) {
client, err := api.NewClient(api.Config{
Address: url,
})
func NewPrometheusClient(url string, bearerToken string, log logr.Logger) (MetricsClient, error) {
log.Info("creating new prometheus client", "url", url)

// Create base transport with TLS config if needed
var baseTransport http.RoundTripper = http.DefaultTransport
if strings.HasPrefix(url, "https") {
log.Info("using https, creating transport with tls config")
baseTransport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}

// Wrap transport with bearer token if provided
var rt http.RoundTripper = baseTransport
if bearerToken != "" {
rt = roundTripperFunc(func(req *http.Request) (*http.Response, error) {
req.Header.Set("Authorization", "Bearer "+bearerToken)
return baseTransport.RoundTrip(req)
})
}

config := api.Config{
Address: url,
RoundTripper: rt,
}

client, err := api.NewClient(config)
if err != nil {
log.Error(err, "failed to create prometheus client")
return nil, err
}
v1api := prometheusv1.NewAPI(client)

log.Info("created prometheus client successfully")
return &prometheusClient{
prometheusAPI: v1api,
}, nil
}

type roundTripperFunc func(*http.Request) (*http.Response, error)

func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}

type prometheusClient struct {
prometheusAPI prometheusv1.API
}
Expand Down