Skip to content
Merged
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 operator/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/redpanda-data/redpanda-operator/operator/cmd/configurator"
"github.com/redpanda-data/redpanda-operator/operator/cmd/envsubst"
"github.com/redpanda-data/redpanda-operator/operator/cmd/run"
"github.com/redpanda-data/redpanda-operator/operator/cmd/sidecar"
"github.com/redpanda-data/redpanda-operator/operator/cmd/syncclusterconfig"
"github.com/redpanda-data/redpanda-operator/operator/cmd/version"
)
Expand All @@ -45,6 +46,7 @@ func init() {
run.Command(),
syncclusterconfig.Command(),
version.Command(),
sidecar.Command(),
)

logOptions.BindFlags(rootCmd.PersistentFlags())
Expand Down
146 changes: 146 additions & 0 deletions operator/cmd/sidecar/sidecar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright 2024 Redpanda Data, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package sidecar

import (
"context"
"errors"
"time"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

"github.com/redpanda-data/redpanda-operator/operator/internal/decommissioning"
)

var schemes = []func(s *runtime.Scheme) error{
clientgoscheme.AddToScheme,
}

func Command() *cobra.Command {
var (
metricsAddr string
probeAddr string
pprofAddr string
clusterNamespace string
clusterName string
decommissionRequeueTimeout time.Duration
decommissionVoteInterval time.Duration
decommissionMaxVoteCount int
redpandaYAMLPath string
)

cmd := &cobra.Command{
Use: "run",
Short: "Run the redpanda sidecar",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

return Run(
ctx,
metricsAddr,
probeAddr,
pprofAddr,
clusterNamespace,
clusterName,
decommissionRequeueTimeout,
decommissionVoteInterval,
decommissionMaxVoteCount,
redpandaYAMLPath,
)
},
}

cmd.Flags().StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
cmd.Flags().StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
cmd.Flags().StringVar(&pprofAddr, "pprof-bind-address", ":8082", "The address the metric endpoint binds to.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: port 8082 in default Redpanda helm chart deployment is used by HTTP listener. Could you add test to deploy Redpanda helm chart with this sidecar?

https://github.com/redpanda-data/helm-charts/blob/b0a8f611127d405d0811eae052fe75d56a70799d/charts/redpanda/ci/16-controller-sidecar-values.yaml

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add the test once I get the rest of the sidecar command finished off with the configwatcher port and pvcunbinder. Will leave this comment open so I don't forget!

cmd.Flags().StringVar(&clusterNamespace, "redpanda-cluster-namespace", "", "The namespace of the cluster that this sidecar manages.")
cmd.Flags().StringVar(&clusterName, "redpanda-cluster-name", "", "The name of the cluster that this sidecar manages.")
cmd.Flags().DurationVar(&decommissionRequeueTimeout, "decommission-requeue-timeout", 10*time.Second, "The time period to wait before rechecking a broker that is being decommissioned.")
cmd.Flags().DurationVar(&decommissionVoteInterval, "decommission-vote-interval", 30*time.Second, "The time period between incrementing decommission vote counts since the last decommission conditions were met.")
cmd.Flags().IntVar(&decommissionMaxVoteCount, "decommission-vote-count", 2, "The number of times that a vote must be tallied when a resource meets decommission conditions for it to actually be decommissioned.")
cmd.Flags().StringVar(&redpandaYAMLPath, "redpanda-yaml", "/etc/redpanda/redpanda.yaml", "Path to redpanda.yaml whose rpk stanza will be used for connecting to a Redpanda cluster.")

return cmd
}

func Run(
ctx context.Context,
metricsAddr string,
probeAddr string,
pprofAddr string,
clusterNamespace string,
clusterName string,
decommissionRequeueTimeout time.Duration,
decommissionVoteInterval time.Duration,
decommissionMaxVoteCount int,
redpandaYAMLPath string,
) error {
setupLog := ctrl.LoggerFrom(ctx).WithName("setup")

if clusterNamespace == "" {
err := errors.New("must specify a cluster-namespace parameter")
setupLog.Error(err, "no cluster namespace provided")
return err
}

if clusterName == "" {
err := errors.New("must specify a cluster-name parameter")
setupLog.Error(err, "no cluster name provided")
return err
}

scheme := runtime.NewScheme()

for _, fn := range schemes {
utilruntime.Must(fn(scheme))
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Metrics: metricsserver.Options{BindAddress: metricsAddr},
HealthProbeBindAddress: probeAddr,
PprofBindAddress: pprofAddr,
LeaderElection: true,
LeaderElectionID: clusterName + "." + clusterNamespace + ".redpanda",
Scheme: scheme,
LeaderElectionNamespace: clusterNamespace,
})
if err != nil {
setupLog.Error(err, "unable to initialize manager")
return err
}

fetcher := decommissioning.NewChainedFetcher(
// prefer RPK profile first and then move on to fetch from helm values
decommissioning.NewRPKProfileFetcher(redpandaYAMLPath),
decommissioning.NewHelmFetcher(mgr),
)

if err := decommissioning.NewStatefulSetDecommissioner(mgr, fetcher, []decommissioning.Option{
decommissioning.WithFilter(decommissioning.FilterStatefulSetOwner(clusterNamespace, clusterName)),
decommissioning.WithRequeueTimeout(decommissionRequeueTimeout),
decommissioning.WithDelayedCacheInterval(decommissionVoteInterval),
decommissioning.WithDelayedCacheMaxCount(decommissionMaxVoteCount),
}...).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "StatefulSetDecommissioner")
return err
}

if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
return err
}

return nil
}
12 changes: 12 additions & 0 deletions operator/config/rbac/bases/operator/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,18 @@ rules:
- patch
- update
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
Expand Down
109 changes: 109 additions & 0 deletions operator/config/rbac/decommissioner-role/role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: decommissioner-role
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- delete
- get
- list
- watch
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- patch
- apiGroups:
- ""
resources:
- pods
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: decommissioner-role
namespace: default
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- delete
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
4 changes: 2 additions & 2 deletions operator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ require (
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0
github.com/prometheus/client_golang v1.20.0
github.com/prometheus/common v0.55.0
github.com/redpanda-data/common-go/net v0.1.0
github.com/redpanda-data/common-go/rpadmin v0.1.9
github.com/redpanda-data/console/backend v0.0.0-20240303221210-05d5d9e85f20
github.com/redpanda-data/helm-charts v0.0.0-20241203151858-926cfe070c6e
Expand All @@ -42,6 +43,7 @@ require (
github.com/twmb/franz-go/pkg/sasl/kerberos v1.1.0
github.com/twmb/franz-go/pkg/sr v1.2.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
golang.org/x/sync v0.8.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -338,7 +340,6 @@ require (
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/redpanda-data/common-go/net v0.1.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/xid v1.5.0 // indirect
Expand Down Expand Up @@ -408,7 +409,6 @@ require (
go.step.sm/crypto v0.40.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
_ "embed"
"encoding/json"
"fmt"
"math/rand"
"slices"
"sort"
"strings"
Expand Down Expand Up @@ -798,7 +797,7 @@ func (s *RedpandaControllerSuite) setupRBAC() string {
Verbs: []string{"*"},
})

name := "testenv-" + s.randString(6)
name := "testenv-" + testenv.RandString(6)

role.Name = name
role.Namespace = s.env.Namespace()
Expand Down Expand Up @@ -843,22 +842,10 @@ func (s *RedpandaControllerSuite) setupRBAC() string {
return name
}

func (s *RedpandaControllerSuite) randString(length int) string {
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"

name := ""
for i := 0; i < length; i++ {
//nolint:gosec // not meant to be a secure random string.
name += string(alphabet[rand.Intn(len(alphabet))])
}

return name
}

func (s *RedpandaControllerSuite) minimalRP(useFlux bool) *redpandav1alpha2.Redpanda {
return &redpandav1alpha2.Redpanda{
ObjectMeta: metav1.ObjectMeta{
Name: "rp-" + s.randString(6), // GenerateName doesn't play nice with SSA.
Name: "rp-" + testenv.RandString(6), // GenerateName doesn't play nice with SSA.
},
Spec: redpandav1alpha2.RedpandaSpec{
ChartRef: redpandav1alpha2.ChartRef{
Expand Down
Loading