Skip to content
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

[RHTAPBUGS-442 Redux] Ensure gitops repository is cleaned up in error states #361

Merged
merged 2 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion controllers/applicationsnapshotenvironmentbinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
if err != nil {
log.Error(err, fmt.Sprintf("unable to get the Component %s %v", componentName, req.NamespacedName))
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
return ctrl.Result{}, err
}

Expand All @@ -179,6 +180,7 @@
if hasComponent.Spec.Application != applicationName {
err := fmt.Errorf("component %s does not belong to the application %s", componentName, applicationName)
log.Error(err, "")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}
Expand All @@ -194,6 +196,7 @@
if isKubernetesCluster && clusterIngressDomain == "" {
err = fmt.Errorf("ingress domain cannot be empty on a Kubernetes cluster")
log.Error(err, "unable to create an ingress resource on a Kubernetes cluster")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}
Expand All @@ -205,46 +208,50 @@
if err != nil {
errMsg := fmt.Sprintf("Unable to parse the devfile from Component status, exiting reconcile loop %v", req.NamespacedName)
log.Error(err, errMsg)
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, fmt.Errorf("%v: %v", errMsg, err))
return ctrl.Result{}, err
}

deployAssociatedComponents, err := devfileParser.GetDeployComponents(compDevfileData)
if err != nil {
log.Error(err, "unable to get deploy components")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}

Check warning on line 222 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L218-L222

Added lines #L218 - L222 were not covered by tests

var hostname string
if isKubernetesCluster {
hostname, err = devfile.GetIngressHostName(hasComponent.Name, appSnapshotEnvBinding.Namespace, clusterIngressDomain)
if err != nil {
log.Error(err, fmt.Sprintf("unable to get generate a host name from an ingress domain for %s %v", hasComponent.Name, req.NamespacedName))
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}

Check warning on line 232 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L228-L232

Added lines #L228 - L232 were not covered by tests
}

// Generate a route name for the component

kubernetesResources, err := devfile.GetResourceFromDevfile(log, compDevfileData, deployAssociatedComponents, hasComponent.Name, hasComponent.Spec.Application, hasComponent.Spec.ContainerImage, hostname)
if err != nil {
log.Error(err, "unable to get kubernetes resources from the devfile outerloop components")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}

Check warning on line 243 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L239-L243

Added lines #L239 - L243 were not covered by tests

// Create a random, generated name for the route
// ToDo: Ideally we wouldn't need to loop here, but since the Component status is a list, we can't avoid it
var routeName string
for _, compStatus := range appSnapshotEnvBinding.Status.Components {
if compStatus.Name == componentName {
if compStatus.GeneratedRouteName != "" {
routeName = compStatus.GeneratedRouteName
log.Info(fmt.Sprintf("route name for component is %s", routeName))
}
break

Check warning on line 254 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L250-L254

Added lines #L250 - L254 were not covered by tests
}
}
if routeName == "" {
Expand All @@ -269,13 +276,15 @@
if imageName == "" {
err := fmt.Errorf("application snapshot %s did not reference component %s", snapshotName, componentName)
log.Error(err, "")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}

gitOpsRemoteURL, gitOpsBranch, gitOpsContext, err := util.ProcessGitOpsStatus(hasComponent.Status.GitOps, ghClient.Token)
if err != nil {
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
return ctrl.Result{}, err
}

Expand Down Expand Up @@ -347,7 +356,7 @@
err = r.Generator.GenerateOverlaysAndPush(tempDir, clone, gitOpsRemoteURL, genOptions, applicationName, environmentName, imageName, "", r.AppFS, gitOpsBranch, gitOpsContext, true, componentGeneratedResources)
if err != nil {
log.Error(err, fmt.Sprintf("unable to get generate gitops resources for %s %v", componentName, req.NamespacedName))
_ = r.AppFS.RemoveAll(tempDir) // not worried with an err, its a best case attempt to delete the temp clone dir
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir) // not worried with an err, its a best case attempt to delete the temp clone dir

Check warning on line 359 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L359

Added line #L359 was not covered by tests
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}
Expand All @@ -360,6 +369,7 @@
if commitID, err = r.Generator.GetCommitIDFromRepo(r.AppFS, repoPath); err != nil {
//gitops generator errors are sanitized
log.Error(err, "")
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir)
r.SetConditionAndUpdateCR(ctx, req, &appSnapshotEnvBinding, err)
return ctrl.Result{}, err
}
Expand Down Expand Up @@ -444,7 +454,7 @@
return true
},
DeleteFunc: func(e event.DeleteEvent) bool {
log := log.WithValues("namespace", e.Object.GetNamespace())

Check warning on line 457 in controllers/applicationsnapshotenvironmentbinding_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/applicationsnapshotenvironmentbinding_controller.go#L457

Added line #L457 was not covered by tests
logutil.LogAPIResourceChangeEvent(log, e.Object.GetName(), "Environment", logutil.ResourceDelete, nil)
return false
},
Expand Down
1 change: 1 addition & 0 deletions controllers/component_controller_finalizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
//Gitops functions return sanitized error messages
err = r.Generator.GitRemoveComponent(tempDir, gitOpsURL, component.Name, gitOpsBranch, gitOpsContext)
if err != nil {
ioutils.RemoveFolderAndLogError(r.Log, r.AppFS, tempDir)

Check warning on line 89 in controllers/component_controller_finalizer.go

View check run for this annotation

Codecov / codecov/patch

controllers/component_controller_finalizer.go#L89

Added line #L89 was not covered by tests
return err
}

Expand Down
8 changes: 5 additions & 3 deletions pkg/util/ioutils/ioutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ func CreateTempPath(prefix string, appFs afero.Afero) (string, error) {
// RemoveFolderAndLogError removes the specified folder. If the delete fails, no error is returned, but an error is logged
// Used in cases where we're cleaning up after encountering an error, but want to return the original error instead.
func RemoveFolderAndLogError(log logr.Logger, fs afero.Fs, path string) {
err := fs.RemoveAll(path)
if err != nil {
log.Error(err, fmt.Sprintf("Unable to delete folder %s", path))
if path != "" {
err := fs.RemoveAll(path)
if err != nil {
log.Error(err, fmt.Sprintf("Unable to delete folder %s", path))
}
}
}
13 changes: 11 additions & 2 deletions pkg/util/ioutils/ioutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func TestRemoveFolderAndLogError(t *testing.T) {
tests := []struct {
name string
fs afero.Afero
path string
}{
{
name: "inmemory fs",
Expand All @@ -172,21 +173,29 @@ func TestRemoveFolderAndLogError(t *testing.T) {
{
name: "read only fs",
fs: readOnlyFs,
path: "/somepath",
},
{
name: "local fs",
fs: fs,
},
{
name: "empty path",
fs: fs,
path: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
path, _ := CreateTempPath("TestCreateTempPath", tt.fs)
if tt.path == "" && tt.name != "empty path" {
tt.path, _ = CreateTempPath("TestCreateTempPath", tt.fs)
}
log := zap.New(zap.UseFlagOptions(&zap.Options{
Development: true,
TimeEncoder: zapcore.ISO8601TimeEncoder,
}))
RemoveFolderAndLogError(log, tt.fs, path)
RemoveFolderAndLogError(log, tt.fs, tt.path)
})
}
}
Loading