Skip to content

Commit

Permalink
NAS-130339 / 24.10 / Apps filesystem attachment handler (#14113)
Browse files Browse the repository at this point in the history
* Add filesystem attachment handler for docker service

* Register docker fs attachment delegate

* Add fs attachment delegate for apps

* Be more verbose about the logic where we check if an app is a valid attachment given respective path
  • Loading branch information
sonicaj authored Aug 1, 2024
1 parent 063bc39 commit 6eea579
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/middlewared/middlewared/plugins/apps/fs_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from middlewared.common.attachment import FSAttachmentDelegate


class AppFSAttachmentDelegate(FSAttachmentDelegate):
name = 'apps'
title = 'Apps'

async def query(self, path, enabled, options=None):
apps_attached = []
for app in await self.middleware.call('app.query'):
# We don't want to consider those apps which fit in the following criteria:
# - app has no volumes
# - app is stopped and we are looking for enabled apps
# - app is not stopped and we are looking for disabled apps
if not (skip_app := not app['active_workloads']['volumes']):
if enabled:
skip_app |= app['state'] == 'STOPPED'
else:
skip_app |= app['state'] != 'STOPPED'

if skip_app:
continue

if await self.middleware.call(
'filesystem.is_child', [volume['source'] for volume in app['active_workloads']['volumes']], path
):
apps_attached.append({
'id': app['name'],
'name': app['name'],
})

return apps_attached

async def delete(self, attachments):
for attachment in attachments:
try:
await (await self.middleware.call('app.stop', attachment['id'])).wait(raise_error=True)
except Exception:
self.middleware.logger.error('Unable to stop %r app', attachment['id'], exc_info=True)

async def toggle(self, attachments, enabled):
# if enabled is true - we are going to ignore that as we don't want to scale up releases
# automatically when a path becomes available
for attachment in ([] if enabled else attachments):
action = 'start' if enabled else 'stop'
try:
await (await self.middleware.call(f'app.{action}', attachment['id'])).wait(raise_error=True)
except Exception:
self.middleware.logger.error('Unable to %s %r app', action, attachment['id'], exc_info=True)

async def stop(self, attachments):
await self.toggle(attachments, False)

async def start(self, attachments):
await self.toggle(attachments, True)


async def setup(middleware):
middleware.create_task(
middleware.call('pool.dataset.register_attachment_delegate', AppFSAttachmentDelegate(middleware))
)
54 changes: 54 additions & 0 deletions src/middlewared/middlewared/plugins/docker/attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os

from middlewared.common.attachment import FSAttachmentDelegate


class DockerFSAttachmentDelegate(FSAttachmentDelegate):
name = 'docker'
title = 'Docker'
service = 'docker'

async def query(self, path, enabled, options=None):
results = []

k8s_config = await self.middleware.call('docker.config')
if not k8s_config['pool']:
return results

query_dataset = os.path.relpath(path, '/mnt')
if query_dataset in (k8s_config['dataset'], k8s_config['pool']) or query_dataset.startswith(
f'{k8s_config["dataset"]}/'
):
results.append({'id': k8s_config['pool']})

return results

async def get_attachment_name(self, attachment):
return attachment['id']

async def delete(self, attachments):
if attachments:
await (await self.middleware.call('docker.update', {'pool': None})).wait(raise_error=True)

async def toggle(self, attachments, enabled):
await getattr(self, 'start' if enabled else 'stop')(attachments)

async def stop(self, attachments):
if not attachments:
return
try:
await self.middleware.call('service.stop', self.service)
except Exception as e:
self.middleware.logger.error('Failed to stop docker: %s', e)

async def start(self, attachments):
if not attachments:
return
try:
await self.middleware.call('docker.state.start_service')
except Exception:
self.middleware.logger.error('Failed to start docker')


async def setup(middleware):
await middleware.call('pool.dataset.register_attachment_delegate', DockerFSAttachmentDelegate(middleware))

0 comments on commit 6eea579

Please sign in to comment.