generated from kyma-project/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement backup and restore for Cluster Role Bindings and OIDC #591
Merged
Merged
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
3f56a3d
Started implementing CRB backup
akgalwas d535628
CRB backup implemented
akgalwas 611150b
Started implementing CRB backup
akgalwas 57c21e1
Fix in backup
akgalwas acab547
Restore crbs implemented
akgalwas a3e36f7
Backup crbs that refer to cluster-admin ClusterRole only
akgalwas 4eff7bb
OIDC backup restore implemented
akgalwas 3f991d1
Added checks for shoot generation before restore
akgalwas cc204ec
Minor fixes
akgalwas c90ff81
Added checking if CRD exists
akgalwas 8c570cd
Restore working
akgalwas f2deb7d
Added restoring OIDC
akgalwas 423b782
Added flags for including RBAC and OIDC
akgalwas 9901874
Merge branch 'main' into backup-restore-3
akgalwas 1eb5d55
Fixes in the backup
akgalwas 3be3e0c
Fixes for restoring OIDC and CRBs
akgalwas 11d5507
Review remarks 1
akgalwas aadcb47
Review remarks 2
akgalwas 8711b87
Added audit log config for restore
akgalwas f475a34
Minor refactor
akgalwas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,13 @@ import ( | |
"fmt" | ||
"github.com/gardener/gardener/pkg/apis/core/v1beta1" | ||
gardener_types "github.com/gardener/gardener/pkg/client/core/clientset/versioned/typed/core/v1beta1" | ||
authenticationv1alpha1 "github.com/gardener/oidc-webhook-authenticator/apis/authentication/v1alpha1" | ||
"github.com/kyma-project/infrastructure-manager/hack/runtime-migrator-app/internal/backup" | ||
"github.com/kyma-project/infrastructure-manager/hack/runtime-migrator-app/internal/initialisation" | ||
"github.com/kyma-project/infrastructure-manager/hack/runtime-migrator-app/internal/restore" | ||
"github.com/kyma-project/infrastructure-manager/hack/runtime-migrator-app/internal/shoot" | ||
"github.com/kyma-project/infrastructure-manager/pkg/gardener/kubeconfig" | ||
v12 "k8s.io/api/rbac/v1" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/utils/ptr" | ||
"log/slog" | ||
|
@@ -24,15 +27,15 @@ const ( | |
type Restore struct { | ||
shootClient gardener_types.ShootInterface | ||
dynamicGardenerClient client.Client | ||
kubeconfigProvider kubeconfig.Provider | ||
kcpClient client.Client | ||
outputWriter restore.OutputWriter | ||
results restore.Results | ||
cfg initialisation.RestoreConfig | ||
} | ||
|
||
const fieldManagerName = "kim" | ||
const fieldManagerName = "kim-restore" | ||
|
||
func NewRestore(cfg initialisation.RestoreConfig, kubeconfigProvider kubeconfig.Provider, shootClient gardener_types.ShootInterface, dynamicGardenerClient client.Client) (Restore, error) { | ||
func NewRestore(cfg initialisation.RestoreConfig, kcpClient client.Client, shootClient gardener_types.ShootInterface, dynamicGardenerClient client.Client) (Restore, error) { | ||
outputWriter, err := restore.NewOutputWriter(cfg.OutputPath) | ||
if err != nil { | ||
return Restore{}, err | ||
|
@@ -41,7 +44,7 @@ func NewRestore(cfg initialisation.RestoreConfig, kubeconfigProvider kubeconfig. | |
return Restore{ | ||
shootClient: shootClient, | ||
dynamicGardenerClient: dynamicGardenerClient, | ||
kubeconfigProvider: kubeconfigProvider, | ||
kcpClient: kcpClient, | ||
outputWriter: outputWriter, | ||
results: restore.NewRestoreResults(outputWriter.NewResultsDir), | ||
cfg: cfg, | ||
|
@@ -57,7 +60,7 @@ func (r Restore) Do(ctx context.Context, runtimeIDs []string) error { | |
return err | ||
} | ||
|
||
restorer := restore.NewRestorer(r.cfg.BackupDir) | ||
restorer := restore.NewRestorer(r.cfg.BackupDir, r.cfg.RestoreCRB, r.cfg.RestoreOIDC) | ||
|
||
for _, runtimeID := range runtimeIDs { | ||
currentShoot, err := shoot.Fetch(ctx, shootList, r.shootClient, runtimeID) | ||
|
@@ -77,7 +80,7 @@ func (r Restore) Do(ctx context.Context, runtimeIDs []string) error { | |
continue | ||
} | ||
|
||
shootToRestore, err := restorer.Do(runtimeID, currentShoot.Name) | ||
objectsToRestore, err := restorer.Do(runtimeID, currentShoot.Name) | ||
if err != nil { | ||
errMsg := fmt.Sprintf("Failed to restore runtime: %v", err) | ||
r.results.ErrorOccurred(runtimeID, currentShoot.Name, errMsg) | ||
|
@@ -86,14 +89,28 @@ func (r Restore) Do(ctx context.Context, runtimeIDs []string) error { | |
continue | ||
} | ||
|
||
if currentShoot.Generation == objectsToRestore.OriginalShoot.Generation { | ||
slog.Warn("Verify the current state of the system. Shoot was not modified after backup was prepared. Skipping.", "runtimeID", runtimeID) | ||
r.results.OperationSkipped(runtimeID, currentShoot.Name) | ||
|
||
continue | ||
} | ||
|
||
//if currentShoot.Generation > objectsToRestore.OriginalShoot.Generation+1 { | ||
// slog.Warn("Verify the current state of the system. Restore should be performed manually, as the backup may overwrite more that on change.", "runtimeID", runtimeID) | ||
// r.results.AutomaticRestoreImpossible(runtimeID, currentShoot.Name) | ||
// | ||
// continue | ||
//} | ||
|
||
if r.cfg.IsDryRun { | ||
slog.Info("Runtime processed successfully (dry-run)", "runtimeID", runtimeID) | ||
r.results.OperationSucceeded(runtimeID, currentShoot.Name) | ||
r.results.OperationSucceeded(runtimeID, currentShoot.Name, nil, nil) | ||
|
||
continue | ||
} | ||
|
||
err = r.applyResources(ctx, shootToRestore) | ||
appliedCRBs, appliedOIDC, err := r.applyResources(ctx, objectsToRestore, runtimeID) | ||
if err != nil { | ||
errMsg := fmt.Sprintf("Failed to restore runtime: %v", err) | ||
r.results.ErrorOccurred(runtimeID, currentShoot.Name, errMsg) | ||
|
@@ -103,26 +120,134 @@ func (r Restore) Do(ctx context.Context, runtimeIDs []string) error { | |
} | ||
|
||
slog.Info("Runtime restore performed successfully", "runtimeID", runtimeID) | ||
r.results.OperationSucceeded(runtimeID, currentShoot.Name) | ||
r.results.OperationSucceeded(runtimeID, currentShoot.Name, appliedCRBs, appliedOIDC) | ||
} | ||
|
||
resultsFile, err := r.outputWriter.SaveRestoreResults(r.results) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
slog.Info(fmt.Sprintf("Restore completed. Successfully restored backups: %d, Failed operations: %d", r.results.Succeeded, r.results.Failed)) | ||
slog.Info(fmt.Sprintf("Restore completed. Successfully restored backups: %d, Failed operations: %d, Skipped backups: %d, ", r.results.Succeeded, r.results.Failed, r.results.Skipped)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also align report for the number of skipped backups with backup.go file. Currently in dry-run mode skipped backups are not reported correctly.
|
||
slog.Info(fmt.Sprintf("Restore results saved in: %s", resultsFile)) | ||
|
||
return nil | ||
} | ||
|
||
func (r Restore) applyResources(ctx context.Context, shootToRestore v1beta1.Shoot) error { | ||
func (r Restore) applyResources(ctx context.Context, objectsToRestore backup.RuntimeBackup, runtimeID string) ([]v12.ClusterRoleBinding, []authenticationv1alpha1.OpenIDConnect, error) { | ||
err := r.applyShoot(ctx, objectsToRestore.ShootToRestore) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
clusterClient, err := initialisation.GetRuntimeClient(ctx, r.kcpClient, runtimeID) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
appliedCRBs, err := r.applyCRBs(ctx, clusterClient, objectsToRestore.ClusterRoleBindings) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
appliedOIDC, err := r.applyOIDC(ctx, clusterClient, objectsToRestore.OIDCConfig) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return appliedCRBs, appliedOIDC, nil | ||
} | ||
|
||
func (r Restore) applyShoot(ctx context.Context, shoot v1beta1.Shoot) error { | ||
patchCtx, cancel := context.WithTimeout(ctx, timeoutK8sOperation) | ||
defer cancel() | ||
|
||
return r.dynamicGardenerClient.Patch(patchCtx, &shootToRestore, client.Apply, &client.PatchOptions{ | ||
return r.dynamicGardenerClient.Patch(patchCtx, &shoot, client.Apply, &client.PatchOptions{ | ||
FieldManager: fieldManagerName, | ||
Force: ptr.To(true), | ||
}) | ||
} | ||
|
||
func (r Restore) applyCRBs(ctx context.Context, clusterClient client.Client, crbs []v12.ClusterRoleBinding) ([]v12.ClusterRoleBinding, error) { | ||
appliedCRBs := make([]v12.ClusterRoleBinding, 0) | ||
|
||
for _, crb := range crbs { | ||
key := client.ObjectKey{ | ||
Name: crb.Name, | ||
Namespace: crb.Namespace, | ||
} | ||
applied, err := applyCRBIfDoesntExist(ctx, key, &crb, clusterClient) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if applied { | ||
appliedCRBs = append(appliedCRBs, crb) | ||
} | ||
} | ||
|
||
return appliedCRBs, nil | ||
} | ||
|
||
func (r Restore) applyOIDC(ctx context.Context, clusterClient client.Client, oidcConfigs []authenticationv1alpha1.OpenIDConnect) ([]authenticationv1alpha1.OpenIDConnect, error) { | ||
appliedOIDCs := make([]authenticationv1alpha1.OpenIDConnect, 0) | ||
|
||
for _, oidc := range oidcConfigs { | ||
key := client.ObjectKey{ | ||
Name: oidc.Name, | ||
Namespace: oidc.Namespace, | ||
} | ||
applied, err := applyOIDCIfDoesntExist(ctx, key, &oidc, clusterClient) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if applied { | ||
appliedOIDCs = append(appliedOIDCs, oidc) | ||
} | ||
} | ||
|
||
return appliedOIDCs, nil | ||
} | ||
|
||
func applyCRBIfDoesntExist(ctx context.Context, key client.ObjectKey, object *v12.ClusterRoleBinding, clusterClient client.Client) (bool, error) { | ||
getCtx, cancelGet := context.WithTimeout(ctx, timeoutK8sOperation) | ||
defer cancelGet() | ||
|
||
var existingObject v12.ClusterRoleBinding | ||
|
||
err := clusterClient.Get(getCtx, key, &existingObject, &client.GetOptions{}) | ||
if err == nil { | ||
return false, nil | ||
} | ||
|
||
if err != nil && !errors.IsNotFound(err) { | ||
return false, err | ||
} | ||
|
||
createCtx, cancelCreate := context.WithTimeout(ctx, timeoutK8sOperation) | ||
defer cancelCreate() | ||
|
||
return true, clusterClient.Create(createCtx, object, &client.CreateOptions{}) | ||
} | ||
|
||
func applyOIDCIfDoesntExist(ctx context.Context, key client.ObjectKey, object *authenticationv1alpha1.OpenIDConnect, clusterClient client.Client) (bool, error) { | ||
getCtx, cancelGet := context.WithTimeout(ctx, timeoutK8sOperation) | ||
defer cancelGet() | ||
|
||
var existingObject authenticationv1alpha1.OpenIDConnect | ||
|
||
err := clusterClient.Get(getCtx, key, &existingObject, &client.GetOptions{}) | ||
if err == nil { | ||
return false, nil | ||
} | ||
slog.Error(err.Error()) | ||
if err != nil && !errors.IsNotFound(err) { | ||
return false, err | ||
} | ||
|
||
createCtx, cancelCreate := context.WithTimeout(ctx, timeoutK8sOperation) | ||
defer cancelCreate() | ||
|
||
return true, clusterClient.Create(createCtx, object, &client.CreateOptions{}) | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced if we should have this condition to skip restore process. What about restoring possibly deleted or broken CRBs? Those objects are are not related with shoot generation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done