Skip to content

Commit

Permalink
fix: Add validation method for agent pre-requisite
Browse files Browse the repository at this point in the history
Move prometheus-agent pre-requisites to validation
function `Runnable()` to avoid creating prometheusagentcontroller
incase of validation failure.

Signed-off-by: Jayapriya Pai <slashpai9@gmail.com>
  • Loading branch information
slashpai committed Apr 12, 2023
1 parent 1448496 commit 5118fee
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 34 deletions.
23 changes: 17 additions & 6 deletions cmd/operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,20 @@ func Main() int {
return 1
}

pao, err := prometheusagentcontroller.New(ctx, cfg, log.With(logger, "component", "prometheusagentoperator"), r)
if err != nil {
fmt.Fprint(os.Stderr, "instantiating prometheus-agent controller failed: ", err)
cancel()
return 1
var pao *prometheusagentcontroller.Operator
ok, err := prometheusagentcontroller.Runnable(ctx, cfg, log.With(logger, "component", "prometheusagentoperator"))

if !ok && err != nil {
fmt.Fprint(os.Stderr, "pre-requistes for prometheus-agent controller failed: ", err)
}

if ok {
pao, err = prometheusagentcontroller.New(ctx, cfg, log.With(logger, "component", "prometheusagentoperator"), r)
if err != nil {
fmt.Fprint(os.Stderr, "instantiating prometheus-agent controller failed: ", err)
cancel()
return 1
}
}

ao, err := alertmanagercontroller.New(ctx, cfg, log.With(logger, "component", "alertmanageroperator"), r)
Expand Down Expand Up @@ -360,7 +369,9 @@ func Main() int {
}))

wg.Go(func() error { return po.Run(ctx) })
wg.Go(func() error { return pao.Run(ctx) })
if pao != nil {
wg.Go(func() error { return pao.Run(ctx) })
}
wg.Go(func() error { return ao.Run(ctx) })
wg.Go(func() error { return to.Run(ctx) })

Expand Down
24 changes: 24 additions & 0 deletions pkg/k8sutil/k8sutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"strings"

"github.com/cespare/xxhash/v2"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
Expand All @@ -37,6 +39,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
clientappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
clientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -114,6 +117,27 @@ func NewClusterConfig(host string, tlsInsecure bool, tlsConfig *rest.TLSClientCo
return cfg, nil
}

func CreateK8sClient(cfg *rest.Config) (*kubernetes.Clientset, error) {
client, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, err
}
return client, nil
}

func IsCRDInstalled(resource string, groupVersion string, kclient *kubernetes.Clientset, logger log.Logger) (bool, error) {
crdInstalled, err := IsAPIGroupVersionResourceSupported(kclient.Discovery(), groupVersion, resource)
if err != nil {
level.Warn(logger).Log("msg", "failed to check if the API supports the PrometheusAgent CRD", "err ", err)
return false, err
}
if !crdInstalled {
level.Info(logger).Log("msg", "Prometheus agent controller disabled because the PrometheusAgent CRD isn't installed")
return false, err
}
return true, nil
}

func IsResourceNotFoundError(err error) bool {
se, ok := err.(*apierrors.StatusError)
if !ok {
Expand Down
75 changes: 47 additions & 28 deletions pkg/prometheus/agent/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
)

Expand Down Expand Up @@ -82,14 +83,55 @@ type Operator struct {
endpointSliceSupported bool
}

func createK8sClusterConfig(conf operator.Config) (*rest.Config, error) {
cfg, err := k8sutil.NewClusterConfig(conf.Host, conf.TLSInsecure, &conf.TLSConfig)
if err != nil {
return nil, err
}

return cfg, nil
}

func Runnable(ctx context.Context, conf operator.Config, logger log.Logger) (bool, error) {
cfg, err := createK8sClusterConfig(conf)
if err != nil {
return false, errors.Wrap(err, "instantiating cluster config failed")
}

kclient, err := k8sutil.CreateK8sClient(cfg)
if err != nil {
return false, errors.Wrap(err, "instantiating kubernetes client failed")
}

crdInstalled, err := k8sutil.IsCRDInstalled(monitoringv1alpha1.SchemeGroupVersion.String(), monitoringv1alpha1.PrometheusAgentName, kclient, logger)
if !crdInstalled {
return false, err
}

verbs := map[string][]string{
monitoringv1alpha1.PrometheusAgentName: {"get", "list", "watch"},
fmt.Sprintf("%s/status", monitoringv1alpha1.PrometheusAgentName): {"update"},
}
missingPermissions, err := getMissingPermissions(ctx, kclient, conf, verbs)
if err != nil {
return false, err
}
if len(missingPermissions) > 0 {
level.Warn(logger).Log("msg", "Prometheus agent controller disabled because it lacks the required permissions on PrometheusAgent objects", "missingpermissions", fmt.Sprintf("%v", missingPermissions))
return false, nil
}

return true, nil
}

// New creates a new controller.
func New(ctx context.Context, conf operator.Config, logger log.Logger, r prometheus.Registerer) (*Operator, error) {
cfg, err := k8sutil.NewClusterConfig(conf.Host, conf.TLSInsecure, &conf.TLSConfig)
cfg, err := createK8sClusterConfig(conf)
if err != nil {
return nil, errors.Wrap(err, "instantiating cluster config failed")
}

client, err := kubernetes.NewForConfig(cfg)
client, err := k8sutil.CreateK8sClient(cfg)
if err != nil {
return nil, errors.Wrap(err, "instantiating kubernetes client failed")
}
Expand Down Expand Up @@ -282,25 +324,6 @@ func New(ctx context.Context, conf operator.Config, logger log.Logger, r prometh

// Run the controller.
func (c *Operator) Run(ctx context.Context) error {
crdInstalled, err := k8sutil.IsAPIGroupVersionResourceSupported(c.kclient.Discovery(), monitoringv1alpha1.SchemeGroupVersion.String(), monitoringv1alpha1.PrometheusAgentName)
if err != nil {
level.Warn(c.logger).Log("msg", "failed to check if the API supports the PrometheusAgent CRD", "err ", err)
return nil
}
if !crdInstalled {
level.Info(c.logger).Log("msg", "Prometheus agent controller disabled because the PrometheusAgent CRD isn't installed")
return nil
}

missingPermissions, err := c.getMissingPermissions(ctx)
if err != nil {
return err
}
if len(missingPermissions) > 0 {
level.Warn(c.logger).Log("msg", "Prometheus agent controller disabled because it lacks the required permissions on PrometheusAgent objects", "missingpermissions", fmt.Sprintf("%v", missingPermissions))
return nil
}

errChan := make(chan error)
go func() {
v, err := c.kclient.Discovery().ServerVersion()
Expand Down Expand Up @@ -1335,18 +1358,14 @@ func (c *Operator) handleMonitorNamespaceUpdate(oldo, curo interface{}) {

// getMissingPermissions returns the RBAC permissions that the controller would need to be
// granted to fulfill its mission. An empty map means that everything is ok.
func (c *Operator) getMissingPermissions(ctx context.Context) (map[string][]string, error) {
verbs := map[string][]string{
monitoringv1alpha1.PrometheusAgentName: {"get", "list", "watch"},
fmt.Sprintf("%s/status", monitoringv1alpha1.PrometheusAgentName): {"update"},
}
func getMissingPermissions(ctx context.Context, kclient *kubernetes.Clientset, conf operator.Config, verbs map[string][]string) (map[string][]string, error) {
var ssar *authv1.SelfSubjectAccessReview
var ssarResponse *authv1.SelfSubjectAccessReview
var err error

missingPermissions := map[string][]string{}

for ns := range c.config.Namespaces.PrometheusAllowList {
for ns := range conf.Namespaces.PrometheusAllowList {
for resource, verbs := range verbs {
for _, verb := range verbs {
ssar = &authv1.SelfSubjectAccessReview{
Expand All @@ -1360,7 +1379,7 @@ func (c *Operator) getMissingPermissions(ctx context.Context) (map[string][]stri
},
},
}
ssarResponse, err = c.kclient.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, ssar, metav1.CreateOptions{})
ssarResponse, err = kclient.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, ssar, metav1.CreateOptions{})
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 5118fee

Please sign in to comment.