mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
Adding docs for v1beta1 vs v1alpha1. Added one test for v1alpha1 compatibility
Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
This commit is contained in:
parent
2f0f97bf64
commit
a2a4effa4a
15 changed files with 114 additions and 12 deletions
39
docs/guides-v1beta1.md
Normal file
39
docs/guides-v1beta1.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Upgrading CRD versions
|
||||
|
||||
From version v0.5.0, `v1alpha1` version is deprecated, and `v1beta1` is in place. This guide will cover the main differences between the two versions, and a procedure on how to safely upgrade it.
|
||||
|
||||
## Differences between versions
|
||||
Versions v1alpha1 and v1beta1 are fully-compatible for SecretStores and ClusterSecretStores. For ExternalSecrets, there is a difference on the `dataFrom` method.
|
||||
|
||||
While in v1alpha1, we could define a `dataFrom` with the following format:
|
||||
|
||||
```
|
||||
spec:
|
||||
dataFrom:
|
||||
- key: my-key
|
||||
- key: my-other-key
|
||||
```
|
||||
|
||||
In v1beta1 is possible to use two methods. One of them is `Extract` and has the exact same behavior as `dataFrom` in v1alpha1. The other is `Find`, which allows finding multiple external secrets and map them into a single Kubernetes secret. Here is an example of `Find`:
|
||||
|
||||
```
|
||||
spec:
|
||||
dataFrom:
|
||||
- find:
|
||||
name: #matches any secret name ending in foo-bar
|
||||
regexp: .*foo-bar$
|
||||
- find:
|
||||
tags: #matches any secrets with the following metadata.
|
||||
env: dev
|
||||
app: web
|
||||
```
|
||||
|
||||
## Upgrading between versions
|
||||
|
||||
If you already have an installation of ESO using `v1alpha1`, we recommend you to upgrade to `v1beta1`. If you do not use `dataFrom` in your ExternalSecrets, or if you deploy the CRDs using official the official Helm charts, the upgrade can be done with no risk of losing data.
|
||||
|
||||
If you are installing CRDs manually, you will need to deploy the bundle CRD file available at `deploys/crds/bundle.yaml`. This bundle file contains `v1beta1` definition and a conversion webhook configuration. This configuration will ensure that new requests to handle any CRD object will only be valid after the upgrade is successfully complete - so there are no risks of losing data due to an incomplete upgrade.
|
||||
|
||||
Once the configuration is finished, at each reconcile, any `ExternalSecret`, `SecretStore`, and `ClusterSecretStore` stored in etcd in `v1alpha1` will be automatically converted to `v1beta1`.
|
||||
|
||||
Since `v1alpha1` is now deprecated, be sure to upgrade any resources you have to `v1beta1`.
|
|
@ -26,6 +26,7 @@ import (
|
|||
"k8s.io/client-go/rest"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework/addon"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework/log"
|
||||
|
@ -35,6 +36,7 @@ import (
|
|||
func init() {
|
||||
_ = kscheme.AddToScheme(util.Scheme)
|
||||
_ = esv1beta1.AddToScheme(util.Scheme)
|
||||
_ = esv1alpha1.AddToScheme(util.Scheme)
|
||||
}
|
||||
|
||||
type Framework struct {
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework/log"
|
||||
)
|
||||
|
@ -29,10 +30,11 @@ var TargetSecretName = "target-secret"
|
|||
|
||||
// TestCase contains the test infra to run a table driven test.
|
||||
type TestCase struct {
|
||||
Framework *Framework
|
||||
ExternalSecret *esv1beta1.ExternalSecret
|
||||
Secrets map[string]SecretEntry
|
||||
ExpectedSecret *v1.Secret
|
||||
Framework *Framework
|
||||
ExternalSecret *esv1beta1.ExternalSecret
|
||||
ExternalSecretV1Alpha1 *esv1alpha1.ExternalSecret
|
||||
Secrets map[string]SecretEntry
|
||||
ExpectedSecret *v1.Secret
|
||||
}
|
||||
|
||||
type SecretEntry struct {
|
||||
|
@ -68,9 +70,16 @@ func TableFunc(f *Framework, prov SecretStoreProvider) func(...func(*TestCase))
|
|||
}()
|
||||
}
|
||||
|
||||
// create external secret
|
||||
err = tc.Framework.CRClient.Create(context.Background(), tc.ExternalSecret)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// create v1alpha1 external secret, if provided
|
||||
if tc.ExternalSecretV1Alpha1 != nil {
|
||||
err = tc.Framework.CRClient.Create(context.Background(), tc.ExternalSecretV1Alpha1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
} else {
|
||||
// create v1beta1 external secret otherwise
|
||||
err = tc.Framework.CRClient.Create(context.Background(), tc.ExternalSecret)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
}
|
||||
|
||||
// in case target name is empty
|
||||
if tc.ExternalSecret.Spec.Target.Name == "" {
|
||||
|
|
|
@ -41,5 +41,6 @@ var _ = Describe("[akeyless]", Label("akeyless"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -41,5 +41,6 @@ var _ = Describe("[alibaba]", Label("alibaba"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -41,6 +41,7 @@ var _ = Describe("[aws] ", Label("aws", "parameterstore"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
|
||||
// These are specific to parameterstore
|
||||
Entry(FindByName(f)),
|
||||
|
|
|
@ -45,5 +45,6 @@ var _ = Describe("[aws] ", Label("aws", "secretsmanager"), func() {
|
|||
Entry(common.FindByNameWithPath(f)),
|
||||
Entry(common.FindByTag(f)),
|
||||
Entry(common.FindByTagWithPath(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -38,5 +38,6 @@ var _ = Describe("[azure]", Label("azure", "keyvault", "secret"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
)
|
||||
|
@ -33,6 +34,47 @@ const (
|
|||
secretValue2 = "{\"foo2\":\"foo2-val\",\"bar2\":\"bar2-val\"}"
|
||||
)
|
||||
|
||||
// This case creates one secret with json values and syncs them using a single .Spec.DataFrom block.
|
||||
func SyncV1Alpha1(f *framework.Framework) (string, func(*framework.TestCase)) {
|
||||
return "[common] should sync secrets from v1alpha1 spec", func(tc *framework.TestCase) {
|
||||
secretKey1 := fmt.Sprintf("%s-%s", f.Namespace.Name, "one")
|
||||
targetSecretKey1 := "name"
|
||||
targetSecretValue1 := "great-name"
|
||||
targetSecretKey2 := "surname"
|
||||
targetSecretValue2 := "great-surname"
|
||||
secretValue := fmt.Sprintf("{ %q: %q, %q: %q }", targetSecretKey1, targetSecretValue1, targetSecretKey2, targetSecretValue2)
|
||||
tc.Secrets = map[string]string{
|
||||
secretKey1: secretValue,
|
||||
}
|
||||
tc.ExpectedSecret = &v1.Secret{
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Data: map[string][]byte{
|
||||
targetSecretKey1: []byte(targetSecretValue1),
|
||||
targetSecretKey2: []byte(targetSecretValue2),
|
||||
},
|
||||
}
|
||||
tc.ExternalSecretV1Alpha1 = &esv1alpha1.ExternalSecret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-es",
|
||||
Namespace: f.Namespace.Name,
|
||||
},
|
||||
Spec: esv1alpha1.ExternalSecretSpec{
|
||||
SecretStoreRef: esv1alpha1.SecretStoreRef{
|
||||
Name: f.Namespace.Name,
|
||||
},
|
||||
Target: esv1alpha1.ExternalSecretTarget{
|
||||
Name: framework.TargetSecretName,
|
||||
},
|
||||
DataFrom: []esv1alpha1.ExternalSecretDataRemoteRef{
|
||||
{
|
||||
Key: secretKey1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This case creates multiple secrets with simple key/value pairs and syncs them using multiple .Spec.Data blocks.
|
||||
// Not supported by: vault.
|
||||
func SimpleDataSync(f *framework.Framework) (string, func(*framework.TestCase)) {
|
||||
|
|
|
@ -46,6 +46,7 @@ var _ = Describe("[gcp]", Label("gcp", "secretsmanager"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
Entry("should sync p12 encoded cert secret", p12Cert),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -40,5 +40,6 @@ var _ = Describe("[gitlab]", Label("gitlab"), func() {
|
|||
Entry(common.JSONDataWithTemplate(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -16,10 +16,10 @@ package suite
|
|||
import (
|
||||
|
||||
// import different e2e test suites.
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/aws/parameterstore"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/azure"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/template"
|
||||
// _ "github.com/external-secrets/external-secrets/e2e/suite/aws/parameterstore"
|
||||
// _ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager"
|
||||
// _ "github.com/external-secrets/external-secrets/e2e/suite/azure"
|
||||
// _ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
|
||||
// _ "github.com/external-secrets/external-secrets/e2e/suite/template"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/vault"
|
||||
)
|
||||
|
|
|
@ -39,5 +39,6 @@ var _ = Describe("[oracle]", Label("oracle"), func() {
|
|||
Entry(common.SSHKeySyncDataProperty(f)),
|
||||
Entry(common.SyncWithoutTargetName(f)),
|
||||
Entry(common.JSONDataWithoutTargetName(f)),
|
||||
Entry(common.SyncV1Alpha1(f)),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -46,6 +46,7 @@ var _ = Describe("[vault]", Label("vault"), func() {
|
|||
framework.Compose(withTokenAuth, f, common.JSONDataWithTemplate, useTokenAuth),
|
||||
framework.Compose(withTokenAuth, f, common.DataPropertyDockerconfigJSON, useTokenAuth),
|
||||
framework.Compose(withTokenAuth, f, common.JSONDataWithoutTargetName, useTokenAuth),
|
||||
framework.Compose(withTokenAuth, f, common.SyncV1Alpha1, useTokenAuth),
|
||||
// use cert auth
|
||||
framework.Compose(withCertAuth, f, common.FindByName, useCertAuth),
|
||||
framework.Compose(withCertAuth, f, common.JSONDataFromSync, useCertAuth),
|
||||
|
|
|
@ -35,6 +35,7 @@ nav:
|
|||
- Guides:
|
||||
- Introduction: guides-introduction.md
|
||||
- Getting started: guides-getting-started.md
|
||||
- Upgrading to v1beta1: guides-v1beta1.md
|
||||
- Advanced Templating:
|
||||
v2: guides-templating.md
|
||||
v1: guides-templating-v1.md
|
||||
|
|
Loading…
Reference in a new issue