Phase 4: service store — manifest validation, install/remove, Store UI
- ServiceStoreManager: manifest allowlist (git.pic.ngo/roof/*), volume
denylist, ACCEPT-only iptables rules, ${SERVICE_IP}-only dest_ip
- IP allocator: pool 172.20.0.20-254, skips CONTAINER_OFFSETS VIPs
- Compose overlay: docker-compose.services.yml auto-included via DCF
- Flask blueprint at /api/store: list, install, remove, refresh
- Store.jsx: full install/remove UI with spinners and toast notifications
- 95 new unit tests for ServiceStoreManager (all passing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -474,6 +474,20 @@ class ConfigManager:
|
||||
self.configs['_identity'][key] = value
|
||||
self._save_all_configs()
|
||||
|
||||
def get_installed_services(self) -> dict:
|
||||
return self.configs.get('_identity', {}).get('installed_services', {})
|
||||
|
||||
def set_installed_service(self, service_id: str, record: dict):
|
||||
ident = self.configs.setdefault('_identity', {})
|
||||
ident.setdefault('installed_services', {})[service_id] = record
|
||||
self._save_all_configs()
|
||||
|
||||
def remove_installed_service(self, service_id: str):
|
||||
ident = self.configs.setdefault('_identity', {})
|
||||
ident.setdefault('installed_services', {}).pop(service_id, None)
|
||||
ident.setdefault('service_ips', {}).pop(service_id, None)
|
||||
self._save_all_configs()
|
||||
|
||||
def get_all_configs(self) -> Dict[str, Dict]:
|
||||
"""Get all service configurations"""
|
||||
return self.configs.copy()
|
||||
|
||||
Reference in New Issue
Block a user