lablup / lablup/backend.ai

Separate ImageService layer into AdminImageService, ImageService

Open
#8,403 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
670
Forks
183
Avg merge
17h 7m
Merged PRs (30d)
358

Description

## Motivation

The current `ImageService` at `src/ai/backend/manager/services/image/service.py` mixes admin-only mutations (alias/dealias, modify, scan, preload/unload, resource limits, forget/purge) with user-accessible reads (get, search). This violates the layered separation used elsewhere in the codebase and forces admin-check logic to leak into API handlers instead of being enforced at the service boundary.

- A canonical split pattern already exists — `LoginClientTypeService` has separate `service.py` (user) and `admin_service.py` (admin) with two processor classes.
- Applying the same pattern to ImageService makes the authorization boundary explicit and aligns with our layered architecture.

## Objective

- Split `ImageService` into two services: `ImageService` (read-only, user-accessible) and `AdminImageService` (admin-only mutations).
- Introduce matching `ImageProcessors` / `ImageAdminProcessors` classes, mirroring the `LoginClientTypeService` precedent.
- Update REST v2 and GraphQL (Strawberry) call sites to inject the correct processor per operation.

## Details

Target directory: `src/ai/backend/manager/services/image/`

1. Create `admin_service.py` and move admin-only actions: `alias_image`, `alias_image_by_id`, `dealias_image`, `modify_image`, `update_image_by_id`, `scan_image`, `preload_image`, `unload_image`, `set_image_resource_limit_by_id`, `clear_image_custom_resource_limit_by_id`, `untag_image_from_registry`, `forget_image`, `forget_image_by_id`, `purge_image_by_id`.
1. Keep in `service.py` only read-only user-accessible actions: `get_image_by_id`, `get_image_by_identifier`, `get_images_by_canonicals`, `get_image_installed_agents`, `get_all_images`, `search_images`, `search_aliases`.
1. Split `processors.py` into `ImageProcessors` and `ImageAdminProcessors`, following the `LoginClientTypeProcessors` / `LoginClientTypeAdminProcessors` precedent.
1. Update callers: `src/ai/backend/manager/api/rest/image/handler.py` and `src/ai/backend/manager/api/gql/image/` to dispatch to the correct processor class per operation.
1. Update DI / container wiring where `ImageProcessors` is constructed so the new admin processor is provided.
1. Update / add tests for both services and both processor classes; confirm admin-boundary enforcement.

## Acceptance Criteria

- Admin-only image actions live in `AdminImageService`; read-only actions live in `ImageService`.
- Two processor classes (`ImageProcessors`, `ImageAdminProcessors`) exist and are used appropriately from REST v2 and GraphQL layers.
- Existing REST and GraphQL behavior is preserved; no public API changes.
- pants lint / check / test all pass for the `services/image` and affected API modules.
- Live verification via `./bai` CLI for both admin and non-admin scenarios on the image entity.

## Impact

- Internal refactor only — REST v2 and GraphQL contracts are unchanged.
- Any external plugin or code importing `ImageProcessors` to invoke admin actions must switch to `ImageAdminProcessors`.
- Establishes the pattern for future service splits (e.g. agent, session, vfolder) where admin and user concerns currently share a service.

## References

- `src/ai/backend/manager/services/image/service.py` — current service
- `src/ai/backend/manager/services/login_client_type/` — split pattern to follow
- `src/ai/backend/manager/api/rest/image/handler.py`, `src/ai/backend/manager/api/gql/image/` — affected callers

JIRA Issue: BA-4134

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.