Skip to content

Commit

Permalink
NAS-132216 / 25.04 / Allow deletion of a custom app which has invalid…
Browse files Browse the repository at this point in the history
… compose file (#14891)

* Expose docker networks an app is using

* Allow deletion of a custom app which has invalid yaml
  • Loading branch information
sonicaj authored Nov 7, 2024
1 parent 24d5601 commit ebe1629
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/middlewared/middlewared/plugins/apps/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ def update_internal(self, job, app, data, progress_keyword='Update', trigger_com
Bool('remove_images', default=True),
Bool('remove_ix_volumes', default=False),
Bool('force_remove_ix_volumes', default=False),
Bool('force_remove_custom_app', default=False),
)
)
@job(lock=lambda args: f'app_delete_{args[0]}')
Expand All @@ -354,17 +355,40 @@ def do_delete(self, job, app_name, options):
the original ix-volumes which were created in dragonfish and before for kubernetes based apps. When this
is set, it will result in the deletion of ix-volumes from both docker based apps and k8s based apps and should
be carefully set.
`force_remove_custom_app` should be set when the app being deleted is a custom app and the user wants to
forcefully remove the app. A use-case for this attribute is that user had an invalid yaml in his custom
app and there are no actual docker resources (network/containers/volumes) in place for the custom app, then
docker compose down will fail as the yaml itself is invalid. In this case this flag can be set to proceed
with the deletion of the custom app. However if this app had any docker resources in place, then this flag
will have no effect.
"""
app_config = self.get_instance__sync(app_name)
if options['force_remove_custom_app'] and not app_config['custom_app']:
raise CallError('`force_remove_custom_app` flag is only valid for a custom app', errno=errno.EINVAL)

return self.delete_internal(job, app_name, app_config, options)

@private
def delete_internal(self, job, app_name, app_config, options):
job.set_progress(20, f'Deleting {app_name!r} app')
compose_action(
app_name, app_config['version'], 'down', remove_orphans=True,
remove_volumes=True, remove_images=options['remove_images'],
)
try:
compose_action(
app_name, app_config['version'], 'down', remove_orphans=True,
remove_volumes=True, remove_images=options['remove_images'],
)
except Exception:
# We want to make sure if this fails for a custom app which has no resources deployed, and the explicit
# boolean flag is set, we allow the deletion of the app as there really isn't anything which compose down
# is going to accomplish as there are no containers/networks/volumes in place for the app
if not (
app_config.get('custom_app') and options.get('force_remove_custom_app') and all(
app_config.get('active_workloads', {}).get(k, []) == []
for k in ('container_details', 'volumes', 'networks')
)
):
raise

# Remove app from metadata first as if someone tries to query filesystem info of the app
# where the app resources have been nuked from filesystem, it will error out
self.middleware.call_sync('app.metadata.generate', [app_name]).wait_sync(raise_error=True)
Expand Down
2 changes: 2 additions & 0 deletions src/middlewared/middlewared/plugins/apps/ix_apps/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def get_default_workload_values() -> dict:
'container_details': [], # This would contain service name and image in use
'volumes': [], # This would be docker volumes
'images': [],
'networks': [],
}


Expand Down Expand Up @@ -235,5 +236,6 @@ def translate_resources_to_desired_workflow(app_resources: dict) -> dict:
workloads.update({
'images': list(images),
'volumes': [v.__dict__ for v in volumes],
'networks': app_resources['networks'],
})
return workloads

0 comments on commit ebe1629

Please sign in to comment.