feat: add ops center and node onboarding flow

This commit is contained in:
Your Name
2026-04-18 23:52:51 +08:00
parent 246838ae4c
commit b9c29481b5
142 changed files with 89727 additions and 186 deletions

View File

@@ -0,0 +1,177 @@
import unittest
from app.services.ops_template_service import build_ops_template_payload, get_ops_action_template
class OpsTemplateServiceTests(unittest.TestCase):
def test_node_bootstrap_defaults_and_clamps_number(self) -> None:
ok, message, data = build_ops_template_payload(
"node.bootstrap",
{
"expires_in_hours": 9999,
},
)
self.assertTrue(ok, message)
self.assertEqual("ok", message)
self.assertEqual("", data["control_plane_base_url"])
self.assertEqual("/opt/domaincheck", data["root_dir"])
self.assertEqual(720, data["expires_in_hours"])
self.assertEqual("", data["node_region"])
self.assertEqual("", data["node_role"])
def test_deploy_release_custom_normalizes_lists_and_booleans(self) -> None:
ok, message, data = build_ops_template_payload(
"deploy.release.custom",
{
"release_version": "2026.04.18-rc1",
"artifact_url": "https://example.com/release.tar.gz",
"restart_services": "domaincheck-api\ndomaincheck-worker",
"health_check_urls": "",
"health_check_services": "",
"rollback_on_failure": "false",
"switch_current": "true",
},
)
self.assertTrue(ok, message)
self.assertEqual("ok", message)
self.assertEqual(["domaincheck-api", "domaincheck-worker"], data["restart_services"])
self.assertEqual([], data["health_check_urls"])
self.assertEqual([], data["health_check_services"])
self.assertFalse(data["rollback_on_failure"])
self.assertTrue(data["switch_current"])
self.assertEqual("/opt/domaincheck", data["install_root"])
def test_deploy_release_control_applies_defaults(self) -> None:
ok, message, data = build_ops_template_payload(
"deploy.release.control",
{
"release_version": "2026.04.18-rc1",
"artifact_url": "https://example.com/release.tar.gz",
},
)
self.assertTrue(ok, message)
self.assertEqual(
["domaincheck-api", "domaincheck-worker", "domaincheck-sync-agent"],
data["restart_services"],
)
self.assertEqual(["http://127.0.0.1:8100/health"], data["health_check_urls"])
self.assertEqual(
["domaincheck-api", "domaincheck-worker", "domaincheck-sync-agent"],
data["health_check_services"],
)
self.assertTrue(data["rollback_on_failure"])
self.assertTrue(data["switch_current"])
def test_deploy_release_missing_required_field_fails(self) -> None:
ok, message, data = build_ops_template_payload(
"deploy.release.custom",
{
"release_version": "2026.04.18-rc1",
"artifact_url": "",
},
)
self.assertFalse(ok)
self.assertEqual("artifact_url 不能为空", message)
self.assertEqual({}, data)
def test_logs_collect_lines_are_clamped(self) -> None:
ok, message, data = build_ops_template_payload(
"logs.collect",
{
"service_name": "domaincheck-worker",
"lines": 9999,
},
)
self.assertTrue(ok, message)
self.assertEqual(500, data["lines"])
def test_delivery_queue_templates_normalize_and_require_expected_fields(self) -> None:
replay_ok, replay_message, replay_data = build_ops_template_payload(
"delivery.queue.replay",
{
"record_id": "evt-001",
"limit": 999,
"flush_after_replay": "false",
"reason": "确认状态已修复",
},
)
discard_ok, discard_message, discard_data = build_ops_template_payload(
"delivery.queue.discard",
{
"record_id": "evt-002",
"limit": 0,
"reason": "确认这条死信不再需要补发",
},
)
flush_ok, flush_message, flush_data = build_ops_template_payload(
"delivery.queue.flush",
{
"limit": 999,
},
)
discard_fail_ok, discard_fail_message, discard_fail_data = build_ops_template_payload(
"delivery.queue.discard",
{
"record_id": "evt-003",
"reason": "",
},
)
self.assertTrue(replay_ok, replay_message)
self.assertEqual(200, replay_data["limit"])
self.assertFalse(replay_data["flush_after_replay"])
self.assertEqual("evt-001", replay_data["record_id"])
self.assertTrue(discard_ok, discard_message)
self.assertEqual(1, discard_data["limit"])
self.assertEqual("确认这条死信不再需要补发", discard_data["reason"])
self.assertTrue(flush_ok, flush_message)
self.assertEqual(200, flush_data["limit"])
self.assertFalse(discard_fail_ok)
self.assertEqual("reason 不能为空", discard_fail_message)
self.assertEqual({}, discard_fail_data)
def test_diagnostics_and_service_control_templates_expose_ssh(self) -> None:
health_template = get_ops_action_template("health.snapshot")
logs_template = get_ops_action_template("logs.collect")
diagnostics_template = get_ops_action_template("diagnostics.collect")
service_status_template = get_ops_action_template("service.status")
restart_template = get_ops_action_template("service.restart")
restart_api_template = get_ops_action_template("runtime.restart_api")
stop_worker_template = get_ops_action_template("runtime.stop_worker")
deploy_control_template = get_ops_action_template("deploy.release.control")
deploy_worker_template = get_ops_action_template("deploy.release.worker")
deploy_custom_template = get_ops_action_template("deploy.release.custom")
queue_flush_template = get_ops_action_template("delivery.queue.flush")
queue_replay_template = get_ops_action_template("delivery.queue.replay")
queue_discard_template = get_ops_action_template("delivery.queue.discard")
self.assertIn("ssh", health_template["execution_modes"])
self.assertEqual("远端 Agent", health_template["default_execution_mode_label"])
self.assertEqual("SSH", next(item["label"] for item in health_template["execution_mode_options"] if item["value"] == "ssh"))
self.assertIn("ssh", logs_template["execution_modes"])
self.assertIn("ssh", diagnostics_template["execution_modes"])
self.assertIn("ssh", service_status_template["execution_modes"])
self.assertIn("ssh", restart_template["execution_modes"])
self.assertIn("ssh", restart_api_template["execution_modes"])
self.assertIn("ssh", stop_worker_template["execution_modes"])
self.assertEqual("控制面", get_ops_action_template("node.bootstrap")["default_execution_mode_label"])
self.assertIn("ssh", deploy_control_template["execution_modes"])
self.assertIn("ssh", deploy_worker_template["execution_modes"])
self.assertIn("ssh", deploy_custom_template["execution_modes"])
self.assertEqual(["remote-agent"], queue_flush_template["execution_modes"])
self.assertEqual(["remote-agent"], queue_replay_template["execution_modes"])
self.assertEqual(["remote-agent"], queue_discard_template["execution_modes"])
self.assertEqual("远端 Agent", queue_flush_template["default_execution_mode_label"])
if __name__ == "__main__":
unittest.main()