moai-adk 0.25.4__py3-none-any.whl ā 0.32.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +2 -5
- moai_adk/__main__.py +114 -82
- moai_adk/cli/__init__.py +6 -1
- moai_adk/cli/commands/__init__.py +1 -3
- moai_adk/cli/commands/analyze.py +5 -16
- moai_adk/cli/commands/doctor.py +6 -18
- moai_adk/cli/commands/init.py +56 -125
- moai_adk/cli/commands/language.py +14 -35
- moai_adk/cli/commands/status.py +9 -15
- moai_adk/cli/commands/update.py +1555 -190
- moai_adk/cli/prompts/init_prompts.py +112 -56
- moai_adk/cli/spec_status.py +263 -0
- moai_adk/cli/ui/__init__.py +44 -0
- moai_adk/cli/ui/progress.py +422 -0
- moai_adk/cli/ui/prompts.py +389 -0
- moai_adk/cli/ui/theme.py +129 -0
- moai_adk/cli/worktree/__init__.py +27 -0
- moai_adk/cli/worktree/__main__.py +31 -0
- moai_adk/cli/worktree/cli.py +672 -0
- moai_adk/cli/worktree/exceptions.py +89 -0
- moai_adk/cli/worktree/manager.py +490 -0
- moai_adk/cli/worktree/models.py +65 -0
- moai_adk/cli/worktree/registry.py +128 -0
- moai_adk/core/PHASE2_OPTIMIZATIONS.md +467 -0
- moai_adk/core/analysis/session_analyzer.py +17 -56
- moai_adk/core/claude_integration.py +26 -54
- moai_adk/core/command_helpers.py +10 -10
- moai_adk/core/comprehensive_monitoring_system.py +1183 -0
- moai_adk/core/config/auto_spec_config.py +5 -11
- moai_adk/core/config/migration.py +19 -9
- moai_adk/core/config/unified.py +436 -0
- moai_adk/core/context_manager.py +6 -12
- moai_adk/core/enterprise_features.py +1404 -0
- moai_adk/core/error_recovery_system.py +725 -112
- moai_adk/core/event_driven_hook_system.py +1371 -0
- moai_adk/core/git/__init__.py +8 -0
- moai_adk/core/git/branch_manager.py +3 -11
- moai_adk/core/git/checkpoint.py +1 -3
- moai_adk/core/git/conflict_detector.py +413 -0
- moai_adk/core/git/manager.py +91 -1
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +56 -80
- moai_adk/core/input_validation_middleware.py +1006 -0
- moai_adk/core/integration/engine.py +6 -18
- moai_adk/core/integration/integration_tester.py +10 -9
- moai_adk/core/integration/utils.py +1 -1
- moai_adk/core/issue_creator.py +10 -28
- moai_adk/core/jit_context_loader.py +956 -0
- moai_adk/core/jit_enhanced_hook_manager.py +1987 -0
- moai_adk/core/language_config_resolver.py +485 -0
- moai_adk/core/language_validator.py +28 -41
- moai_adk/core/mcp/setup.py +15 -12
- moai_adk/core/merge/__init__.py +9 -0
- moai_adk/core/merge/analyzer.py +481 -0
- moai_adk/core/migration/alfred_to_moai_migrator.py +383 -0
- moai_adk/core/migration/backup_manager.py +78 -9
- moai_adk/core/migration/custom_element_scanner.py +358 -0
- moai_adk/core/migration/file_migrator.py +8 -17
- moai_adk/core/migration/interactive_checkbox_ui.py +488 -0
- moai_adk/core/migration/selective_restorer.py +470 -0
- moai_adk/core/migration/template_utils.py +74 -0
- moai_adk/core/migration/user_selection_ui.py +338 -0
- moai_adk/core/migration/version_detector.py +6 -10
- moai_adk/core/migration/version_migrator.py +3 -3
- moai_adk/core/performance/cache_system.py +8 -10
- moai_adk/core/phase_optimized_hook_scheduler.py +879 -0
- moai_adk/core/project/checker.py +2 -4
- moai_adk/core/project/detector.py +1 -3
- moai_adk/core/project/initializer.py +135 -23
- moai_adk/core/project/phase_executor.py +54 -81
- moai_adk/core/project/validator.py +6 -12
- moai_adk/core/quality/trust_checker.py +9 -27
- moai_adk/core/realtime_monitoring_dashboard.py +1724 -0
- moai_adk/core/robust_json_parser.py +611 -0
- moai_adk/core/rollback_manager.py +73 -148
- moai_adk/core/session_manager.py +10 -26
- moai_adk/core/skill_loading_system.py +579 -0
- moai_adk/core/spec/confidence_scoring.py +31 -100
- moai_adk/core/spec/ears_template_engine.py +351 -286
- moai_adk/core/spec/quality_validator.py +35 -69
- moai_adk/core/spec_status_manager.py +64 -74
- moai_adk/core/template/backup.py +45 -20
- moai_adk/core/template/config.py +112 -39
- moai_adk/core/template/merger.py +11 -19
- moai_adk/core/template/processor.py +253 -149
- moai_adk/core/template_engine.py +73 -40
- moai_adk/core/template_variable_synchronizer.py +417 -0
- moai_adk/core/unified_permission_manager.py +745 -0
- moai_adk/core/user_behavior_analytics.py +851 -0
- moai_adk/core/version_sync.py +429 -0
- moai_adk/foundation/__init__.py +56 -0
- moai_adk/foundation/backend.py +1027 -0
- moai_adk/foundation/database.py +1115 -0
- moai_adk/foundation/devops.py +1585 -0
- moai_adk/foundation/ears.py +431 -0
- moai_adk/foundation/frontend.py +870 -0
- moai_adk/foundation/git/commit_templates.py +4 -12
- moai_adk/foundation/git.py +376 -0
- moai_adk/foundation/langs.py +484 -0
- moai_adk/foundation/ml_ops.py +1162 -0
- moai_adk/foundation/testing.py +1524 -0
- moai_adk/foundation/trust/trust_principles.py +23 -72
- moai_adk/foundation/trust/validation_checklist.py +57 -162
- moai_adk/project/__init__.py +0 -0
- moai_adk/project/configuration.py +1084 -0
- moai_adk/project/documentation.py +566 -0
- moai_adk/project/schema.py +447 -0
- moai_adk/statusline/alfred_detector.py +1 -3
- moai_adk/statusline/config.py +13 -4
- moai_adk/statusline/enhanced_output_style_detector.py +23 -15
- moai_adk/statusline/main.py +51 -15
- moai_adk/statusline/renderer.py +104 -48
- moai_adk/statusline/update_checker.py +3 -9
- moai_adk/statusline/version_reader.py +140 -46
- moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +549 -0
- moai_adk/templates/.claude/agents/moai/builder-agent.md +445 -0
- moai_adk/templates/.claude/agents/moai/builder-command.md +1132 -0
- moai_adk/templates/.claude/agents/moai/builder-skill.md +601 -0
- moai_adk/templates/.claude/agents/moai/expert-backend.md +831 -0
- moai_adk/templates/.claude/agents/moai/expert-database.md +774 -0
- moai_adk/templates/.claude/agents/moai/expert-debug.md +396 -0
- moai_adk/templates/.claude/agents/moai/expert-devops.md +711 -0
- moai_adk/templates/.claude/agents/moai/expert-frontend.md +666 -0
- moai_adk/templates/.claude/agents/moai/expert-security.md +474 -0
- moai_adk/templates/.claude/agents/moai/expert-uiux.md +1038 -0
- moai_adk/templates/.claude/agents/moai/manager-claude-code.md +429 -0
- moai_adk/templates/.claude/agents/moai/manager-docs.md +570 -0
- moai_adk/templates/.claude/agents/moai/manager-git.md +937 -0
- moai_adk/templates/.claude/agents/moai/manager-project.md +891 -0
- moai_adk/templates/.claude/agents/moai/manager-quality.md +598 -0
- moai_adk/templates/.claude/agents/moai/manager-spec.md +713 -0
- moai_adk/templates/.claude/agents/moai/manager-strategy.md +600 -0
- moai_adk/templates/.claude/agents/moai/manager-tdd.md +603 -0
- moai_adk/templates/.claude/agents/moai/mcp-context7.md +369 -0
- moai_adk/templates/.claude/agents/moai/mcp-figma.md +1567 -0
- moai_adk/templates/.claude/agents/moai/mcp-notion.md +749 -0
- moai_adk/templates/.claude/agents/moai/mcp-playwright.md +427 -0
- moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +994 -0
- moai_adk/templates/.claude/commands/moai/0-project.md +1143 -0
- moai_adk/templates/.claude/commands/moai/1-plan.md +1435 -0
- moai_adk/templates/.claude/commands/moai/2-run.md +883 -0
- moai_adk/templates/.claude/commands/moai/3-sync.md +993 -0
- moai_adk/templates/.claude/commands/moai/9-feedback.md +314 -0
- moai_adk/templates/.claude/hooks/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/lib/__init__.py +85 -0
- moai_adk/templates/.claude/hooks/moai/lib/checkpoint.py +244 -0
- moai_adk/templates/.claude/hooks/moai/lib/common.py +131 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +446 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +639 -0
- moai_adk/templates/.claude/hooks/moai/lib/example_config.json +104 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +590 -0
- moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +317 -0
- moai_adk/templates/.claude/hooks/moai/lib/models.py +102 -0
- moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +28 -0
- moai_adk/templates/.claude/hooks/moai/lib/project.py +768 -0
- moai_adk/templates/.claude/hooks/moai/lib/test_hooks_improvements.py +443 -0
- moai_adk/templates/.claude/hooks/moai/lib/timeout.py +160 -0
- moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +530 -0
- moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +862 -0
- moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +921 -0
- moai_adk/templates/.claude/output-styles/moai/r2d2.md +380 -0
- moai_adk/templates/.claude/output-styles/moai/yoda.md +338 -0
- moai_adk/templates/.claude/settings.json +172 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +247 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +44 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +130 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +152 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +178 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +147 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +319 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +320 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/README.md +53 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/mongodb.md +231 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/postgresql.md +169 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/redis.md +262 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +496 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/examples.md +560 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/accessibility-wcag.md +260 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/component-architecture.md +228 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/design-system-tokens.md +405 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/icon-libraries.md +401 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/theming-system.md +373 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/reference.md +243 -0
- moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +491 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +98 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/SKILL-MODULARIZATION-TEMPLATE.md +278 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/caching-performance.md +459 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/data-validation.md +485 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/json-optimization.md +374 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/toon-encoding.md +308 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +201 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/best-practices-checklist.md +616 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +560 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-iam-official.md +635 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-memory-official.md +543 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-settings-official.md +663 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +113 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +238 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/complete-configuration-guide.md +175 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-examples.md +1674 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-formatting-guide.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-examples.md +1513 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-formatting-guide.md +1086 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-integration-patterns.md +1100 -0
- moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +438 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +515 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/README.md +296 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/agents-reference.md +346 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/commands-reference.md +432 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +757 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/execution-rules.md +687 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/modular-system.md +665 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/progressive-disclosure.md +649 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +864 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/token-optimization.md +708 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +981 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +362 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/examples.md +1232 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/best-practices.md +261 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/integration-patterns.md +194 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/proactive-analysis.md +229 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/trust5-validation.md +169 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/reference.md +1266 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/scripts/quality-gate.sh +668 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/github-actions-quality.yml +481 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/quality-config.yaml +519 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/SKILL.md +352 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/README.md +52 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/error-handling.md +334 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/integration-patterns.md +310 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/security-authentication.md +256 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/server-architecture.md +253 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/README.md +133 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/SKILL.md +296 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/examples.md +1269 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/reference.md +331 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/advanced-patterns.md +465 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/examples.md +270 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/optimization.md +440 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/reference.md +228 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/advanced-patterns.md +336 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-deployment-patterns.md +182 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +17 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +57 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/content-architecture-optimization.md +162 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/deployment.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/framework-core-configuration.md +186 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/i18n-setup.md +55 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/mdx-components.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/optimization.md +303 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +370 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/examples.md +575 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/advanced-patterns.md +394 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/optimization.md +278 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-components.md +457 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-theming.md +373 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/reference.md +74 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/README.md +186 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/SKILL.md +290 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/examples.md +1225 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/reference.md +567 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/scripts/provider-selector.py +323 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/templates/stack-config.yaml +204 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +446 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/advanced-patterns.md +379 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/optimization.md +286 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/README.md +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +387 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/__init__.py +520 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/complete_workflow_demo_fixed.py +574 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_project_setup.py +317 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_workflow_demo.py +663 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/config-migration-example.json +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/question-examples.json +135 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/quick_start.py +196 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/__init__.py +17 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/advanced-patterns.md +158 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/ask_user_integration.py +340 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/batch_questions.py +713 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/config_manager.py +538 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/documentation_manager.py +1336 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/language_initializer.py +730 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/migration_manager.py +608 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/template_optimizer.py +1005 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/config-schema.json +316 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +1362 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/config-template.json +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/product-template.md +44 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/structure-template.md +48 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/tech-template.md +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/config-manager-setup.json +109 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/language-initializer.json +228 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/menu-project-config.json +130 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/project-batch-questions.json +97 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/spec-workflow-setup.json +150 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/test_integration_simple.py +436 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +374 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/code-templates.md +124 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/feedback-templates.md +100 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/template-optimizer.md +138 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/LICENSE.txt +202 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/advanced-patterns.md +576 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/ai-powered-testing.py +294 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/console_logging.py +35 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/element_discovery.py +40 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/static_html_automation.py +34 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +220 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +845 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +1416 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +1234 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +1243 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +1260 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/optimization.md +505 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/reference/playwright-best-practices.md +57 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/scripts/with_server.py +218 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/templates/alfred-integration.md +376 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/workflows/enterprise-testing-workflow.py +571 -0
- moai_adk/templates/.claude/skills/moai-worktree/SKILL.md +410 -0
- moai_adk/templates/.claude/skills/moai-worktree/examples.md +606 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/integration-patterns.md +982 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/parallel-development.md +778 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-commands.md +646 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-management.md +782 -0
- moai_adk/templates/.claude/skills/moai-worktree/reference.md +357 -0
- moai_adk/templates/.git-hooks/pre-commit +103 -41
- moai_adk/templates/.git-hooks/pre-push +116 -21
- moai_adk/templates/.github/workflows/ci-universal.yml +513 -0
- moai_adk/templates/.github/workflows/security-secrets-check.yml +179 -0
- moai_adk/templates/.gitignore +184 -44
- moai_adk/templates/.mcp.json +7 -9
- moai_adk/templates/.moai/cache/personalization.json +10 -0
- moai_adk/templates/.moai/config/config.yaml +344 -0
- moai_adk/templates/.moai/config/presets/manual.yaml +28 -0
- moai_adk/templates/.moai/config/presets/personal.yaml +30 -0
- moai_adk/templates/.moai/config/presets/team.yaml +33 -0
- moai_adk/templates/.moai/config/questions/_schema.yaml +79 -0
- moai_adk/templates/.moai/config/questions/tab1-user.yaml +108 -0
- moai_adk/templates/.moai/config/questions/tab2-project.yaml +122 -0
- moai_adk/templates/.moai/config/questions/tab3-git.yaml +542 -0
- moai_adk/templates/.moai/config/questions/tab4-quality.yaml +167 -0
- moai_adk/templates/.moai/config/questions/tab5-system.yaml +152 -0
- moai_adk/templates/.moai/config/sections/git-strategy.yaml +40 -0
- moai_adk/templates/.moai/config/sections/language.yaml +11 -0
- moai_adk/templates/.moai/config/sections/project.yaml +13 -0
- moai_adk/templates/.moai/config/sections/quality.yaml +15 -0
- moai_adk/templates/.moai/config/sections/system.yaml +14 -0
- moai_adk/templates/.moai/config/sections/user.yaml +5 -0
- moai_adk/templates/.moai/config/statusline-config.yaml +86 -0
- moai_adk/templates/.moai/scripts/setup-glm.py +136 -0
- moai_adk/templates/CLAUDE.md +382 -501
- moai_adk/utils/__init__.py +24 -1
- moai_adk/utils/banner.py +7 -10
- moai_adk/utils/common.py +16 -30
- moai_adk/utils/link_validator.py +4 -12
- moai_adk/utils/safe_file_reader.py +2 -6
- moai_adk/utils/timeout.py +160 -0
- moai_adk/utils/toon_utils.py +256 -0
- moai_adk/version.py +22 -0
- moai_adk-0.32.8.dist-info/METADATA +2478 -0
- moai_adk-0.32.8.dist-info/RECORD +396 -0
- {moai_adk-0.25.4.dist-info ā moai_adk-0.32.8.dist-info}/WHEEL +1 -1
- {moai_adk-0.25.4.dist-info ā moai_adk-0.32.8.dist-info}/entry_points.txt +1 -0
- moai_adk/cli/commands/backup.py +0 -82
- moai_adk/cli/commands/improve_user_experience.py +0 -348
- moai_adk/cli/commands/migrate.py +0 -158
- moai_adk/cli/commands/validate_links.py +0 -118
- moai_adk/templates/.github/workflows/moai-gitflow.yml +0 -413
- moai_adk/templates/.github/workflows/moai-release-create.yml +0 -100
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +0 -188
- moai_adk/utils/user_experience.py +0 -531
- moai_adk-0.25.4.dist-info/METADATA +0 -2279
- moai_adk-0.25.4.dist-info/RECORD +0 -112
- {moai_adk-0.25.4.dist-info ā moai_adk-0.32.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1404 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enterprise-Grade Features for Hook System
|
|
3
|
+
|
|
4
|
+
Phase 3: Enterprise-grade capabilities including zero-downtime deployment,
|
|
5
|
+
CI/CD pipeline integration, multi-tenant support, advanced load balancing,
|
|
6
|
+
comprehensive audit logging, and compliance features.
|
|
7
|
+
|
|
8
|
+
Key Features:
|
|
9
|
+
- Zero-downtime deployment capabilities with blue-green and canary deployments
|
|
10
|
+
- Advanced load balancing and automatic scaling
|
|
11
|
+
- CI/CD pipeline integration with GitHub Actions, GitLab CI, Jenkins
|
|
12
|
+
- Multi-tenant support with resource isolation and per-tenant configuration
|
|
13
|
+
- Comprehensive audit logging and compliance reporting
|
|
14
|
+
- Business continuity and disaster recovery
|
|
15
|
+
- Advanced security and access control
|
|
16
|
+
- Performance optimization and resource management
|
|
17
|
+
- Service mesh integration
|
|
18
|
+
- Advanced monitoring and observability
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import asyncio
|
|
22
|
+
import logging
|
|
23
|
+
import threading
|
|
24
|
+
import time
|
|
25
|
+
import uuid
|
|
26
|
+
from collections import defaultdict, deque
|
|
27
|
+
from dataclasses import dataclass, field
|
|
28
|
+
from datetime import datetime, timedelta
|
|
29
|
+
from enum import Enum
|
|
30
|
+
from typing import Any, Dict, List, Optional
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DeploymentStrategy(Enum):
|
|
36
|
+
"""Deployment strategy types"""
|
|
37
|
+
|
|
38
|
+
BLUE_GREEN = "blue_green"
|
|
39
|
+
CANARY = "canary"
|
|
40
|
+
ROLLING = "rolling"
|
|
41
|
+
RECREATE = "recreate"
|
|
42
|
+
A_B_TESTING = "a_b_testing"
|
|
43
|
+
SHADOW = "shadow"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ScalingPolicy(Enum):
|
|
47
|
+
"""Scaling policy types"""
|
|
48
|
+
|
|
49
|
+
MANUAL = "manual"
|
|
50
|
+
AUTOMATIC = "automatic"
|
|
51
|
+
SCHEDULED = "scheduled"
|
|
52
|
+
EVENT_DRIVEN = "event_driven"
|
|
53
|
+
PREDICTIVE = "predictive"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TenantType(Enum):
|
|
57
|
+
"""Tenant types"""
|
|
58
|
+
|
|
59
|
+
SHARED = "shared" # Shared resources
|
|
60
|
+
DEDICATED = "dedicated" # Dedicated resources
|
|
61
|
+
ISOLATED = "isolated" # Completely isolated
|
|
62
|
+
HYBRID = "hybrid" # Mix of shared and dedicated
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ComplianceStandard(Enum):
|
|
66
|
+
"""Compliance standards"""
|
|
67
|
+
|
|
68
|
+
GDPR = "gdpr" # General Data Protection Regulation
|
|
69
|
+
HIPAA = "hipaa" # Health Insurance Portability
|
|
70
|
+
SOC2 = "soc2" # Service Organization Control 2
|
|
71
|
+
ISO27001 = "iso27001" # ISO 27001 Information Security
|
|
72
|
+
PCI_DSS = "pci_dss" # Payment Card Industry Data Security
|
|
73
|
+
SOX = "sox" # Sarbanes-Oxley Act
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class TenantConfiguration:
|
|
78
|
+
"""Multi-tenant configuration"""
|
|
79
|
+
|
|
80
|
+
tenant_id: str
|
|
81
|
+
tenant_name: str
|
|
82
|
+
tenant_type: TenantType
|
|
83
|
+
resource_limits: Dict[str, Any] = field(default_factory=dict)
|
|
84
|
+
configuration: Dict[str, Any] = field(default_factory=dict)
|
|
85
|
+
compliance_requirements: List[ComplianceStandard] = field(default_factory=list)
|
|
86
|
+
billing_plan: str = "standard"
|
|
87
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
88
|
+
updated_at: datetime = field(default_factory=datetime.now)
|
|
89
|
+
is_active: bool = True
|
|
90
|
+
|
|
91
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
92
|
+
"""Convert to dictionary for serialization"""
|
|
93
|
+
return {
|
|
94
|
+
"tenant_id": self.tenant_id,
|
|
95
|
+
"tenant_name": self.tenant_name,
|
|
96
|
+
"tenant_type": self.tenant_type.value,
|
|
97
|
+
"resource_limits": self.resource_limits,
|
|
98
|
+
"configuration": self.configuration,
|
|
99
|
+
"compliance_requirements": [c.value for c in self.compliance_requirements],
|
|
100
|
+
"billing_plan": self.billing_plan,
|
|
101
|
+
"created_at": self.created_at.isoformat(),
|
|
102
|
+
"updated_at": self.updated_at.isoformat(),
|
|
103
|
+
"is_active": self.is_active,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class DeploymentConfig:
|
|
109
|
+
"""Deployment configuration"""
|
|
110
|
+
|
|
111
|
+
deployment_id: str
|
|
112
|
+
strategy: DeploymentStrategy
|
|
113
|
+
version: str
|
|
114
|
+
environment: str
|
|
115
|
+
tenant_id: Optional[str] = None
|
|
116
|
+
rollback_version: Optional[str] = None
|
|
117
|
+
health_check_url: str = "/health"
|
|
118
|
+
traffic_percentage: int = 100
|
|
119
|
+
deployment_timeout: int = 1800 # 30 minutes
|
|
120
|
+
rollback_on_failure: bool = True
|
|
121
|
+
auto_promote: bool = False
|
|
122
|
+
canary_analysis: Dict[str, Any] = field(default_factory=dict)
|
|
123
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
124
|
+
|
|
125
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
126
|
+
"""Convert to dictionary for serialization"""
|
|
127
|
+
return {
|
|
128
|
+
"deployment_id": self.deployment_id,
|
|
129
|
+
"strategy": self.strategy.value,
|
|
130
|
+
"version": self.version,
|
|
131
|
+
"environment": self.environment,
|
|
132
|
+
"tenant_id": self.tenant_id,
|
|
133
|
+
"rollback_version": self.rollback_version,
|
|
134
|
+
"health_check_url": self.health_check_url,
|
|
135
|
+
"traffic_percentage": self.traffic_percentage,
|
|
136
|
+
"deployment_timeout": self.deployment_timeout,
|
|
137
|
+
"rollback_on_failure": self.rollback_on_failure,
|
|
138
|
+
"auto_promote": self.auto_promote,
|
|
139
|
+
"canary_analysis": self.canary_analysis,
|
|
140
|
+
"metadata": self.metadata,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@dataclass
|
|
145
|
+
class AuditLog:
|
|
146
|
+
"""Audit log entry"""
|
|
147
|
+
|
|
148
|
+
log_id: str
|
|
149
|
+
timestamp: datetime
|
|
150
|
+
tenant_id: Optional[str]
|
|
151
|
+
user_id: str
|
|
152
|
+
action: str
|
|
153
|
+
resource: str
|
|
154
|
+
details: Dict[str, Any] = field(default_factory=dict)
|
|
155
|
+
ip_address: str = ""
|
|
156
|
+
user_agent: str = ""
|
|
157
|
+
compliance_standards: List[ComplianceStandard] = field(default_factory=list)
|
|
158
|
+
severity: str = "info" # info, warning, error, critical
|
|
159
|
+
|
|
160
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
161
|
+
"""Convert to dictionary for serialization"""
|
|
162
|
+
return {
|
|
163
|
+
"log_id": self.log_id,
|
|
164
|
+
"timestamp": self.timestamp.isoformat(),
|
|
165
|
+
"tenant_id": self.tenant_id,
|
|
166
|
+
"user_id": self.user_id,
|
|
167
|
+
"action": self.action,
|
|
168
|
+
"resource": self.resource,
|
|
169
|
+
"details": self.details,
|
|
170
|
+
"ip_address": self.ip_address,
|
|
171
|
+
"user_agent": self.user_agent,
|
|
172
|
+
"compliance_standards": [c.value for c in self.compliance_standards],
|
|
173
|
+
"severity": self.severity,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class LoadBalancer:
|
|
178
|
+
"""Advanced load balancer with multiple algorithms"""
|
|
179
|
+
|
|
180
|
+
def __init__(self):
|
|
181
|
+
self.backends: List[Dict[str, Any]] = []
|
|
182
|
+
self.algorithm = "round_robin" # round_robin, least_connections, weighted, ip_hash
|
|
183
|
+
self.health_checks: Dict[str, Dict[str, Any]] = {}
|
|
184
|
+
self.session_affinity = False
|
|
185
|
+
self.sticky_sessions: Dict[str, str] = {}
|
|
186
|
+
self._lock = threading.Lock()
|
|
187
|
+
self._stats = {
|
|
188
|
+
"total_requests": 0,
|
|
189
|
+
"active_connections": 0,
|
|
190
|
+
"backend_requests": defaultdict(int),
|
|
191
|
+
"health_check_failures": defaultdict(int),
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
def add_backend(
|
|
195
|
+
self,
|
|
196
|
+
backend_id: str,
|
|
197
|
+
url: str,
|
|
198
|
+
weight: int = 1,
|
|
199
|
+
max_connections: int = 100,
|
|
200
|
+
health_check: Optional[Dict[str, Any]] = None,
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Add a backend server"""
|
|
203
|
+
backend = {
|
|
204
|
+
"backend_id": backend_id,
|
|
205
|
+
"url": url,
|
|
206
|
+
"weight": weight,
|
|
207
|
+
"max_connections": max_connections,
|
|
208
|
+
"current_connections": 0,
|
|
209
|
+
"is_healthy": True,
|
|
210
|
+
"last_health_check": datetime.now(),
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
with self._lock:
|
|
214
|
+
self.backends.append(backend)
|
|
215
|
+
if health_check:
|
|
216
|
+
self.health_checks[backend_id] = health_check
|
|
217
|
+
|
|
218
|
+
def remove_backend(self, backend_id: str) -> bool:
|
|
219
|
+
"""Remove a backend server"""
|
|
220
|
+
with self._lock:
|
|
221
|
+
for i, backend in enumerate(self.backends):
|
|
222
|
+
if backend["backend_id"] == backend_id:
|
|
223
|
+
del self.backends[i]
|
|
224
|
+
if backend_id in self.health_checks:
|
|
225
|
+
del self.health_checks[backend_id]
|
|
226
|
+
return True
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
def get_backend(self, session_id: Optional[str] = None, client_ip: str = "") -> Optional[str]:
|
|
230
|
+
"""Get backend for request using load balancing algorithm"""
|
|
231
|
+
with self._lock:
|
|
232
|
+
if not self.backends:
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
# Filter healthy backends
|
|
236
|
+
healthy_backends = [
|
|
237
|
+
b for b in self.backends if b["is_healthy"] and b["current_connections"] < b["max_connections"]
|
|
238
|
+
]
|
|
239
|
+
if not healthy_backends:
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
# Session affinity
|
|
243
|
+
if self.session_affinity and session_id and session_id in self.sticky_sessions:
|
|
244
|
+
sticky_backend_id = self.sticky_sessions[session_id]
|
|
245
|
+
for backend in healthy_backends:
|
|
246
|
+
if backend["backend_id"] == sticky_backend_id:
|
|
247
|
+
backend["current_connections"] += 1
|
|
248
|
+
self._stats["backend_requests"][sticky_backend_id] += 1
|
|
249
|
+
return sticky_backend_id
|
|
250
|
+
|
|
251
|
+
# Load balancing algorithms
|
|
252
|
+
if self.algorithm == "round_robin":
|
|
253
|
+
backend = healthy_backends[self._stats["total_requests"] % len(healthy_backends)]
|
|
254
|
+
elif self.algorithm == "least_connections":
|
|
255
|
+
backend = min(healthy_backends, key=lambda b: b["current_connections"])
|
|
256
|
+
elif self.algorithm == "weighted":
|
|
257
|
+
total_weight = sum(b["weight"] for b in healthy_backends)
|
|
258
|
+
if total_weight == 0:
|
|
259
|
+
backend = healthy_backends[0]
|
|
260
|
+
else:
|
|
261
|
+
import random
|
|
262
|
+
|
|
263
|
+
r = random.randint(1, total_weight)
|
|
264
|
+
current_weight = 0
|
|
265
|
+
for b in healthy_backends:
|
|
266
|
+
current_weight += b["weight"]
|
|
267
|
+
if r <= current_weight:
|
|
268
|
+
backend = b
|
|
269
|
+
break
|
|
270
|
+
elif self.algorithm == "ip_hash":
|
|
271
|
+
backend = healthy_backends[hash(client_ip) % len(healthy_backends)]
|
|
272
|
+
else:
|
|
273
|
+
backend = healthy_backends[0]
|
|
274
|
+
|
|
275
|
+
backend["current_connections"] += 1
|
|
276
|
+
self._stats["total_requests"] += 1
|
|
277
|
+
self._stats["backend_requests"][backend["backend_id"]] += 1
|
|
278
|
+
|
|
279
|
+
# Set session affinity
|
|
280
|
+
if self.session_affinity and session_id:
|
|
281
|
+
self.sticky_sessions[session_id] = backend["backend_id"]
|
|
282
|
+
|
|
283
|
+
return backend["backend_id"]
|
|
284
|
+
|
|
285
|
+
def release_backend(self, backend_id: str) -> None:
|
|
286
|
+
"""Release backend connection"""
|
|
287
|
+
with self._lock:
|
|
288
|
+
for backend in self.backends:
|
|
289
|
+
if backend["backend_id"] == backend_id:
|
|
290
|
+
backend["current_connections"] = max(0, backend["current_connections"] - 1)
|
|
291
|
+
break
|
|
292
|
+
|
|
293
|
+
def perform_health_check(self, backend_id: str) -> bool:
|
|
294
|
+
"""Perform health check on backend"""
|
|
295
|
+
health_check_config = self.health_checks.get(backend_id)
|
|
296
|
+
if not health_check_config:
|
|
297
|
+
return True
|
|
298
|
+
|
|
299
|
+
try:
|
|
300
|
+
# Simulate health check - in real implementation, make HTTP request
|
|
301
|
+
import random
|
|
302
|
+
|
|
303
|
+
is_healthy = random.random() > 0.1 # 90% success rate
|
|
304
|
+
|
|
305
|
+
with self._lock:
|
|
306
|
+
for backend in self.backends:
|
|
307
|
+
if backend["backend_id"] == backend_id:
|
|
308
|
+
backend["is_healthy"] = is_healthy
|
|
309
|
+
backend["last_health_check"] = datetime.now()
|
|
310
|
+
break
|
|
311
|
+
|
|
312
|
+
if is_healthy:
|
|
313
|
+
self._stats["health_check_failures"][backend_id] = 0
|
|
314
|
+
else:
|
|
315
|
+
self._stats["health_check_failures"][backend_id] += 1
|
|
316
|
+
|
|
317
|
+
return is_healthy
|
|
318
|
+
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"Health check failed for backend {backend_id}: {e}")
|
|
321
|
+
with self._lock:
|
|
322
|
+
self._stats["health_check_failures"][backend_id] += 1
|
|
323
|
+
return False
|
|
324
|
+
|
|
325
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
326
|
+
"""Get load balancer statistics"""
|
|
327
|
+
with self._lock:
|
|
328
|
+
return {
|
|
329
|
+
**self._stats,
|
|
330
|
+
"total_backends": len(self.backends),
|
|
331
|
+
"healthy_backends": len([b for b in self.backends if b["is_healthy"]]),
|
|
332
|
+
"algorithm": self.algorithm,
|
|
333
|
+
"session_affinity": self.session_affinity,
|
|
334
|
+
"active_sessions": len(self.sticky_sessions),
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class AutoScaler:
|
|
339
|
+
"""Automatic scaling with multiple policies"""
|
|
340
|
+
|
|
341
|
+
def __init__(self):
|
|
342
|
+
self.min_instances = 1
|
|
343
|
+
self.max_instances = 10
|
|
344
|
+
self.current_instances = 1
|
|
345
|
+
self.scaling_policy = ScalingPolicy.AUTOMATIC
|
|
346
|
+
self.metrics_history: deque = deque(maxlen=100)
|
|
347
|
+
self.scale_up_threshold = 70.0 # CPU usage percentage
|
|
348
|
+
self.scale_down_threshold = 30.0 # CPU usage percentage
|
|
349
|
+
self.scale_up_cooldown = 300 # seconds
|
|
350
|
+
self.scale_down_cooldown = 600 # seconds
|
|
351
|
+
self._last_scale_up = datetime.now() - timedelta(seconds=self.scale_up_cooldown)
|
|
352
|
+
self._last_scale_down = datetime.now() - timedelta(seconds=self.scale_down_cooldown)
|
|
353
|
+
|
|
354
|
+
def update_metrics(self, cpu_usage: float, memory_usage: float, request_rate: float) -> None:
|
|
355
|
+
"""Update metrics for scaling decisions"""
|
|
356
|
+
self.metrics_history.append(
|
|
357
|
+
{
|
|
358
|
+
"timestamp": datetime.now(),
|
|
359
|
+
"cpu_usage": cpu_usage,
|
|
360
|
+
"memory_usage": memory_usage,
|
|
361
|
+
"request_rate": request_rate,
|
|
362
|
+
"instances": self.current_instances,
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def should_scale_up(self) -> bool:
|
|
367
|
+
"""Determine if scaling up is needed"""
|
|
368
|
+
if self.current_instances >= self.max_instances:
|
|
369
|
+
return False
|
|
370
|
+
|
|
371
|
+
if self.scaling_policy != ScalingPolicy.AUTOMATIC:
|
|
372
|
+
return False
|
|
373
|
+
|
|
374
|
+
# Cooldown period
|
|
375
|
+
if (datetime.now() - self._last_scale_up).seconds < self.scale_up_cooldown:
|
|
376
|
+
return False
|
|
377
|
+
|
|
378
|
+
# Get recent metrics
|
|
379
|
+
if len(self.metrics_history) < 5:
|
|
380
|
+
return False
|
|
381
|
+
|
|
382
|
+
recent_metrics = list(self.metrics_history)[-5:]
|
|
383
|
+
avg_cpu = sum(m["cpu_usage"] for m in recent_metrics) / len(recent_metrics)
|
|
384
|
+
avg_request_rate = sum(m["request_rate"] for m in recent_metrics) / len(recent_metrics)
|
|
385
|
+
|
|
386
|
+
# Scale up conditions
|
|
387
|
+
cpu_pressure = avg_cpu > self.scale_up_threshold
|
|
388
|
+
request_pressure = avg_request_rate > 100 # requests per second per instance
|
|
389
|
+
|
|
390
|
+
return cpu_pressure or request_pressure
|
|
391
|
+
|
|
392
|
+
def should_scale_down(self) -> bool:
|
|
393
|
+
"""Determine if scaling down is needed"""
|
|
394
|
+
if self.current_instances <= self.min_instances:
|
|
395
|
+
return False
|
|
396
|
+
|
|
397
|
+
if self.scaling_policy != ScalingPolicy.AUTOMATIC:
|
|
398
|
+
return False
|
|
399
|
+
|
|
400
|
+
# Cooldown period
|
|
401
|
+
if (datetime.now() - self._last_scale_down).seconds < self.scale_down_cooldown:
|
|
402
|
+
return False
|
|
403
|
+
|
|
404
|
+
# Get recent metrics
|
|
405
|
+
if len(self.metrics_history) < 10:
|
|
406
|
+
return False
|
|
407
|
+
|
|
408
|
+
recent_metrics = list(self.metrics_history)[-10:]
|
|
409
|
+
avg_cpu = sum(m["cpu_usage"] for m in recent_metrics) / len(recent_metrics)
|
|
410
|
+
avg_request_rate = sum(m["request_rate"] for m in recent_metrics) / len(recent_metrics)
|
|
411
|
+
|
|
412
|
+
# Scale down conditions
|
|
413
|
+
cpu_ok = avg_cpu < self.scale_down_threshold
|
|
414
|
+
request_ok = avg_request_rate < 50 # requests per second per instance
|
|
415
|
+
|
|
416
|
+
return cpu_ok and request_ok
|
|
417
|
+
|
|
418
|
+
def scale_up(self) -> bool:
|
|
419
|
+
"""Scale up to next instance count"""
|
|
420
|
+
if self.current_instances < self.max_instances:
|
|
421
|
+
self.current_instances += 1
|
|
422
|
+
self._last_scale_up = datetime.now()
|
|
423
|
+
logger.info(f"Scaled up to {self.current_instances} instances")
|
|
424
|
+
return True
|
|
425
|
+
return False
|
|
426
|
+
|
|
427
|
+
def scale_down(self) -> bool:
|
|
428
|
+
"""Scale down to previous instance count"""
|
|
429
|
+
if self.current_instances > self.min_instances:
|
|
430
|
+
self.current_instances -= 1
|
|
431
|
+
self._last_scale_down = datetime.now()
|
|
432
|
+
logger.info(f"Scaled down to {self.current_instances} instances")
|
|
433
|
+
return True
|
|
434
|
+
return False
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class DeploymentManager:
|
|
438
|
+
"""Advanced deployment management"""
|
|
439
|
+
|
|
440
|
+
def __init__(self, load_balancer: LoadBalancer, auto_scaler: AutoScaler):
|
|
441
|
+
self.load_balancer = load_balancer
|
|
442
|
+
self.auto_scaler = auto_scaler
|
|
443
|
+
self.active_deployments: Dict[str, DeploymentConfig] = {}
|
|
444
|
+
self.deployment_history: List[Dict[str, Any]] = []
|
|
445
|
+
self.rollback_points: Dict[str, Dict[str, Any]] = {}
|
|
446
|
+
self._lock = threading.Lock()
|
|
447
|
+
|
|
448
|
+
async def deploy(self, config: DeploymentConfig) -> Dict[str, Any]:
|
|
449
|
+
"""Execute deployment with specified strategy"""
|
|
450
|
+
deployment_result: Dict[str, Any] = {
|
|
451
|
+
"deployment_id": config.deployment_id,
|
|
452
|
+
"status": "in_progress",
|
|
453
|
+
"started_at": datetime.now().isoformat(),
|
|
454
|
+
"strategy": config.strategy.value,
|
|
455
|
+
"steps": [],
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
try:
|
|
459
|
+
if config.strategy == DeploymentStrategy.BLUE_GREEN:
|
|
460
|
+
result = await self._deploy_blue_green(config)
|
|
461
|
+
elif config.strategy == DeploymentStrategy.CANARY:
|
|
462
|
+
result = await self._deploy_canary(config)
|
|
463
|
+
elif config.strategy == DeploymentStrategy.ROLLING:
|
|
464
|
+
result = await self._deploy_rolling(config)
|
|
465
|
+
else:
|
|
466
|
+
raise ValueError(f"Unsupported deployment strategy: {config.strategy}")
|
|
467
|
+
|
|
468
|
+
deployment_result.update(result)
|
|
469
|
+
|
|
470
|
+
# Store deployment
|
|
471
|
+
with self._lock:
|
|
472
|
+
self.active_deployments[config.deployment_id] = config
|
|
473
|
+
self.deployment_history.append(
|
|
474
|
+
{
|
|
475
|
+
**deployment_result,
|
|
476
|
+
"completed_at": datetime.now().isoformat(),
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
return deployment_result
|
|
481
|
+
|
|
482
|
+
except Exception as e:
|
|
483
|
+
deployment_result["status"] = "failed"
|
|
484
|
+
deployment_result["error"] = str(e)
|
|
485
|
+
deployment_result["completed_at"] = datetime.now().isoformat()
|
|
486
|
+
return deployment_result
|
|
487
|
+
|
|
488
|
+
async def _deploy_blue_green(self, config: DeploymentConfig) -> Dict[str, Any]:
|
|
489
|
+
"""Blue-green deployment strategy"""
|
|
490
|
+
steps = []
|
|
491
|
+
|
|
492
|
+
# Step 1: Create green environment
|
|
493
|
+
steps.append(
|
|
494
|
+
{
|
|
495
|
+
"step": "create_green",
|
|
496
|
+
"description": "Creating green environment",
|
|
497
|
+
"status": "in_progress",
|
|
498
|
+
"started_at": datetime.now().isoformat(),
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
green_backend_id = f"green-{config.deployment_id}"
|
|
503
|
+
self.load_balancer.add_backend(
|
|
504
|
+
green_backend_id,
|
|
505
|
+
f"http://green-{config.version}.example.com",
|
|
506
|
+
health_check={
|
|
507
|
+
"path": config.health_check_url,
|
|
508
|
+
"interval": 30,
|
|
509
|
+
"timeout": 10,
|
|
510
|
+
},
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
steps[-1]["status"] = "completed"
|
|
514
|
+
|
|
515
|
+
# Step 2: Deploy to green
|
|
516
|
+
steps.append(
|
|
517
|
+
{
|
|
518
|
+
"step": "deploy_green",
|
|
519
|
+
"description": f"Deploying version {config.version} to green environment",
|
|
520
|
+
"status": "in_progress",
|
|
521
|
+
"started_at": datetime.now().isoformat(),
|
|
522
|
+
}
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
# Simulate deployment time
|
|
526
|
+
await asyncio.sleep(2)
|
|
527
|
+
steps[-1]["status"] = "completed"
|
|
528
|
+
|
|
529
|
+
# Step 3: Health check green
|
|
530
|
+
steps.append(
|
|
531
|
+
{
|
|
532
|
+
"step": "health_check",
|
|
533
|
+
"description": "Performing health check on green environment",
|
|
534
|
+
"status": "in_progress",
|
|
535
|
+
"started_at": datetime.now().isoformat(),
|
|
536
|
+
}
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
is_healthy = self.load_balancer.perform_health_check(green_backend_id)
|
|
540
|
+
steps[-1]["status"] = "completed" if is_healthy else "failed"
|
|
541
|
+
|
|
542
|
+
if not is_healthy:
|
|
543
|
+
# Cleanup and rollback
|
|
544
|
+
self.load_balancer.remove_backend(green_backend_id)
|
|
545
|
+
return {"success": False, "steps": steps, "error": "Health check failed"}
|
|
546
|
+
|
|
547
|
+
# Step 4: Switch traffic to green
|
|
548
|
+
steps.append(
|
|
549
|
+
{
|
|
550
|
+
"step": "switch_traffic",
|
|
551
|
+
"description": "Switching traffic to green environment",
|
|
552
|
+
"status": "in_progress",
|
|
553
|
+
"started_at": datetime.now().isoformat(),
|
|
554
|
+
}
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
# Remove blue backends
|
|
558
|
+
blue_backends = [b for b in self.load_balancer.backends if b["backend_id"].startswith("blue-")]
|
|
559
|
+
for backend in blue_backends:
|
|
560
|
+
self.load_balancer.remove_backend(backend["backend_id"])
|
|
561
|
+
|
|
562
|
+
steps[-1]["status"] = "completed"
|
|
563
|
+
|
|
564
|
+
# Step 5: Rename green to blue
|
|
565
|
+
steps.append(
|
|
566
|
+
{
|
|
567
|
+
"step": "promote_green",
|
|
568
|
+
"description": "Promoting green environment to production",
|
|
569
|
+
"status": "in_progress",
|
|
570
|
+
"started_at": datetime.now().isoformat(),
|
|
571
|
+
}
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
# Remove green prefix (in real implementation, this would rename services)
|
|
575
|
+
self.load_balancer.remove_backend(green_backend_id)
|
|
576
|
+
self.load_balancer.add_backend(
|
|
577
|
+
f"blue-{config.version}",
|
|
578
|
+
f"http://blue-{config.version}.example.com",
|
|
579
|
+
health_check={
|
|
580
|
+
"path": config.health_check_url,
|
|
581
|
+
"interval": 30,
|
|
582
|
+
"timeout": 10,
|
|
583
|
+
},
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
steps[-1]["status"] = "completed"
|
|
587
|
+
|
|
588
|
+
# Create rollback point
|
|
589
|
+
self.rollback_points[config.deployment_id] = {
|
|
590
|
+
"version": config.rollback_version,
|
|
591
|
+
"timestamp": datetime.now(),
|
|
592
|
+
"backends": [b["backend_id"] for b in self.load_balancer.backends],
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return {"success": True, "steps": steps}
|
|
596
|
+
|
|
597
|
+
async def _deploy_canary(self, config: DeploymentConfig) -> Dict[str, Any]:
|
|
598
|
+
"""Canary deployment strategy"""
|
|
599
|
+
steps: List[Dict[str, Any]] = []
|
|
600
|
+
|
|
601
|
+
# Step 1: Create canary environment
|
|
602
|
+
steps.append(
|
|
603
|
+
{
|
|
604
|
+
"step": "create_canary",
|
|
605
|
+
"description": f"Creating canary environment with {config.traffic_percentage}% traffic",
|
|
606
|
+
"status": "in_progress",
|
|
607
|
+
"started_at": datetime.now().isoformat(),
|
|
608
|
+
}
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
canary_backend_id = f"canary-{config.deployment_id}"
|
|
612
|
+
self.load_balancer.add_backend(
|
|
613
|
+
canary_backend_id,
|
|
614
|
+
f"http://canary-{config.version}.example.com",
|
|
615
|
+
weight=config.traffic_percentage,
|
|
616
|
+
health_check={
|
|
617
|
+
"path": config.health_check_url,
|
|
618
|
+
"interval": 30,
|
|
619
|
+
"timeout": 10,
|
|
620
|
+
},
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
steps[-1]["status"] = "completed"
|
|
624
|
+
|
|
625
|
+
# Step 2: Deploy to canary
|
|
626
|
+
steps.append(
|
|
627
|
+
{
|
|
628
|
+
"step": "deploy_canary",
|
|
629
|
+
"description": f"Deploying version {config.version} to canary environment",
|
|
630
|
+
"status": "in_progress",
|
|
631
|
+
"started_at": datetime.now().isoformat(),
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
await asyncio.sleep(1)
|
|
636
|
+
steps[-1]["status"] = "completed"
|
|
637
|
+
|
|
638
|
+
# Step 3: Monitor canary performance
|
|
639
|
+
steps.append(
|
|
640
|
+
{
|
|
641
|
+
"step": "monitor_canary",
|
|
642
|
+
"description": "Monitoring canary performance metrics",
|
|
643
|
+
"status": "in_progress",
|
|
644
|
+
"started_at": datetime.now().isoformat(),
|
|
645
|
+
}
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# Simulate canary analysis
|
|
649
|
+
config.canary_analysis.get("period", 300) # 5 minutes
|
|
650
|
+
await asyncio.sleep(1) # Simulate monitoring
|
|
651
|
+
|
|
652
|
+
# Simulate canary analysis results
|
|
653
|
+
canary_success_rate = 95.0
|
|
654
|
+
performance_score = 88.0
|
|
655
|
+
|
|
656
|
+
steps[-1]["status"] = "completed"
|
|
657
|
+
steps[-1]["analysis"] = {
|
|
658
|
+
"success_rate": canary_success_rate,
|
|
659
|
+
"performance_score": performance_score,
|
|
660
|
+
"recommendation": "promote" if canary_success_rate > 90 else "rollback",
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
# Step 4: Make promotion decision
|
|
664
|
+
steps.append(
|
|
665
|
+
{
|
|
666
|
+
"step": "decision",
|
|
667
|
+
"description": "Making deployment decision based on canary analysis",
|
|
668
|
+
"status": "in_progress",
|
|
669
|
+
"started_at": datetime.now().isoformat(),
|
|
670
|
+
}
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
should_promote = canary_success_rate > 90 and performance_score > 80
|
|
674
|
+
|
|
675
|
+
if should_promote and config.auto_promote:
|
|
676
|
+
# Promote canary to full deployment
|
|
677
|
+
steps.append(
|
|
678
|
+
{
|
|
679
|
+
"step": "promote_canary",
|
|
680
|
+
"description": "Promoting canary to full deployment",
|
|
681
|
+
"status": "in_progress",
|
|
682
|
+
"started_at": datetime.now().isoformat(),
|
|
683
|
+
}
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
# Update weights to route all traffic to canary
|
|
687
|
+
self.load_balancer.remove_backend(canary_backend_id)
|
|
688
|
+
self.load_balancer.add_backend(
|
|
689
|
+
f"prod-{config.version}",
|
|
690
|
+
f"http://prod-{config.version}.example.com",
|
|
691
|
+
weight=100,
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
steps[-1]["status"] = "completed"
|
|
695
|
+
else:
|
|
696
|
+
# Rollback canary
|
|
697
|
+
steps.append(
|
|
698
|
+
{
|
|
699
|
+
"step": "rollback_canary",
|
|
700
|
+
"description": "Rolling back canary deployment",
|
|
701
|
+
"status": "in_progress",
|
|
702
|
+
"started_at": datetime.now().isoformat(),
|
|
703
|
+
}
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
self.load_balancer.remove_backend(canary_backend_id)
|
|
707
|
+
|
|
708
|
+
steps[-1]["status"] = "completed"
|
|
709
|
+
|
|
710
|
+
steps[-1]["status"] = "completed"
|
|
711
|
+
steps[-1]["decision"] = "promote" if should_promote else "rollback"
|
|
712
|
+
|
|
713
|
+
return {"success": True, "steps": steps}
|
|
714
|
+
|
|
715
|
+
async def _deploy_rolling(self, config: DeploymentConfig) -> Dict[str, Any]:
|
|
716
|
+
"""Rolling deployment strategy"""
|
|
717
|
+
steps = []
|
|
718
|
+
|
|
719
|
+
# Simulate rolling update through all instances
|
|
720
|
+
total_instances = self.auto_scaler.current_instances
|
|
721
|
+
for i in range(total_instances):
|
|
722
|
+
step_name = f"update_instance_{i + 1}"
|
|
723
|
+
steps.append(
|
|
724
|
+
{
|
|
725
|
+
"step": step_name,
|
|
726
|
+
"description": f"Updating instance {i + 1}/{total_instances}",
|
|
727
|
+
"status": "in_progress",
|
|
728
|
+
"started_at": datetime.now().isoformat(),
|
|
729
|
+
}
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
# Simulate instance update
|
|
733
|
+
await asyncio.sleep(0.5)
|
|
734
|
+
|
|
735
|
+
# Health check after update
|
|
736
|
+
steps[-1]["status"] = "completed"
|
|
737
|
+
|
|
738
|
+
return {"success": True, "steps": steps}
|
|
739
|
+
|
|
740
|
+
def rollback(self, deployment_id: str) -> Dict[str, Any]:
|
|
741
|
+
"""Rollback deployment"""
|
|
742
|
+
rollback_result = {
|
|
743
|
+
"deployment_id": deployment_id,
|
|
744
|
+
"status": "in_progress",
|
|
745
|
+
"started_at": datetime.now().isoformat(),
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
try:
|
|
749
|
+
with self._lock:
|
|
750
|
+
rollback_point = self.rollback_points.get(deployment_id)
|
|
751
|
+
if not rollback_point:
|
|
752
|
+
rollback_result["status"] = "failed"
|
|
753
|
+
rollback_result["error"] = "No rollback point found"
|
|
754
|
+
return rollback_result
|
|
755
|
+
|
|
756
|
+
# Remove current backends
|
|
757
|
+
current_backends = [b["backend_id"] for b in self.load_balancer.backends.copy()]
|
|
758
|
+
for backend_id in current_backends:
|
|
759
|
+
self.load_balancer.remove_backend(backend_id)
|
|
760
|
+
|
|
761
|
+
# Restore rollback point backends
|
|
762
|
+
for backend_id in rollback_point["backends"]:
|
|
763
|
+
self.load_balancer.add_backend(backend_id, f"http://{backend_id}.example.com")
|
|
764
|
+
|
|
765
|
+
rollback_result["status"] = "completed"
|
|
766
|
+
rollback_result["completed_at"] = datetime.now().isoformat()
|
|
767
|
+
rollback_result["rollback_version"] = rollback_point["version"]
|
|
768
|
+
|
|
769
|
+
logger.info(f"Rollback completed for deployment {deployment_id}")
|
|
770
|
+
|
|
771
|
+
except Exception as e:
|
|
772
|
+
rollback_result["status"] = "failed"
|
|
773
|
+
rollback_result["error"] = str(e)
|
|
774
|
+
|
|
775
|
+
return rollback_result
|
|
776
|
+
|
|
777
|
+
def get_deployment_status(self, deployment_id: str) -> Dict[str, Any]:
|
|
778
|
+
"""Get deployment status"""
|
|
779
|
+
with self._lock:
|
|
780
|
+
config = self.active_deployments.get(deployment_id)
|
|
781
|
+
if not config:
|
|
782
|
+
# Check deployment history
|
|
783
|
+
for deployment in self.deployment_history:
|
|
784
|
+
if deployment["deployment_id"] == deployment_id:
|
|
785
|
+
return deployment
|
|
786
|
+
|
|
787
|
+
if config:
|
|
788
|
+
return {
|
|
789
|
+
"deployment_id": deployment_id,
|
|
790
|
+
"strategy": config.strategy.value,
|
|
791
|
+
"version": config.version,
|
|
792
|
+
"environment": config.environment,
|
|
793
|
+
"status": "active",
|
|
794
|
+
"config": config.to_dict(),
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return {"deployment_id": deployment_id, "status": "not_found"}
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
class TenantManager:
|
|
801
|
+
"""Multi-tenant management with resource isolation"""
|
|
802
|
+
|
|
803
|
+
def __init__(self):
|
|
804
|
+
self.tenants: Dict[str, TenantConfiguration] = {}
|
|
805
|
+
self.tenant_resources: Dict[str, Dict[str, Any]] = defaultdict(dict)
|
|
806
|
+
self.tenant_metrics: Dict[str, Dict[str, Any]] = defaultdict(dict)
|
|
807
|
+
self.compliance_reports: Dict[str, List[Dict[str, Any]]] = defaultdict(list)
|
|
808
|
+
self._lock = threading.Lock()
|
|
809
|
+
|
|
810
|
+
def create_tenant(
|
|
811
|
+
self,
|
|
812
|
+
tenant_name: str,
|
|
813
|
+
tenant_type: TenantType,
|
|
814
|
+
resource_limits: Optional[Dict[str, Any]] = None,
|
|
815
|
+
compliance_requirements: Optional[List[ComplianceStandard]] = None,
|
|
816
|
+
billing_plan: str = "standard",
|
|
817
|
+
) -> str:
|
|
818
|
+
"""Create new tenant"""
|
|
819
|
+
tenant_id = str(uuid.uuid4())
|
|
820
|
+
|
|
821
|
+
tenant = TenantConfiguration(
|
|
822
|
+
tenant_id=tenant_id,
|
|
823
|
+
tenant_name=tenant_name,
|
|
824
|
+
tenant_type=tenant_type,
|
|
825
|
+
resource_limits=resource_limits or {},
|
|
826
|
+
compliance_requirements=compliance_requirements or [],
|
|
827
|
+
billing_plan=billing_plan,
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
with self._lock:
|
|
831
|
+
self.tenants[tenant_id] = tenant
|
|
832
|
+
self._initialize_tenant_resources(tenant)
|
|
833
|
+
|
|
834
|
+
logger.info(f"Created tenant: {tenant_name} ({tenant_id})")
|
|
835
|
+
return tenant_id
|
|
836
|
+
|
|
837
|
+
def _initialize_tenant_resources(self, tenant: TenantConfiguration) -> None:
|
|
838
|
+
"""Initialize tenant resources"""
|
|
839
|
+
if tenant.tenant_type == TenantType.ISOLATED:
|
|
840
|
+
# Create isolated resources
|
|
841
|
+
self.tenant_resources[tenant.tenant_id] = {
|
|
842
|
+
"database": f"db_{tenant.tenant_id}",
|
|
843
|
+
"cache": f"cache_{tenant.tenant_id}",
|
|
844
|
+
"storage": f"storage_{tenant.tenant_id}",
|
|
845
|
+
"queue": f"queue_{tenant.tenant_id}",
|
|
846
|
+
}
|
|
847
|
+
elif tenant.tenant_type == TenantType.DEDICATED:
|
|
848
|
+
# Create dedicated resources
|
|
849
|
+
self.tenant_resources[tenant.tenant_id] = {
|
|
850
|
+
"cpu_cores": tenant.resource_limits.get("cpu_cores", 2),
|
|
851
|
+
"memory_gb": tenant.resource_limits.get("memory_gb", 4),
|
|
852
|
+
"storage_gb": tenant.resource_limits.get("storage_gb", 100),
|
|
853
|
+
}
|
|
854
|
+
else:
|
|
855
|
+
# Use shared resources
|
|
856
|
+
self.tenant_resources[tenant.tenant_id] = {}
|
|
857
|
+
|
|
858
|
+
def get_tenant(self, tenant_id: str) -> Optional[TenantConfiguration]:
|
|
859
|
+
"""Get tenant configuration"""
|
|
860
|
+
with self._lock:
|
|
861
|
+
return self.tenants.get(tenant_id)
|
|
862
|
+
|
|
863
|
+
def update_tenant(self, tenant_id: str, updates: Dict[str, Any]) -> bool:
|
|
864
|
+
"""Update tenant configuration"""
|
|
865
|
+
with self._lock:
|
|
866
|
+
tenant = self.tenants.get(tenant_id)
|
|
867
|
+
if not tenant:
|
|
868
|
+
return False
|
|
869
|
+
|
|
870
|
+
for key, value in updates.items():
|
|
871
|
+
if hasattr(tenant, key):
|
|
872
|
+
setattr(tenant, key, value)
|
|
873
|
+
elif key in tenant.__dict__:
|
|
874
|
+
tenant.__dict__[key] = value
|
|
875
|
+
|
|
876
|
+
tenant.updated_at = datetime.now()
|
|
877
|
+
return True
|
|
878
|
+
|
|
879
|
+
def delete_tenant(self, tenant_id: str) -> bool:
|
|
880
|
+
"""Delete tenant"""
|
|
881
|
+
with self._lock:
|
|
882
|
+
if tenant_id in self.tenants:
|
|
883
|
+
del self.tenants[tenant_id]
|
|
884
|
+
if tenant_id in self.tenant_resources:
|
|
885
|
+
del self.tenant_resources[tenant_id]
|
|
886
|
+
if tenant_id in self.tenant_metrics:
|
|
887
|
+
del self.tenant_metrics[tenant_id]
|
|
888
|
+
if tenant_id in self.compliance_reports:
|
|
889
|
+
del self.compliance_reports[tenant_id]
|
|
890
|
+
return True
|
|
891
|
+
return False
|
|
892
|
+
|
|
893
|
+
def list_tenants(self, active_only: bool = True) -> List[TenantConfiguration]:
|
|
894
|
+
"""List all tenants"""
|
|
895
|
+
with self._lock:
|
|
896
|
+
tenants = list(self.tenants.values())
|
|
897
|
+
if active_only:
|
|
898
|
+
tenants = [t for t in tenants if t.is_active]
|
|
899
|
+
return tenants
|
|
900
|
+
|
|
901
|
+
def get_tenant_usage(self, tenant_id: str) -> Dict[str, Any]:
|
|
902
|
+
"""Get tenant resource usage"""
|
|
903
|
+
return self.tenant_metrics.get(tenant_id, {})
|
|
904
|
+
|
|
905
|
+
def update_tenant_metrics(self, tenant_id: str, metrics: Dict[str, Any]) -> None:
|
|
906
|
+
"""Update tenant metrics"""
|
|
907
|
+
with self._lock:
|
|
908
|
+
if tenant_id in self.tenant_metrics:
|
|
909
|
+
self.tenant_metrics[tenant_id].update(metrics)
|
|
910
|
+
|
|
911
|
+
def generate_compliance_report(self, tenant_id: str, standard: ComplianceStandard) -> Dict[str, Any]:
|
|
912
|
+
"""Generate compliance report for tenant"""
|
|
913
|
+
tenant = self.get_tenant(tenant_id)
|
|
914
|
+
if not tenant or standard not in tenant.compliance_requirements:
|
|
915
|
+
return {"error": "Tenant not found or compliance standard not required"}
|
|
916
|
+
|
|
917
|
+
report_id = str(uuid.uuid4())
|
|
918
|
+
report: Dict[str, Any] = {
|
|
919
|
+
"report_id": report_id,
|
|
920
|
+
"tenant_id": tenant_id,
|
|
921
|
+
"standard": standard.value,
|
|
922
|
+
"generated_at": datetime.now().isoformat(),
|
|
923
|
+
"status": "compliant", # or "non_compliant"
|
|
924
|
+
"findings": [],
|
|
925
|
+
"recommendations": [],
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
# Add to compliance reports
|
|
929
|
+
self.compliance_reports[tenant_id].append(report)
|
|
930
|
+
|
|
931
|
+
return report
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
class AuditLogger:
|
|
935
|
+
"""Comprehensive audit logging system"""
|
|
936
|
+
|
|
937
|
+
def __init__(self, retention_days: int = 365):
|
|
938
|
+
self.retention_days = retention_days
|
|
939
|
+
self.audit_logs: deque = deque(maxlen=100000) # Large buffer for audit logs
|
|
940
|
+
self.compliance_index: Dict[str, List[str]] = defaultdict(list)
|
|
941
|
+
self._lock = threading.Lock()
|
|
942
|
+
|
|
943
|
+
def log(
|
|
944
|
+
self,
|
|
945
|
+
action: str,
|
|
946
|
+
resource: str,
|
|
947
|
+
user_id: str,
|
|
948
|
+
tenant_id: Optional[str] = None,
|
|
949
|
+
details: Optional[Dict[str, Any]] = None,
|
|
950
|
+
ip_address: str = "",
|
|
951
|
+
user_agent: str = "",
|
|
952
|
+
compliance_standards: Optional[List[ComplianceStandard]] = None,
|
|
953
|
+
severity: str = "info",
|
|
954
|
+
) -> str:
|
|
955
|
+
"""Log audit event"""
|
|
956
|
+
log_id = str(uuid.uuid4())
|
|
957
|
+
|
|
958
|
+
audit_log = AuditLog(
|
|
959
|
+
log_id=log_id,
|
|
960
|
+
timestamp=datetime.now(),
|
|
961
|
+
tenant_id=tenant_id,
|
|
962
|
+
user_id=user_id,
|
|
963
|
+
action=action,
|
|
964
|
+
resource=resource,
|
|
965
|
+
details=details or {},
|
|
966
|
+
ip_address=ip_address,
|
|
967
|
+
user_agent=user_agent,
|
|
968
|
+
compliance_standards=compliance_standards or [],
|
|
969
|
+
severity=severity,
|
|
970
|
+
)
|
|
971
|
+
|
|
972
|
+
with self._lock:
|
|
973
|
+
self.audit_logs.append(audit_log)
|
|
974
|
+
|
|
975
|
+
# Update compliance index
|
|
976
|
+
if compliance_standards:
|
|
977
|
+
for standard in compliance_standards:
|
|
978
|
+
self.compliance_index[standard.value].append(log_id)
|
|
979
|
+
|
|
980
|
+
return log_id
|
|
981
|
+
|
|
982
|
+
def search_logs(
|
|
983
|
+
self,
|
|
984
|
+
tenant_id: Optional[str] = None,
|
|
985
|
+
user_id: Optional[str] = None,
|
|
986
|
+
action: Optional[str] = None,
|
|
987
|
+
resource: Optional[str] = None,
|
|
988
|
+
compliance_standard: Optional[ComplianceStandard] = None,
|
|
989
|
+
start_time: Optional[datetime] = None,
|
|
990
|
+
end_time: Optional[datetime] = None,
|
|
991
|
+
severity: Optional[str] = None,
|
|
992
|
+
limit: Optional[int] = None,
|
|
993
|
+
) -> List[AuditLog]:
|
|
994
|
+
"""Search audit logs with filters"""
|
|
995
|
+
with self._lock:
|
|
996
|
+
filtered_logs = []
|
|
997
|
+
|
|
998
|
+
for log in self.audit_logs:
|
|
999
|
+
# Apply filters
|
|
1000
|
+
if tenant_id and log.tenant_id != tenant_id:
|
|
1001
|
+
continue
|
|
1002
|
+
if user_id and log.user_id != user_id:
|
|
1003
|
+
continue
|
|
1004
|
+
if action and log.action != action:
|
|
1005
|
+
continue
|
|
1006
|
+
if resource and log.resource != resource:
|
|
1007
|
+
continue
|
|
1008
|
+
if severity and log.severity != severity:
|
|
1009
|
+
continue
|
|
1010
|
+
if compliance_standard and compliance_standard not in log.compliance_standards:
|
|
1011
|
+
continue
|
|
1012
|
+
if start_time and log.timestamp < start_time:
|
|
1013
|
+
continue
|
|
1014
|
+
if end_time and log.timestamp > end_time:
|
|
1015
|
+
continue
|
|
1016
|
+
|
|
1017
|
+
filtered_logs.append(log)
|
|
1018
|
+
|
|
1019
|
+
# Sort by timestamp (newest first)
|
|
1020
|
+
filtered_logs.sort(key=lambda log: log.timestamp, reverse=True)
|
|
1021
|
+
|
|
1022
|
+
if limit:
|
|
1023
|
+
filtered_logs = filtered_logs[:limit]
|
|
1024
|
+
|
|
1025
|
+
return filtered_logs
|
|
1026
|
+
|
|
1027
|
+
def get_compliance_report(
|
|
1028
|
+
self,
|
|
1029
|
+
standard: ComplianceStandard,
|
|
1030
|
+
tenant_id: Optional[str] = None,
|
|
1031
|
+
days: int = 30,
|
|
1032
|
+
) -> Dict[str, Any]:
|
|
1033
|
+
"""Generate compliance report"""
|
|
1034
|
+
end_time = datetime.now()
|
|
1035
|
+
start_time = end_time - timedelta(days=days)
|
|
1036
|
+
|
|
1037
|
+
logs = self.search_logs(
|
|
1038
|
+
tenant_id=tenant_id,
|
|
1039
|
+
compliance_standard=standard,
|
|
1040
|
+
start_time=start_time,
|
|
1041
|
+
end_time=end_time,
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
logs_by_severity: Dict[str, int] = defaultdict(int)
|
|
1045
|
+
logs_by_action: Dict[str, int] = defaultdict(int)
|
|
1046
|
+
|
|
1047
|
+
for log in logs:
|
|
1048
|
+
logs_by_severity[log.severity] += 1
|
|
1049
|
+
logs_by_action[log.action] += 1
|
|
1050
|
+
|
|
1051
|
+
report: Dict[str, Any] = {
|
|
1052
|
+
"standard": standard.value,
|
|
1053
|
+
"period": f"{days} days",
|
|
1054
|
+
"total_logs": len(logs),
|
|
1055
|
+
"generated_at": end_time.isoformat(),
|
|
1056
|
+
"tenant_id": tenant_id,
|
|
1057
|
+
"logs_by_severity": dict(logs_by_severity),
|
|
1058
|
+
"logs_by_action": dict(logs_by_action),
|
|
1059
|
+
"unique_users": len(set(log.user_id for log in logs)),
|
|
1060
|
+
"unique_resources": len(set(log.resource for log in logs)),
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
return dict(report)
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
class EnterpriseFeatures:
|
|
1067
|
+
"""
|
|
1068
|
+
Enterprise-Grade Features Manager
|
|
1069
|
+
|
|
1070
|
+
Integrates all enterprise-grade capabilities including zero-downtime deployment,
|
|
1071
|
+
advanced load balancing, auto-scaling, multi-tenant support, and comprehensive audit logging.
|
|
1072
|
+
"""
|
|
1073
|
+
|
|
1074
|
+
def __init__(
|
|
1075
|
+
self,
|
|
1076
|
+
min_instances: int = 1,
|
|
1077
|
+
max_instances: int = 10,
|
|
1078
|
+
scaling_policy: ScalingPolicy = ScalingPolicy.AUTOMATIC,
|
|
1079
|
+
enable_multi_tenant: bool = True,
|
|
1080
|
+
enable_audit_logging: bool = True,
|
|
1081
|
+
audit_retention_days: int = 365,
|
|
1082
|
+
):
|
|
1083
|
+
"""Initialize enterprise features"""
|
|
1084
|
+
self.min_instances = min_instances
|
|
1085
|
+
self.max_instances = max_instances
|
|
1086
|
+
self.scaling_policy = scaling_policy
|
|
1087
|
+
self.enable_multi_tenant = enable_multi_tenant
|
|
1088
|
+
self.enable_audit_logging = enable_audit_logging
|
|
1089
|
+
|
|
1090
|
+
# Initialize components
|
|
1091
|
+
self.load_balancer = LoadBalancer()
|
|
1092
|
+
self.auto_scaler = AutoScaler()
|
|
1093
|
+
self.deployment_manager = DeploymentManager(self.load_balancer, self.auto_scaler)
|
|
1094
|
+
self.tenant_manager = TenantManager() if enable_multi_tenant else None
|
|
1095
|
+
self.audit_logger = AuditLogger(audit_retention_days) if enable_audit_logging else None
|
|
1096
|
+
|
|
1097
|
+
# Configure auto_scaler
|
|
1098
|
+
self.auto_scaler.min_instances = min_instances
|
|
1099
|
+
self.auto_scaler.max_instances = max_instances
|
|
1100
|
+
self.auto_scaler.scaling_policy = scaling_policy
|
|
1101
|
+
|
|
1102
|
+
# System state
|
|
1103
|
+
self._running = False
|
|
1104
|
+
self._startup_time = datetime.now()
|
|
1105
|
+
|
|
1106
|
+
logger.info("Enterprise features initialized")
|
|
1107
|
+
|
|
1108
|
+
async def start(self) -> None:
|
|
1109
|
+
"""Start enterprise features"""
|
|
1110
|
+
if self._running:
|
|
1111
|
+
return
|
|
1112
|
+
|
|
1113
|
+
logger.info("Starting Enterprise Features...")
|
|
1114
|
+
|
|
1115
|
+
try:
|
|
1116
|
+
# Start background tasks
|
|
1117
|
+
self._start_background_tasks()
|
|
1118
|
+
|
|
1119
|
+
self._running = True
|
|
1120
|
+
logger.info("Enterprise Features started successfully")
|
|
1121
|
+
|
|
1122
|
+
except Exception as e:
|
|
1123
|
+
logger.error(f"Error starting enterprise features: {e}")
|
|
1124
|
+
raise
|
|
1125
|
+
|
|
1126
|
+
def stop(self) -> None:
|
|
1127
|
+
"""Stop enterprise features"""
|
|
1128
|
+
if not self._running:
|
|
1129
|
+
return
|
|
1130
|
+
|
|
1131
|
+
logger.info("Stopping Enterprise Features...")
|
|
1132
|
+
self._running = False
|
|
1133
|
+
logger.info("Enterprise Features stopped")
|
|
1134
|
+
|
|
1135
|
+
def _start_background_tasks(self) -> None:
|
|
1136
|
+
"""Start background monitoring and scaling tasks"""
|
|
1137
|
+
|
|
1138
|
+
def monitor_loop():
|
|
1139
|
+
while self._running:
|
|
1140
|
+
try:
|
|
1141
|
+
# Update auto-scaler metrics
|
|
1142
|
+
self.auto_scaler.update_metrics(
|
|
1143
|
+
cpu_usage=50.0, # Would get actual metrics
|
|
1144
|
+
memory_usage=60.0,
|
|
1145
|
+
request_rate=150.0,
|
|
1146
|
+
)
|
|
1147
|
+
|
|
1148
|
+
# Check scaling decisions
|
|
1149
|
+
if self.auto_scaler.should_scale_up():
|
|
1150
|
+
self.auto_scaler.scale_up()
|
|
1151
|
+
self.deployment_manager.load_balancer.add_backend(
|
|
1152
|
+
f"instance-{self.auto_scaler.current_instances}-{uuid.uuid4().hex[:8]}",
|
|
1153
|
+
f"http://instance-{self.auto_scaler.current_instances}.example.com",
|
|
1154
|
+
)
|
|
1155
|
+
elif self.auto_scaler.should_scale_down():
|
|
1156
|
+
self.auto_scaler.scale_down()
|
|
1157
|
+
# Remove excess backend (simplified)
|
|
1158
|
+
backends = self.deployment_manager.load_balancer.backends.copy()
|
|
1159
|
+
if len(backends) > self.auto_scaler.current_instances:
|
|
1160
|
+
backend_to_remove = backends[-1]
|
|
1161
|
+
self.deployment_manager.load_balancer.remove_backend(backend_to_remove["backend_id"])
|
|
1162
|
+
|
|
1163
|
+
time.sleep(30) # Check every 30 seconds
|
|
1164
|
+
|
|
1165
|
+
except Exception as e:
|
|
1166
|
+
logger.error(f"Error in monitoring loop: {e}")
|
|
1167
|
+
time.sleep(30)
|
|
1168
|
+
|
|
1169
|
+
# Start monitoring thread
|
|
1170
|
+
monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
|
|
1171
|
+
monitor_thread.start()
|
|
1172
|
+
|
|
1173
|
+
async def deploy_application(
|
|
1174
|
+
self,
|
|
1175
|
+
version: str,
|
|
1176
|
+
strategy: DeploymentStrategy = DeploymentStrategy.BLUE_GREEN,
|
|
1177
|
+
environment: str = "production",
|
|
1178
|
+
tenant_id: Optional[str] = None,
|
|
1179
|
+
**kwargs,
|
|
1180
|
+
) -> Dict[str, Any]:
|
|
1181
|
+
"""Deploy application with enterprise-grade strategy"""
|
|
1182
|
+
deployment_config = DeploymentConfig(
|
|
1183
|
+
deployment_id=str(uuid.uuid4()),
|
|
1184
|
+
strategy=strategy,
|
|
1185
|
+
version=version,
|
|
1186
|
+
environment=environment,
|
|
1187
|
+
tenant_id=tenant_id,
|
|
1188
|
+
**kwargs,
|
|
1189
|
+
)
|
|
1190
|
+
|
|
1191
|
+
return await self.deployment_manager.deploy(deployment_config)
|
|
1192
|
+
|
|
1193
|
+
def rollback_deployment(self, deployment_id: str) -> Dict[str, Any]:
|
|
1194
|
+
"""Rollback deployment"""
|
|
1195
|
+
return self.deployment_manager.rollback(deployment_id)
|
|
1196
|
+
|
|
1197
|
+
def create_tenant(self, tenant_name: str, tenant_type: TenantType = TenantType.SHARED, **kwargs) -> str:
|
|
1198
|
+
"""Create new tenant"""
|
|
1199
|
+
if not self.enable_multi_tenant:
|
|
1200
|
+
raise RuntimeError("Multi-tenant support is not enabled")
|
|
1201
|
+
|
|
1202
|
+
return self.tenant_manager.create_tenant(tenant_name, tenant_type, **kwargs)
|
|
1203
|
+
|
|
1204
|
+
def log_audit_event(self, action: str, resource: str, user_id: str, **kwargs) -> str:
|
|
1205
|
+
"""Log audit event"""
|
|
1206
|
+
if not self.enable_audit_logging:
|
|
1207
|
+
return ""
|
|
1208
|
+
|
|
1209
|
+
return self.audit_logger.log(action, resource, user_id, **kwargs)
|
|
1210
|
+
|
|
1211
|
+
def get_system_status(self) -> Dict[str, Any]:
|
|
1212
|
+
"""Get comprehensive system status"""
|
|
1213
|
+
status = {
|
|
1214
|
+
"status": "running" if self._running else "stopped",
|
|
1215
|
+
"uptime_seconds": (datetime.now() - self._startup_time).total_seconds(),
|
|
1216
|
+
"features": {
|
|
1217
|
+
"load_balancing": True,
|
|
1218
|
+
"auto_scaling": True,
|
|
1219
|
+
"multi_tenant": self.enable_multi_tenant,
|
|
1220
|
+
"audit_logging": self.enable_audit_logging,
|
|
1221
|
+
},
|
|
1222
|
+
"load_balancer": self.load_balancer.get_stats(),
|
|
1223
|
+
"auto_scaler": {
|
|
1224
|
+
"current_instances": self.auto_scaler.current_instances,
|
|
1225
|
+
"min_instances": self.auto_scaler.min_instances,
|
|
1226
|
+
"max_instances": self.auto_scaler.max_instances,
|
|
1227
|
+
"scaling_policy": self.auto_scaler.scaling_policy.value,
|
|
1228
|
+
},
|
|
1229
|
+
"deployment_manager": {
|
|
1230
|
+
"active_deployments": len(self.deployment_manager.active_deployments),
|
|
1231
|
+
"deployment_history": len(self.deployment_manager.deployment_history),
|
|
1232
|
+
"rollback_points": len(self.deployment_manager.rollback_points),
|
|
1233
|
+
},
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
if self.tenant_manager:
|
|
1237
|
+
status["tenant_manager"] = {
|
|
1238
|
+
"total_tenants": len(self.tenant_manager.tenants),
|
|
1239
|
+
"active_tenants": len([t for t in self.tenant_manager.tenants.values() if t.is_active]),
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if self.audit_logger:
|
|
1243
|
+
status["audit_logger"] = {
|
|
1244
|
+
"total_logs": len(self.audit_logger.audit_logs),
|
|
1245
|
+
"compliance_index": {
|
|
1246
|
+
standard: len(logs) for standard, logs in self.audit_logger.compliance_index.items()
|
|
1247
|
+
},
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
return status
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
# Global instance for easy access
|
|
1254
|
+
_enterprise_features: Optional[EnterpriseFeatures] = None
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
def get_enterprise_features(
|
|
1258
|
+
min_instances: int = 1,
|
|
1259
|
+
max_instances: int = 10,
|
|
1260
|
+
scaling_policy: ScalingPolicy = ScalingPolicy.AUTOMATIC,
|
|
1261
|
+
enable_multi_tenant: bool = True,
|
|
1262
|
+
enable_audit_logging: bool = True,
|
|
1263
|
+
) -> EnterpriseFeatures:
|
|
1264
|
+
"""Get or create global enterprise features instance"""
|
|
1265
|
+
global _enterprise_features
|
|
1266
|
+
if _enterprise_features is None:
|
|
1267
|
+
_enterprise_features = EnterpriseFeatures(
|
|
1268
|
+
min_instances=min_instances,
|
|
1269
|
+
max_instances=max_instances,
|
|
1270
|
+
scaling_policy=scaling_policy,
|
|
1271
|
+
enable_multi_tenant=enable_multi_tenant,
|
|
1272
|
+
enable_audit_logging=enable_audit_logging,
|
|
1273
|
+
)
|
|
1274
|
+
return _enterprise_features
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
# Convenience functions
|
|
1278
|
+
async def start_enterprise_features() -> None:
|
|
1279
|
+
"""Start enterprise features"""
|
|
1280
|
+
enterprise = get_enterprise_features()
|
|
1281
|
+
await enterprise.start()
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
def stop_enterprise_features() -> None:
|
|
1285
|
+
"""Stop enterprise features"""
|
|
1286
|
+
enterprise = get_enterprise_features()
|
|
1287
|
+
enterprise.stop()
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
async def deploy_application(
|
|
1291
|
+
version: str,
|
|
1292
|
+
strategy: DeploymentStrategy = DeploymentStrategy.BLUE_GREEN,
|
|
1293
|
+
**kwargs: Any,
|
|
1294
|
+
) -> Dict[str, Any]:
|
|
1295
|
+
"""Deploy application with enterprise features"""
|
|
1296
|
+
enterprise = get_enterprise_features()
|
|
1297
|
+
return await enterprise.deploy_application(version, strategy, **kwargs)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
if __name__ == "__main__":
|
|
1301
|
+
# Example usage
|
|
1302
|
+
async def main():
|
|
1303
|
+
print("š¢ Starting Enterprise Features Demo...")
|
|
1304
|
+
|
|
1305
|
+
# Initialize enterprise features
|
|
1306
|
+
enterprise = EnterpriseFeatures(
|
|
1307
|
+
min_instances=2,
|
|
1308
|
+
max_instances=5,
|
|
1309
|
+
scaling_policy=ScalingPolicy.AUTOMATIC,
|
|
1310
|
+
enable_multi_tenant=True,
|
|
1311
|
+
enable_audit_logging=True,
|
|
1312
|
+
)
|
|
1313
|
+
|
|
1314
|
+
try:
|
|
1315
|
+
# Start the system
|
|
1316
|
+
await enterprise.start()
|
|
1317
|
+
|
|
1318
|
+
# Create a tenant
|
|
1319
|
+
print("\nš¢ Creating multi-tenant environment...")
|
|
1320
|
+
tenant_id = enterprise.create_tenant(
|
|
1321
|
+
tenant_name="Demo Corporation",
|
|
1322
|
+
tenant_type=TenantType.DEDICATED,
|
|
1323
|
+
resource_limits={
|
|
1324
|
+
"cpu_cores": 4,
|
|
1325
|
+
"memory_gb": 8,
|
|
1326
|
+
"storage_gb": 200,
|
|
1327
|
+
},
|
|
1328
|
+
compliance_requirements=[
|
|
1329
|
+
ComplianceStandard.GDPR,
|
|
1330
|
+
ComplianceStandard.SOC2,
|
|
1331
|
+
],
|
|
1332
|
+
billing_plan="enterprise",
|
|
1333
|
+
)
|
|
1334
|
+
print(f"Created tenant: {tenant_id}")
|
|
1335
|
+
|
|
1336
|
+
# Log some audit events
|
|
1337
|
+
print("\nš Recording audit events...")
|
|
1338
|
+
enterprise.log_audit_event(
|
|
1339
|
+
action="tenant_created",
|
|
1340
|
+
resource="tenant_manager",
|
|
1341
|
+
user_id="admin",
|
|
1342
|
+
tenant_id=tenant_id,
|
|
1343
|
+
compliance_standards=[ComplianceStandard.GDPR],
|
|
1344
|
+
details={"plan": "enterprise"},
|
|
1345
|
+
)
|
|
1346
|
+
|
|
1347
|
+
enterprise.log_audit_event(
|
|
1348
|
+
action="deployment_started",
|
|
1349
|
+
resource="application",
|
|
1350
|
+
user_id="admin",
|
|
1351
|
+
tenant_id=tenant_id,
|
|
1352
|
+
details={"version": "1.0.0"},
|
|
1353
|
+
)
|
|
1354
|
+
|
|
1355
|
+
# Perform blue-green deployment
|
|
1356
|
+
print("\nš Performing blue-green deployment...")
|
|
1357
|
+
deployment_result = await enterprise.deploy_application(
|
|
1358
|
+
version="1.0.0",
|
|
1359
|
+
strategy=DeploymentStrategy.BLUE_GREEN,
|
|
1360
|
+
tenant_id=tenant_id,
|
|
1361
|
+
health_check_url="/api/health",
|
|
1362
|
+
auto_promote=True,
|
|
1363
|
+
)
|
|
1364
|
+
|
|
1365
|
+
print(f"Deployment result: {deployment_result['status']}")
|
|
1366
|
+
print(f"Steps completed: {len(deployment_result.get('steps', []))}")
|
|
1367
|
+
|
|
1368
|
+
# Let deployment process
|
|
1369
|
+
await asyncio.sleep(3)
|
|
1370
|
+
|
|
1371
|
+
# Get system status
|
|
1372
|
+
status = enterprise.get_system_status()
|
|
1373
|
+
print("\nš Enterprise System Status:")
|
|
1374
|
+
print(f" Status: {status['status']}")
|
|
1375
|
+
print(f" Uptime: {status['uptime_seconds']:.1f}s")
|
|
1376
|
+
print(f" Load Balancer: {status['load_balancer']['total_backends']} backends")
|
|
1377
|
+
auto_current = status["auto_scaler"]["current_instances"]
|
|
1378
|
+
auto_max = status["auto_scaler"]["max_instances"]
|
|
1379
|
+
print(f" Auto Scaler: {auto_current}/{auto_max} instances")
|
|
1380
|
+
print(f" Multi-tenant: {status['features']['multi_tenant']}")
|
|
1381
|
+
print(f" Audit Logging: {status['features']['audit_logging']}")
|
|
1382
|
+
|
|
1383
|
+
# Get tenant status
|
|
1384
|
+
tenant_status = enterprise.get_system_status()
|
|
1385
|
+
if "tenant_manager" in tenant_status:
|
|
1386
|
+
tm = tenant_status["tenant_manager"]
|
|
1387
|
+
print(f" Tenants: {tm['total_tenants']} total, {tm['active_tenants']} active")
|
|
1388
|
+
|
|
1389
|
+
print("\nā
Enterprise Features demo completed successfully!")
|
|
1390
|
+
|
|
1391
|
+
except Exception as e:
|
|
1392
|
+
print(f"\nā Demo failed: {str(e)}")
|
|
1393
|
+
import traceback
|
|
1394
|
+
|
|
1395
|
+
traceback.print_exc()
|
|
1396
|
+
|
|
1397
|
+
finally:
|
|
1398
|
+
# Stop the system
|
|
1399
|
+
print("\nš Stopping enterprise features...")
|
|
1400
|
+
enterprise.stop()
|
|
1401
|
+
print("ā
System stopped")
|
|
1402
|
+
|
|
1403
|
+
# Run the demo
|
|
1404
|
+
asyncio.run(main())
|