Skip to content

feat(BA-5669): Add optional Harbor registry installation in TUI dev installer#10963

Open
Yaminyam wants to merge 2 commits intomainfrom
feat/BA-5669-harbor-installer
Open

feat(BA-5669): Add optional Harbor registry installation in TUI dev installer#10963
Yaminyam wants to merge 2 commits intomainfrom
feat/BA-5669-harbor-installer

Conversation

@Yaminyam
Copy link
Copy Markdown
Member

Summary

Add a new --with-harbor option to the TUI installer (dev mode) that stands up a local Harbor container registry using Harbor's official offline installer. Harbor is not added to halfstack — it is managed separately via ./dev harbor.

How it works

  • CliArgs / InstallVariable gain with_harbor, harbor_http_port, harbor_admin_password, harbor_download_uri
  • ServiceConfig gains harbor_enabled, harbor_hostname, harbor_http_port, harbor_admin_password
  • DevContext.configure_harbor():
    1. Downloads Harbor offline installer archive (cached by filename)
    2. Extracts into <base>/harbor/
    3. Loads bundled harbor.yml.tmpl via ruamel.yaml round-trip (preserving comments), sets hostname, http.port, harbor_admin_password, database.password, data_volume, removes https block
    4. Runs Harbor's install.sh to generate docker-compose.yml and all per-service config files, then immediately runs docker compose down so that nothing is left running — lifecycle is owned explicitly by the user
  • DevContext.configure() calls configure_harbor() when with_harbor=True, otherwise the method is a no-op
  • New ./dev harbor <start|stop|restart|status|logs> subcommand wraps docker compose against <base>/harbor
  • InstallReport post-install guide shows a Harbor tab with URL and admin credentials when Harbor is enabled

Design notes

  • Follows the same in-place-edit pattern as other service configs (tomlkit for TOML → ruamel.yaml for YAML). No Jinja, no separate template files bundled in the installer package.
  • Kept out of halfstack because Harbor is optional and Backend.AI is fully functional without it.
  • ./dev harbor is separate from the tmux-managed services because Harbor runs as a bunch of Docker containers, not a single foreground process.

Test plan

  • ./backendai-install install --with-harbor on a clean dev env produces a working harbor/docker-compose.yml
  • ./dev harbor start brings Harbor up
  • Harbor UI is accessible at http://127.0.0.1:8084 with admin / Harbor12345
  • ./dev harbor stop brings it down cleanly
  • Without --with-harbor, the installer behaves exactly as before
  • pants lint/check pass (verified)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 10, 2026 08:13
@github-actions github-actions bot added the size:L 100~500 LoC label Apr 10, 2026
Yaminyam added a commit that referenced this pull request Apr 10, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an opt-in Harbor registry setup path to the dev-mode TUI installer, plus a ./dev harbor helper to manage the generated Harbor Compose stack.

Changes:

  • Added CLI/install variables and service config fields to enable/configure an optional local Harbor registry
  • Implemented DevContext.configure_harbor() to download/extract Harbor offline installer, generate harbor.yml, and run Harbor’s prepare/install flow
  • Added ./dev harbor <start|stop|restart|status|logs> and updated post-install report with a Harbor tab

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/ai/backend/install/types.py Adds Harbor-related install args/variables and service config fields
src/ai/backend/install/context.py Implements Harbor download/extract/configure + hooks into install flow
src/ai/backend/install/cli.py Exposes --with-harbor and Harbor configuration CLI options
src/ai/backend/install/app.py Adds a Harbor tab to the post-install guide and wires args into InstallVariable
dev Adds ./dev harbor subcommand wrapper around docker compose in ./harbor
changes/10963.feature.md Changelog entry for the new Harbor option

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1162 to +1169
await self.run_exec(
["bash", "install.sh"],
cwd=harbor_dir,
)
await self.run_exec(
["docker", "compose", "down", "--remove-orphans"],
cwd=harbor_dir,
)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sequence can unintentionally stop an already-running Harbor instance when the installer is re-run (or if the user started Harbor in parallel), because docker compose down will tear down the project regardless of who started it. Prefer running Harbor’s config generation step without starting containers (e.g., invoking the bundled prepare script directly if available), or at minimum detect whether Harbor services were running before install.sh and only bring them down if they were started by this configure step.

Copilot uses AI. Check for mistakes.
Comment on lines +1110 to +1117
# Copy everything into our harbor_dir (overwriting previous contents,
# but preserving generated docker-compose.yml if idempotent re-run).
for child in extracted_harbor_dir.iterdir():
dest = harbor_dir / child.name
if child.is_dir():
shutil.copytree(child, dest, dirs_exist_ok=True)
else:
shutil.copy2(child, dest)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying extracted files over an existing harbor/ directory with dirs_exist_ok=True doesn’t remove files that no longer exist in the newer Harbor archive, which can leave stale scripts/configs behind and make behavior version-dependent. Consider syncing into a clean directory (e.g., delete/recreate harbor/, or extract into a temp dir and then replace the directory atomically), optionally preserving only explicitly whitelisted generated files if needed.

Copilot uses AI. Check for mistakes.
Comment on lines +1084 to +1088
self.log_header(f"Downloading Harbor offline installer from {download_uri}")
await self.run_exec(
["curl", "-fL", "--output", str(archive_path), download_uri],
cwd=base_path,
)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downloading and executing an installer archive without any integrity verification is risky (even with TLS). Consider adding an integrity check (e.g., a pinned SHA-256 passed via CLI/config and validated before extraction) and failing fast if the checksum does not match.

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +116
@click.option(
"--harbor-admin-password",
type=str,
default="Harbor12345",
show_default=True,
help="Initial admin password for the local Harbor instance.",
)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a well-known default admin password (and showing it in --help) makes it easy to accidentally deploy Harbor with weak credentials. A safer default is to generate a random password when --with-harbor is enabled (and display it once in the install report), or require explicit input; at minimum, avoid advertising the default via show_default=True and add a strong warning when the default is used.

Copilot uses AI. Check for mistakes.
@Yaminyam Yaminyam requested a review from a team April 14, 2026 01:09
Yaminyam and others added 2 commits April 19, 2026 14:32
…nstaller

Adds a new --with-harbor option to the dev-mode TUI installer that stands
up a local Harbor container registry using Harbor's official offline
installer.

Behavior:
- CLI flag --with-harbor (plus --harbor-http-port / --harbor-admin-password
  / --harbor-download-uri) propagates through CliArgs -> InstallVariable
  -> ServiceConfig.
- DevContext.configure_harbor() downloads the Harbor offline installer
  archive (if not already cached), extracts it into <base>/harbor, edits
  the bundled harbor.yml.tmpl in-place via ruamel.yaml round-trip editing
  (mirroring the tomlkit pattern used for other service configs, so that
  comments and default values are preserved), and then runs Harbor's own
  install.sh to generate docker-compose.yml and the per-service config
  files. Containers are stopped immediately after prepare so that
  lifecycle is explicitly owned by the user via ./dev.
- Harbor is only installed when --with-harbor is passed; configure_harbor
  is a no-op otherwise and no behaviour changes for existing installs.
- ./dev gains a 'harbor' subcommand (start/stop/restart/status/logs) that
  wraps docker compose against <base>/harbor. It is separate from the
  tmux-managed service pipeline since Harbor runs as Docker containers.
- InstallReport (post-install guide) gains a Harbor tab showing the URL
  and admin credentials when Harbor is enabled.

No halfstack changes: Harbor is explicitly kept out of halfstack since it
is not a required Backend.AI component.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Yaminyam Yaminyam force-pushed the feat/BA-5669-harbor-installer branch from 3a9707b to f25191f Compare April 19, 2026 05:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100~500 LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants