diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a368ef0e..8b116b18 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,21 @@ on: - v* jobs: + bump_version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: | + sed -i "s/const operatorVersion = \".*\"/const operatorVersion = \"${GITHUB_REF_NAME#v}\"/" main.go + - uses: Amraneze/push-to-protected-branch@v1.5.0 + with: + repository: ${{ github.repository }} + branch_name: ${{ github.ref_name }} + github_token: ${{ secrets.AIVEN_CI_PAT__VALID_WHILE_ALEKS_IS_EMPLOYED }} + commit_message: "chore(version): bump operator version" + files_to_commit: main.go build_default_release_manifest: runs-on: ubuntu-latest steps: diff --git a/controllers/basic_controller.go b/controllers/basic_controller.go index a5fc54de..1a427285 100644 --- a/controllers/basic_controller.go +++ b/controllers/basic_controller.go @@ -36,11 +36,13 @@ type ( Controller struct { client.Client - Log logr.Logger - Scheme *runtime.Scheme - Recorder record.EventRecorder - DefaultToken string - AvGenClient avngen.Client + Log logr.Logger + Scheme *runtime.Scheme + Recorder record.EventRecorder + DefaultToken string + AvGenClient avngen.Client + KubeVersion string + OperatorVersion string } // Handlers represents Aiven API handlers @@ -123,13 +125,13 @@ func (c *Controller) reconcileInstance(ctx context.Context, req ctrl.Request, h return ctrl.Result{}, errNoTokenProvided } - avn, err := NewAivenClient(token) + avn, err := NewAivenClient(token, c.KubeVersion, c.OperatorVersion) if err != nil { c.Recorder.Event(o, corev1.EventTypeWarning, eventUnableToCreateClient, err.Error()) return ctrl.Result{}, fmt.Errorf("cannot initialize aiven client: %w", err) } - avnGen, err := NewAivenGeneratedClient(token) + avnGen, err := NewAivenGeneratedClient(token, c.KubeVersion, c.OperatorVersion) if err != nil { c.Recorder.Event(o, corev1.EventTypeWarning, eventUnableToCreateClient, err.Error()) return ctrl.Result{}, fmt.Errorf("cannot initialize aiven generated client: %w", err) diff --git a/controllers/common.go b/controllers/common.go index b1ba8784..25efb2be 100644 --- a/controllers/common.go +++ b/controllers/common.go @@ -3,6 +3,7 @@ package controllers import ( "context" "errors" + "fmt" "net/http" "reflect" "strconv" @@ -44,12 +45,9 @@ const ( errConditionCreateOrUpdate errCondition = "CreateOrUpdate" ) -var ( - version = "dev" - errTerminationProtectionOn = errors.New("termination protection is on") -) +var errTerminationProtectionOn = errors.New("termination protection is on") -func checkServiceIsRunning(ctx context.Context, avn *aiven.Client, avnGen avngen.Client, project, serviceName string) (bool, error) { +func checkServiceIsRunning(ctx context.Context, _ *aiven.Client, avnGen avngen.Client, project, serviceName string) (bool, error) { s, err := avnGen.ServiceGet(ctx, project, serviceName) if err != nil { // if service is not found, it is not running @@ -135,13 +133,13 @@ func isAivenServerError(err error) bool { } // NewAivenClient returns Aiven client (aiven/aiven-go-client/v2) -func NewAivenClient(token string) (*aiven.Client, error) { - return aiven.NewTokenClient(token, "k8s-operator/"+version) +func NewAivenClient(token, kubeVersion, operatorVersion string) (*aiven.Client, error) { + return aiven.NewTokenClient(token, fmt.Sprintf("k8s-operator/%s/%s", kubeVersion, operatorVersion)) } // NewAivenGeneratedClient returns Aiven generated client client (aiven/go-client-codegen) -func NewAivenGeneratedClient(token string) (avngen.Client, error) { - return avngen.NewClient(avngen.TokenOpt(token), avngen.UserAgentOpt("k8s-operator/"+version)) +func NewAivenGeneratedClient(token, kubeVersion, operatorVersion string) (avngen.Client, error) { + return avngen.NewClient(avngen.TokenOpt(token), avngen.UserAgentOpt(fmt.Sprintf("k8s-operator/%s/%s", kubeVersion, operatorVersion))) } func fromAnyPointer[T any](v *T) T { diff --git a/controllers/setup.go b/controllers/setup.go index 0f5d6ba5..ecb48b32 100644 --- a/controllers/setup.go +++ b/controllers/setup.go @@ -7,7 +7,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -func SetupControllers(mgr ctrl.Manager, defaultToken string) error { +func SetupControllers(mgr ctrl.Manager, defaultToken, kubeVersion, operatorVersion string) error { if err := (&SecretFinalizerGCController{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("SecretFinalizerGCController"), @@ -16,120 +16,120 @@ func SetupControllers(mgr ctrl.Manager, defaultToken string) error { } if err := (&ProjectReconciler{ - Controller: newController(mgr, "Project", defaultToken), + Controller: newController(mgr, "Project", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Project: %w", err) } if err := (&PostgreSQLReconciler{ - Controller: newController(mgr, "PostgreSQL", defaultToken), + Controller: newController(mgr, "PostgreSQL", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller PostgreSQL: %w", err) } if err := (&ConnectionPoolReconciler{ - Controller: newController(mgr, "ConnectionPool", defaultToken), + Controller: newController(mgr, "ConnectionPool", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller ConnectionPool: %w", err) } if err := (&DatabaseReconciler{ - Controller: newController(mgr, "Database", defaultToken), + Controller: newController(mgr, "Database", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Database: %w", err) } if err := (&KafkaReconciler{ - Controller: newController(mgr, "Kafka", defaultToken), + Controller: newController(mgr, "Kafka", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Kafka: %w", err) } if err := (&ProjectVPCReconciler{ - Controller: newController(mgr, "ProjectVPC", defaultToken), + Controller: newController(mgr, "ProjectVPC", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller ProjectVPC: %w", err) } if err := (&KafkaTopicReconciler{ - Controller: newController(mgr, "KafkaTopic", defaultToken), + Controller: newController(mgr, "KafkaTopic", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller KafkaTopic: %w", err) } if err := (&KafkaACLReconciler{ - Controller: newController(mgr, "KafkaACL", defaultToken), + Controller: newController(mgr, "KafkaACL", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller KafkaACL: %w", err) } if err := (&KafkaConnectReconciler{ - Controller: newController(mgr, "KafkaConnect", defaultToken), + Controller: newController(mgr, "KafkaConnect", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller KafkaConnect: %w", err) } if err := (&ServiceUserReconciler{ - Controller: newController(mgr, "ServiceUser", defaultToken), + Controller: newController(mgr, "ServiceUser", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller ServiceUser: %w", err) } if err := (&KafkaSchemaReconciler{ - Controller: newController(mgr, "KafkaSchema", defaultToken), + Controller: newController(mgr, "KafkaSchema", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller KafkaSchema: %w", err) } if err := (&ServiceIntegrationReconciler{ - Controller: newController(mgr, "ServiceIntegration", defaultToken), + Controller: newController(mgr, "ServiceIntegration", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller ServiceIntegration: %w", err) } if err := (&KafkaConnectorReconciler{ - Controller: newController(mgr, "KafkaConnector", defaultToken), + Controller: newController(mgr, "KafkaConnector", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller KafkaConnector: %w", err) } if err := (&RedisReconciler{ - Controller: newController(mgr, "Redis", defaultToken), + Controller: newController(mgr, "Redis", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Redis: %w", err) } if err := (&OpenSearchReconciler{ - Controller: newController(mgr, "OpenSearch", defaultToken), + Controller: newController(mgr, "OpenSearch", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller OpenSearch: %w", err) } if err := (&ClickhouseReconciler{ - Controller: newController(mgr, "Clickhouse", defaultToken), + Controller: newController(mgr, "Clickhouse", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Clickhouse: %w", err) } if err := (&ClickhouseUserReconciler{ - Controller: newController(mgr, "ClickhouseUser", defaultToken), + Controller: newController(mgr, "ClickhouseUser", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller ClickhouseUser: %w", err) } if err := (&MySQLReconciler{ - Controller: newController(mgr, "MySQL", defaultToken), + Controller: newController(mgr, "MySQL", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller MySQL: %w", err) } if err := (&CassandraReconciler{ - Controller: newController(mgr, "Cassandra", defaultToken), + Controller: newController(mgr, "Cassandra", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Cassandra: %w", err) } if err := (&GrafanaReconciler{ - Controller: newController(mgr, "Grafana", defaultToken), + Controller: newController(mgr, "Grafana", defaultToken, kubeVersion, operatorVersion), }).SetupWithManager(mgr); err != nil { return fmt.Errorf("controller Grafana: %w", err) } @@ -138,12 +138,14 @@ func SetupControllers(mgr ctrl.Manager, defaultToken string) error { return nil } -func newController(mgr ctrl.Manager, name, defaultToken string) Controller { +func newController(mgr ctrl.Manager, name, defaultToken, kubeVersion, operatorVersion string) Controller { return Controller{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName(name), - Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor(strings.ToLower(name) + "-reconciler"), - DefaultToken: defaultToken, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName(name), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor(strings.ToLower(name) + "-reconciler"), + DefaultToken: defaultToken, + KubeVersion: kubeVersion, + OperatorVersion: operatorVersion, } } diff --git a/main.go b/main.go index a23ced1d..dd806ac6 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/discovery" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" ctrl "sigs.k8s.io/controller-runtime" @@ -28,6 +29,9 @@ var ( setupLog = ctrl.Log.WithName("setup") ) +// operatorVersion is the current version of the operator. +const operatorVersion = "0.17.0" + const port = 9443 func init() { @@ -79,8 +83,19 @@ func main() { os.Exit(1) } + discoveryClient, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig()) + if err != nil { + setupLog.Error(err, "unable to create discovery client") + os.Exit(1) + } + kubeVersion, err := discoveryClient.ServerVersion() + if err != nil { + setupLog.Error(err, "unable to get kube version") + os.Exit(1) + } + defaultToken := os.Getenv("DEFAULT_AIVEN_TOKEN") - err = controllers.SetupControllers(mgr, defaultToken) + err = controllers.SetupControllers(mgr, defaultToken, kubeVersion.String(), operatorVersion) if err != nil { setupLog.Error(err, "controllers setup error") } diff --git a/tests/suite_test.go b/tests/suite_test.go index 52d2e189..68a85e1f 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -13,6 +13,7 @@ import ( "github.com/kelseyhightower/envconfig" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -34,6 +35,10 @@ const ( secretRefKey = "token" ) +// operatorVersion defines the version of the operator that is used in the tests. +// It is defined as "test" to be able to differentiate it from the actual operator version when running tests. +const operatorVersion = "test" + type testConfig struct { Token string `envconfig:"AIVEN_TOKEN" required:"true"` Project string `envconfig:"AIVEN_PROJECT_NAME" required:"true"` @@ -103,11 +108,6 @@ func setupSuite() (*envtest.Environment, error) { return nil, err } - avnClient, err = controllers.NewAivenClient(cfg.Token) - if err != nil { - return nil, err - } - mgr, err := ctrl.NewManager(c, ctrl.Options{ Scheme: scheme.Scheme, MetricsBindAddress: "0", @@ -131,12 +131,26 @@ func setupSuite() (*envtest.Environment, error) { ctx, cancel := testCtx() defer cancel() + discoveryClient, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig()) + if err != nil { + return nil, fmt.Errorf("unable to create discovery client: %w", err) + } + kubeVersion, err := discoveryClient.ServerVersion() + if err != nil { + return nil, fmt.Errorf("unable to get k8s version: %w", err) + } + + avnClient, err = controllers.NewAivenClient(cfg.Token, kubeVersion.String()+"-test", operatorVersion+"-test") + if err != nil { + return nil, err + } + err = k8sClient.Create(ctx, secret) if err != nil { return nil, err } - err = controllers.SetupControllers(mgr, cfg.Token) + err = controllers.SetupControllers(mgr, cfg.Token, kubeVersion.String(), operatorVersion) if err != nil { return nil, fmt.Errorf("unable to setup controllers: %w", err) }