iac-code 0.1.0__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.
- iac_code/__init__.py +2 -0
- iac_code/acp/__init__.py +97 -0
- iac_code/acp/convert.py +423 -0
- iac_code/acp/http_sse.py +448 -0
- iac_code/acp/mcp.py +54 -0
- iac_code/acp/metrics.py +71 -0
- iac_code/acp/server.py +662 -0
- iac_code/acp/session.py +446 -0
- iac_code/acp/slash_registry.py +125 -0
- iac_code/acp/state.py +99 -0
- iac_code/acp/tools.py +112 -0
- iac_code/acp/types.py +13 -0
- iac_code/acp/version.py +26 -0
- iac_code/agent/__init__.py +19 -0
- iac_code/agent/agent_loop.py +640 -0
- iac_code/agent/agent_tool.py +269 -0
- iac_code/agent/agent_types.py +87 -0
- iac_code/agent/message.py +153 -0
- iac_code/agent/system_prompt.py +313 -0
- iac_code/cli/__init__.py +3 -0
- iac_code/cli/headless.py +114 -0
- iac_code/cli/main.py +246 -0
- iac_code/cli/output_formats.py +125 -0
- iac_code/commands/__init__.py +93 -0
- iac_code/commands/auth.py +1055 -0
- iac_code/commands/clear.py +34 -0
- iac_code/commands/compact.py +43 -0
- iac_code/commands/debug.py +45 -0
- iac_code/commands/effort.py +116 -0
- iac_code/commands/exit.py +10 -0
- iac_code/commands/help.py +49 -0
- iac_code/commands/model.py +130 -0
- iac_code/commands/registry.py +245 -0
- iac_code/commands/resume.py +49 -0
- iac_code/commands/tasks.py +41 -0
- iac_code/config.py +304 -0
- iac_code/i18n/__init__.py +141 -0
- iac_code/i18n/locales/zh/LC_MESSAGES/messages.po +1355 -0
- iac_code/memory/__init__.py +1 -0
- iac_code/memory/memory_manager.py +92 -0
- iac_code/memory/memory_tools.py +88 -0
- iac_code/providers/__init__.py +1 -0
- iac_code/providers/anthropic_provider.py +284 -0
- iac_code/providers/base.py +128 -0
- iac_code/providers/dashscope_provider.py +47 -0
- iac_code/providers/deepseek_provider.py +36 -0
- iac_code/providers/manager.py +399 -0
- iac_code/providers/openai_provider.py +344 -0
- iac_code/providers/retry.py +58 -0
- iac_code/providers/stream_watchdog.py +47 -0
- iac_code/providers/thinking.py +164 -0
- iac_code/services/__init__.py +1 -0
- iac_code/services/agent_factory.py +127 -0
- iac_code/services/cloud_credentials.py +22 -0
- iac_code/services/context_manager.py +221 -0
- iac_code/services/providers/__init__.py +1 -0
- iac_code/services/providers/aliyun.py +232 -0
- iac_code/services/session_index.py +281 -0
- iac_code/services/session_storage.py +245 -0
- iac_code/services/telemetry/__init__.py +66 -0
- iac_code/services/telemetry/attributes.py +84 -0
- iac_code/services/telemetry/client.py +330 -0
- iac_code/services/telemetry/config.py +76 -0
- iac_code/services/telemetry/constants.py +75 -0
- iac_code/services/telemetry/content_serializer.py +124 -0
- iac_code/services/telemetry/events.py +42 -0
- iac_code/services/telemetry/fallback.py +59 -0
- iac_code/services/telemetry/identity.py +73 -0
- iac_code/services/telemetry/metrics.py +62 -0
- iac_code/services/telemetry/names.py +199 -0
- iac_code/services/telemetry/sanitize.py +88 -0
- iac_code/services/telemetry/sink.py +67 -0
- iac_code/services/telemetry/tracing.py +38 -0
- iac_code/services/telemetry/types.py +13 -0
- iac_code/services/token_budget.py +54 -0
- iac_code/services/token_counter.py +76 -0
- iac_code/skills/__init__.py +1 -0
- iac_code/skills/bundled/__init__.py +94 -0
- iac_code/skills/bundled/iac_aliyun/SKILL.md +192 -0
- iac_code/skills/bundled/iac_aliyun/__init__.py +16 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/ecs.md +167 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/oss.md +69 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/rds.md +95 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/redis.md +100 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/slb.md +60 -0
- iac_code/skills/bundled/iac_aliyun/references/cloud-products/vpc.md +54 -0
- iac_code/skills/bundled/iac_aliyun/references/ros-template.md +155 -0
- iac_code/skills/bundled/iac_aliyun/references/template-parameters.md +206 -0
- iac_code/skills/bundled/iac_aliyun/references/terraform-template.md +101 -0
- iac_code/skills/bundled/iac_aliyun/scripts/tf2ros.py +77 -0
- iac_code/skills/bundled/simplify.py +28 -0
- iac_code/skills/discovery.py +136 -0
- iac_code/skills/frontmatter.py +119 -0
- iac_code/skills/listing.py +92 -0
- iac_code/skills/loader.py +42 -0
- iac_code/skills/processor.py +81 -0
- iac_code/skills/renderer.py +157 -0
- iac_code/skills/skill_definition.py +82 -0
- iac_code/skills/skill_tool.py +261 -0
- iac_code/state/__init__.py +5 -0
- iac_code/state/app_state.py +122 -0
- iac_code/tasks/__init__.py +1 -0
- iac_code/tasks/notification_queue.py +28 -0
- iac_code/tasks/task_state.py +66 -0
- iac_code/tasks/task_tools.py +114 -0
- iac_code/tools/__init__.py +8 -0
- iac_code/tools/base.py +226 -0
- iac_code/tools/bash.py +133 -0
- iac_code/tools/cloud/__init__.py +0 -0
- iac_code/tools/cloud/aliyun/__init__.py +0 -0
- iac_code/tools/cloud/aliyun/aliyun_api.py +510 -0
- iac_code/tools/cloud/aliyun/aliyun_doc_search.py +145 -0
- iac_code/tools/cloud/aliyun/endpoints.yml +343 -0
- iac_code/tools/cloud/aliyun/ros_client.py +56 -0
- iac_code/tools/cloud/aliyun/ros_stack.py +633 -0
- iac_code/tools/cloud/aliyun/ros_stack_instances.py +247 -0
- iac_code/tools/cloud/base_api.py +162 -0
- iac_code/tools/cloud/base_stack.py +242 -0
- iac_code/tools/cloud/registry.py +20 -0
- iac_code/tools/cloud/types.py +105 -0
- iac_code/tools/edit_file.py +121 -0
- iac_code/tools/glob.py +103 -0
- iac_code/tools/grep.py +254 -0
- iac_code/tools/list_files.py +104 -0
- iac_code/tools/read_file.py +127 -0
- iac_code/tools/result_storage.py +39 -0
- iac_code/tools/tool_executor.py +165 -0
- iac_code/tools/web_fetch.py +177 -0
- iac_code/tools/write_file.py +88 -0
- iac_code/types/__init__.py +40 -0
- iac_code/types/permissions.py +26 -0
- iac_code/types/skill_source.py +11 -0
- iac_code/types/stream_events.py +227 -0
- iac_code/ui/__init__.py +5 -0
- iac_code/ui/banner.py +110 -0
- iac_code/ui/components/__init__.py +0 -0
- iac_code/ui/components/dialog.py +142 -0
- iac_code/ui/components/divider.py +20 -0
- iac_code/ui/components/fuzzy_picker.py +308 -0
- iac_code/ui/components/progress_bar.py +54 -0
- iac_code/ui/components/search_box.py +165 -0
- iac_code/ui/components/select.py +319 -0
- iac_code/ui/components/status_icon.py +42 -0
- iac_code/ui/components/tabs.py +128 -0
- iac_code/ui/core/__init__.py +0 -0
- iac_code/ui/core/in_place_render.py +129 -0
- iac_code/ui/core/input_history.py +118 -0
- iac_code/ui/core/key_event.py +41 -0
- iac_code/ui/core/prompt_input.py +507 -0
- iac_code/ui/core/raw_input.py +302 -0
- iac_code/ui/core/screen.py +80 -0
- iac_code/ui/dialogs/__init__.py +0 -0
- iac_code/ui/dialogs/global_search.py +178 -0
- iac_code/ui/dialogs/history_search.py +100 -0
- iac_code/ui/dialogs/model_picker.py +280 -0
- iac_code/ui/dialogs/quick_open.py +108 -0
- iac_code/ui/dialogs/resume_picker.py +749 -0
- iac_code/ui/keybindings/__init__.py +0 -0
- iac_code/ui/keybindings/manager.py +124 -0
- iac_code/ui/renderer.py +1535 -0
- iac_code/ui/repl.py +772 -0
- iac_code/ui/spinner.py +112 -0
- iac_code/ui/suggestions/__init__.py +0 -0
- iac_code/ui/suggestions/aggregator.py +171 -0
- iac_code/ui/suggestions/command_provider.py +43 -0
- iac_code/ui/suggestions/directory_provider.py +95 -0
- iac_code/ui/suggestions/file_provider.py +121 -0
- iac_code/ui/suggestions/shell_history_provider.py +108 -0
- iac_code/ui/suggestions/token_extractor.py +77 -0
- iac_code/ui/suggestions/types.py +45 -0
- iac_code/ui/transcript_view.py +199 -0
- iac_code/utils/__init__.py +0 -0
- iac_code/utils/background_housekeeping.py +53 -0
- iac_code/utils/cleanup.py +68 -0
- iac_code/utils/json_utils.py +60 -0
- iac_code/utils/log.py +150 -0
- iac_code/utils/project_paths.py +74 -0
- iac_code/utils/tool_input_parser.py +62 -0
- iac_code-0.1.0.dist-info/LICENSE +201 -0
- iac_code-0.1.0.dist-info/METADATA +64 -0
- iac_code-0.1.0.dist-info/RECORD +184 -0
- iac_code-0.1.0.dist-info/WHEEL +5 -0
- iac_code-0.1.0.dist-info/entry_points.txt +2 -0
- iac_code-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Token counting utilities with model-aware encoding selection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
|
|
10
|
+
_MESSAGE_OVERHEAD = 4
|
|
11
|
+
_TOOL_USE_OVERHEAD = 10
|
|
12
|
+
|
|
13
|
+
# Map model name prefixes to tiktoken encoding names.
|
|
14
|
+
_MODEL_ENCODING_MAP = {
|
|
15
|
+
"gpt-4o": "o200k_base",
|
|
16
|
+
"gpt-4": "cl100k_base",
|
|
17
|
+
"gpt-5": "o200k_base",
|
|
18
|
+
"claude": "cl100k_base",
|
|
19
|
+
"qwen": "cl100k_base",
|
|
20
|
+
"qwq": "cl100k_base",
|
|
21
|
+
"o3": "o200k_base",
|
|
22
|
+
"o4": "o200k_base",
|
|
23
|
+
}
|
|
24
|
+
_DEFAULT_ENCODING = "cl100k_base"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _select_encoding(model: str) -> str:
|
|
28
|
+
model_lower = model.lower()
|
|
29
|
+
for prefix, encoding in _MODEL_ENCODING_MAP.items():
|
|
30
|
+
if model_lower.startswith(prefix):
|
|
31
|
+
return encoding
|
|
32
|
+
return _DEFAULT_ENCODING
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TokenCounter:
|
|
36
|
+
"""Count tokens using tiktoken with model-aware encoding selection."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, model: str = "") -> None:
|
|
39
|
+
self._encoder = None
|
|
40
|
+
encoding_name = _select_encoding(model)
|
|
41
|
+
try:
|
|
42
|
+
import tiktoken
|
|
43
|
+
|
|
44
|
+
self._encoder = tiktoken.get_encoding(encoding_name)
|
|
45
|
+
except Exception:
|
|
46
|
+
logger.debug("tiktoken not available, using estimation fallback")
|
|
47
|
+
|
|
48
|
+
def count_text(self, text: str) -> int:
|
|
49
|
+
if not text:
|
|
50
|
+
return 0
|
|
51
|
+
if self._encoder:
|
|
52
|
+
return len(self._encoder.encode(text))
|
|
53
|
+
return max(1, len(text) // 4)
|
|
54
|
+
|
|
55
|
+
def count_message(self, message: dict[str, Any]) -> int:
|
|
56
|
+
count = _MESSAGE_OVERHEAD
|
|
57
|
+
content = message.get("content", "")
|
|
58
|
+
if isinstance(content, str):
|
|
59
|
+
count += self.count_text(content)
|
|
60
|
+
elif isinstance(content, list):
|
|
61
|
+
for block in content:
|
|
62
|
+
if isinstance(block, dict):
|
|
63
|
+
block_type = block.get("type", "")
|
|
64
|
+
if block_type == "text":
|
|
65
|
+
count += self.count_text(block.get("text", ""))
|
|
66
|
+
elif block_type == "tool_use":
|
|
67
|
+
count += _TOOL_USE_OVERHEAD
|
|
68
|
+
count += self.count_text(block.get("name", ""))
|
|
69
|
+
count += self.count_text(json.dumps(block.get("input", {})))
|
|
70
|
+
elif block_type == "tool_result":
|
|
71
|
+
count += self.count_text(block.get("content", ""))
|
|
72
|
+
count += _TOOL_USE_OVERHEAD
|
|
73
|
+
return count
|
|
74
|
+
|
|
75
|
+
def count_messages(self, messages: list[dict[str, Any]]) -> int:
|
|
76
|
+
return sum(self.count_message(m) for m in messages)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Skill system — extensible prompt injection framework."""
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Built-in skill registration system."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Callable
|
|
6
|
+
|
|
7
|
+
from iac_code.skills.frontmatter import SkillFrontmatter
|
|
8
|
+
from iac_code.skills.skill_definition import SkillContext, SkillDefinition
|
|
9
|
+
from iac_code.types.skill_source import SkillSource
|
|
10
|
+
|
|
11
|
+
# Global bundled skill list
|
|
12
|
+
_bundled_skills: list[SkillDefinition] = []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register_bundled_skill(
|
|
16
|
+
*,
|
|
17
|
+
name: str,
|
|
18
|
+
description: str,
|
|
19
|
+
prompt: str | None = None,
|
|
20
|
+
get_prompt: Callable | None = None,
|
|
21
|
+
when_to_use: str = "",
|
|
22
|
+
argument_hint: str = "",
|
|
23
|
+
arguments: list[str] | None = None,
|
|
24
|
+
allowed_tools: list[str] | None = None,
|
|
25
|
+
model: str = "inherit",
|
|
26
|
+
effort: str = "",
|
|
27
|
+
user_invocable: bool = True,
|
|
28
|
+
context: str = "inline",
|
|
29
|
+
agent: str = "general-purpose",
|
|
30
|
+
skill_root: str = "",
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Register a bundled skill."""
|
|
33
|
+
frontmatter = SkillFrontmatter(
|
|
34
|
+
name=name,
|
|
35
|
+
description=description,
|
|
36
|
+
when_to_use=when_to_use,
|
|
37
|
+
argument_hint=argument_hint,
|
|
38
|
+
arguments=arguments or [],
|
|
39
|
+
allowed_tools=allowed_tools or [],
|
|
40
|
+
model=model,
|
|
41
|
+
effort=effort,
|
|
42
|
+
user_invocable=user_invocable,
|
|
43
|
+
context=context,
|
|
44
|
+
agent=agent,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Create prompt provider
|
|
48
|
+
# Only use a custom provider for get_prompt functions.
|
|
49
|
+
# Plain prompt strings go through the standard renderer so that
|
|
50
|
+
# skill_root injection and other pipeline steps apply automatically.
|
|
51
|
+
provider = _FunctionPromptProvider(get_prompt) if get_prompt is not None else None
|
|
52
|
+
|
|
53
|
+
skill = SkillDefinition(
|
|
54
|
+
name=name,
|
|
55
|
+
description=description,
|
|
56
|
+
frontmatter=frontmatter,
|
|
57
|
+
content=prompt or "",
|
|
58
|
+
source=SkillSource.BUNDLED,
|
|
59
|
+
skill_root=skill_root,
|
|
60
|
+
content_length=len(prompt or ""),
|
|
61
|
+
_prompt_provider=provider,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
_bundled_skills.append(skill)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_bundled_skills() -> list[SkillDefinition]:
|
|
68
|
+
"""Return all registered bundled skills."""
|
|
69
|
+
return list(_bundled_skills)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def init_bundled_skills() -> None:
|
|
73
|
+
"""Initialize all bundled skills. Called once at startup."""
|
|
74
|
+
# Guard against double initialization
|
|
75
|
+
if _bundled_skills:
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
from iac_code.skills.bundled.simplify import register_simplify_skill
|
|
79
|
+
|
|
80
|
+
register_simplify_skill()
|
|
81
|
+
|
|
82
|
+
from iac_code.skills.bundled.iac_aliyun import register_iac_aliyun_skill
|
|
83
|
+
|
|
84
|
+
register_iac_aliyun_skill()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class _FunctionPromptProvider:
|
|
88
|
+
"""Prompt provider that delegates to an async function."""
|
|
89
|
+
|
|
90
|
+
def __init__(self, func: Callable) -> None:
|
|
91
|
+
self._func = func
|
|
92
|
+
|
|
93
|
+
async def get_prompt(self, args: str, context: SkillContext) -> str:
|
|
94
|
+
return await self._func(args, context)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: iac-aliyun
|
|
3
|
+
description: 阿里云 IaC 模板生成、解释、完善与部署
|
|
4
|
+
when_to_use: 当用户涉及云资源创建、模板生成、模板解释、部署等 IaC 相关操作时
|
|
5
|
+
user_invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 阿里云 IaC 技能
|
|
9
|
+
|
|
10
|
+
阿里云 IaC 模板生成、解释、完善与部署。帮助用户通过 ROS/Terraform 模板管理云资源。
|
|
11
|
+
|
|
12
|
+
## 地域
|
|
13
|
+
|
|
14
|
+
所有 API 调用都需要地域,按以下优先级确定:
|
|
15
|
+
1. **用户指定**(如"在北京创建")→ 使用用户指定的地域
|
|
16
|
+
2. **工具默认地域**(用户未指定时)→ aliyun_api 工具的 region_id 参数描述中会显示默认地域(如 `Defaults to 'cn-hangzhou'`),使用该默认值并告知用户
|
|
17
|
+
3. **均无**(工具参数无默认值且用户未指定)→ 请用户指定目标地域,或使用 /auth 命令设置默认地域
|
|
18
|
+
|
|
19
|
+
确定后,所有 API 调用统一使用该地域。
|
|
20
|
+
|
|
21
|
+
**注意**:ROS 的模板、资源类型、模块是全局资源,任意地域查询结果相同。用户说"查所有地域的模板"时,只需查一个地域即可,不要遍历地域列表。
|
|
22
|
+
|
|
23
|
+
## 场景处理
|
|
24
|
+
|
|
25
|
+
### 生成模板
|
|
26
|
+
- **资源需求**(用户指定资源如"创建 VPC+ECS")→ 直接生成模板
|
|
27
|
+
- **应用部署**(用户想部署某个应用但不清楚该应用是什么)→ 先 aliyun_doc_search 搜索,搜不到再 web_fetch 搜索
|
|
28
|
+
- 如果部署地域属于中国,那么对 Docker、PyPI、npm、Maven、Go 等需配置国内镜像源,否则可能有网络问题等
|
|
29
|
+
- **业务需求**(用户描述业务场景)→ 提供 1-3 个方案含优缺点,用户选择后生成
|
|
30
|
+
- 默认 ROS 模板,用户指定 Terraform 时生成 Terraform 文件。**ROS 与 Terraform 共用同一套校验/部署链路(均通过 aliyun_api / ros_stack)**,不要建议用户用 `terraform init/apply` 等本地 CLI 替代
|
|
31
|
+
- 对用户未指定的参数直接使用合理默认值,不反复询问
|
|
32
|
+
- **库存相关属性必须参数化为 Parameters**,不写死具体值(见「参数化规则」)
|
|
33
|
+
|
|
34
|
+
### 解释/完善模板
|
|
35
|
+
- 分析用户提供的模板,解释结构和功能
|
|
36
|
+
- 按用户需求在已有模板上迭代完善
|
|
37
|
+
|
|
38
|
+
### 部署/更新/删除
|
|
39
|
+
- 所有写操作必须先向用户确认,删除/更新操作使用 ⚠️ 警告措辞
|
|
40
|
+
- 简洁询问是否部署,不展示工具调用细节
|
|
41
|
+
|
|
42
|
+
### 询价
|
|
43
|
+
- 查询部署的预估价格
|
|
44
|
+
|
|
45
|
+
## 参数化规则
|
|
46
|
+
|
|
47
|
+
生成模板时,以下属性**必须**定义为 Parameters(部署前通过 API 查询确定实际值):
|
|
48
|
+
|
|
49
|
+
| 产品 | 须参数化的属性 |
|
|
50
|
+
|------|---------------|
|
|
51
|
+
| ECS | ZoneId, InstanceType, ImageId, SystemDiskCategory, DataDiskCategory |
|
|
52
|
+
| RDS | ZoneId, DBInstanceClass, DBInstanceStorageType |
|
|
53
|
+
| Redis | ZoneId, InstanceClass |
|
|
54
|
+
| SLB/ALB | ZoneId |
|
|
55
|
+
|
|
56
|
+
以下属性**不需要**参数化,直接使用合理默认值:
|
|
57
|
+
- 网络:VPC CIDR、VSwitch CIDR
|
|
58
|
+
- 命名:实例名称、资源名称
|
|
59
|
+
- 安全:安全组规则
|
|
60
|
+
- 配置:备份策略、监控设置、标签
|
|
61
|
+
|
|
62
|
+
## 资源命名
|
|
63
|
+
|
|
64
|
+
资源名称应体现业务用途,**不要**包含工具名(如 terraform、ros):
|
|
65
|
+
- 好:`my-vpc`、`web-server`、`app-db`
|
|
66
|
+
- 差:`vpc-terraform`、`ros-ecs`、`tf-vswitch`
|
|
67
|
+
|
|
68
|
+
## 模板生成流程
|
|
69
|
+
|
|
70
|
+
1. 分析需求,确定资源列表
|
|
71
|
+
2. 查阅 [references/cloud-products/](references/cloud-products/) 下对应产品文件,了解选型策略和库存相关属性
|
|
72
|
+
3. 生成模板(库存相关属性按「参数化规则」定义为 Parameters,所有 Parameters 必须添加 AssociationProperty)并写入文件
|
|
73
|
+
- **Terraform**:生成 `.tf` 等文件后,必须先用 `tf2ros.py` 打包为 ROS Terraform 类型模板(用法见 [references/terraform-template.md](references/terraform-template.md) 的「与 ROS 集成」节),后续步骤校验/部署的都是这份打包后的 `.yml`
|
|
74
|
+
4. 调用 aliyun_api(product="ros", action="ValidateTemplate", params={"TemplateURL": <模板文件路径>}) 校验
|
|
75
|
+
5. 校验失败 → 分析错误 → 修复 → 重试(最多 5 轮)
|
|
76
|
+
6. 校验通过 → 展示模板 → 询问是否部署(**ROS 与 Terraform 一致**,禁止用 `terraform init/apply` 等本地 CLI 步骤替代部署确认)
|
|
77
|
+
|
|
78
|
+
> **TemplateURL 支持本地文件路径**:aliyun_api(product=ros)和 ros_stack 中,TemplateURL 可传本地文件路径(如 `/tmp/template.yml`),工具会自动读取文件内容。避免将大模板内容直接作为参数传递。
|
|
79
|
+
|
|
80
|
+
## 部署流程
|
|
81
|
+
|
|
82
|
+
### 可用性查询
|
|
83
|
+
|
|
84
|
+
当用户确认执行以下操作时,**必须先查询可用性**:
|
|
85
|
+
|
|
86
|
+
| 操作 | 查询范围 |
|
|
87
|
+
|------|----------|
|
|
88
|
+
| CreateStack | 全量查询所有库存相关 Parameters |
|
|
89
|
+
| ContinueCreateStack | 查询失败资源相关的 Parameters |
|
|
90
|
+
| UpdateStack | 查询变更涉及的 Parameters |
|
|
91
|
+
| CreateStackInstances | 按每个目标地域分别查询 |
|
|
92
|
+
| UpdateStackInstances | 按每个目标地域查询变更涉及的 Parameters |
|
|
93
|
+
|
|
94
|
+
查询步骤:
|
|
95
|
+
1. 解析模板 Parameters,识别库存相关参数及对应产品
|
|
96
|
+
2. 调用各产品可用性 API(具体 API 见 [references/cloud-products/](references/cloud-products/) 各产品文件的「可用性查询」节)
|
|
97
|
+
3. 找出公共可用区(所有资源都有库存的可用区)
|
|
98
|
+
4. 按 cloud-products 中的推荐规格优先匹配,不可用时选最接近的替代
|
|
99
|
+
5. 得到选定参数。**若操作为 CreateStack 或 UpdateStack,接「部署前询价」;其他操作(ContinueCreateStack 等)直接展示选定结果并请求用户确认。**
|
|
100
|
+
|
|
101
|
+
### 有模板的询价
|
|
102
|
+
|
|
103
|
+
1. 如果没有查询可用性,按照「可用性查询」进行
|
|
104
|
+
2. 调用 aliyun_api(product="ros", action="GetTemplateEstimateCost", params={...}) 询价。**模板参数必须按 `Parameters.<N>.ParameterKey` / `Parameters.<N>.ParameterValue` 平铺**(下标从 1 起),不要把参数名作为顶层 key 传入。**ROS 原生模板和 Terraform 类型模板调用同一 API,传参格式完全一致**——`ParameterKey` 即模板中的 Parameters 名(ROS)或 variable 名(Terraform,通常蛇形命名,如 `zone_id`)。示例(参数平铺通用规则见「aliyun_api 参数约定」):
|
|
105
|
+
```python
|
|
106
|
+
aliyun_api(
|
|
107
|
+
product="ros",
|
|
108
|
+
action="GetTemplateEstimateCost",
|
|
109
|
+
params={
|
|
110
|
+
"TemplateURL": "/tmp/ros-ecs-nginx-template.yml",
|
|
111
|
+
"Parameters.1.ParameterKey": "zone_id",
|
|
112
|
+
"Parameters.1.ParameterValue": "cn-hangzhou-k",
|
|
113
|
+
"Parameters.2.ParameterKey": "instance_type",
|
|
114
|
+
"Parameters.2.ParameterValue": "ecs.g7.large",
|
|
115
|
+
"Parameters.3.ParameterKey": "image_id",
|
|
116
|
+
"Parameters.3.ParameterValue": "centos_stream_9_x64_20G_alibase_20260414.vhd",
|
|
117
|
+
"Parameters.4.ParameterKey": "system_disk_category",
|
|
118
|
+
"Parameters.4.ParameterValue": "cloud_essd",
|
|
119
|
+
},
|
|
120
|
+
region_id="cn-hangzhou",
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
3. 合并展示「选定参数 + 预估费用」(格式见「询价展示格式」),一次性请求用户确认
|
|
124
|
+
4. **UpdateStack 特别提示**:展示时附加 `此为更新后模板的总费用预估,而非变更前后价差`
|
|
125
|
+
5. 用户确认 → 进入「执行部署」;用户拒绝 → 终止并告知已取消部署
|
|
126
|
+
|
|
127
|
+
**询价失败**:不阻塞部署。按如下格式展示后继续征求部署确认:
|
|
128
|
+
```
|
|
129
|
+
为您选定以下参数:
|
|
130
|
+
- 可用区:cn-beijing-h
|
|
131
|
+
- ECS 实例规格:ecs.g7.large (2c8g)
|
|
132
|
+
- ...
|
|
133
|
+
|
|
134
|
+
预估费用(按量付费):
|
|
135
|
+
- web-server (ECS ecs.g7.large): ¥xx/h
|
|
136
|
+
- app-db (RDS mysql.n4.large.1): ¥xx/h
|
|
137
|
+
- 其他(VPC / 安全组 / 交换机 等): 免费
|
|
138
|
+
合计: ¥xx/h
|
|
139
|
+
|
|
140
|
+
⚠️ 询价失败: <错误简述>
|
|
141
|
+
常见原因: 部分资源类型不支持询价 / 账号询价权限缺失 / API 暂时异常
|
|
142
|
+
|
|
143
|
+
确认部署?
|
|
144
|
+
```
|
|
145
|
+
6. 用户确认 → 将选定值作为 Parameters 传入部署操作
|
|
146
|
+
|
|
147
|
+
无法找到公共可用区时,告知用户冲突详情,建议换规格系列或换地域。
|
|
148
|
+
|
|
149
|
+
### 执行部署
|
|
150
|
+
|
|
151
|
+
- 使用 ros_stack 工具执行 CreateStack/UpdateStack/ContinueCreateStack/DeleteStack,禁止用 Bash
|
|
152
|
+
- CreateStack 必须传 `DisableRollback: true`
|
|
153
|
+
|
|
154
|
+
## 参考文件
|
|
155
|
+
|
|
156
|
+
| 文件 | 内容 |
|
|
157
|
+
|------|------|
|
|
158
|
+
| [references/template-parameters.md](references/template-parameters.md) | 模板参数规范:AssociationProperty、Label、分组(ROS/Terraform 共用) |
|
|
159
|
+
| [references/cloud-products/](references/cloud-products/) | 云产品选型文件(ecs.md、rds.md、redis.md、slb.md、vpc.md、oss.md) |
|
|
160
|
+
| [references/ros-template.md](references/ros-template.md) | ROS 原生模板最佳实践:RunCommand、嵌套栈、条件部署 |
|
|
161
|
+
| [references/terraform-template.md](references/terraform-template.md) | Terraform 最佳实践:文件组织、变量、Data Source、ROS 集成 |
|
|
162
|
+
|
|
163
|
+
## 资源和文档搜索
|
|
164
|
+
|
|
165
|
+
- 不确定的资源属性或Schema:
|
|
166
|
+
- ROS → aliyun_api(product="ros", action="GetResourceType", params={"ResourceType": "<类型>"})
|
|
167
|
+
- Terraform → aliyun_api(product="IaCService", action="GetResourceType", style="ROA", method="GET", pathname="/resourceType/<类型>")
|
|
168
|
+
- 不熟悉的资源类型/属性 → aliyun_doc_search(ROS 传 category_id=28850,Terraform 传 category_id=95817)
|
|
169
|
+
- 想要了解应用部署方案、解决方案、云产品相关知识 -> aliyun_doc_search
|
|
170
|
+
- 摘要不够 → web_fetch 获取完整文档
|
|
171
|
+
|
|
172
|
+
## aliyun_api 参数约定
|
|
173
|
+
|
|
174
|
+
**以下规则仅适用于 RPC 风格 API**(`style` 未传或传 `"RPC"`;ROA 风格用 JSON body/query,不受此约束)。
|
|
175
|
+
|
|
176
|
+
调用 RPC API 时,**array、object 类参数需平铺为带数字下标的键**,工具不会自动展开。规则:
|
|
177
|
+
|
|
178
|
+
- 下标从 `1` 起,依次递增
|
|
179
|
+
- `array[string]` → `<Name>.<N>`
|
|
180
|
+
- `array[object]` → `<Name>.<N>.<SubKey>`
|
|
181
|
+
- 嵌套列表按同样规则继续展开
|
|
182
|
+
- `object` → `<Name>.<SubKey>`
|
|
183
|
+
|
|
184
|
+
## 错误处理
|
|
185
|
+
|
|
186
|
+
### 校验失败
|
|
187
|
+
分析错误原因 → 查 GetResourceType Schema(如需)→ 修复 → 重试(最多 5 轮)
|
|
188
|
+
|
|
189
|
+
### 部署失败
|
|
190
|
+
分析错误原因:
|
|
191
|
+
- 权限/配额 → 告知用户处理
|
|
192
|
+
- 模板/参数 → 修复后 ContinueCreateStack(不重新 CreateStack)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from iac_code.skills.bundled import register_bundled_skill
|
|
4
|
+
|
|
5
|
+
SKILL_DIR = Path(__file__).parent
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register_iac_aliyun_skill() -> None:
|
|
9
|
+
register_bundled_skill(
|
|
10
|
+
name="iac-aliyun",
|
|
11
|
+
description="阿里云 IaC 模板生成、解释、完善与部署",
|
|
12
|
+
prompt=(SKILL_DIR / "SKILL.md").read_text(),
|
|
13
|
+
when_to_use="当用户涉及云资源创建、模板生成、模板解释、部署等 IaC 相关操作时",
|
|
14
|
+
user_invocable=False,
|
|
15
|
+
skill_root=str(SKILL_DIR),
|
|
16
|
+
)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# 阿里云 ECS 选型指南
|
|
2
|
+
|
|
3
|
+
## 实例规格推荐策略
|
|
4
|
+
|
|
5
|
+
### 规格族选择
|
|
6
|
+
|
|
7
|
+
个人场景:
|
|
8
|
+
- 成本优先: e,如果e实例没库存,自动使用性价比优先配置
|
|
9
|
+
- 性价比优先:u1-/u2a-/u2i-
|
|
10
|
+
- 性能优先:g9i/c9i/r9i
|
|
11
|
+
|
|
12
|
+
非个人场景:
|
|
13
|
+
- 价格优先配置: u1-/u2a-/u2i-
|
|
14
|
+
- 性价比优先配置:u1-/u2a-/u2i-
|
|
15
|
+
- 性能优先配置:g9i/c9i/r9i
|
|
16
|
+
|
|
17
|
+
### vCPU / 内存确定原则
|
|
18
|
+
|
|
19
|
+
- 确定内存CPU比:1:1, 1:2, 1:4, 1:8(基于大模型和预置素材判断)
|
|
20
|
+
- 确定规格族列表:非个人用户不推荐e实例
|
|
21
|
+
- 多款规格策略:
|
|
22
|
+
- 性价比优先配置:,
|
|
23
|
+
- 规格族选择:选用中低价位的规格族:e,u1-/u2a-/u2i-,9代规格族 -> 选用u
|
|
24
|
+
- 基于场景确定标准的内存和CPU大小
|
|
25
|
+
- 价格优先配置:
|
|
26
|
+
- 规格族选择:如果有比性价比优先规格族低的规格,则选定低价格的规格族,CPU 内存 不变
|
|
27
|
+
- 如果没有比性价比优先的规格族低的规格族:则降低 vCPU内存配置:`vCPU = min(2, Standard_vCPU / 2)`, `Mem = min(2, Standard_Mem / 2)`
|
|
28
|
+
- 性能优先配置:
|
|
29
|
+
- 规格族选择:如果有更高性能的规格族,则选择更高性能规格族,对应CPU、内存不变
|
|
30
|
+
- 如果没有更高配置规格族,规格族使用性价比优先规格族,但是内存CPU 要升级配置:`vCPU = 2 * Standard_vCPU`, `Mem = Standard_Mem * 2`
|
|
31
|
+
|
|
32
|
+
### 场景化推荐表
|
|
33
|
+
|
|
34
|
+
下表为内置场景模板,可直接套用;未明确匹配的场景,由大模型基于最相近场景推理。
|
|
35
|
+
|
|
36
|
+
| 场景 | 子场景 | CPU:内存 | 云盘(系统盘/数据盘一致) | 成本优先 | 性价比优先 | 性能优先 | 推荐理由 |
|
|
37
|
+
|------|--------|----------|---------------------------|----------|------------|----------|----------|
|
|
38
|
+
| Web 应用服务 | 个人网站 | 1:2 | ESSD PL0 | 2c2g | 2c4g | 4c8g | 轻量级应用,重视成本控制,内存用于页面缓存 |
|
|
39
|
+
| Web 应用服务 | 小程序 | 1:2 | ESSD PL0 | 2c2g | 2c4g | 4c8g | 并发适中,内存缓存 API 响应数据 |
|
|
40
|
+
| Web 应用服务 | 企业官网 | 1:2 | ESSD AutoPL | 2c4g | 4c8g | 8c16g | 稳定性要求高,需要处理适度并发访问 |
|
|
41
|
+
| Web 应用服务 | 后端服务 | 1:2 | ESSD PL0 | 2c4g | 4c8g | 8c16g | API 处理密集,需要并发处理能力和内存缓存 |
|
|
42
|
+
| Web 应用服务 | 开发测试环境 | 1:2 | ESSD PL0 | 1c2g | 2c4g | 4c8g | 开发调试使用,成本敏感,配置够用即可 |
|
|
43
|
+
| AI 与智能应用 | 大模型 / 深度学习训练 | 1:8 | ESSD AutoPL | 16c128g | 32c256g | 64c512g | 训练需要大内存存储模型参数和训练数据 |
|
|
44
|
+
| AI 与智能应用 | AI 模型推理服务 | 1:4 | ESSD AutoPL | 4c16g | 8c32g | 16c64g | 推理需要内存加载模型,CPU 处理推理请求 |
|
|
45
|
+
| AI 与智能应用 | 智能体平台部署 | 1:4 | ESSD AutoPL | 8c32g | 16c64g | 32c128g | 多服务运行,内存需求大,支持并发智能体 |
|
|
46
|
+
| AI 与智能应用 | 智能体应用部署 | 1:4 | ESSD AutoPL | 4c16g | 8c32g | 16c64g | 应用运行时需要充足内存加载 AI 模型 |
|
|
47
|
+
| 数据库服务 | MySQL / PostgreSQL | 1:4 | ESSD AutoPL | 4c16g | 8c32g | 16c64g | 关系型数据库需要大内存缓存数据页和索引 |
|
|
48
|
+
| 数据库服务 | MongoDB / Cassandra | 1:8 | ESSD AutoPL | 4c24g | 8c48g | 16c96g | NoSQL 需要更多内存存储文档和分布式数据 |
|
|
49
|
+
| 数据库服务 | Redis / Memcached | 1:8 | ESSD AutoPL | 2c16g | 4c32g | 8c64g | 内存数据库,内存是核心资源,CPU 需求相对较低 |
|
|
50
|
+
| 数据库服务 | 高并发 OLTP | 1:4 | ESSD AutoPL | 8c32g | 16c64g | 32c128g | 事务处理需要高并发能力和大内存缓存 |
|
|
51
|
+
| 数据库服务 | 高性能分析型数据库 | 1:6 | ESSD AutoPL | 8c48g | 16c96g | 32c192g | 分析查询需要大内存缓存和复杂计算处理 |
|
|
52
|
+
| 大数据与实时计算 | 实时日志采集与分析 | 1:4 | ESSD AutoPL | 4c16g | 8c32g | 16c64g | 实时处理需要内存缓冲和流式计算能力 |
|
|
53
|
+
| 大数据与实时计算 | 用户行为与埋点数据分析 | 1:4 | ESSD AutoPL | 8c32g | 16c64g | 32c128g | 大数据量分析处理,需要内存存储中间结果 |
|
|
54
|
+
| 大数据与实时计算 | 数据仓库 ETL 任务 | 1:4 | ESSD AutoPL | 8c32g | 16c64g | 32c128g | ETL 需要大内存处理数据转换和临时存储 |
|
|
55
|
+
| 大数据与实时计算 | IoT 设备数据接入 | 1:4 | ESSD AutoPL | 4c12g | 8c24g | 16c48g | 高并发接入,适度内存缓冲设备数据 |
|
|
56
|
+
| 游戏服务 | 轻量级网页游戏 | 1:2 | ESSD PL0 | 2c4g | 4c8g | 8c16g | 简单逻辑,重视响应速度和并发处理 |
|
|
57
|
+
| 游戏服务 | 大型 PC 端游服务器 | 1:2 | ESSD AutoPL | 8c16g | 16c32g | 32c64g | 复杂游戏逻辑,高 CPU 需求处理游戏状态 |
|
|
58
|
+
| 游戏服务 | 移动对战类手游 | 1:2 | ESSD AutoPL | 4c8g | 8c16g | 16c32g | 实时对战,低延迟要求,快速状态同步 |
|
|
59
|
+
| 游戏服务 | 云游戏视频编码推流 | 1:3 | ESSD AutoPL | 8c24g | 16c48g | 32c96g | 视频编码处理需要更多内存缓存视频帧 |
|
|
60
|
+
| 高性能计算 | 自动驾驶仿真测试 | 1:4 | ESSD AutoPL | 16c64g | 32c128g | 64c256g | 复杂仿真需要大内存存储场景数据和计算结果 |
|
|
61
|
+
| 高性能计算 | 工业 CAE / CFD 仿真 | 1:4 | ESSD AutoPL | 16c64g | 32c128g | 64c256g | 科学计算内存密集,需要大量数值计算 |
|
|
62
|
+
| 高性能计算 | 科学计算与数值模拟 | 1:4 | ESSD AutoPL | 16c64g | 32c128g | 64c256g | 大规模计算需要大内存存储矩阵和中间结果 |
|
|
63
|
+
| 高性能计算 | 基因测序与生物信息 | 1:6 | ESSD AutoPL | 16c96g | 32c192g | 64c384g | 生物数据处理内存需求极大,序列比对算法复杂 |
|
|
64
|
+
| 音视频与图形渲染 | 视频转码与格式转换 | 1:2 | ESSD AutoPL | 8c16g | 16c32g | 32c64g | CPU 密集型转码,适度内存缓存视频数据 |
|
|
65
|
+
| 音视频与图形渲染 | 直播流接收与分发 | 1:3 | ESSD PL0 | 4c12g | 8c24g | 16c48g | 流处理需要内存缓冲,支持多路流并发 |
|
|
66
|
+
| 音视频与图形渲染 | 3D 动画离线渲染 | 1:4 | ESSD AutoPL | 16c64g | 32c128g | 64c256g | 渲染需要大内存存储 3D 场景和纹理数据 |
|
|
67
|
+
| 音视频与图形渲染 | 短视频合成与 AI 滤镜 | 1:4 | ESSD AutoPL | 8c32g | 16c64g | 32c128g | AI 处理需要内存加载滤镜模型和视频帧 |
|
|
68
|
+
|
|
69
|
+
## 存储配置推荐
|
|
70
|
+
|
|
71
|
+
数据盘和系统盘一视同仁,标准推荐策略如下:
|
|
72
|
+
- e实例 固定推荐 ESSD Entry
|
|
73
|
+
- 其他实例基于场景推荐策略(表格/Json文件)匹配ESSD 级别,未预定义的场景,请基于已有场景让大模型推理确定级别。
|
|
74
|
+
|
|
75
|
+
多款配置推荐生成策略:以上是基于标准配置推荐的策略,默认可以衍生多款配置:
|
|
76
|
+
- 如果标准配置是PL0,则高配版刻配置AutoPL,成本优先版刻配置PL0或者 ESSD Entry (E实例)
|
|
77
|
+
- 如果标准配置是AutoPL,则高配版可以是AutoPL,成本优先版可以是ESSD PL0
|
|
78
|
+
|
|
79
|
+
基于以上原则可以默认生成多款存储配置。
|
|
80
|
+
1. 默认同一个业务场景,系统盘、数据盘规格一致,
|
|
81
|
+
2. 以上云盘的配置可以适用于新加数据盘,性能级别一致,默认增加1块数据盘,大小为100GB。
|
|
82
|
+
|
|
83
|
+
## 镜像选择
|
|
84
|
+
|
|
85
|
+
- **Alibaba Cloud Linux 4**:推荐,针对阿里云优化,内核定制
|
|
86
|
+
- **Ubuntu 24.04**:社区支持好,生态丰富
|
|
87
|
+
- **CentOS Stream 9**:兼容 RHEL,适合企业场景
|
|
88
|
+
- **Windows Server 2025**:Windows 工作负载
|
|
89
|
+
|
|
90
|
+
调用 DescribeImages 可指定 ImageName 进行模糊搜索。比如 ImageName="aliyun_4_*
|
|
91
|
+
|
|
92
|
+
## 网络带宽
|
|
93
|
+
|
|
94
|
+
- 默认按流量计费:适合流量不稳定的业务
|
|
95
|
+
- 按带宽计费:适合流量持续稳定、高带宽场景
|
|
96
|
+
- 公网 IP 可选按量购买 EIP,支持弹性绑定/解绑
|
|
97
|
+
|
|
98
|
+
## 安全组最佳实践
|
|
99
|
+
|
|
100
|
+
**默认不开 22/3389**——用 RunCommand/Invocation 部署即可,业务只开必要端口(Web → 80/443,层间通信 → `SourceGroupId`)。
|
|
101
|
+
|
|
102
|
+
**须开 22/3389 时**(用户明确要求 SSH 或含跳板机):`SourceCidrIp` 必须限定来源,严禁 `0.0.0.0/0`:
|
|
103
|
+
- 执行 `curl -s https://api.ipify.org` 取当前公网 IP,写成 `<ip>/32`
|
|
104
|
+
- 获取失败 → 请用户提供白名单 IP,不得回退到 `0.0.0.0/0`
|
|
105
|
+
|
|
106
|
+
## 登录凭证
|
|
107
|
+
|
|
108
|
+
**默认不写入 Password 和 KeyPairName**——模板中保持二者均不设置,应用部署通过 RunCommand/Invocation 执行命令,无需登录凭证。
|
|
109
|
+
|
|
110
|
+
## 在实例中执行 Shell 命令
|
|
111
|
+
|
|
112
|
+
- ROS 模板:参见 [../ros-template.md](../ros-template.md)「在实例中执行命令」章节
|
|
113
|
+
- Terraform:参见 [../terraform-template.md](../terraform-template.md)「在实例中执行命令」章节
|
|
114
|
+
|
|
115
|
+
## 高可用架构建议
|
|
116
|
+
|
|
117
|
+
- 生产环境:至少 2 台 ECS,分布在不同可用区
|
|
118
|
+
- 结合 SLB 做负载均衡
|
|
119
|
+
- 使用弹性伸缩(ESS)应对流量波动
|
|
120
|
+
- 重要数据存 RDS/OSS,避免依赖本地磁盘
|
|
121
|
+
|
|
122
|
+
## 库存相关属性(模板中须参数化为 Parameters)
|
|
123
|
+
|
|
124
|
+
| 属性 | 说明 |
|
|
125
|
+
|------|------|
|
|
126
|
+
| ZoneId | 可用区 |
|
|
127
|
+
| InstanceType | 实例规格 |
|
|
128
|
+
| ImageId | 镜像 ID(可用镜像受 InstanceType 影响) |
|
|
129
|
+
| SystemDiskCategory | 系统盘类型 |
|
|
130
|
+
| DataDiskCategory | 数据盘类型(如有数据盘) |
|
|
131
|
+
|
|
132
|
+
## 可用性查询
|
|
133
|
+
|
|
134
|
+
### 1. 查询可用实例规格
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
aliyun_api(product="ecs", action="DescribeAvailableResource", params={
|
|
138
|
+
"DestinationResource": "InstanceType",
|
|
139
|
+
"IoOptimized": "optimized",
|
|
140
|
+
"InstanceChargeType": "PostPaid"
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
> InstanceChargeType 也可传 "PrePaid"(包年包月)。
|
|
145
|
+
|
|
146
|
+
返回结果按可用区分组,包含各可用区支持的实例规格列表。
|
|
147
|
+
|
|
148
|
+
### 2. 查询可用磁盘类型
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
aliyun_api(product="ecs", action="DescribeAvailableResource", params={
|
|
152
|
+
"DestinationResource": "SystemDisk",
|
|
153
|
+
"ZoneId": "<选定的可用区>",
|
|
154
|
+
"InstanceType": "<选定的实例规格>",
|
|
155
|
+
"InstanceChargeType": "PostPaid"
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 3. 筛选逻辑
|
|
160
|
+
|
|
161
|
+
1. 从返回的可用区列表中,筛出同时满足实例规格族和磁盘类型的可用区
|
|
162
|
+
2. 按「实例规格推荐策略」的档位顺序匹配规格族(成本/性价比/性能 三档分别选)
|
|
163
|
+
3. 同档位规格族不可用时:
|
|
164
|
+
- **个人 `e` 实例缺货** → 按"性价比优先"档位重新选
|
|
165
|
+
- **其他规格族缺货** → 在同档位的备选规格族列表中按顺序回退(如 `u1` → `u2a` → `u2i`)
|
|
166
|
+
- 整档位都不可用时,选同实例族中最接近 vCPU/内存的可用规格
|
|
167
|
+
4. 云盘类型按「存储配置推荐」生成,并以可用磁盘类型查询结果做最终校验
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 阿里云 OSS 对象存储指南
|
|
2
|
+
|
|
3
|
+
## 存储类型
|
|
4
|
+
|
|
5
|
+
| 类型 | 访问频率 | 最低存储时间 | 适用场景 |
|
|
6
|
+
|------|----------|-------------|----------|
|
|
7
|
+
| 标准(Standard) | 频繁 | 无 | 热数据、网站图片、视频 |
|
|
8
|
+
| 低频访问(IA) | 不频繁(月均 1-2 次) | 30 天 | 备份、归档数据 |
|
|
9
|
+
| 归档(Archive) | 极少 | 60 天 | 长期归档,读取需解冻 |
|
|
10
|
+
| 冷归档(Cold Archive) | 极少 | 180 天 | 合规存档,成本最低 |
|
|
11
|
+
|
|
12
|
+
**推荐**:业务数据用标准,日志/备份用低频访问,合规数据用归档。
|
|
13
|
+
|
|
14
|
+
## Bucket 配置要点
|
|
15
|
+
|
|
16
|
+
资源类型 `ALIYUN::OSS::Bucket`,关键属性:
|
|
17
|
+
- `StorageClass`:Standard / IA / Archive / ColdArchive
|
|
18
|
+
- `AccessControl`:private(推荐)/ public-read / public-read-write
|
|
19
|
+
- `VersioningConfiguration.Status: Enabled`:开启版本控制,防误删
|
|
20
|
+
- `ServerSideEncryptionRule.SSEAlgorithm: AES256`:服务端加密
|
|
21
|
+
|
|
22
|
+
## 访问控制
|
|
23
|
+
|
|
24
|
+
### 访问权限级别
|
|
25
|
+
|
|
26
|
+
| 权限 | 说明 | 推荐场景 |
|
|
27
|
+
|------|------|----------|
|
|
28
|
+
| private | 所有访问需鉴权 | 生产数据、敏感文件 |
|
|
29
|
+
| public-read | 公开可读,写入需鉴权 | 静态网站、CDN 资源 |
|
|
30
|
+
| public-read-write | 完全公开 | 不推荐用于生产 |
|
|
31
|
+
|
|
32
|
+
### RAM Policy 控制
|
|
33
|
+
|
|
34
|
+
- 应用服务使用 RAM 角色(而非 AK)访问 OSS
|
|
35
|
+
- 按最小权限原则:只授予必要的 `oss:PutObject`、`oss:GetObject` 等权限
|
|
36
|
+
- 禁止应用服务使用 `oss:DeleteBucket` 等危险权限
|
|
37
|
+
|
|
38
|
+
### 防盗链
|
|
39
|
+
|
|
40
|
+
通过 `RefererConfiguration` 设置 Referer 白名单,`AllowEmptyReferer: false` 禁止空 Referer 访问。
|
|
41
|
+
|
|
42
|
+
## 生命周期规则
|
|
43
|
+
|
|
44
|
+
通过 `LifecycleConfiguration.Rules` 配置:
|
|
45
|
+
- `Expiration.Days`:指定天数后自动删除
|
|
46
|
+
- `Transitions`:指定天数后转为低频(IA)或归档(Archive)存储类型
|
|
47
|
+
|
|
48
|
+
## 静态网站托管
|
|
49
|
+
|
|
50
|
+
通过 `WebsiteConfiguration` 配置 `IndexDocument` 和 `ErrorDocument`。
|
|
51
|
+
|
|
52
|
+
## CDN 加速
|
|
53
|
+
|
|
54
|
+
- OSS Bucket 绑定 CDN 域名,加速静态资源访问
|
|
55
|
+
- CDN 回源协议选 HTTPS,开启回源鉴权
|
|
56
|
+
- 缓存规则:静态资源(图片/JS/CSS)TTL 7 天,HTML 文件 TTL 10 分钟
|
|
57
|
+
|
|
58
|
+
## 跨区域复制(CRR)
|
|
59
|
+
|
|
60
|
+
- 关键数据开启跨区域复制,实现容灾
|
|
61
|
+
- 两端 Bucket 均需开启版本控制
|
|
62
|
+
|
|
63
|
+
## 最佳实践
|
|
64
|
+
|
|
65
|
+
- 生产 Bucket 禁止公网写入,通过 STS Token 临时授权
|
|
66
|
+
- 重要数据开启版本控制,防止误覆盖或误删
|
|
67
|
+
- 日志 Bucket 独立于业务 Bucket,避免权限混用
|
|
68
|
+
- 大文件(> 1 GB)使用分片上传(Multipart Upload)
|
|
69
|
+
- 定期审计 Bucket 权限,防止权限漂移
|