mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-08-04 04:54:15 -04:00
cli: store upgrade files in versioned folders (#1929)
* upgrade versioning * dont pass upgrade kind as boolean * whitespace * fix godot lint check * clarify upgrade check directory suffix * cli: dry-run Terraform migrations on `upgrade check` (#1942) * dry-run Terraform migrations on upgrade check * clean whole upgrade dir * clean up check workspace after planning * fix parsing * extend upgrade check test * rename unused parameters * exclude false positives in test
This commit is contained in:
parent
f3c2198a9a
commit
b25228d175
13 changed files with 300 additions and 127 deletions
|
@ -17,17 +17,13 @@ import (
|
|||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
backupFolder = filepath.Join(constants.UpgradeDir, "backups") + string(filepath.Separator)
|
||||
crdBackupFolder = filepath.Join(backupFolder, "crds") + string(filepath.Separator)
|
||||
)
|
||||
|
||||
func (c *Client) backupCRDs(ctx context.Context) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
||||
func (c *Client) backupCRDs(ctx context.Context, upgradeID string) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
||||
crds, err := c.kubectl.GetCRDs(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting CRDs: %w", err)
|
||||
}
|
||||
|
||||
crdBackupFolder := c.crdBackupFolder(upgradeID)
|
||||
if err := c.fs.MkdirAll(crdBackupFolder); err != nil {
|
||||
return nil, fmt.Errorf("creating backup dir: %w", err)
|
||||
}
|
||||
|
@ -54,7 +50,7 @@ func (c *Client) backupCRDs(ctx context.Context) ([]apiextensionsv1.CustomResour
|
|||
return crds, nil
|
||||
}
|
||||
|
||||
func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition) error {
|
||||
func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition, upgradeID string) error {
|
||||
for _, crd := range crds {
|
||||
for _, version := range crd.Spec.Versions {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: version.Name, Resource: crd.Spec.Names.Plural}
|
||||
|
@ -63,6 +59,7 @@ func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomRes
|
|||
return fmt.Errorf("retrieving CR %s: %w", crd.Name, err)
|
||||
}
|
||||
|
||||
backupFolder := c.backupFolder(upgradeID)
|
||||
for _, cr := range crs {
|
||||
targetFolder := filepath.Join(backupFolder, gvr.Group, gvr.Version, cr.GetNamespace(), cr.GetKind())
|
||||
if err := c.fs.MkdirAll(targetFolder); err != nil {
|
||||
|
@ -83,3 +80,11 @@ func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomRes
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) backupFolder(upgradeID string) string {
|
||||
return filepath.Join(constants.UpgradeDir, upgradeID, "backups") + string(filepath.Separator)
|
||||
}
|
||||
|
||||
func (c *Client) crdBackupFolder(upgradeID string) string {
|
||||
return filepath.Join(c.backupFolder(upgradeID), "crds") + string(filepath.Separator)
|
||||
}
|
||||
|
|
|
@ -24,16 +24,19 @@ import (
|
|||
|
||||
func TestBackupCRDs(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
upgradeID string
|
||||
crd string
|
||||
expectedFile string
|
||||
getCRDsError error
|
||||
wantError bool
|
||||
}{
|
||||
"success": {
|
||||
upgradeID: "1234",
|
||||
crd: "apiVersion: \nkind: \nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
||||
expectedFile: "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
||||
},
|
||||
"api request fails": {
|
||||
upgradeID: "1234",
|
||||
getCRDsError: errors.New("api error"),
|
||||
wantError: true,
|
||||
},
|
||||
|
@ -55,14 +58,14 @@ func TestBackupCRDs(t *testing.T) {
|
|||
log: stubLog{},
|
||||
}
|
||||
|
||||
_, err = client.backupCRDs(context.Background())
|
||||
_, err = client.backupCRDs(context.Background(), tc.upgradeID)
|
||||
if tc.wantError {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
|
||||
data, err := afero.ReadFile(memFs, filepath.Join(crdBackupFolder, crd.Name+".yaml"))
|
||||
data, err := afero.ReadFile(memFs, filepath.Join(client.crdBackupFolder(tc.upgradeID), crd.Name+".yaml"))
|
||||
require.NoError(err)
|
||||
assert.YAMLEq(tc.expectedFile, string(data))
|
||||
})
|
||||
|
@ -71,6 +74,7 @@ func TestBackupCRDs(t *testing.T) {
|
|||
|
||||
func TestBackupCRs(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
upgradeID string
|
||||
crd apiextensionsv1.CustomResourceDefinition
|
||||
resource unstructured.Unstructured
|
||||
expectedFile string
|
||||
|
@ -78,6 +82,7 @@ func TestBackupCRs(t *testing.T) {
|
|||
wantError bool
|
||||
}{
|
||||
"success": {
|
||||
upgradeID: "1234",
|
||||
crd: apiextensionsv1.CustomResourceDefinition{
|
||||
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
||||
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
||||
|
@ -95,6 +100,7 @@ func TestBackupCRs(t *testing.T) {
|
|||
expectedFile: "metadata:\n name: foobar\n",
|
||||
},
|
||||
"api request fails": {
|
||||
upgradeID: "1234",
|
||||
crd: apiextensionsv1.CustomResourceDefinition{
|
||||
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
||||
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
||||
|
@ -126,14 +132,14 @@ func TestBackupCRs(t *testing.T) {
|
|||
log: stubLog{},
|
||||
}
|
||||
|
||||
err := client.backupCRs(context.Background(), []apiextensionsv1.CustomResourceDefinition{tc.crd})
|
||||
err := client.backupCRs(context.Background(), []apiextensionsv1.CustomResourceDefinition{tc.crd}, tc.upgradeID)
|
||||
if tc.wantError {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
|
||||
data, err := afero.ReadFile(memFs, filepath.Join(backupFolder, tc.crd.Spec.Group, tc.crd.Spec.Versions[0].Name, tc.resource.GetNamespace(), tc.resource.GetKind(), tc.resource.GetName()+".yaml"))
|
||||
data, err := afero.ReadFile(memFs, filepath.Join(client.backupFolder(tc.upgradeID), tc.crd.Spec.Group, tc.crd.Spec.Versions[0].Name, tc.resource.GetNamespace(), tc.resource.GetKind(), tc.resource.GetName()+".yaml"))
|
||||
require.NoError(err)
|
||||
assert.YAMLEq(tc.expectedFile, string(data))
|
||||
})
|
||||
|
|
|
@ -102,7 +102,7 @@ func (c *Client) shouldUpgrade(releaseName, newVersion string) error {
|
|||
// Upgrade runs a helm-upgrade on all deployments that are managed via Helm.
|
||||
// If the CLI receives an interrupt signal it will cancel the context.
|
||||
// Canceling the context will prompt helm to abort and roll back the ongoing upgrade.
|
||||
func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool) error {
|
||||
func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool, upgradeID string) error {
|
||||
upgradeErrs := []error{}
|
||||
upgradeReleases := []*chart.Chart{}
|
||||
invalidUpgrade := &compatibility.InvalidUpgradeError{}
|
||||
|
@ -138,11 +138,11 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout tim
|
|||
return errors.Join(upgradeErrs...)
|
||||
}
|
||||
|
||||
crds, err := c.backupCRDs(ctx)
|
||||
crds, err := c.backupCRDs(ctx, upgradeID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating CRD backup: %w", err)
|
||||
}
|
||||
if err := c.backupCRs(ctx, crds); err != nil {
|
||||
if err := c.backupCRs(ctx, crds, upgradeID); err != nil {
|
||||
return fmt.Errorf("creating CR backup: %w", err)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue