mirror of
				https://github.com/1Password/onepassword-operator.git
				synced 2025-10-31 11:49:40 +00:00 
			
		
		
		
	 cabc020cc6
			
		
	
	cabc020cc6
	
	
	
		
			
			* Add missing improvements from Operator SDK 1.34.1 These were not mentioned in the upgrade documentation for version 1.34.x (https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.34.0/), but I've found them by compating the release with the previous one (https://github.com/operator-framework/operator-sdk/compare/v1.33.0...v1.34.1). * Upgrade to Operator SDK 1.36.0 Source of upgrade steps: https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.36.0/ Key differences: - Go packages `k8s.io/*` are already at a version higher than the one in the upgrade. - `ENVTEST_K8S_VERSION` is at a version higher than the one in the upgrade - We didn't have the golangci-lint make command before, thus we only needed to add things. * Upgrade to Operator SDK 1.38.0 Source of upgrade steps: https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.38.0/ * Upgrade to Operator SDK 1.39.0 Source of upgrade steps: https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.39.0/ * Upgrade to Operator SDK 1.40.0 Source of upgrade steps: https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.40.0/ I didn't do the "Add app.kubernetes.io/name label to your manifests" since it seems that we have it already, and it's customized. * Address lint errors * Update golangci-lint version used to support Go 1.24 * Improve workflows - Make workflow targets more specific. - Make build workflow only build (i.e. remove test part of it). - Rearrange steps and improve naming for build workflow. * Add back deleted test Initially the test has been removed due to lint saying that it was duplicate code, but it falsely errored since the values are different. * Improve code and add missing upgrade pieces * Upgrade to Operator SDK 1.41.1 Source of upgrade steps: https://sdk.operatorframework.io/docs/upgrading-sdk-version/v1.41.0/ Upgrading to 1.41.1 from 1.40.0 doesn't have any migration steps. Key elements: - Upgrade to golangci-lint v2 - Made the manifests using the updated controller tools * Address linter errors golanci-lint v2 seems to be more robust than the previous one, which is beneficial. Thus, we address the linter errors thrown by v2 and improve our code even further. * Add Makefile improvements These were brought in by comparing the Makefile of a freshly created operator using the latest operator-sdk with ours. * Add missing default kustomization for 1.40.0 upgrade * Bring default kustomization to latest version This is done by putting the file's content from a newly-generated operator. * Switch metrics-bind-address default value back to 8080 This ensures that the upgrade is backwards-compatible. * Add webhook-related scaffolding This enables us to easily add support for webhooks by running `operator-sdk create webhook` whenever we want to add them. * Fix typo
		
			
				
	
	
		
			242 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| MIT License
 | |
| 
 | |
| Copyright (c) 2020-2024 1Password
 | |
| 
 | |
| Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| of this software and associated documentation files (the "Software"), to deal
 | |
| in the Software without restriction, including without limitation the rights
 | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| copies of the Software, and to permit persons to whom the Software is
 | |
| furnished to do so, subject to the following conditions:
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included in all
 | |
| copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
| SOFTWARE.
 | |
| */
 | |
| 
 | |
| package controller
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	. "github.com/onsi/ginkgo/v2"
 | |
| 	. "github.com/onsi/gomega"
 | |
| 	"github.com/stretchr/testify/mock"
 | |
| 
 | |
| 	"k8s.io/client-go/kubernetes/scheme"
 | |
| 	"k8s.io/client-go/rest"
 | |
| 	ctrl "sigs.k8s.io/controller-runtime"
 | |
| 	"sigs.k8s.io/controller-runtime/pkg/client"
 | |
| 	"sigs.k8s.io/controller-runtime/pkg/envtest"
 | |
| 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 | |
| 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 | |
| 
 | |
| 	onepasswordcomv1 "github.com/1Password/onepassword-operator/api/v1"
 | |
| 	"github.com/1Password/onepassword-operator/pkg/mocks"
 | |
| 	"github.com/1Password/onepassword-operator/pkg/onepassword/model"
 | |
| 	// +kubebuilder:scaffold:imports
 | |
| )
 | |
| 
 | |
| // These tests use Ginkgo (BDD-style Go testing framework). Refer to
 | |
| // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
 | |
| 
 | |
| const (
 | |
| 	username = "test-user"
 | |
| 	password = "QmHumKc$mUeEem7caHtbaBaJ"
 | |
| 
 | |
| 	username2 = "test-user2"
 | |
| 	password2 = "4zotzqDqXKasLFT2jzTs"
 | |
| 
 | |
| 	annotationRegExpString = "^operator.1password.io\\/[a-zA-Z\\.]+"
 | |
| )
 | |
| 
 | |
| // Define utility constants for object names and testing timeouts/durations and intervals.
 | |
| const (
 | |
| 	namespace = "default"
 | |
| 
 | |
| 	timeout  = time.Second * 10
 | |
| 	duration = time.Second * 10
 | |
| 	interval = time.Millisecond * 250
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	cfg                       *rest.Config
 | |
| 	k8sClient                 client.Client
 | |
| 	testEnv                   *envtest.Environment
 | |
| 	ctx                       context.Context
 | |
| 	cancel                    context.CancelFunc
 | |
| 	onePasswordItemReconciler *OnePasswordItemReconciler
 | |
| 	deploymentReconciler      *DeploymentReconciler
 | |
| 	mockGetItemByIDFunc       *mock.Call
 | |
| 
 | |
| 	item1 = &TestItem{
 | |
| 		ItemID:  "nwrhuano7bcwddcviubpp4mhfq",
 | |
| 		VaultID: "hfnjvi6aymbsnfc2xeeoheizda",
 | |
| 		Name:    "test-item",
 | |
| 		Version: 123,
 | |
| 		Path:    "vaults/hfnjvi6aymbsnfc2xeeoheizda/items/nwrhuano7bcwddcviubpp4mhfq",
 | |
| 		Data: map[string]string{
 | |
| 			"username": username,
 | |
| 			"password": password,
 | |
| 		},
 | |
| 		SecretData: map[string][]byte{
 | |
| 			"password": []byte(password),
 | |
| 			"username": []byte(username),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	item2 = &TestItem{
 | |
| 		ItemID:  "nwrhuano7bcwddcviubpp4mhf2",
 | |
| 		VaultID: "hfnjvi6aymbsnfc2xeeoheizd2",
 | |
| 		Name:    "test-item2",
 | |
| 		Path:    "vaults/hfnjvi6aymbsnfc2xeeoheizd2/items/nwrhuano7bcwddcviubpp4mhf2",
 | |
| 		Version: 456,
 | |
| 		Data: map[string]string{
 | |
| 			"username": username2,
 | |
| 			"password": password2,
 | |
| 		},
 | |
| 		SecretData: map[string][]byte{
 | |
| 			"password": []byte(password2),
 | |
| 			"username": []byte(username2),
 | |
| 		},
 | |
| 	}
 | |
| )
 | |
| 
 | |
| type TestItem struct {
 | |
| 	ItemID     string
 | |
| 	VaultID    string
 | |
| 	Name       string
 | |
| 	Version    int
 | |
| 	Path       string
 | |
| 	Data       map[string]string
 | |
| 	SecretData map[string][]byte
 | |
| }
 | |
| 
 | |
| func (ti *TestItem) ToModel() *model.Item {
 | |
| 	item := &model.Item{}
 | |
| 	item.Version = ti.Version
 | |
| 	item.VaultID = ti.VaultID
 | |
| 	item.ID = ti.ItemID
 | |
| 
 | |
| 	item.Fields = []model.ItemField{}
 | |
| 	for k, v := range ti.Data {
 | |
| 		item.Fields = append(item.Fields, model.ItemField{Label: k, Value: v})
 | |
| 	}
 | |
| 
 | |
| 	return item
 | |
| }
 | |
| 
 | |
| func TestAPIs(t *testing.T) {
 | |
| 	RegisterFailHandler(Fail)
 | |
| 
 | |
| 	RunSpecs(t, "Controller Suite")
 | |
| }
 | |
| 
 | |
| var _ = BeforeSuite(func() {
 | |
| 	logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
 | |
| 
 | |
| 	ctx, cancel = context.WithCancel(context.TODO())
 | |
| 
 | |
| 	By("bootstrapping test environment")
 | |
| 	testEnv = &envtest.Environment{
 | |
| 		CRDDirectoryPaths:     []string{filepath.Join("..", "..", "config", "crd", "bases")},
 | |
| 		ErrorIfCRDPathMissing: true,
 | |
| 	}
 | |
| 
 | |
| 	// Retrieve the first found binary directory to allow running tests from IDEs
 | |
| 	if getFirstFoundEnvTestBinaryDir() != "" {
 | |
| 		testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
 | |
| 	}
 | |
| 
 | |
| 	var err error
 | |
| 	// cfg is defined in this file globally.
 | |
| 	cfg, err = testEnv.Start()
 | |
| 	Expect(err).NotTo(HaveOccurred())
 | |
| 	Expect(cfg).NotTo(BeNil())
 | |
| 
 | |
| 	err = onepasswordcomv1.AddToScheme(scheme.Scheme)
 | |
| 	Expect(err).NotTo(HaveOccurred())
 | |
| 
 | |
| 	// +kubebuilder:scaffold:scheme
 | |
| 
 | |
| 	k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
 | |
| 	Expect(err).NotTo(HaveOccurred())
 | |
| 	Expect(k8sClient).NotTo(BeNil())
 | |
| 
 | |
| 	k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
 | |
| 		Scheme: scheme.Scheme,
 | |
| 	})
 | |
| 	Expect(err).ToNot(HaveOccurred())
 | |
| 
 | |
| 	mockOpClient := &mocks.TestClient{}
 | |
| 	mockGetItemByIDFunc = mockOpClient.On("GetItemByID", mock.Anything, mock.Anything)
 | |
| 
 | |
| 	onePasswordItemReconciler = &OnePasswordItemReconciler{
 | |
| 		Client:   k8sManager.GetClient(),
 | |
| 		Scheme:   k8sManager.GetScheme(),
 | |
| 		OpClient: mockOpClient,
 | |
| 	}
 | |
| 	err = (onePasswordItemReconciler).SetupWithManager(k8sManager)
 | |
| 	Expect(err).ToNot(HaveOccurred())
 | |
| 
 | |
| 	r, _ := regexp.Compile(annotationRegExpString)
 | |
| 	deploymentReconciler = &DeploymentReconciler{
 | |
| 		Client:             k8sManager.GetClient(),
 | |
| 		Scheme:             k8sManager.GetScheme(),
 | |
| 		OpClient:           mockOpClient,
 | |
| 		OpAnnotationRegExp: r,
 | |
| 	}
 | |
| 	err = (deploymentReconciler).SetupWithManager(k8sManager)
 | |
| 	Expect(err).ToNot(HaveOccurred())
 | |
| 
 | |
| 	go func() {
 | |
| 		defer GinkgoRecover()
 | |
| 		err = k8sManager.Start(ctx)
 | |
| 		Expect(err).ToNot(HaveOccurred(), "failed to run manager")
 | |
| 	}()
 | |
| 
 | |
| })
 | |
| 
 | |
| var _ = AfterSuite(func() {
 | |
| 	cancel()
 | |
| 	By("tearing down the test environment")
 | |
| 	err := testEnv.Stop()
 | |
| 	Expect(err).NotTo(HaveOccurred())
 | |
| })
 | |
| 
 | |
| // getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
 | |
| // ENVTEST-based tests depend on specific binaries, usually located in paths set by
 | |
| // controller-runtime. When running tests directly (e.g., via an IDE) without using
 | |
| // Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
 | |
| //
 | |
| // This function streamlines the process by finding the required binaries, similar to
 | |
| // setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
 | |
| // properly set up, run 'make setup-envtest' beforehand.
 | |
| func getFirstFoundEnvTestBinaryDir() string {
 | |
| 	basePath := filepath.Join("..", "..", "bin", "k8s")
 | |
| 	entries, err := os.ReadDir(basePath)
 | |
| 	if err != nil {
 | |
| 		logf.Log.Error(err, "Failed to read directory", "path", basePath)
 | |
| 		return ""
 | |
| 	}
 | |
| 	for _, entry := range entries {
 | |
| 		if entry.IsDir() {
 | |
| 			return filepath.Join(basePath, entry.Name())
 | |
| 		}
 | |
| 	}
 | |
| 	return ""
 | |
| }
 |