主仓只保留代码:移出 contracts/deploy/docs 与模板监听包/原型图,并提交后台工单页改动。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-14 15:00:34 +08:00
co-authored by Cursor
parent 1b4299787c
commit cea3a6e51e
233 changed files with 394 additions and 18943 deletions
+10
View File
@@ -69,3 +69,13 @@ agent-release.zip
# Office 打开产生的临时锁文件
~$*
**/~$*
# 本地资料/运维脚本/合同副本:不进主仓(代码在 inquiry-* / aibot-bridge / prompt / tools)
/contracts/
/deploy/
/docs/
/海陆空报价单模板/
/询价机器人V1.0.24原型图/
/友通达询价智能体监听包/
/_tmp_analyze_templates.py
/styles.css
-16
View File
@@ -1,16 +0,0 @@
# 字段合同(contracts)
本目录存放字段 / 字典投影 JSON。智能体写字段校验、主账写 TMS 字典投影前,**必须**以本目录**正式**文件为准。
## 当前状态
| 文件名 | 状态 |
|---|---|
| `inquiry-required-fields-v1.json` | 正式(已从现网对照源拉入) |
| `tms-dictionary-projection-v2.json` | 正式(已从现网对照源拉入) |
| `quote-template-mapping-v1.json` | 正式(报价模板映射/黄区/样例预览合同) |
| `*.PLACEHOLDER.json` | 历史占位,加载器优先正式文件 |
备份另见 `_ref/prod-pull/contracts/`(勿提交密钥目录)。
代码加载:`agent.schema.load_contract` / `require_formal_contract`。
@@ -1,5 +0,0 @@
{
"_comment": "占位:正式合同由产品/仓库内审交付到同名 inquiry-required-fields-v1.json。禁止从现网服务器或现网发布目录拷贝。骨架阶段禁止依赖本文件做业务判断。",
"schemaVersion": "v1-placeholder",
"fields": []
}
-102
View File
@@ -1,102 +0,0 @@
{
"schema_version": 1,
"contract_id": "INQUIRY_REQUIRED_FIELDS_V1",
"status": "APPROVED",
"approved_by": "user",
"approved_at": "2026-08-30T02:30:00+08:00",
"requirement_id": "REQ-20260830-030",
"last_amended_requirement_id": "REQ-20260831-009 revision 1",
"stage_semantics": {
"PRICE_REQUIRED": "首次查价必须满足的字段;只按已确认的业务线和二级类型激活。",
"COLLAB_REQUIRED": "首次查价字段保持有效后,进入协同阶段追加的必填字段。"
},
"value_validity": {
"scope": "ONLY_CURRENTLY_ACTIVATED_REQUIRED_FIELDS",
"completion_rule": "TRIMMED_NON_EMPTY_VALUE_IS_PRESENT",
"content_validation": "DISABLED_LOCAL_VALUE_FORMAT_AND_COMPATIBILITY_VALIDATION_EXCEPT_DECLARED_MACHINE_TYPES",
"accepted_user_values": "当前作用域字段收到任意非空值即视为已采集;本地不得按单位、车型、布尔文案、别名、格式或封闭枚举拒绝。SEA箱型箱量保持一个原始业务字段,结构化containerItems只由DeepSeek B投影;投影不可用时由TMS查询边返回1003。",
"inactive_field_display_not_a_fact": "未激活字段摘要中的-只表示不适用,不作为字段值进入完整性校验。"
},
"model_scopes": {
"PRICING": "DeepSeek B只接收本合同pricing_required中当前激活字段、必要路由身份和optional_projection_fields中当前业务线允许的可选事实;缺项只按pricing_required计算。",
"COLLABORATION": "DeepSeek B接收同一票不可变销售原话、已确认运输模式和陆运二级类型,只返回当前激活协同字段;结果保存到独立快照。点击协同时必须重新执行本范围。"
},
"pricing_required": {
"SEA": {
"always": ["起运港", "目的港", "品名", "货量", "整柜或拼柜", "箱型箱量"],
"display_names": {"货量": "货物数量"}
},
"AIR": {
"always": ["起运港", "目的港", "品名", "件数", "毛重", "体积", "包装方式"],
"display_names": {"起运港": "起运地", "目的港": "目的地", "毛重": "重量(KG)", "体积": "体积(CBM)", "包装方式": "包装类型"}
},
"LAND": {
"国内运输拼车": {
"always": ["起运港", "目的港", "品名", "体积", "毛重"],
"display_names": {"起运港": "始发站", "目的港": "目的地", "品名": "货物品名", "体积": "体积(CBM)", "毛重": "重量(KG)"}
},
"国内运输整车": {
"always": ["起运港", "目的港", "品名", "车型数量"],
"display_names": {"起运港": "始发站", "目的港": "目的地", "品名": "货物品名", "车型数量": "车型/数量"}
},
"跨境集拼": {
"always": ["起运港", "目的港", "品名", "体积", "毛重"],
"display_names": {"起运港": "始发站", "目的港": "目的地", "品名": "货物品名", "体积": "体积(CBM)", "毛重": "重量(KG)"}
},
"跨境整车": {
"always": ["起运港", "目的港", "品名"],
"display_names": {"起运港": "起运地", "目的港": "目的地", "品名": "货物品名"}
},
"中港": {
"always": ["起运港", "目的港", "品名", "车型数量"],
"display_names": {"起运港": "始发站", "目的港": "目的地", "品名": "货物品名", "车型数量": "车型/数量"}
}
}
},
"optional_projection_fields": {
"LAND": ["件数", "毛重", "体积", "时效要求", "cargo_items"],
"semantics": "这些字段不是首次查价必填项;只有销售原话明确出现且DeepSeek B给出逐项证据时才保真保存。代码不得从原始自然语言猜测,只可对模型结构化cargo_items做单位与算术投影。"
},
"collaboration_required": {
"SEA": ["贸易条款", "货好时间", "HS编码", "是否含油", "是否含电", "是否含磁"],
"AIR": ["是否含电", "是否含磁"],
"LAND": {
"国内运输整车": ["时效要求", "客户名称", "货值", "包装方式", "是否危险品"],
"国内运输拼车": ["时效要求", "客户名称", "包装方式", "货值", "是否危险品"],
"跨境整车": ["时效要求", "客户名称", "HS编码", "车型数量", "贸易条款", "货值", "包装方式", "是否危险品"],
"跨境集拼": ["时效要求", "客户名称", "HS编码", "贸易条款", "包装方式", "是否危险品"],
"中港": {"same_as": "跨境整车"}
}
},
"collaboration_value_contracts": {
"enforcement": "SUGGESTION_ONLY_USER_TYPED_NON_EMPTY_VALUE_IS_ACCEPTED",
"LAND": {
"时效要求": {
"国内运输整车": ["普件(常用线路/常规车型)", "普件(非常用线路/临时线路/特种车型)", "急件"],
"国内运输拼车": ["普件(常用线路/常规车型)", "普件(非常用线路/临时线路/特种车型)", "急件"],
"跨境整车": ["普件(中港、东南亚常用线路/常规车型)", "普件(中亚、中欧、东南亚涉及国内+国外段)", "普件(中亚、中欧、东南亚涉及境外段清派等特殊要求)", "急件"],
"跨境集拼": ["普件(中港、东南亚常用线路/常规车型)", "普件(中亚、中欧、东南亚涉及国内+国外段)", "普件(中亚、中欧、东南亚涉及境外段清派等特殊要求)", "急件"],
"中港": {"same_as": "跨境整车"}
}
}
},
"legacy_read_aliases": {
"时效要求": ["服务档位", "货物类型", "服务类型", "普件/急件"]
},
"semantic_ownership": {
"owner": "DeepSeek B",
"must_output": ["raw_value", "normalized_value", "evidence", "segment_binding", "cargo_binding"],
"forbidden_local_capabilities": ["semantic_regex", "alias_inference", "content_normalization", "semantic_fallback", "value_format_rejection", "closed_enum_value_rejection"]
},
"machine_types": {},
"deterministic_invariants": [
"SEA货物数量与AIR件数是不同字段;自然语言数量落入哪个字段只能由DeepSeek B依据已解析业务线决定。",
"SEA箱型箱量是一个首次查价必填字段,整柜/FCL和拼柜/LCL均激活;任意非空原值完成采集。",
"SEA箱型箱量原值到containerItems.type/quantity的结构化投影只由DeepSeek B输出,本地不得拆分、去单位或限制格式。",
"DeepSeek B不能形成可用containerItems时不得重新补问箱型或箱量,由item投影或TMS查询边返回业务1003。",
"AIR包装类型使用内部字段包装方式承载,但只在AIR首次查价作用域激活。",
"尺寸原文不得在本地代码中用正则、别名或关键词解析为体积(CBM);DeepSeek B已输出带证据的结构化cargo_items后,代码可按单位做确定性乘法和加总并投影总体积。",
"协同字段只能在对应基础查价字段满足后追加,不得反向扩大首次查价必填。",
"代码只校验字段键作用域、JSON结构、非空、条件激活、权限、版本与幂等;字段内容格式、规范性和是否适合报价由模型与下游报价服务负责。"
]
}
-145
View File
@@ -1,145 +0,0 @@
{
"schemaVersion": "quote-template-mapping-v1",
"description": "报价模板常变版:原 Excel 几乎不改;黄色=固定区;映射点=系统字段→单元格;千问只辅助映射不发明价格。",
"rules": {
"yellowMeansFixed": true,
"yellowNote": "黄色填充单元格为版式固定内容,生成与预览时永不覆盖。",
"clearFillableBeforeWrite": true,
"layoutAuthority": "uploaded_excel",
"noUnifiedColumns": true,
"llmRole": "suggest_field_to_cell_mapping_only",
"priceSource": "frozen_quote_facts_only",
"versionFreeze": "generated_quote_binds_templateId_plus_templateVersion"
},
"modes": {
"auto": "可自动生成报价文件",
"manual": "仅下载给人工填写,不进自动生成"
},
"mappingJsonShape": {
"schemaVersion": "quote-template-mapping-v1",
"sheet": "主工作表名(可空,默认第一个)",
"fields": {
"customer_name": "SheetName!C3",
"quote_no": "SheetName!F4"
},
"fee_rows": {
"anchor": "SheetName!A15",
"columns": {
"name": "B",
"amount": "D",
"remark": "F"
},
"styleCopyRows": 1
},
"fixedYellowCells": ["SheetName!A1", "SheetName!B2"],
"candidates": [],
"unmappedRequired": []
},
"systemFields": [
{ "code": "customer_name", "label": "客户名称", "requiredHint": true },
{ "code": "contact_name", "label": "联系人", "requiredHint": false },
{ "code": "contact_phone", "label": "电话", "requiredHint": false },
{ "code": "quote_no", "label": "报价单编号", "requiredHint": true },
{ "code": "quote_date", "label": "报价日期", "requiredHint": true },
{ "code": "valid_until", "label": "有效期至", "requiredHint": false },
{ "code": "currency", "label": "币别", "requiredHint": false },
{ "code": "sales_name", "label": "业务员", "requiredHint": false },
{ "code": "pol", "label": "起运港", "requiredHint": false },
{ "code": "pod", "label": "目的港", "requiredHint": false },
{ "code": "origin", "label": "始发地", "requiredHint": false },
{ "code": "destination", "label": "目的地", "requiredHint": false },
{ "code": "commodity", "label": "品名", "requiredHint": false },
{ "code": "quantity", "label": "货物数量", "requiredHint": false },
{ "code": "container_type_qty", "label": "箱型箱量", "requiredHint": false },
{ "code": "fcl_or_lcl", "label": "整柜或拼柜", "requiredHint": false },
{ "code": "trade_terms", "label": "贸易条款", "requiredHint": false },
{ "code": "cargo_ready_date", "label": "货好时间", "requiredHint": false },
{ "code": "pieces", "label": "件数", "requiredHint": false },
{ "code": "weight_kg", "label": "重量", "requiredHint": false },
{ "code": "volume_cbm", "label": "体积", "requiredHint": false },
{ "code": "total_amount", "label": "报价合计", "requiredHint": false },
{ "code": "fee_rows", "label": "费用明细行", "requiredHint": false }
],
"labelDictionary": {
"客户名称": "customer_name",
"客户": "customer_name",
"客户:": "customer_name",
"联系人": "contact_name",
"联系人:": "contact_name",
"电话": "contact_phone",
"电话:": "contact_phone",
"报价单编号": "quote_no",
"报价编号": "quote_no",
"报价日期": "quote_date",
"询价日期": "quote_date",
"有效期至": "valid_until",
"报价有效期": "valid_until",
"币别": "currency",
"业务员": "sales_name",
"起运港": "pol",
"起 运 港": "pol",
"目的港": "pod",
"目 的 港": "pod",
"始发地": "origin",
"始发站": "origin",
"目的地": "destination",
"品名": "commodity",
"品 名": "commodity",
"货物数量": "quantity",
"箱型箱量": "container_type_qty",
"整柜或拼柜": "fcl_or_lcl",
"贸易条款": "trade_terms",
"货好时间": "cargo_ready_date",
"件数": "pieces",
"件 数": "pieces",
"重量": "weight_kg",
"重 量": "weight_kg",
"体积": "volume_cbm",
"体 积": "volume_cbm"
},
"samplePreviewFacts": {
"customer_name": "ABC Trading Co.",
"contact_name": "张三",
"contact_phone": "13800000000",
"quote_no": "QT-202607020001",
"quote_date": "2026-07-02",
"valid_until": "2026-07-05",
"currency": "USD",
"sales_name": "张敏",
"pol": "CNSHA",
"pod": "USLAX",
"origin": "深圳",
"destination": "洛杉矶",
"commodity": "通用货物",
"quantity": "2",
"container_type_qty": "40HQ x 2",
"fcl_or_lcl": "FCL",
"trade_terms": "FOB",
"cargo_ready_date": "2026-07-10",
"pieces": "10",
"weight_kg": "1200",
"volume_cbm": "8.5",
"total_amount": "3680.00",
"fee_rows": [
{ "name": "O/F 海运费", "amount": "2900", "remark": "" },
{ "name": "THC + DOC + SEAL", "amount": "780", "remark": "" }
]
},
"categories": {
"海运": ["海运报价单模板"],
"空运": ["空运到港报价单模板", "空运到门报价单模板"],
"陆运": [
"双清或中越",
"国内整车",
"国内拼车",
"跨境整车",
"跨境集拼",
"中港",
"凭祥保税仓&普仓仓储"
]
},
"seedModeHints": {
"manualKeywords": ["人工报价", "双清", "保税仓", "仓储"],
"autoDefault": true
}
}
@@ -1,5 +0,0 @@
{
"_comment": "占位:正式合同由产品/仓库内审交付到同名 tms-dictionary-projection-v2.json。禁止从现网服务器或现网发布目录拷贝。骨架阶段禁止依赖本文件做业务判断。",
"schemaVersion": "v2-placeholder",
"projections": []
}
-163
View File
@@ -1,163 +0,0 @@
{
"schema_version": 2,
"contract_version": "TMS-DICTIONARY-PROJECTION-V2",
"supersedes": ".project-control/architecture/tms-dictionary-projection-v1.json",
"required_fields_contract_ref": ".project-control/architecture/inquiry-required-fields-v1.json",
"business_semantics_owner": "DEEPSEEK_B",
"protocol_projection_owner": "JAVA_TMS_ADAPTER",
"last_amended_requirement_id": "REQ-20260831-009 revision 1",
"matching_policy": {
"mode": "EXACT_ONLY",
"allowed_keys": ["source_code", "source_name"],
"allow_regex": false,
"allow_fuzzy": false,
"allow_alias_inference": false,
"allow_suffix_trimming": false,
"allow_last_write_wins": false,
"multiple_distinct_values": "AMBIGUOUS",
"zero_values": "UNMAPPED",
"air_package_fallback": {
"target_field": "packageType",
"value": 1,
"meaning": "全部",
"preserve_raw_source": true
}
},
"catalog_statuses": [
"PROJECTABLE",
"AMBIGUOUS_NAME_GROUP",
"SOURCE_VALUE_MISSING",
"REFERENCE_ONLY"
],
"resolution_statuses": [
"RESOLVED",
"UNMAPPED",
"AMBIGUOUS",
"SOURCE_VALUE_MISSING",
"CARDINALITY_UNSUPPORTED",
"NOT_APPLICABLE"
],
"dictionary_domains": [
"air_airport",
"air_packaging_type",
"land_address",
"land_vehicle",
"sea_container",
"land_transport_type",
"currency_reference"
],
"projection_rules": [
{
"transport_mode": "AIR",
"transport_type": null,
"source_field": "origin",
"target_field": "originCode",
"dictionary_domain": "air_airport",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "AIR",
"transport_type": null,
"source_field": "destination",
"target_field": "destinationCode",
"dictionary_domain": "air_airport",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "AIR",
"transport_type": null,
"source_field": "packagingType",
"target_field": "packageType",
"dictionary_domain": "air_packaging_type",
"output_column": "projection_value",
"default_source_value": "全部"
},
{
"transport_mode": "LAND",
"transport_type": null,
"source_field": "origin",
"target_field": "originCode",
"dictionary_domain": "land_address",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "LAND",
"transport_type": null,
"source_field": "destination",
"target_field": "destinationCode",
"dictionary_domain": "land_address",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "LAND",
"transport_type": "DOMESTIC_FTL|HK",
"source_field": "vehicleItems",
"target_field": "vehicleType",
"dictionary_domain": "land_vehicle",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "SEA",
"transport_type": null,
"source_field": "containerItems",
"target_field": "containerType",
"dictionary_domain": "sea_container",
"output_column": "projection_value",
"default_source_value": null
},
{
"transport_mode": "LAND",
"transport_type": null,
"source_field": "transportType",
"target_field": "landTransportType",
"dictionary_domain": "land_transport_type",
"output_column": "projection_value",
"default_source_value": null
}
],
"direct_projection_rules": [
{
"transport_mode": "SEA",
"transport_type": null,
"source_field": "containerItems",
"source_item_field": "quantity",
"target_field": "containerQty",
"value_type": "positive_integer",
"dictionary_domain": null,
"unit_in_value": false
}
],
"non_blocking_projection_failures": [
{
"transport_mode": "LAND",
"dictionary_domain": "land_address",
"target_fields": ["originCode", "destinationCode"],
"resolution_status": "UNMAPPED",
"required_source_names": ["origin", "destination"],
"behavior": "保留投影审计;名称非空时以名称且代码空值继续真实TMS查询。AMBIGUOUS、SOURCE_VALUE_MISSING及其他业务线仍失败关闭。"
}
],
"direct_passthrough_fields": [
{
"transport_mode": "LAND",
"source_field": "时效要求",
"target_field": "routeCategory",
"behavior": "逐字透传用户值,不做字典或本地语义映射。"
}
],
"unsupported_projection_fields": [
{
"field": "seaPortCode",
"reason": "SOURCE_WORKBOOK_HAS_NO_SEA_PORT_DICTIONARY"
},
{
"field": "currency",
"reason": "WORKBOOK_NUMERIC_VALUE_IS_REFERENCE_ONLY_NOT_ISO4217_PROJECTION"
}
]
}
-71
View File
@@ -1,71 +0,0 @@
# 切流目标:新系统取代 `C:\yutongda`(方案 B)
决策日期:2026-09-12。
运行根(新正式):`E:\wwwroot`(`admin\current` / `agent\current`)。
现网旧根:`C:\yutongda`(切流完成前禁止删、禁止改其 `ops` 指针)。
对照合同:`prompt/13-环境对照.md`。本文件只写**执行顺序与禁区**。
## 目标态(切完之后)
| 项 | 值 |
|---|---|
| `YTD_ENV` | `prod` |
| 运行根 | `E:\wwwroot` |
| 主账 | 新 Java 主账(非 Jeecg),端口按切流日约定(可继续 8180 或改回 8080) |
| 智能体 HTTP | 合并进程(现 8910,切流后可改挂 8810 或保持 8910 只改 Nginx) |
| Worker | 唯一后台进程 |
| AIBOT | 仅新桥(现规划 8913);**旧 8813 必须先停** |
| 域名 / 企微 | 仍为 `ai.ytd-scm.com` / `1000010`(URL 不用改) |
| MySQL / PG / Redis / 桶 | **正式列取值**;新主账**不复用 Jeecg 表结构**,用新库或迁完再切库名 |
## 当前阶段(切流前)
已做:Nginx 回调/`inquiry-form`/`agent/health` → 8910;静态后台 → `E:\wwwroot\admin\current`。
未做:新主账 8180、Worker、真库、Graph/Redis、AIBOT 切流。
**切流前数据必须继续隔离**(新系统资源名:`inquiry_robot` / `inquiry_robot_runtime` / `inquiry_robot:` / 桶 `inquiry_robot`),禁止新进程写 `jeecg-boot` / `ytd_runtime` / `ytd:prod:` / `ytd-inquiry`。
不要再用 `ytd_test*` 命名。
## 阶段清单
### P0 — 新正式底座(仍隔离库)
1. 服务器安装 **JDK 17+**(已装:`E:\wwwroot\tools\jdk-17`,Microsoft OpenJDK 17.0.16;环境变量 `JDK17_HOME`。旧 Jeecg 仍用 `C:\yutongda\tools\jdk8`)。
2. 开通/确认新系统库账号:MySQL `inquiry_robot`、PG `inquiry_robot_runtime`、Redis db1 前缀 `inquiry_robot:`、桶 `inquiry-robot`(勿指 `jeecg-boot`)。
- Redis / MinIO 已在应用机配通;MySQL/PG 建库 SQL 在 `E:\wwwroot\ops\sql\`,需数据机管理员执行(现网 `ytd_jeecg` / `ytd_runtime` **无建库权限**)。
3. 部署并常驻:主账 `8180`、智能体 `8910`、Worker;后台静态已在 `admin\current`。
4. 主账:工单六态 + transition API;智能体改打 `BIZ_API_BASE_URL=http://127.0.0.1:8180`。
5. Redis 队列/幂等、PG checkpoint 接通。
6. 业务验收:建单 → 补问 → 报价 → 六态,不依赖旧 Jeecg 写路径。
### P1 — 切流日(取代现网进程)
须单独批准。失败则按现网流程回滚 `ai.conf` 与进程。
1. 备份:`ai.conf`、`E:\wwwroot\ops\active-release.json`、现网 `C:\yutongda\ops\active-release*.json`。
2. `.env` 改为 `YTD_ENV=prod`;库/Redis/桶继续用 `inquiry_robot*`(或甲方最终正式名);去掉告警 `[test]`。
3. Nginx:`/jeecgboot` 指到**新主账**(勿再指旧 8080,除非回滚)。
4. 停现网:旧智能体相关(8810 等)、**先停 8813**,再起新 AIBOT `8913` 并 `WECOM_AIBOT_ENABLED=true`。
5. 确认 8080 旧 Jeecg:按产品决定停或只读保留;**新后台只打新主账**。
6. 冒烟:企微收发、后台登录、建单、六态、健康检查。
7. 观察期后再处理旧目录归档(不要当天直接删 `C:\yutongda`)。
### P2 — 收尾
- TMS lock/release 按产品打开。
- 旧 release / 旧库只读归档。
- 发布脚本只写 `E:\wwwroot`,不再用现网累计发布器切活动指针。
## 硬禁止(直到 P1 批准)
- 新主账 / 智能体连接 `jeecg-boot`、`ytd_runtime`、Redis `/0` + `ytd:prod:`、桶 `ytd-inquiry`
- 与现网 **同时** 连接同一 AIBOT 长连接
- 删除或改写 `C:\yutongda\ops` 活动指针
- 把半成品 `YTD_ENV=prod` 却仍混用现网库密钥
## 回滚(P1 失败)
1. `ai.conf` 恢复切流前备份;硬重启 Nginx(避免 BOM / 卡死的 Restart-Service)。
2. 停 `E:\wwwroot` 新进程中已接管的部分;拉起现网对应进程。
3. 确认 `https://ai.ytd-scm.com/wecom/callback` 回到现网行为。
-58
View File
@@ -1,58 +0,0 @@
# 本地一键:同步源码 → 构建最新 dist → 上传 → 切后台到 8180
# 用法:在仓库根目录 .\deploy\Deploy-YtdAdminLatest.ps1
# 要求:SSH 密钥 ~/.ssh/id_ed25519_ytd;服务器 8180/8910/8080 已在听。
# 副作用:更新 E:\wwwroot\admin\current;改 Nginx /jeecgboot -> 8180;不碰 C:\yutongda。
$ErrorActionPreference = 'Stop'
$RepoRoot = Split-Path -Parent $PSScriptRoot
$SrcBackend = Join-Path $RepoRoot 'inquiry-backend'
$BuildRoot = 'C:\ytd\inquiry-backend'
$Key = Join-Path $env:USERPROFILE '.ssh\id_ed25519_ytd'
$Remote = 'ytd_extdev_0903@129.211.181.80'
$Incoming = 'C:/Users/ytd_extdev_0903/incoming'
if (-not (Test-Path $Key)) { throw "missing SSH key $Key" }
if (-not (Test-Path $SrcBackend)) { throw "missing $SrcBackend" }
Write-Host '=== 1) sync source to english build path ==='
New-Item -ItemType Directory -Force -Path (Split-Path $BuildRoot) | Out-Null
# 排除 node_modules / dist / .git,再单独保证依赖
robocopy $SrcBackend $BuildRoot /MIR /XD node_modules dist .git .vite .husky /XF *.log /NFL /NDL /NJH /NJS /nc /ns /np | Out-Null
# robocopy exit 0-7 ok
if ($LASTEXITCODE -ge 8) { throw "robocopy failed code=$LASTEXITCODE" }
Copy-Item (Join-Path $SrcBackend '.env.production') (Join-Path $BuildRoot '.env.production') -Force
if (-not (Test-Path (Join-Path $BuildRoot 'node_modules'))) {
Write-Host '=== pnpm install ==='
Push-Location $BuildRoot
try { pnpm install --frozen-lockfile } catch { pnpm install }
Pop-Location
}
Write-Host '=== 2) build production dist ==='
Push-Location $BuildRoot
if (Test-Path 'dist') { Remove-Item 'dist' -Recurse -Force }
pnpm run build
if ($LASTEXITCODE -ne 0) { Pop-Location; throw "build failed $LASTEXITCODE" }
if (-not (Test-Path 'dist\index.html')) { Pop-Location; throw 'dist/index.html missing' }
Pop-Location
$zip = Join-Path $env:TEMP 'admin-dist.zip'
if (Test-Path $zip) { Remove-Item $zip -Force }
Compress-Archive -Path (Join-Path $BuildRoot 'dist\*') -DestinationPath $zip -Force
Write-Host ("zip bytes=" + (Get-Item $zip).Length)
Write-Host '=== 3) upload ==='
scp -o BatchMode=yes -i $Key `
$zip `
(Join-Path $RepoRoot 'deploy\ai.conf.cutover-8180') `
(Join-Path $RepoRoot 'deploy\_remote_cutover_admin_8180.ps1') `
"${Remote}:${Incoming}/"
if ($LASTEXITCODE -ne 0) { throw "scp failed $LASTEXITCODE" }
Write-Host '=== 4) remote cutover ==='
ssh -o BatchMode=yes -i $Key $Remote "powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_cutover_admin_8180.ps1"
if ($LASTEXITCODE -ne 0) { throw "remote cutover failed $LASTEXITCODE" }
Write-Host 'DONE: admin latest published; /jeecgboot -> 8180'
Write-Host '请强刷 https://ai.ytd-scm.com/ (Ctrl+F5),用 Jeecg 账号登录'
-126
View File
@@ -1,126 +0,0 @@
# Install test agent on server and cut over Nginx wecom callback to 8910
$ErrorActionPreference = "Stop"
$ReleaseId = "scaffold-agent-" + (Get-Date -Format "yyyyMMdd-HHmmss")
$Root = "E:\wwwroot"
$Release = Join-Path $Root "agent\releases\$ReleaseId"
$AgentCurrent = Join-Path $Root "agent\current"
$Python = "C:\yutongda\tools\Python312\python.exe"
$Nginx = "C:\nginx-1.18.0"
$Zip = "C:\Users\ytd_extdev_0903\incoming\agent-release.zip"
$EnvSrc = "C:\Users\ytd_extdev_0903\incoming\env.file"
$AiConfNew = "C:\Users\ytd_extdev_0903\incoming\ai.conf.cutover-8910"
Write-Output "=== create dirs ==="
New-Item -ItemType Directory -Force -Path $Release, "$Root\logs", "$Root\ops", "$Root\admin\releases", "$Root\agent\releases", "C:\Users\ytd_extdev_0903\incoming" | Out-Null
if (-not (Test-Path $Zip)) { throw "missing $Zip" }
if (-not (Test-Path $Python)) { throw "missing $Python" }
Write-Output "=== expand release ==="
Expand-Archive -Path $Zip -DestinationPath $Release -Force
$AgentHome = Join-Path $Release "agent"
if (-not (Test-Path (Join-Path $AgentHome "agent\http_app.py"))) {
throw "http_app.py not found under $AgentHome"
}
Write-Output "AgentHome=$AgentHome"
Write-Output "=== env ==="
Copy-Item $EnvSrc (Join-Path $Root ".env") -Force
Copy-Item $EnvSrc (Join-Path $Release ".env") -Force
Copy-Item $EnvSrc (Join-Path $AgentHome ".env") -Force
Write-Output "=== venv + pip ==="
$venvDir = Join-Path $AgentHome ".venv"
$venvPy = Join-Path $venvDir "Scripts\python.exe"
$venvPip = Join-Path $venvDir "Scripts\pip.exe"
if (-not (Test-Path $venvPy)) {
& $Python -m venv $venvDir
if ($LASTEXITCODE -ne 0) { throw "venv failed" }
}
& $venvPip install --default-timeout=180 -i https://pypi.tuna.tsinghua.edu.cn/simple -r (Join-Path $AgentHome "requirements.txt")
if ($LASTEXITCODE -ne 0) { throw "pip install failed" }
Write-Output "=== switch agent\\current junction ==="
if (Test-Path $AgentCurrent) {
cmd /c "rmdir `"$AgentCurrent`"" | Out-Null
if (Test-Path $AgentCurrent) { Remove-Item $AgentCurrent -Recurse -Force }
}
cmd /c "mklink /J `"$AgentCurrent`" `"$AgentHome`""
if (-not (Test-Path (Join-Path $AgentCurrent "agent\http_app.py"))) { throw "agent current missing http_app" }
Write-Output "=== stop old listener 8910 ==="
Get-NetTCPConnection -LocalPort 8910 -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty OwningProcess -Unique |
ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }
Start-Sleep -Seconds 1
Write-Output "=== write run-agent-http.cmd ==="
$runCmd = @"
@echo off
cd /d "$AgentCurrent"
set YTD_ENV=test
set AGENT_HTTP_PORT=8910
:loop
"$AgentCurrent\.venv\Scripts\python.exe" -m agent.http_app >> "$Root\logs\agent-http.out.log" 2>> "$Root\logs\agent-http.err.log"
echo agent exited, restart in 3s >> "$Root\logs\agent-http.err.log"
timeout /t 3 /nobreak >nul
goto loop
"@
Set-Content -Path (Join-Path $Root "ops\run-agent-http.cmd") -Value $runCmd -Encoding ASCII
Write-Output "=== start agent via WMI ==="
$wmi = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{
CommandLine = "cmd.exe /c `"$(Join-Path $Root 'ops\run-agent-http.cmd')`""
}
Write-Output "WMI_Return=$($wmi.ReturnValue) ProcessId=$($wmi.ProcessId)"
Start-Sleep -Seconds 6
try {
$h = Invoke-WebRequest -Uri "http://127.0.0.1:8910/health" -UseBasicParsing -TimeoutSec 8
Write-Output "HEALTH=$($h.StatusCode) $($h.Content)"
} catch {
Get-Content (Join-Path $Root "logs\agent-http.err.log") -Tail 50 -ErrorAction SilentlyContinue
throw "agent health failed: $_"
}
$listenPid = 0
$listen = Get-NetTCPConnection -LocalPort 8910 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if ($listen) { $listenPid = $listen.OwningProcess }
Write-Output "=== pointer ==="
@{
root = $Root
releaseId = $ReleaseId
releaseRoot = $Release
agentHome = $AgentHome
agentCurrent = $AgentCurrent
adminCurrent = (Join-Path $Root "admin\current")
pid = $listenPid
updatedAt = (Get-Date).ToString("o")
} | ConvertTo-Json | Set-Content (Join-Path $Root "ops\active-release.json") -Encoding UTF8
Write-Output "=== nginx cutover (no BOM, hard restart) ==="
$ai = Join-Path $Nginx "myconf\ai.conf"
$bak = Join-Path $Nginx ("myconf\ai.conf.bak-before-cutover-" + (Get-Date -Format "yyyyMMdd-HHmmss"))
Copy-Item $ai $bak -Force
$bytes = [System.IO.File]::ReadAllBytes($AiConfNew)
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) {
$list = New-Object System.Collections.Generic.List[byte]
for ($i = 3; $i -lt $bytes.Length; $i++) { [void]$list.Add($bytes[$i]) }
$bytes = $list.ToArray()
}
[System.IO.File]::WriteAllBytes($ai, $bytes)
$old = Get-Location
Set-Location $Nginx
& .\nginx.exe -t
if ($LASTEXITCODE -ne 0) {
Copy-Item $bak $ai -Force
Set-Location $old
throw "nginx -t failed, restored"
}
Get-Process nginx -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
try { Start-Service Nginx1.18 -ErrorAction Stop } catch {
Start-Process -FilePath (Join-Path $Nginx "nginx.exe") -WorkingDirectory $Nginx -WindowStyle Hidden
}
Set-Location $old
Write-Output "NGINX_RESTARTED bak=$bak"
Write-Output "DONE release=$ReleaseId"
-20
View File
@@ -1,20 +0,0 @@
# 部署占位(仅测试机 / 切流后 wwwroot)
新系统运行根:`E:\wwwroot`(`admin\current` / `agent\current`)。
## 每次发最新后台(正式 Jeecg Vue)
在仓库根执行:
```powershell
.\deploy\Deploy-YtdAdminLatest.ps1
```
会:同步 `inquiry-backend` → 英文路径构建 → 上传 `admin-dist.zip` → 切 `admin\current` → Nginx `/jeecgboot` 指到 **8180**。
禁止改 `C:\yutongda`。现网旧路径 `/jeecg-boot` 仍可指 8080 作兼容。
## 其他
- 智能体安全发布:`_remote_safe_deploy_agent.ps1`(不改 Nginx)
- 主账 WMI 拉起:`_remote_wmi_start_ledger.ps1`
- 并存期勿双连 AIBOT(8913)
-15
View File
@@ -1,15 +0,0 @@
# 友通达询价智能体 · 测试骨架启动脚本(占位)
# 职责:在开发机或 C:\ytd-test 起五个空壳进程做健康检查。
# 禁止:改现网 C:\yutongda 指针、改 Nginx 回调、连接真实 AIBOT Bot。
# 用法:在仓库根目录执行 .\deploy\Start-YtdTestScaffold.ps1
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
Write-Host "仓库根: $RepoRoot"
Write-Host "请分别启动(详见根 README):"
Write-Host " 1) ledger -> LEDGER_PORT=8180"
Write-Host " 2) agent HTTP -> AGENT_HTTP_PORT=8910"
Write-Host " 3) agent Worker(无对外端口)"
Write-Host " 4) aibot-bridge -> AIBOT_BRIDGE_PORT=8913 且仅 127.0.0.1"
Write-Host " 5) admin Vite 开发服(生产用静态构建,勿开 3100 进正式 Nginx)"
Write-Host "冒烟: curl http://127.0.0.1:8180/health ; 8910/health ; 8913/health"
-28
View File
@@ -1,28 +0,0 @@
@echo off
setlocal EnableExtensions
cd /d "%~dp0"
REM Double-click: fetch recent remote agent 8910 logs once, then pause.
where powershell.exe >nul 2>&1
if errorlevel 1 (
echo ERROR: powershell.exe not found.
goto :end
)
if not exist "%~dp0Watch-Agent8910.ps1" (
echo ERROR: Watch-Agent8910.ps1 missing next to this bat.
goto :end
)
echo Starting Watch-Agent8910 -Once ...
echo.
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0Watch-Agent8910.ps1" -Once %*
set ERR=%ERRORLEVEL%
echo.
echo Finished. ExitCode=%ERR%
:end
echo.
pause
exit /b %ERR%
-34
View File
@@ -1,34 +0,0 @@
@echo off
setlocal EnableExtensions
cd /d "%~dp0"
REM Double-click: follow remote agent 8910 logs. Ctrl+C to stop.
REM Colleague setup: see Watch-Agent8910.colleague.txt (Chinese guide also available).
REM Pass-through args, e.g. Watch-Agent8910.bat -Once
where powershell.exe >nul 2>&1
if errorlevel 1 (
echo ERROR: powershell.exe not found.
goto :end
)
if not exist "%~dp0Watch-Agent8910.ps1" (
echo ERROR: Watch-Agent8910.ps1 missing next to this bat.
goto :end
)
echo Starting LIVE follow Watch-Agent8910 ...
echo Keep this window open. New WeCom messages should appear here automatically.
echo Do NOT use Once.bat if you want realtime.
echo Local logs: repo\logs\YYYYMMDD_info.log and _error.log
echo Press Ctrl+C to stop.
echo.
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0Watch-Agent8910.ps1" %*
set ERR=%ERRORLEVEL%
echo.
echo Finished. ExitCode=%ERR%
:end
echo.
pause
exit /b %ERR%
-315
View File
@@ -1,315 +0,0 @@
# 只读:拉服务器新系统 8910 的业务/错误日志,并落到本机 logs/(UTF-8 BOM,记事本可直接打开)。
# 用法:双击 Watch-Agent8910.bat / Watch-Agent8910-Once.bat
# 本机:logs/yyyyMMdd_info.log 、 logs/yyyyMMdd_error.log
# 服务器旧日志可能是 GBK、新日志是 UTF-8;远程按「逐行 UTF-8,失败则 GBK」解码,避免乱码。
[CmdletBinding()]
param(
[switch]$Once,
[switch]$All,
[switch]$Access,
[switch]$Gbk,
[switch]$NoLocalLog,
[int]$Tail = 120
)
$ErrorActionPreference = 'Stop'
$SshKey = if ($env:YTD_SSH_KEY) { $env:YTD_SSH_KEY } else { Join-Path $env:USERPROFILE '.ssh\id_ed25519_ytd' }
$SshHost = if ($env:YTD_SSH_HOST) { $env:YTD_SSH_HOST } else { 'ytd_extdev_0903@129.211.181.80' }
$LogOut = 'E:\wwwroot\logs\agent-http.out.log'
$LogErr = 'E:\wwwroot\logs\agent-http.err.log'
# once / follow 用不同远程脚本名,避免互相覆盖导致「持续监听」其实跑成 Once
$WatchTag = if ($Once) { 'once' } else { 'follow' }
$IncomingRemotePath = "C:/Users/ytd_extdev_0903/incoming/_watch_agent8910_$WatchTag.ps1"
$IncomingLocalRun = "C:\Users\ytd_extdev_0903\incoming\_watch_agent8910_$WatchTag.ps1"
$Pattern = '回调|inject-text|inject:|outbox|inbox|errcode|errmsg|60020|ERROR|WARNING|Traceback|Exception|ModuleNotFoundError|sender=|touser=|crypto|ChannelRuntime|dispatch intent|企微发送|验签|解密|reply='
if (-not (Test-Path $SshKey)) {
throw "缺少 SSH 密钥: $SshKey"
}
try {
chcp 65001 | Out-Null
[Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
} catch {
Write-Host 'warn: console UTF-8 setup failed'
}
$RepoRoot = Split-Path -Parent $PSScriptRoot
# 在仓库 deploy/ 下:写到仓库根 logs/;单独解压给同事:写到本工具目录 logs/
if ((Split-Path -Leaf $PSScriptRoot) -eq 'deploy') {
$LocalLogDir = Join-Path $RepoRoot 'logs'
} else {
$LocalLogDir = Join-Path $PSScriptRoot 'logs'
}
$Day = Get-Date -Format 'yyyyMMdd'
$LocalInfoLog = Join-Path $LocalLogDir ($Day + '_info.log')
$LocalErrorLog = Join-Path $LocalLogDir ($Day + '_error.log')
$Utf8NoBom = New-Object System.Text.UTF8Encoding $false
$Utf8Bom = New-Object System.Text.UTF8Encoding $true
function Ensure-Utf8BomFile([string]$path) {
if (-not (Test-Path $path) -or ((Get-Item $path).Length -eq 0)) {
[System.IO.File]::WriteAllText($path, '', $Utf8Bom)
return
}
$fs = [System.IO.File]::OpenRead($path)
try {
$b0 = $fs.ReadByte(); $b1 = $fs.ReadByte(); $b2 = $fs.ReadByte()
} finally { $fs.Close() }
if ($b0 -eq 0xEF -and $b1 -eq 0xBB -and $b2 -eq 0xBF) { return }
$raw = [System.IO.File]::ReadAllBytes($path)
$bom = [byte[]](0xEF, 0xBB, 0xBF)
$merged = New-Object byte[] ($bom.Length + $raw.Length)
[Array]::Copy($bom, 0, $merged, 0, 3)
[Array]::Copy($raw, 0, $merged, 3, $raw.Length)
[System.IO.File]::WriteAllBytes($path, $merged)
}
if (-not $NoLocalLog) {
New-Item -ItemType Directory -Force -Path $LocalLogDir | Out-Null
Ensure-Utf8BomFile $LocalInfoLog
Ensure-Utf8BomFile $LocalErrorLog
$sessionHdr = '===== watch start ' + (Get-Date).ToString('yyyy-MM-dd HH:mm:ss') + ' host=' + $SshHost + ' once=' + $Once.IsPresent + ' ====='
[System.IO.File]::AppendAllText($LocalInfoLog, $sessionHdr + [Environment]::NewLine, $Utf8NoBom)
[System.IO.File]::AppendAllText($LocalErrorLog, $sessionHdr + [Environment]::NewLine, $Utf8NoBom)
}
function Write-LocalLine([string]$line) {
Write-Host $line
if ($NoLocalLog) { return }
if ($line -match '^(目标:|主日志|访问日志|日志编码|过滤:|本机落盘:|说明:|---+|=====)') {
$isErr = $false
} else {
$isErr = ($line -cmatch '\] WARNING |\] ERROR |Traceback|Exception|ModuleNotFoundError') -or
($line -match 'errcode=\d+|errmsg=.+|health_fail|MISSING |解密失败|验签/解密失败|relation "agent_inbox"|not allow to access from your ip')
}
$target = if ($isErr) { $LocalErrorLog } else { $LocalInfoLog }
try {
[System.IO.File]::AppendAllText($target, $line + [Environment]::NewLine, $Utf8NoBom)
} catch {
Write-Host ('warn: write local log failed: ' + $_.Exception.Message)
}
}
Write-LocalLine ("目标: $SshHost")
Write-LocalLine ("主日志(业务/错误): $LogErr")
if ($Access -or $All) { Write-LocalLine ("访问日志: $LogOut") }
Write-LocalLine ("日志编码: smart UTF-8/GBK" + $(if ($Gbk) { ' (force GBK)' } else { '' }))
if ($All) { Write-LocalLine '过滤: 关闭' } else { Write-LocalLine ("过滤: $Pattern") }
if (-not $NoLocalLog) {
Write-LocalLine ("本机落盘: $LocalInfoLog")
Write-LocalLine ("本机落盘: $LocalErrorLog")
}
Write-LocalLine '说明: 本地日志为 UTF-8 BOM;请重新跑 Once 覆盖旧乱码内容(可先删当天 log 再跑)'
Write-LocalLine '---'
# follow=1 / once=0,避免 $true/$false 在远程被覆盖或解析歧义
$waitFlag = if ($Once) { '0' } else { '1' }
$allLiteral = if ($All) { '$true' } else { '$false' }
$accessLiteral = if ($Access) { '$true' } else { '$false' }
$forceGbkLiteral = if ($Gbk) { '$true' } else { '$false' }
# 远程:逐行按 UTF-8 严格解码,失败再用 GBK(936);输出强制 Flush,避免持续监听被缓冲卡住
$remoteScript = @"
`$ErrorActionPreference = 'Continue'
try {
chcp 65001 | Out-Null
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(`$false)
`$OutputEncoding = [System.Text.UTF8Encoding]::new(`$false)
} catch {}
`$out = '$LogOut'
`$err = '$LogErr'
`$tail = $Tail
`$waitFlag = '$waitFlag'
`$wait = (`$waitFlag -eq '1')
`$all = $allLiteral
`$wantAccess = $accessLiteral
`$pat = '$Pattern'
`$forceGbk = $forceGbkLiteral
`$utf8Strict = New-Object System.Text.UTF8Encoding `$false, `$true
`$gbk = [System.Text.Encoding]::GetEncoding(936)
function Emit([string]`$s) {
[Console]::Out.WriteLine(`$s)
[Console]::Out.Flush()
}
function Decode-LogBytes([byte[]]`$chunk) {
if (`$null -eq `$chunk -or `$chunk.Length -eq 0) { return '' }
if (`$forceGbk) { return `$gbk.GetString(`$chunk) }
try { return `$utf8Strict.GetString(`$chunk) } catch { return `$gbk.GetString(`$chunk) }
}
function Get-SmartTailLines([string]`$path, [int]`$n) {
if (-not (Test-Path `$path)) { return @() }
`$fs = [System.IO.File]::Open(`$path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
try {
`$ms = New-Object System.IO.MemoryStream
`$fs.CopyTo(`$ms)
`$bytes = `$ms.ToArray()
} finally {
`$fs.Close()
}
`$lines = New-Object System.Collections.Generic.List[string]
`$start = 0
for (`$i = 0; `$i -lt `$bytes.Length; `$i++) {
if (`$bytes[`$i] -ne 10) { continue }
`$end = `$i
if (`$end -gt `$start -and `$bytes[`$end - 1] -eq 13) { `$end = `$end - 1 }
`$len = `$end - `$start
if (`$len -lt 0) { `$len = 0 }
`$chunk = New-Object byte[] `$len
if (`$len -gt 0) { [Array]::Copy(`$bytes, `$start, `$chunk, 0, `$len) }
`$lines.Add((Decode-LogBytes `$chunk))
`$start = `$i + 1
}
if (`$start -lt `$bytes.Length) {
`$len = `$bytes.Length - `$start
`$chunk = New-Object byte[] `$len
[Array]::Copy(`$bytes, `$start, `$chunk, 0, `$len)
`$lines.Add((Decode-LogBytes `$chunk))
}
if (`$lines.Count -le `$n) { return `$lines.ToArray() }
return `$lines.GetRange(`$lines.Count - `$n, `$n).ToArray()
}
Emit ('mode=' + `$waitFlag + ' follow=' + `$wait)
Emit '=== remote health 8910 ==='
try {
`$h = Invoke-WebRequest -Uri 'http://127.0.0.1:8910/health' -UseBasicParsing -TimeoutSec 5
Emit `$h.Content
} catch {
Emit ('health_fail: ' + `$_.Exception.Message)
}
Emit '=== business/error log (err) ==='
function Show-Err([string]`$line) {
if (`$all) { Emit ('[err] ' + `$line); return }
if (`$line -match `$pat) { Emit ('[err] ' + `$line) }
}
function Show-Out([string]`$line) {
if (-not `$wantAccess -and -not `$all) { return }
if (`$all) { Emit ('[out] ' + `$line); return }
if (`$line -match '/wecom/callback|inject-text') { Emit ('[out] ' + `$line) }
}
if (-not (Test-Path `$err)) { Emit ('MISSING ' + `$err) }
if (-not `$wait) {
if (Test-Path `$err) {
Get-SmartTailLines `$err `$tail | ForEach-Object { Show-Err `$_ }
}
if (`$wantAccess -or `$all) {
Emit '=== access log (out) ==='
if (Test-Path `$out) {
Get-SmartTailLines `$out `$tail | ForEach-Object { Show-Out `$_ }
}
}
exit 0
}
Emit 'following err.log ... (Ctrl+C to stop)'
`$lastLen = @{}
`$carry = @{}
foreach (`$f in @(`$err, `$out)) {
if (Test-Path `$f) { `$lastLen[`$f] = (Get-Item `$f).Length } else { `$lastLen[`$f] = 0 }
`$carry[`$f] = ''
}
if (Test-Path `$err) { Get-SmartTailLines `$err `$tail | ForEach-Object { Show-Err `$_ } }
# 尾部打完后,从当前文件末尾继续跟,避免重复刷旧行
foreach (`$f in @(`$err, `$out)) {
if (Test-Path `$f) { `$lastLen[`$f] = (Get-Item `$f).Length }
}
`$heartbeatAt = [DateTime]::UtcNow
while (`$true) {
Start-Sleep -Milliseconds 500
if (([DateTime]::UtcNow - `$heartbeatAt).TotalSeconds -ge 30) {
Emit ('... still watching ' + (Get-Date).ToString('HH:mm:ss'))
`$heartbeatAt = [DateTime]::UtcNow
}
`$targets = @()
if (Test-Path `$err) { `$targets += `$err }
if ((`$wantAccess -or `$all) -and (Test-Path `$out)) { `$targets += `$out }
foreach (`$f in `$targets) {
if (-not `$lastLen.ContainsKey(`$f)) { `$lastLen[`$f] = 0; `$carry[`$f] = '' }
`$len = (Get-Item `$f).Length
if (`$len -lt `$lastLen[`$f]) { `$lastLen[`$f] = 0; `$carry[`$f] = '' }
if (`$len -le `$lastLen[`$f]) { continue }
`$fs = [System.IO.File]::Open(`$f, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
try {
[void]`$fs.Seek(`$lastLen[`$f], [System.IO.SeekOrigin]::Begin)
`$buf = New-Object byte[] (`$len - `$lastLen[`$f])
`$read = `$fs.Read(`$buf, 0, `$buf.Length)
} finally { `$fs.Close() }
`$lastLen[`$f] = `$len
if (`$read -le 0) { continue }
`$chunk = New-Object byte[] `$read
[Array]::Copy(`$buf, 0, `$chunk, 0, `$read)
`$text = `$carry[`$f] + (Decode-LogBytes `$chunk)
`$parts = `$text -split "`n"
if (-not (`$text.EndsWith("`n") -or `$text.EndsWith("`r"))) {
if (`$parts.Count -ge 1) {
`$carry[`$f] = `$parts[`$parts.Count - 1].TrimEnd("`r")
`$limit = `$parts.Count - 1
} else {
`$carry[`$f] = `$text
`$limit = 0
}
} else {
`$carry[`$f] = ''
`$limit = `$parts.Count
}
for (`$pi = 0; `$pi -lt `$limit; `$pi++) {
`$line = `$parts[`$pi].TrimEnd("`r")
if (-not `$line) { continue }
if (`$f -eq `$out) { Show-Out `$line } else { Show-Err `$line }
}
}
}
"@
$localTemp = Join-Path $env:TEMP 'ytd-watch-agent8910-remote.ps1'
[System.IO.File]::WriteAllText($localTemp, $remoteScript, $Utf8NoBom)
& scp.exe -o BatchMode=yes -o ConnectTimeout=12 -i $SshKey $localTemp "${SshHost}:${IncomingRemotePath}"
if ($LASTEXITCODE -ne 0) { throw "scp failed: $LASTEXITCODE" }
$sshArgs = @(
'-o', 'BatchMode=yes',
'-o', 'ConnectTimeout=12',
'-i', $SshKey,
$SshHost,
"powershell -NoProfile -ExecutionPolicy Bypass -File `"$IncomingLocalRun`""
)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = 'ssh.exe'
$psi.Arguments = ($sshArgs | ForEach-Object {
if ($_ -match '\s') { '"' + $_ + '"' } else { $_ }
}) -join ' '
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$psi.StandardOutputEncoding = [System.Text.Encoding]::UTF8
$psi.StandardErrorEncoding = [System.Text.Encoding]::UTF8
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $psi
[void]$proc.Start()
while (-not $proc.StandardOutput.EndOfStream) {
$line = $proc.StandardOutput.ReadLine()
if ($null -ne $line) { Write-LocalLine $line }
}
$errTail = $proc.StandardError.ReadToEnd()
if ($errTail) {
foreach ($eline in ($errTail -split "`r?`n")) {
if ($eline) { Write-LocalLine $eline }
}
}
$proc.WaitForExit()
exit $proc.ExitCode
-40
View File
@@ -1,40 +0,0 @@
友通达询价智能体 - 8910 日志监听小工具(给同事)
【包内文件】
- Watch-Agent8910.bat 持续实时监听(推荐双击这个)
- Watch-Agent8910-Once.bat 只看最近一段后结束
- Watch-Agent8910.ps1 主脚本(勿单独乱改)
- 使用说明.txt 本文件
【本包不含】
- SSH 私钥(勿通过微信群传播密钥;向负责人单独索取或登记公钥)
【使用前准备】
1. Windows 10/11,自带 OpenSSH(命令行能运行 ssh / scp)
2. 解压到任意目录,例如 D:\tools\YtdWatchAgent8910\
3. 配置密钥(二选一):
A. 把私钥放到:%USERPROFILE%\.ssh\id_ed25519_ytd
B. 或先设置再运行:
set YTD_SSH_KEY=你的私钥完整路径
set YTD_SSH_HOST=ytd_extdev_0903@129.211.181.80
说明:SSH 账号一般仍是 ytd_extdev_0903(服务器共用账号),不是改成同事自己的名字。
【怎么用】
1. 双击 Watch-Agent8910.bat
2. 看到 mode=1 follow=True 和 following err.log ... 表示实时监听已接通
3. 保持窗口开着;企微给「询价小助手」发消息,这里应自动刷出新日志
4. 结束:Ctrl+C,再按任意键关窗口
只要快速看一眼:双击 Watch-Agent8910-Once.bat
【本机日志】
运行后在本工具目录下生成:
logs\日期_info.log
logs\日期_error.log
例如:logs\20260913_info.log
【注意】
- 只读拉服务器日志,不会改 Nginx、不会切流
- 行首 [err] 表示来自服务器 err 日志文件,不等于业务失败;看后面的 INFO/WARNING
- 乱码可试:Watch-Agent8910.bat -Gbk
- 不要把私钥打进这个压缩包
-98
View File
@@ -1,98 +0,0 @@
# 本机:打包 agent/admin,上传 jar,远端重启主账与智能体,并 seed 模板
$ErrorActionPreference = 'Stop'
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
if (-not $here) { $here = (Get-Location).Path }
$Repo = (Resolve-Path (Join-Path $here '..')).Path
$key = Join-Path $env:USERPROFILE '.ssh\id_ed25519_ytd'
$remote = 'ytd_extdev_0903@129.211.181.80'
$incoming = "${remote}:C:/Users/ytd_extdev_0903/incoming"
Write-Host ("here=" + $here)
Write-Host ("Repo=" + $Repo)
if (-not (Test-Path (Join-Path $Repo 'inquiry-agent'))) { throw "bad repo path: $Repo" }
Write-Host '=== package agent ==='
$stage = Join-Path $env:TEMP 'ytd-agent-release-stage'
$zipAgent = Join-Path $Repo 'agent-release.zip'
if (Test-Path $stage) { Remove-Item $stage -Recurse -Force }
New-Item -ItemType Directory -Force -Path (Join-Path $stage 'agent') | Out-Null
robocopy (Join-Path $Repo 'inquiry-agent') (Join-Path $stage 'agent') /E /XD .venv __pycache__ .git /XF *.pyc /NFL /NDL /NJH /NJS /nc /ns /np | Out-Null
if (Test-Path $zipAgent) { Remove-Item $zipAgent -Force }
Compress-Archive -Path (Join-Path $stage 'agent') -DestinationPath $zipAgent -Force
Write-Host ("agent_zip=" + (Get-Item $zipAgent).Length)
$jar = Join-Path $Repo 'inquiry-api\jeecg-module-system\jeecg-system-start\target\jeecg-system-start-3.5.3.jar'
if (-not (Test-Path $jar)) { throw 'jar missing' }
Write-Host ("jar_bytes=" + (Get-Item $jar).Length)
Write-Host '=== build admin ==='
$Src = Join-Path $Repo 'inquiry-backend'
$Build = 'C:\ytd\inquiry-backend'
robocopy $Src $Build /MIR /XD node_modules dist .git .vite .husky /XF *.log /NFL /NDL /NJH /NJS /nc /ns /np | Out-Null
if (Test-Path (Join-Path $Src '.env.production')) {
Copy-Item (Join-Path $Src '.env.production') (Join-Path $Build '.env.production') -Force
}
Copy-Item (Join-Path $Src 'vite.config.ts') (Join-Path $Build 'vite.config.ts') -Force
Push-Location $Build
if (Test-Path dist) { Remove-Item dist -Recurse -Force }
pnpm run build
$code = $LASTEXITCODE
Pop-Location
if ($code -ne 0) { throw "admin build failed $code" }
$zipAdmin = Join-Path $env:TEMP 'admin-dist.zip'
if (Test-Path $zipAdmin) { Remove-Item $zipAdmin -Force }
Compress-Archive -Path "$Build\dist\*" -DestinationPath $zipAdmin -Force
Write-Host ("admin_zip=" + (Get-Item $zipAdmin).Length)
$cfgZip = Join-Path $env:TEMP 'ledger-config.zip'
if (Test-Path $cfgZip) { Remove-Item $cfgZip -Force }
$cfgStage = Join-Path $env:TEMP 'ledger-cfg-stage-qt'
if (Test-Path $cfgStage) { Remove-Item $cfgStage -Recurse -Force }
New-Item -ItemType Directory $cfgStage | Out-Null
Copy-Item (Join-Path $Repo 'deploy\config\application-inquiry.yml') (Join-Path $cfgStage 'application-inquiry.yml') -Force
Compress-Archive -Path "$cfgStage\*" -DestinationPath $cfgZip -Force
# templates zip for seed
$tplZip = Join-Path $env:TEMP 'quote-templates-seed.zip'
if (Test-Path $tplZip) { Remove-Item $tplZip -Force }
$tplStage = Join-Path $env:TEMP 'quote-templates-seed-stage'
if (Test-Path $tplStage) { Remove-Item $tplStage -Recurse -Force }
New-Item -ItemType Directory $tplStage | Out-Null
$tplDir = Get-ChildItem -Path $Repo -Directory | Where-Object { $_.Name -like '*报价*' -and $_.Name -like '*模板*' } | Select-Object -First 1
if (-not $tplDir) { throw 'template folder not found under repo' }
robocopy $tplDir.FullName (Join-Path $tplStage 'templates') /E /XF ~$* /NFL /NDL /NJH /NJS /nc /ns /np | Out-Null
Write-Host ("templates_from=" + $tplDir.FullName)
Copy-Item (Join-Path $Repo 'deploy\seed\quote_templates_seed_manifest_v1.json') (Join-Path $tplStage 'manifest.json') -Force
Compress-Archive -Path "$tplStage\*" -DestinationPath $tplZip -Force
Write-Host '=== upload ==='
scp -o BatchMode=yes -i $key `
$zipAgent `
$zipAdmin `
$jar `
$cfgZip `
$tplZip `
(Join-Path $Repo 'deploy\_remote_wmi_start_ledger.ps1') `
(Join-Path $Repo 'deploy\_remote_safe_deploy_agent.ps1') `
(Join-Path $Repo 'deploy\_remote_cutover_admin_8180.ps1') `
(Join-Path $Repo 'deploy\_remote_seed_quote_templates.ps1') `
$incoming
if ($LASTEXITCODE -ne 0) { throw 'scp failed' }
Write-Host 'UPLOAD_OK'
Write-Host '=== deploy ledger ==='
ssh -o BatchMode=yes -i $key $remote "powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1"
if ($LASTEXITCODE -ne 0) { throw 'ledger deploy failed' }
Write-Host '=== deploy agent ==='
ssh -o BatchMode=yes -i $key $remote "powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_safe_deploy_agent.ps1"
if ($LASTEXITCODE -ne 0) { throw 'agent deploy failed' }
Write-Host '=== deploy admin ==='
ssh -o BatchMode=yes -i $key $remote "powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_cutover_admin_8180.ps1"
if ($LASTEXITCODE -ne 0) { throw 'admin deploy failed' }
Write-Host '=== wait ledger ==='
Start-Sleep -Seconds 25
ssh -o BatchMode=yes -i $key $remote "powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_seed_quote_templates.ps1"
if ($LASTEXITCODE -ne 0) { throw 'seed failed' }
Write-Host 'QUOTE_TEMPLATE_DEPLOY_DONE'
-28
View File
@@ -1,28 +0,0 @@
$ErrorActionPreference = 'Continue'
Write-Host "hostname=$(hostname)"
Write-Host "whoami=$(whoami)"
Write-Host "pwd=$pwd"
@(
'E:\wwwroot',
'C:\yutongda',
'D:\own',
'C:\tools\apache-maven-3.9.16'
) | ForEach-Object { Write-Host "path $_ = $(Test-Path $_)" }
function Probe($h,$p) {
$t = New-Object System.Net.Sockets.TcpClient
try {
$ok = $t.ConnectAsync($h,[int]$p).Wait(2000)
Write-Host "tcp ${h}:${p} = $($t.Connected)"
} catch {
Write-Host "tcp ${h}:${p} = fail"
} finally { try { $t.Close() } catch {} }
}
Probe '127.0.0.1' 3306
Probe '10.206.0.14' 3306
Probe '10.206.0.15' 3306
Probe '10.206.0.14' 6379
Probe '127.0.0.1' 8180
Write-Host '---listeners---'
netstat -ano | findstr 'LISTENING' | findstr ':8180 :3100 :8080 :3306 :6379'
-19
View File
@@ -1,19 +0,0 @@
$ErrorActionPreference = 'Stop'
$path = 'C:\yutongda\secure\application-database-credentials.json'
if (-not (Test-Path -LiteralPath $path)) { throw 'Application database credential file missing' }
$acl = New-Object System.Security.AccessControl.FileSecurity
$acl.SetAccessRuleProtection($true, $false)
foreach ($identity in @('BUILTIN\Administrators', 'NT AUTHORITY\SYSTEM')) {
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($identity, 'FullControl', 'Allow')
$acl.AddAccessRule($rule)
}
Set-Acl -LiteralPath $path -AclObject $acl
$json = Get-Content -Raw -LiteralPath $path | ConvertFrom-Json
[ordered]@{
status = 'PASS'
path = $path
sha256 = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash
keys = @($json.PSObject.Properties.Name)
contains_admin_credentials = ($json.PSObject.Properties.Name -contains 'mysql_root' -or $json.PSObject.Properties.Name -contains 'postgres_admin')
secrets_in_output = $false
} | ConvertTo-Json -Compress
-44
View File
@@ -1,44 +0,0 @@
# 发布后验收:端口、健康、现网未误停
$ErrorActionPreference = 'Continue'
Write-Output '=== ports ==='
foreach ($x in 8080, 8810, 8813, 8180, 8910, 8913) {
$c = Get-NetTCPConnection -LocalPort $x -State Listen -EA SilentlyContinue | Select-Object -First 1
if ($c) { Write-Output "$x LISTEN pid=$($c.OwningProcess)" } else { Write-Output "$x down" }
}
Write-Output '=== health ==='
foreach ($u in @(
'http://127.0.0.1:8910/health',
'http://127.0.0.1:8180/jeecgboot/',
'http://127.0.0.1:8180/jeecgboot/sys/randomImage/deploycheck',
'http://127.0.0.1:8080/jeecg-boot/'
)) {
try {
$r = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 8
Write-Output ("OK " + $r.StatusCode + " " + $u)
} catch {
$code = $null
try { $code = $_.Exception.Response.StatusCode.value__ } catch {}
Write-Output ("FAIL " + $u + " code=" + $code)
}
}
Write-Output '=== worker ==='
$found = $false
Get-CimInstance Win32_Process | ForEach-Object {
if ($_.CommandLine -and $_.CommandLine -like '*worker_app*' -and $_.CommandLine -like '*wwwroot*agent*') {
Write-Output ("worker pid=" + $_.ProcessId)
$found = $true
}
}
if (-not $found) { Write-Output 'worker NOT found' }
Write-Output '=== pointer ==='
Get-Content 'E:\wwwroot\ops\active-release.json' -Raw
Write-Output '=== yutongda pointer untouched ==='
if (Test-Path 'C:\yutongda\ops\active-release.json') {
Write-Output 'C:\yutongda\ops\active-release.json still exists (not deleted)'
}
Write-Output 'ACCEPT_DONE'
-34
View File
@@ -1,34 +0,0 @@
# 远端:给 inquiry_robot.inq_ticket 补 quote_date。禁止动 jeecg-boot。
# 口令只从 E:\wwwroot\.env 读,不写进仓库、不回显。
$ErrorActionPreference = 'Stop'
Get-Content 'E:\wwwroot\.env' | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith('#')) { return }
$i = $line.IndexOf('=')
if ($i -lt 1) { return }
$k = $line.Substring(0, $i).Trim()
$v = $line.Substring($i + 1).Trim().Trim('"')
Set-Item -Path "Env:$k" -Value $v
}
if (-not $env:MYSQL_DB) { throw 'MYSQL_DB missing' }
if ($env:MYSQL_DB -ne 'inquiry_robot') { throw ("refuse db=" + $env:MYSQL_DB) }
$mysql = 'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe'
if (-not (Test-Path $mysql)) { throw "missing $mysql" }
$hostName = if ($env:MYSQL_HOST) { $env:MYSQL_HOST } else { '10.206.0.14' }
$tcp = New-Object System.Net.Sockets.TcpClient
try {
$null = $tcp.ConnectAsync('127.0.0.1', 3306).Wait(1000)
if ($tcp.Connected) { $hostName = '127.0.0.1' }
} catch {
} finally {
$tcp.Close()
}
Write-Host "alter host=$hostName db=$env:MYSQL_DB"
$sqlFile = 'C:\Users\ytd_extdev_0903\incoming\inquiry_ticket_quote_date_v1.sql'
if (-not (Test-Path $sqlFile)) { throw "missing $sqlFile" }
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" --default-character-set=utf8mb4 $env:MYSQL_DB -e "source $($sqlFile.Replace('\','/'))"
if ($LASTEXITCODE -ne 0) { throw "fail sql code=$LASTEXITCODE" }
Write-Host 'SQL_OK'
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" --default-character-set=utf8mb4 $env:MYSQL_DB -e "SHOW COLUMNS FROM inq_ticket LIKE 'quote_date'\G"
if ($LASTEXITCODE -ne 0) { throw "fail verify code=$LASTEXITCODE" }
Write-Host 'VERIFY_DONE'
-11
View File
@@ -1,11 +0,0 @@
Write-Output "=== now listen ==="
netstat -ano | findstr ":8910"
Write-Output "=== curl ==="
cmd /c "curl.exe -s http://127.0.0.1:8910/health"
Write-Output ""
Write-Output "=== err log tail ==="
Get-Content "C:\ytd-test\logs\agent-http.err.log" -Tail 40 -ErrorAction SilentlyContinue
Write-Output "=== out log tail ==="
Get-Content "C:\ytd-test\logs\agent-http.out.log" -Tail 20 -ErrorAction SilentlyContinue
Write-Output "=== python procs ==="
Get-CimInstance Win32_Process -Filter "Name='python.exe'" | Select-Object ProcessId, CommandLine | Format-List
-13
View File
@@ -1,13 +0,0 @@
# 检查 config overlay 是否含 redis username,以及最近失败原因
$ErrorActionPreference = 'Continue'
$cfg = 'E:\wwwroot\inquiry-new\config\application-inquiry.yml'
Write-Output '=== config exists ==='
Test-Path $cfg
if (Test-Path $cfg) {
Get-Content $cfg | Select-Object -First 25
}
Write-Output '=== log markers ==='
Select-String -Path 'E:\wwwroot\inquiry-new\logs\stdout.log' -Pattern 'WRONGPASS|redisContainer|Started Jeecg|Application run failed' |
Select-Object -Last 12 |
ForEach-Object { $_.Line.Substring(0, [Math]::Min(220, $_.Line.Length)) }
Write-Output 'CFG_CHECK_DONE'
-13
View File
@@ -1,13 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== admin-secrets.env? ==="
Test-Path "E:\wwwroot\ops\admin-secrets.env"
if (Test-Path "E:\wwwroot\ops\admin-secrets.env") {
Get-Content "E:\wwwroot\ops\admin-secrets.env" | ForEach-Object {
if ($_ -match '^([^=]+)=') { $matches[1] }
}
}
Write-Output "=== sql files ==="
Get-ChildItem "E:\wwwroot\ops\sql" | Select-Object Name, Length
Write-Output "=== secrets json exists ==="
Test-Path "E:\wwwroot\ops\inquiry_robot_db_secrets.json"
Write-Output "DONE"
-10
View File
@@ -1,10 +0,0 @@
Write-Output "=== listen 8910 ==="
netstat -ano | findstr ":8910"
Write-Output "=== local health ==="
cmd /c "curl.exe -s http://127.0.0.1:8910/health"
Write-Output ""
Write-Output "=== agent logs ==="
Get-Content "C:\ytd-test\logs\agent-http.err.log" -Tail 30 -ErrorAction SilentlyContinue
Get-Content "C:\ytd-test\logs\agent-http.out.log" -Tail 30 -ErrorAction SilentlyContinue
Write-Output "=== pointer ==="
Get-Content "C:\ytd-test\ops\active-release.json" -Raw -ErrorAction SilentlyContinue
-18
View File
@@ -1,18 +0,0 @@
$ErrorActionPreference='Stop'
$Fat='E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
$work=Join-Path $env:TEMP 'chk-captcha-class'
if(Test-Path $work){Remove-Item $work -Recurse -Force}
New-Item -ItemType Directory $work|Out-Null
$jarCmd=$null
foreach($c in @('C:\yutongda\tools\jdk8\bin\jar.exe','E:\wwwroot\tools\jdk-17\bin\jar.exe')){ if(Test-Path $c){ $jarCmd=$c; break } }
Push-Location $work
& $jarCmd xf $Fat 'BOOT-INF/lib/jeecg-system-biz-3.5.3.jar'
& $jarCmd xf 'BOOT-INF/lib/jeecg-system-biz-3.5.3.jar' 'org/jeecg/modules/system/controller/LoginController.class'
$classPath = Join-Path $work 'org\jeecg\modules\system\controller\LoginController.class'
if (-not (Test-Path $classPath)) { throw ("class missing under " + $work) }
$bytes=[IO.File]::ReadAllBytes($classPath)
$ascii=[Text.Encoding]::ASCII.GetString($bytes)
$has= $ascii.Contains('loginCaptchaEnabled')
Write-Host ("has_loginCaptchaEnabled=" + $has)
Write-Host ("class_bytes=" + $bytes.Length)
Pop-Location
-2
View File
@@ -1,2 +0,0 @@
$p='C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.CAPTCHA.jar'
if(Test-Path $p){ $i=Get-Item $p; "CAPTCHA length=$($i.Length) time=$($i.LastWriteTime)" } else { 'CAPTCHA missing' }
-40
View File
@@ -1,40 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== env resource lines (no secrets) ==="
$envFile = "E:\wwwroot\.env"
if (Test-Path $envFile) {
Select-String -Path $envFile -Pattern '^(MYSQL_HOST|MYSQL_PORT|MYSQL_DB|MYSQL_USER|PG_HOST|PG_PORT|PG_DATABASE|PG_USER|REDIS_URL|REDIS_KEY_PREFIX|YTD_REDIS_HOST|YTD_REDIS_PORT|OBJECT_STORAGE_)=' |
ForEach-Object {
$line = $_.Line
if ($line -match 'PASSWORD|SECRET|ACCESS_KEY|REDIS_URL=') {
if ($line -match '^REDIS_URL=') {
# mask password in redis url
$line -replace '://([^:]+):([^@]+)@', '://$1:***@'
} elseif ($line -match '=') {
($line -split '=',2)[0] + '=***'
} else { $line }
} else { $line }
}
} else { "missing .env" }
Write-Output "=== password filled? (bool only) ==="
function HasVal([string]$key) {
$m = Select-String -Path $envFile -Pattern ("^" + [regex]::Escape($key) + "=(.+)$") | Select-Object -First 1
if (-not $m) { return "$key=MISSING" }
$v = ($m.Line -split '=',2)[1]
if ([string]::IsNullOrWhiteSpace($v) -or $v -match '^<.*>$') { return "$key=EMPTY" }
return "$key=SET"
}
HasVal "MYSQL_PASSWORD"
HasVal "PG_PASSWORD"
HasVal "OBJECT_STORAGE_ACCESS_KEY"
HasVal "OBJECT_STORAGE_SECRET_KEY"
HasVal "REDIS_URL"
Write-Output "=== local tools that can probe ==="
@(
'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe',
'C:\yutongda\tools\pgsql\bin\psql.exe',
'C:\yutongda\tools\redis-5.0.14.1\redis-cli.exe'
) | ForEach-Object { "$_ exists=$(Test-Path $_)" }
Write-Output "DONE"
-9
View File
@@ -1,9 +0,0 @@
$ErrorActionPreference = 'Continue'
$hits = Select-String -Path 'E:\wwwroot\admin\current\assets\*.js' -Pattern '数据进入主账' -SimpleMatch -ErrorAction SilentlyContinue
if ($hits) {
Write-Output 'HINT_STILL_PRESENT'
$hits | Select-Object -First 3 | ForEach-Object { $_.Filename }
} else {
Write-Output 'HINT_GONE'
}
Write-Output 'CHECK_DONE'
-11
View File
@@ -1,11 +0,0 @@
$ErrorActionPreference="Stop"
$work=Join-Path $env:TEMP "chk-inquiry-class"
if(Test-Path $work){Remove-Item $work -Recurse -Force}
New-Item -ItemType Directory $work|Out-Null
$jarCmd="C:\yutongda\tools\jdk8\bin\jar.exe"
$Fat="E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar"
Push-Location $work
& $jarCmd xf $Fat "BOOT-INF/lib/jeecg-module-inquiry-3.5.3.jar"
& $jarCmd tf "BOOT-INF/lib/jeecg-module-inquiry-3.5.3.jar" | findstr /i "QuoteTemplate Controller"
Write-Host "CLASS_CHECK_DONE"
Pop-Location
-12
View File
@@ -1,12 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== docker/winget ==="
Get-Command docker, winget, choco -ErrorAction SilentlyContinue | Select-Object Name
docker version 2>&1 | Select-Object -First 5
Write-Output "=== local listen 3306/5432 ==="
foreach ($p in 3306,5432,13306,15432) {
$c = Get-NetTCPConnection -LocalPort $p -State Listen -EA SilentlyContinue | Select-Object -First 1
if ($c) { "$p local-LISTEN" } else { "$p local-free" }
}
Write-Output "=== E free ==="
Get-PSDrive E | Format-Table @{n='FreeGB';e={[math]::Round($_.Free/1GB,1)}}
Write-Output "DONE"
-3
View File
@@ -1,3 +0,0 @@
$p='C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.NEW.jar'
if(Test-Path $p){ $i=Get-Item $p; "exists length=$($i.Length) time=$($i.LastWriteTime)" } else { 'missing NEW jar' }
Get-Process java -EA SilentlyContinue | Select-Object Id | Measure-Object | ForEach-Object { "java_count=$($_.Count)" }
-50
View File
@@ -1,50 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Host "=== run-ledger-inner redis bits ==="
Get-Content "E:\wwwroot\ops\run-ledger-inner.ps1" | Select-Object -First 55 | ForEach-Object { Write-Host $_ }
$env:YTD_REDIS_PASSWORD = $null
Get-Content "E:\wwwroot\.env" | ForEach-Object {
$t = $_.Trim()
if (-not $t -or $t.StartsWith("#")) { return }
$i = $t.IndexOf("=")
if ($i -lt 1) { return }
Set-Item -Path ("Env:" + $t.Substring(0,$i).Trim()) -Value $t.Substring($i+1).Trim().Trim("`"")
}
$ulen = 0; if ($env:YTD_REDIS_USERNAME) { $ulen = $env:YTD_REDIS_USERNAME.Length }
$plen = 0; if ($env:YTD_REDIS_PASSWORD) { $plen = $env:YTD_REDIS_PASSWORD.Length }
$ulen2 = 0; $rlen = 0; if ($env:REDIS_URL) { $rlen = $env:REDIS_URL.Length }
Write-Host ("before_parse user_len=$ulen pw_len=$plen url_len=$rlen")
if (-not $env:YTD_REDIS_PASSWORD -and $env:REDIS_URL) {
if ($env:REDIS_URL -match "redis://:([^@]+)@") {
$env:YTD_REDIS_PASSWORD = $Matches[1]
Write-Host "matched_form_password_only"
} elseif ($env:REDIS_URL -match "redis://([^:/@]+):([^@]+)@") {
if (-not $env:YTD_REDIS_USERNAME) { $env:YTD_REDIS_USERNAME = $Matches[1] }
$env:YTD_REDIS_PASSWORD = $Matches[2]
Write-Host "matched_form_user_pass"
} elseif ($env:REDIS_URL -match "redis://[^:]+:([^@]+)@") {
$env:YTD_REDIS_PASSWORD = $Matches[1]
Write-Host "matched_form_legacy"
} else {
Write-Host "NO_REGEX_MATCH"
}
}
$ulen = 0; if ($env:YTD_REDIS_USERNAME) { $ulen = $env:YTD_REDIS_USERNAME.Length }
$plen = 0; if ($env:YTD_REDIS_PASSWORD) { $plen = $env:YTD_REDIS_PASSWORD.Length }
Write-Host ("after_parse user_len=$ulen pw_len=$plen")
if ($env:REDIS_URL) {
$u = $env:REDIS_URL
$at = ([regex]::Matches($u,"@")).Count
$auth = $u.Substring(8).Split("@")[0]
$parts = $auth.Split(":").Count
Write-Host ("url_probe at_count=$at auth_colon_parts=$parts")
}
$login = Invoke-RestMethod -Uri "http://127.0.0.1:8180/jeecgboot/sys/login" -Method POST -Body "{\"username\":\"admin\",\"password\":\"123456\",\"captcha\":\"\",\"checkKey\":\"\"}" -ContentType "application/json;charset=UTF-8"
$h = @{ "X-Access-Token" = $login.result.token }
$r = Invoke-WebRequest -Uri "http://127.0.0.1:8180/jeecgboot/inquiry/quoteTemplate/list?pageNo=1&pageSize=5" -Headers $h -UseBasicParsing
Write-Host "=== list ==="
$n = [Math]::Min(600, $r.Content.Length)
Write-Host $r.Content.Substring(0, $n)
Write-Host "PARSE_CHECK_DONE"
-98
View File
@@ -1,98 +0,0 @@
# 只读排查:同事公钥是否在 authorized_keys、本机防火墙/SSH 相关线索
# 不改任何配置,不输出私钥。
$ErrorActionPreference = 'Continue'
Write-Output '=== host ==='
whoami
hostname
$ak = Join-Path $env:USERPROFILE '.ssh\authorized_keys'
Write-Output "=== authorized_keys: $ak ==="
if (-not (Test-Path $ak)) {
Write-Output 'NO_AUTHORIZED_KEYS_FILE'
exit 0
}
$lines = Get-Content $ak | Where-Object { $_ -and $_.Trim() -notmatch '^#' }
Write-Output ("key_lines=" + $lines.Count)
$needle = 'IFBmb3YG1ZOJ3kaj8z3H55GXmv+hPIbYgN298VKorgFv'
$commentNeedle = 'ytd-external-developer'
$hit = $false
foreach ($line in $lines) {
if ($line -like "*$needle*") {
Write-Output 'PUBKEY_FOUND=yes'
Write-Output ("PUBKEY_LINE_PREFIX=" + $line.Substring(0, [Math]::Min(60, $line.Length)))
$hit = $true
}
if ($line -like "*$commentNeedle*") {
Write-Output 'COMMENT_FOUND=yes'
}
}
if (-not $hit) {
Write-Output 'PUBKEY_FOUND=no'
Write-Output 'PUBKEY_NOT_IN_AUTHORIZED_KEYS'
}
Write-Output '=== key comments (safe) ==='
foreach ($line in $lines) {
if ($line -match '^ssh-\S+\s+\S+\s+(.+)$') {
Write-Output ("comment=" + $Matches[1])
} elseif ($line -match '^ssh-\S+\s+\S+$') {
Write-Output 'comment=(none)'
} else {
Write-Output 'line=(unparsed-or-options)'
}
}
Write-Output '=== OpenSSH firewall rules (OpenSSH/22) ==='
try {
Get-NetFirewallRule -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match 'OpenSSH|SSH' -or $_.Name -match 'OpenSSH|SSH' } |
Select-Object -First 20 DisplayName, Enabled, Direction, Action, Profile |
Format-Table -AutoSize | Out-String | Write-Output
} catch {
Write-Output ("firewall_query_err=" + $_.Exception.Message)
}
Write-Output '=== firewall rules mentioning 38.175.103.103 ==='
try {
$addrRules = Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue |
Where-Object { $_.RemoteAddress -match '38\.175\.103\.103' -or ($_.RemoteAddress -is [array] -and ($_.RemoteAddress -contains '38.175.103.103')) }
if ($addrRules) {
foreach ($af in $addrRules) {
$rule = Get-NetFirewallRule -AssociatedNetFirewallAddressFilter $af -ErrorAction SilentlyContinue
if ($rule) {
Write-Output ("rule=" + $rule.DisplayName + "; enabled=" + $rule.Enabled + "; action=" + $rule.Action + "; dir=" + $rule.Direction + "; remote=" + ($af.RemoteAddress -join ','))
}
}
} else {
Write-Output 'NO_FIREWALL_RULE_WITH_THAT_IP'
}
} catch {
Write-Output ("addr_filter_err=" + $_.Exception.Message)
}
Write-Output '=== inbound allow rules on local port 22 (if any) ==='
try {
Get-NetFirewallPortFilter -Protocol TCP -ErrorAction SilentlyContinue |
Where-Object { $_.LocalPort -eq 22 -or $_.LocalPort -eq '22' } |
ForEach-Object {
$rule = Get-NetFirewallRule -AssociatedNetFirewallPortFilter $_ -ErrorAction SilentlyContinue
if ($rule) {
$af = Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $rule -ErrorAction SilentlyContinue
Write-Output ("rule=" + $rule.DisplayName + "; enabled=" + $rule.Enabled + "; action=" + $rule.Action + "; remote=" + (($af.RemoteAddress) -join ','))
}
}
} catch {
Write-Output ("port22_err=" + $_.Exception.Message)
}
Write-Output '=== sshd service ==='
try {
Get-Service sshd -ErrorAction SilentlyContinue | Format-List Name, Status, StartType | Out-String | Write-Output
} catch {
Write-Output ("sshd_err=" + $_.Exception.Message)
}
Write-Output 'DONE'
@@ -1,42 +0,0 @@
# Classify tables in inquiry_robot: core vs demo. No secrets.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"; $user = "inquiry_robot"; $pass = $null; $db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
$out = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1
$tables = $out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
Write-Output ("total=" + $tables.Count)
$demo = @()
$coreSys = @()
$online = @()
$quartz = @()
$jimu = @()
$other = @()
foreach ($t in $tables) {
if ($t -match '^(ceshi_|demo_|test_|jeecg_demo|sys_gateway_route)') { $demo += $t }
elseif ($t -match '^(onl_|online_)') { $online += $t }
elseif ($t -match '^(QRTZ_|qrtz_)') { $quartz += $t }
elseif ($t -match '^(jimu_|jmreport)') { $jimu += $t }
elseif ($t -match '^(sys_|design_|oss_|rep_)') { $coreSys += $t }
else { $other += $t }
}
Write-Output ("core_sys=" + $coreSys.Count)
Write-Output ("online=" + $online.Count)
Write-Output ("quartz=" + $quartz.Count)
Write-Output ("jimu=" + $jimu.Count)
Write-Output ("demoish=" + $demo.Count)
Write-Output ("other=" + $other.Count)
Write-Output "=== demoish ==="
$demo | ForEach-Object { $_ }
Write-Output "=== other ==="
$other | ForEach-Object { $_ }
Write-Output "DONE"
-77
View File
@@ -1,77 +0,0 @@
# After redeploy: remove all releases except current junction targets
$ErrorActionPreference = 'Continue'
$Root = 'E:\wwwroot'
function Resolve-Link([string]$p) {
if (-not (Test-Path $p)) { return $null }
$i = Get-Item $p -Force
if ($i.Target -and $i.Target.Count -gt 0) { return [string]$i.Target[0] }
return $null
}
$keepAgent = Resolve-Link (Join-Path $Root 'agent\current')
$keepAdmin = Resolve-Link (Join-Path $Root 'admin\current')
Write-Output ('keepAgent=' + $keepAgent)
Write-Output ('keepAdmin=' + $keepAdmin)
function Try-Remove([string]$path) {
try {
Remove-Item $path -Recurse -Force -ErrorAction Stop
Write-Output ('REMOVED ' + $path)
return $true
} catch {
Write-Output ('LOCK ' + $path + ' :: ' + $_.Exception.Message)
return $false
}
}
# Stop python/java only if commandline clearly points at OLD release paths we will delete
$keepAgentRoot = $null
if ($keepAgent) {
# .../releases/<id>/agent -> releases/<id>
$keepAgentRoot = Split-Path $keepAgent -Parent
}
Get-CimInstance Win32_Process | ForEach-Object {
$cl = $_.CommandLine
if (-not $cl) { return }
if ($cl -like '*\agent\releases\*' -and $keepAgentRoot -and $cl -notlike ('*' + $keepAgentRoot + '*')) {
if ($cl -like '*python*' -or $cl -like '*http_app*' -or $cl -like '*worker_app*') {
Write-Output ('stop stale pid=' + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
}
Start-Sleep -Seconds 2
if (Test-Path (Join-Path $Root 'agent\releases')) {
Get-ChildItem (Join-Path $Root 'agent\releases') | Where-Object { $_.PSIsContainer } | ForEach-Object {
$rel = $_.FullName
$agentHomePath = Join-Path $rel 'agent'
if ($keepAgent -and ($keepAgent -eq $agentHomePath -or $keepAgent.StartsWith($rel + '\'))) {
Write-Output ('KEEP ' + $rel)
} else {
Try-Remove $rel | Out-Null
}
}
}
if (Test-Path (Join-Path $Root 'admin\releases')) {
Get-ChildItem (Join-Path $Root 'admin\releases') | Where-Object { $_.PSIsContainer } | ForEach-Object {
$rel = $_.FullName
$dist = Join-Path $rel 'dist'
if ($keepAdmin -and ($keepAdmin -eq $dist -or $keepAdmin.StartsWith($rel + '\'))) {
Write-Output ('KEEP ' + $rel)
} else {
Try-Remove $rel | Out-Null
}
}
}
# trim env bak keep 2 newest
Get-ChildItem $Root -Filter '.env.bak*' -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending |
Select-Object -Skip 2 |
ForEach-Object { Try-Remove $_.FullName | Out-Null }
Write-Output 'CLEANUP_AFTER_OK'
-119
View File
@@ -1,119 +0,0 @@
# Cleanup old releases under E:\wwwroot; keep current targets only
$ErrorActionPreference = 'Stop'
$Root = 'E:\wwwroot'
function Get-JunctionTarget([string]$link) {
if (-not (Test-Path $link)) { return $null }
$item = Get-Item $link -Force
if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) {
cmd /c ("dir /AL `"$link`"") | Out-Null
# Resolve via Get-Item Target if available
try {
if ($item.Target -and $item.Target.Count -gt 0) { return [string]$item.Target[0] }
} catch {}
}
# Fallback: read active-release.json
return $null
}
$ptrPath = Join-Path $Root 'ops\active-release.json'
$keepAgent = $null
$keepAdmin = $null
if (Test-Path $ptrPath) {
$ptr = Get-Content $ptrPath -Raw | ConvertFrom-Json
if ($ptr.agentHome) { $keepAgent = [string]$ptr.agentHome }
if ($ptr.adminRelease) { $keepAdmin = [string]$ptr.adminRelease }
}
$agentCurrent = Join-Path $Root 'agent\current'
$adminCurrent = Join-Path $Root 'admin\current'
$t1 = Get-JunctionTarget $agentCurrent
$t2 = Get-JunctionTarget $adminCurrent
if ($t1) { $keepAgent = $t1 }
if ($t2) { $keepAdmin = $t2 }
# Resolve junction via fsutil / dir listing
function Resolve-Link([string]$p) {
if (-not (Test-Path $p)) { return $null }
$out = cmd /c ("fsutil reparsepoint query `"$p`"") 2>$null
# Alternative: (Get-Item).Target
$i = Get-Item $p -Force
if ($i.LinkType -eq 'Junction' -or ($i.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
if ($i.Target) { return ([string]$i.Target[0]) }
}
return $null
}
$ka = Resolve-Link $agentCurrent
$kb = Resolve-Link $adminCurrent
if ($ka) { $keepAgent = $ka }
if ($kb) { $keepAdmin = $kb }
Write-Output ('keepAgent=' + $keepAgent)
Write-Output ('keepAdmin=' + $keepAdmin)
$removed = @()
# agent releases: E:\wwwroot\agent\releases\<id>\agent or <id>
$agentRelRoot = Join-Path $Root 'agent\releases'
if (Test-Path $agentRelRoot) {
Get-ChildItem $agentRelRoot -ErrorAction SilentlyContinue | Where-Object { $_.PSIsContainer } | ForEach-Object {
$rel = $_.FullName
$agentHome = Join-Path $rel 'agent'
$isKeep = $false
if ($keepAgent) {
if ($keepAgent -eq $agentHome -or $keepAgent -eq $rel -or $keepAgent.StartsWith($rel + '\')) { $isKeep = $true }
}
if (-not $isKeep) {
Write-Output ('REMOVE agent ' + $rel)
Remove-Item $rel -Recurse -Force
$removed += $rel
} else {
Write-Output ('KEEP agent ' + $rel)
}
}
}
$adminRelRoot = Join-Path $Root 'admin\releases'
if (Test-Path $adminRelRoot) {
Get-ChildItem $adminRelRoot -ErrorAction SilentlyContinue | Where-Object { $_.PSIsContainer } | ForEach-Object {
$rel = $_.FullName
$dist = Join-Path $rel 'dist'
$isKeep = $false
if ($keepAdmin) {
if ($keepAdmin -eq $dist -or $keepAdmin -eq $rel -or $keepAdmin.StartsWith($rel + '\')) { $isKeep = $true }
}
if (-not $isKeep) {
Write-Output ('REMOVE admin ' + $rel)
Remove-Item $rel -Recurse -Force
$removed += $rel
} else {
Write-Output ('KEEP admin ' + $rel)
}
}
}
# old env backups older than keep recent 2
Get-ChildItem $Root -Filter '.env.bak*' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -Skip 2 | ForEach-Object {
Write-Output ('REMOVE bak ' + $_.Name)
Remove-Item $_.FullName -Force
$removed += $_.FullName
}
# incoming zips older
$incoming = 'C:\Users\ytd_extdev_0903\incoming'
if (Test-Path $incoming) {
Get-ChildItem $incoming -Include '*.zip','jeecg-system-start*.jar' -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
ForEach-Object {
Write-Output ('REMOVE incoming ' + $_.Name)
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
}
}
Write-Output ('removed_count=' + $removed.Count)
Write-Output 'CLEANUP_OK'
# ports sanity: must not touch yutongda
foreach ($x in 8080,8180,8910) {
$c = Get-NetTCPConnection -LocalPort $x -State Listen -EA SilentlyContinue | Select-Object -First 1
if ($c) { Write-Output ("port $x LISTEN") } else { Write-Output ("port $x down") }
}
-177
View File
@@ -1,177 +0,0 @@
# 清空 inquiry_robot:询价工单及相关、员工岗位;账号仅保留 admin。
# 只动业务/账号数据,不动角色菜单、报价模板、机器人回复语。
# 禁止对现网 jeecg-boot 执行。
$ErrorActionPreference = "Stop"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
if (-not (Test-Path $mysql)) {
$alt = Get-ChildItem "C:\yutongda\tools" -Recurse -Filter "mysql.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
if ($alt) { $mysql = $alt.FullName }
}
if (-not (Test-Path $mysql)) { throw "mysql.exe not found" }
$envFile = "E:\wwwroot\.env"
if (-not (Test-Path $envFile)) { throw "missing $envFile" }
$hostn = "10.206.0.14"
$user = "inquiry_robot"
$pass = $null
$db = "inquiry_robot"
$port = "3306"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PORT=(.+)$') { $port = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
if (-not $pass) { throw "MYSQL_PASSWORD missing in .env" }
if ($db -ne "inquiry_robot") { throw "refuse: MYSQL_DB=$db (must be inquiry_robot)" }
Write-Output ("target=" + $hostn + ":" + $port + "/" + $db + " user=" + $user)
# 先看清除前计数(表不存在则跳过)
$beforeSql = @"
SELECT 'BEFORE' AS phase;
SELECT 'inq_ticket' AS t, COUNT(*) AS c FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_ticket'
AND (SELECT COUNT(*) FROM inq_ticket) IS NOT NULL;
"@
function Invoke-Mysql([string]$sql) {
$out = & $mysql -h $hostn -P $port -u $user "-p$pass" --default-character-set=utf8mb4 --batch --raw $db -e $sql 2>&1
$out | ForEach-Object {
$s = "$_"
if ($s -match "Warning|Using a password") { return }
$s
}
if ($LASTEXITCODE -ne 0) {
throw ("mysql failed exit=" + $LASTEXITCODE + " sql_head=" + $sql.Substring(0, [Math]::Min(80, $sql.Length)))
}
}
# 动态:仅对已存在的表做 TRUNCATE / DELETE
$clearSql = @"
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS=0;
-- ---------- 工单及附属 ----------
DELETE FROM inq_exception_case WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_exception_case');
DELETE FROM inq_attachment WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_attachment');
DELETE FROM inq_quote WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_quote');
DELETE FROM inq_ticket_status_log WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_ticket_status_log');
DELETE FROM inq_ticket_segment WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_ticket_segment');
DELETE FROM inq_ticket WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_ticket');
DELETE FROM inq_dashboard_snapshot WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_dashboard_snapshot');
-- ---------- 员工岗位 ----------
DELETE FROM inq_staff_role WHERE EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='inq_staff_role');
-- ---------- 账号:仅保留 admin ----------
-- 先删非 admin 的关联,再删非 admin 用户
DELETE ur FROM sys_user_role ur
INNER JOIN sys_user u ON u.id = ur.user_id
WHERE LOWER(u.username) <> 'admin';
DELETE ut FROM sys_user_tenant ut
INNER JOIN sys_user u ON u.id = ut.user_id
WHERE LOWER(u.username) <> 'admin';
DELETE ud FROM sys_user_depart ud
INNER JOIN sys_user u ON u.id = ud.user_id
WHERE LOWER(u.username) <> 'admin';
DELETE FROM sys_user WHERE LOWER(username) <> 'admin';
SET FOREIGN_KEY_CHECKS=1;
SELECT 'AFTER_COUNTS' AS phase;
SELECT 'inq_ticket' AS t, (SELECT COUNT(*) FROM inq_ticket) AS c
UNION ALL SELECT 'inq_ticket_status_log', (SELECT COUNT(*) FROM inq_ticket_status_log)
UNION ALL SELECT 'inq_ticket_segment', (SELECT COUNT(*) FROM inq_ticket_segment)
UNION ALL SELECT 'inq_quote', (SELECT COUNT(*) FROM inq_quote)
UNION ALL SELECT 'inq_attachment', (SELECT COUNT(*) FROM inq_attachment)
UNION ALL SELECT 'inq_exception_case', (SELECT COUNT(*) FROM inq_exception_case)
UNION ALL SELECT 'inq_staff_role', (SELECT COUNT(*) FROM inq_staff_role)
UNION ALL SELECT 'sys_user', (SELECT COUNT(*) FROM sys_user)
UNION ALL SELECT 'sys_user_role', (SELECT COUNT(*) FROM sys_user_role);
SELECT id, username, realname, status FROM sys_user;
"@
# 部分环境可能没有某附属表:改用逐表安全清理
$probe = Invoke-Mysql "SHOW TABLES;"
Write-Output "=== tables ==="
$probe | ForEach-Object { $_ }
$tables = @($probe | Where-Object { $_ -and $_ -ne "Tables_in_inquiry_robot" })
function Table-Exists([string]$name) {
return $tables -contains $name
}
$stmts = New-Object System.Collections.Generic.List[string]
$stmts.Add("SET NAMES utf8mb4;")
$stmts.Add("SET FOREIGN_KEY_CHECKS=0;")
# 工单相关
foreach ($t in @(
"inq_exception_case",
"inq_attachment",
"inq_quote",
"inq_ticket_status_log",
"inq_ticket_segment",
"inq_ticket",
"inq_dashboard_snapshot",
"inq_staff_role"
)) {
if (Table-Exists $t) {
$stmts.Add("DELETE FROM ``$t``;")
Write-Output ("will_clear=" + $t)
} else {
Write-Output ("skip_missing=" + $t)
}
}
if (Table-Exists "sys_user") {
if (Table-Exists "sys_user_role") {
$stmts.Add("DELETE ur FROM sys_user_role ur INNER JOIN sys_user u ON u.id = ur.user_id WHERE LOWER(u.username) <> 'admin';")
}
if (Table-Exists "sys_user_tenant") {
$stmts.Add("DELETE ut FROM sys_user_tenant ut INNER JOIN sys_user u ON u.id = ut.user_id WHERE LOWER(u.username) <> 'admin';")
}
if (Table-Exists "sys_user_depart") {
$stmts.Add("DELETE ud FROM sys_user_depart ud INNER JOIN sys_user u ON u.id = ud.user_id WHERE LOWER(u.username) <> 'admin';")
}
$stmts.Add("DELETE FROM sys_user WHERE LOWER(username) <> 'admin';")
Write-Output "will_clear_sys_user_keep_admin=1"
} else {
Write-Output "skip_missing=sys_user"
}
$stmts.Add("SET FOREIGN_KEY_CHECKS=1;")
# 执行前计数
Write-Output "=== BEFORE ==="
foreach ($t in @("inq_ticket","inq_staff_role","sys_user")) {
if (Table-Exists $t) {
Invoke-Mysql "SELECT '$t' AS t, COUNT(*) AS c FROM ``$t``;" | ForEach-Object { $_ }
}
}
if (Table-Exists "sys_user") {
Invoke-Mysql "SELECT username, realname FROM sys_user;" | ForEach-Object { $_ }
}
$execSql = ($stmts -join "`n")
Write-Output "=== EXEC ==="
Invoke-Mysql $execSql | ForEach-Object { $_ }
Write-Output "=== AFTER ==="
foreach ($t in @("inq_ticket","inq_ticket_status_log","inq_ticket_segment","inq_quote","inq_attachment","inq_exception_case","inq_staff_role","sys_user","sys_user_role")) {
if (Table-Exists $t) {
Invoke-Mysql "SELECT '$t' AS t, COUNT(*) AS c FROM ``$t``;" | ForEach-Object { $_ }
}
}
if (Table-Exists "sys_user") {
Invoke-Mysql "SELECT id, username, realname, status FROM sys_user;" | ForEach-Object { $_ }
}
Write-Output "CLEAR_DEMO_DATA_DONE"
@@ -1,58 +0,0 @@
$ErrorActionPreference = "Continue"
function Load-EnvFile($path) {
$map = @{}
if (-not (Test-Path $path)) { return $map }
Get-Content $path | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith("#")) { return }
$i = $line.IndexOf("=")
if ($i -lt 1) { return }
$k = $line.Substring(0,$i).Trim()
$v = $line.Substring($i+1).Trim().Trim('"')
$map[$k] = $v
}
return $map
}
function Show-RedisKeys($label, $map) {
$keys = @("YTD_REDIS_HOST","YTD_REDIS_PORT","YTD_REDIS_DB","YTD_REDIS_USERNAME","YTD_REDIS_PASSWORD","REDIS_URL","REDIS_PASSWORD","REDIS_USERNAME")
Write-Host ("=== " + $label + " ===")
foreach ($k in $keys) {
if ($map.ContainsKey($k)) {
$v = $map[$k]
$safe = $v
if ($k -match "PASSWORD|URL") {
if ($k -eq "REDIS_URL" -and $v -match "redis://([^:/@]+):([^@]+)@([^:/]+)") {
Write-Host (" REDIS_URL user=" + $Matches[1] + " pw_len=" + $Matches[2].Length + " host=" + $Matches[3])
continue
}
Write-Host (" " + $k + " len=" + $v.Length)
} else {
Write-Host (" " + $k + "=" + $v)
}
}
}
}
$candidates = @(
"E:\wwwroot\.env",
"C:\yutongda\.env",
"C:\yutongda\releases\admin-rel26-local-source-20260911d\backend\.env",
"C:\yutongda\releases\admin-rel26-local-source-20260911d\.env",
"E:\wwwroot\inquiry-new\.env"
)
Get-ChildItem "C:\yutongda" -Filter ".env" -Recurse -Depth 4 -ErrorAction SilentlyContinue | Select-Object -First 10 | ForEach-Object { $candidates += $_.FullName }
$candidates = $candidates | Select-Object -Unique
foreach ($p in $candidates) {
if (Test-Path $p) { Show-RedisKeys $p (Load-EnvFile $p) }
}
# Compare whether URL password equals any YTD_REDIS_PASSWORD found
$www = Load-EnvFile "E:\wwwroot\.env"
$urlPw = $null; $urlUser = $null
if ($www["REDIS_URL"] -match "redis://([^:/@]+):([^@]+)@") { $urlUser = $Matches[1]; $urlPw = $Matches[2] }
Get-ChildItem "C:\yutongda" -Filter ".env" -Recurse -Depth 4 -ErrorAction SilentlyContinue | ForEach-Object {
$m = Load-EnvFile $_.FullName
if ($m.ContainsKey("YTD_REDIS_PASSWORD") -and $urlPw) {
$same = ($m["YTD_REDIS_PASSWORD"] -eq $urlPw)
Write-Host ("cmp " + $_.FullName + " YTD_pw_len=" + $m["YTD_REDIS_PASSWORD"].Length + " same_as_www_url_pw=" + $same + " user=" + $m["YTD_REDIS_USERNAME"])
}
}
Write-Host "COMPARE_DONE"
-22
View File
@@ -1,22 +0,0 @@
# Confirm final smoke + .env hosts (no secrets).
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$sec = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
$intranet = "10.206.0.15"
Write-Output "=== .env hosts ==="
Select-String -Path "E:\wwwroot\.env" -Pattern '^(MYSQL_HOST|PG_HOST|MYSQL_DB|PG_DATABASE|MYSQL_USER|PG_USER)=' | ForEach-Object { $_.Line }
$mp = [string]$sec.mysql_password
$out = & $mysql -h $intranet -P3306 -uinquiry_robot "-p$mp" --batch -N inquiry_robot -e "SELECT 'mysql_ok'" 2>&1
Write-Output ("mysql=" + (($out | ForEach-Object {"$_"}) -join " "))
$env:PGPASSWORD = [string]$sec.pg_password
$out2 = & $psql -h $intranet -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_ok'" 2>&1
Write-Output ("pg=" + (($out2 | ForEach-Object {"$_"}) -join " "))
Remove-Item Env:PGPASSWORD -EA SilentlyContinue
Write-Output "=== status json ==="
Get-Content "E:\wwwroot\ops\data-plane-status.json" -Raw
Write-Output "CONFIRM_DONE"
-4
View File
@@ -1,4 +0,0 @@
New-Item -ItemType Directory -Force -Path "E:\wwwroot\ops\docs" | Out-Null
Copy-Item "C:\Users\ytd_extdev_0903\incoming\CUTOVER-TO-PROD.md" "E:\wwwroot\ops\docs\CUTOVER-TO-PROD.md" -Force
Write-Output "COPIED"
Test-Path "E:\wwwroot\ops\docs\CUTOVER-TO-PROD.md"
-6
View File
@@ -1,6 +0,0 @@
Copy-Item "C:\Users\ytd_extdev_0903\incoming\ops-sql-README.md" "E:\wwwroot\ops\sql\README.md" -Force
New-Item -ItemType Directory -Force -Path "E:\wwwroot\ops\docs" | Out-Null
Copy-Item "C:\Users\ytd_extdev_0903\incoming\CUTOVER-TO-PROD.md" "E:\wwwroot\ops\docs\CUTOVER-TO-PROD.md" -Force
Get-Content "E:\wwwroot\ops\data-plane-status.json"
Get-ChildItem "E:\wwwroot\ops\sql" | Select-Object Name
Write-Output "DOC_OK"
-21
View File
@@ -1,21 +0,0 @@
# Count ag_ business tables + prefixes in old jeecg-boot.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$j = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
$h = [string]$j.mysql_host
$u = [string]$j.mysql_username
$p = [string]$j.mysql_password
$out = & $mysql -h $h -P 3306 -u $u "-p$p" --batch -N -e "SELECT table_name FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' ORDER BY table_name" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
Write-Output ("total=" + $out.Count)
$ag = @($out | Where-Object { $_ -like 'ag_*' })
Write-Output ("ag_business=" + $ag.Count)
Write-Output ("sys_=" + @($out | Where-Object { $_ -like 'sys_*' }).Count)
Write-Output ("onl_=" + @($out | Where-Object { $_ -like 'onl_*' }).Count)
Write-Output ("jimu_=" + @($out | Where-Object { $_ -like 'jimu_*' }).Count)
Write-Output ("quartz=" + @($out | Where-Object { $_ -like 'qrtz_*' -or $_ -like 'QRTZ_*' }).Count)
Write-Output "=== ag_ tables ==="
$ag | ForEach-Object { $_ }
Write-Output "DONE"
-30
View File
@@ -1,30 +0,0 @@
# Count tables in old prod MySQL jeecg-boot (and inquiry_ prefix).
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$j = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
$h = [string]$j.mysql_host
$u = [string]$j.mysql_username
$p = [string]$j.mysql_password
function Q([string]$sql) {
$out = & $mysql -h $h -P 3306 -u $u "-p$p" --batch -N -e $sql 2>&1
return ($out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning|ERROR" })
}
$total = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE'"
$inquiry = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND table_name LIKE 'inquiry_%'"
$sys = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND table_name LIKE 'sys_%'"
$onl = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND table_name LIKE 'onl_%'"
$qrtz = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND (table_name LIKE 'qrtz_%' OR table_name LIKE 'QRTZ_%')"
$jimu = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND table_name LIKE 'jimu_%'"
$other = Q "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='jeecg-boot' AND table_type='BASE TABLE' AND table_name NOT LIKE 'inquiry_%' AND table_name NOT LIKE 'sys_%' AND table_name NOT LIKE 'onl_%' AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'QRTZ_%' AND table_name NOT LIKE 'jimu_%'"
Write-Output ("db=jeecg-boot host=" + $h)
Write-Output ("total=" + $total)
Write-Output ("inquiry_=" + $inquiry)
Write-Output ("sys_=" + $sys)
Write-Output ("onl_=" + $onl)
Write-Output ("quartz=" + $qrtz)
Write-Output ("jimu_=" + $jimu)
Write-Output ("other=" + $other)
Write-Output "DONE"
-220
View File
@@ -1,220 +0,0 @@
# Finish empty DBs on APP SERVER, expose via intranet 10.206.0.15 (not 127.0.0.1).
# Cannot CREATE on 10.206.0.14 without DBA. Document as interim.
# Never print secrets.
$ErrorActionPreference = "Stop"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$pgData = "C:\yutongda\data\pgsql" # may vary; detect
$ops = "E:\wwwroot\ops"
$sec = Get-Content "$ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
$mysqlPass = [string]$sec.mysql_password
$pgPass = [string]$sec.pg_password
$intranet = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -like '10.*' } | Select-Object -First 1 -ExpandProperty IPAddress)
if (-not $intranet) { throw "no 10.x intranet IP" }
Write-Output ("intranet=" + $intranet)
function Mysql-Ok([string]$h, [string]$u, [string]$p, [string]$db) {
$a = @("-h$h","-P3306","-u$u","-p$p","--connect-timeout=8","--batch","-N")
if ($db) { $a += $db }
$a += @("-e","SELECT 1")
$out = & $mysql @a 2>&1
$text = ($out | ForEach-Object {"$_"}) -join "`n"
if ($text -match "ERROR") { return $false }
$lines = $out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
return ($lines -contains "1")
}
# Resolve root password
$rootPass = $null
foreach ($f in @("$ops\local_mysql_root_secret.json", "$ops\.mysql_root_stash.tmp")) {
if (-not (Test-Path $f)) { continue }
if ($f -match '\.json$') {
$rootPass = [string](Get-Content $f -Raw | ConvertFrom-Json).root_password
} else {
$rootPass = (Get-Content $f -Raw).Trim()
}
if ($rootPass -and (Mysql-Ok "127.0.0.1" "root" $rootPass $null)) {
Write-Output ("mysql_root_ok via=" + $f + " len=" + $rootPass.Length)
break
}
$rootPass = $null
}
if (-not $rootPass) {
# try skip-grant again briefly if service allows stop
Write-Output "mysql_root_missing; will re-run maintenance create"
}
Write-Output "=== MySQL: ensure inquiry_robot ==="
if ($rootPass) {
$sql = @"
CREATE DATABASE IF NOT EXISTS ``inquiry_robot`` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'$intranet' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'localhost';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'127.0.0.1';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'%';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'$intranet';
FLUSH PRIVILEGES;
SELECT 'mysql_ok' AS s;
"@
$sqlPath = "$ops\sql\_run_ir_mysql.sql"
Set-Content $sqlPath -Value $sql -Encoding ascii
$o = & $mysql -h127.0.0.1 -P3306 -uroot "-p$rootPass" -e "source $($sqlPath -replace '\\','/')" 2>&1 | Out-String
if ($o -notmatch "mysql_ok") { Write-Output $o; throw "mysql create failed" }
Remove-Item $sqlPath -Force -EA SilentlyContinue
} else {
throw "no mysql root; cannot finish MySQL empty DB on app server"
}
# Smoke via intranet IP
if (-not (Mysql-Ok $intranet "inquiry_robot" $mysqlPass "inquiry_robot")) {
# bind-address may block; check my.ini
Write-Output "intranet mysql smoke failed; checking bind-address"
Select-String -Path "C:\yutongda\tools\mysql-8.0.39-winx64\my.ini" -Pattern "bind-address|skip-networking" |
ForEach-Object { $_.Line }
# retry 127
if (-not (Mysql-Ok "127.0.0.1" "inquiry_robot" $mysqlPass "inquiry_robot")) {
throw "mysql app smoke failed even on 127.0.0.1"
}
Write-Output "mysql_ok_127_only"
} else {
Write-Output "mysql_ok_intranet"
}
Write-Output "=== PG: ensure listen on intranet + role/db ==="
$env:PGPASSWORD = (Get-Content "C:\yutongda\secure\pgpass.txt" -Raw).Trim()
# find data dir
$pgConfCandidates = @(
"C:\yutongda\data\pgsql\postgresql.conf",
"C:\yutongda\tools\pgsql\data\postgresql.conf",
"C:\yutongda\data\postgresql\postgresql.conf"
)
$pgConf = $pgConfCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $pgConf) {
# ask running postgres
$dd = & $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -tAc "SHOW data_directory;" 2>&1
$dd = ($dd | ForEach-Object {"$_"}).Trim()
Write-Output ("pg_data_directory=" + $dd)
if ($dd -and (Test-Path (Join-Path $dd "postgresql.conf"))) {
$pgConf = Join-Path $dd "postgresql.conf"
}
}
if (-not $pgConf) { throw "postgresql.conf not found" }
Write-Output ("pgConf=" + $pgConf)
$pgHba = Join-Path (Split-Path $pgConf -Parent) "pg_hba.conf"
# ensure listen_addresses includes intranet or *
$confText = Get-Content $pgConf -Raw
if ($confText -notmatch "(?m)^\s*listen_addresses\s*=\s*'[^']*${intranet}" -and $confText -notmatch "(?m)^\s*listen_addresses\s*=\s*'\*'") {
if ($confText -match "(?m)^\s*#?\s*listen_addresses\s*=") {
$confText = [regex]::Replace($confText, "(?m)^\s*#?\s*listen_addresses\s*=\s*.*$", "listen_addresses = '*' # inquiry_robot interim", 1)
} else {
$confText += "`r`nlisten_addresses = '*'`r`n"
}
Set-Content $pgConf -Value $confText -Encoding UTF8
Write-Output "pg_listen_patched"
} else {
Write-Output "pg_listen_ok"
}
# ensure hba allows intranet md5/scram
$hba = Get-Content $pgHba
$need = "host inquiry_robot_runtime inquiry_robot_runtime 10.206.0.0/16 scram-sha-256"
if (-not ($hba -match "inquiry_robot_runtime")) {
Add-Content $pgHba $need
Add-Content $pgHba "host inquiry_robot_runtime inquiry_robot_runtime 127.0.0.1/32 scram-sha-256"
Write-Output "pg_hba_patched"
} else {
Write-Output "pg_hba_ok"
}
# create role/db if missing
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -v ON_ERROR_STOP=1 -c @"
DO `$`$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'inquiry_robot_runtime') THEN
CREATE ROLE inquiry_robot_runtime LOGIN PASSWORD '$pgPass';
ELSE
ALTER ROLE inquiry_robot_runtime WITH LOGIN PASSWORD '$pgPass';
END IF;
END
`$`$;
SELECT 'role_ok';
"@ 2>&1 | ForEach-Object { if ($_ -notmatch $pgPass) { "$_" } }
$exists = & $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='inquiry_robot_runtime'" 2>&1
if (($exists | Out-String) -notmatch "1") {
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -c "CREATE DATABASE inquiry_robot_runtime OWNER inquiry_robot_runtime;" 2>&1 | ForEach-Object { "$_" }
}
& $psql -h 127.0.0.1 -p 5432 -U postgres -d inquiry_robot_runtime -c "GRANT ALL ON SCHEMA public TO inquiry_robot_runtime;" 2>&1 | Out-Null
# reload or restart PG
$pgSvc = Get-Service *pgsql*,*postgres*,YTD-PG*,YTD-Postgres* -EA SilentlyContinue
Write-Output ("pg_services=" + (($pgSvc | ForEach-Object { $_.Name + ":" + $_.Status }) -join ","))
try {
& "$($psql -replace 'psql.exe','pg_ctl.exe')" reload -D (Split-Path $pgConf -Parent) 2>&1 | Out-Null
} catch {}
# prefer reload via SQL
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -c "SELECT pg_reload_conf();" 2>&1 | Out-Null
# If listen_addresses changed, need restart
$listen = & $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -tAc "SHOW listen_addresses;" 2>&1
Write-Output ("listen_now=" + (($listen | ForEach-Object {"$_"}).Trim()))
if ((($listen | Out-String) -notmatch "\*|${intranet}")) {
Write-Output "restarting postgres for listen_addresses"
if ($pgSvc) {
Restart-Service $pgSvc[0].Name -Force
Start-Sleep -Seconds 5
}
}
$env:PGPASSWORD = $pgPass
$pgSmokeLocal = & $psql -h 127.0.0.1 -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_ok'" 2>&1
Write-Output ("pg_local=" + (($pgSmokeLocal | ForEach-Object {"$_"}) -join " "))
$pgSmokeNet = & $psql -h $intranet -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_ok'" 2>&1
Write-Output ("pg_intranet=" + (($pgSmokeNet | ForEach-Object {"$_"}) -join " "))
Remove-Item Env:PGPASSWORD -EA SilentlyContinue
Write-Output "=== patch .env to intranet app-server IP ==="
$envPath = "E:\wwwroot\.env"
$jdbc = "jdbc:mysql://${intranet}:3306/inquiry_robot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true&tinyInt1isBit=false&serverTimezone=Asia/Shanghai"
$lines = Get-Content $envPath
$out = foreach ($line in $lines) {
if ($line -match '^MYSQL_HOST=') { "MYSQL_HOST=$intranet" }
elseif ($line -match '^PG_HOST=') { "PG_HOST=$intranet" }
elseif ($line -match '^YTD_MYSQL_URL=') { "YTD_MYSQL_URL=$jdbc" }
elseif ($line -match '^MYSQL_PASSWORD=') { "MYSQL_PASSWORD=$mysqlPass" }
elseif ($line -match '^PG_PASSWORD=') { "PG_PASSWORD=$pgPass" }
else { $line }
}
Set-Content $envPath -Value $out -Encoding UTF8
Copy-Item $envPath "E:\wwwroot\agent\current\.env" -Force -EA SilentlyContinue
# cleanup maint sql with secrets if present
Remove-Item "$ops\sql\_maint_create_inquiry_robot.sql" -Force -EA SilentlyContinue
Remove-Item "$ops\sql\_run_create_inquiry_robot_mysql.sql" -Force -EA SilentlyContinue
$status = @{
mysqlHost = $intranet
pgHost = $intranet
mysqlDb = "inquiry_robot"
pgDb = "inquiry_robot_runtime"
mysqlCreated = $true
pgCreated = $true
placement = "app-server-local-via-intranet-ip"
note = "Interim: empty DBs on app server 10.206.0.15 local mysqld/postgres, apps connect via intranet IP (not 127.0.0.1). Target later: migrate to data host 10.206.0.14 when DBA available. Do not use jeecg-boot/ytd_runtime."
needDbaForDataHost14 = $true
updatedAt = (Get-Date).ToString("o")
} | ConvertTo-Json
Set-Content "$ops\data-plane-status.json" -Value $status -Encoding UTF8
Write-Output $status
# final smoke summary
Write-Output ("FINAL mysql@" + $intranet + "=" + (Mysql-Ok $intranet "inquiry_robot" $mysqlPass "inquiry_robot"))
Write-Output ("FINAL mysql@127=" + (Mysql-Ok "127.0.0.1" "inquiry_robot" $mysqlPass "inquiry_robot"))
Write-Output "CREATE_INTERIM_DONE"
-126
View File
@@ -1,126 +0,0 @@
# 在应用机本机 mysqld 上创建空库 inquiry_robot(表稍后 Flyway)。
# 口令:优先 E:\wwwroot\ops\.mysql_root_stash.tmp,否则尝试现网 application-database-credentials.json 中的 mysql_password。
# 不向 stdout 打印任何口令。副作用:改 E:\wwwroot\.env 的 MYSQL/PG HOST 为 127.0.0.1。
$ErrorActionPreference = "Stop"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$secrets = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
$dbCred = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
function Test-MysqlRoot([string]$pass) {
if ([string]::IsNullOrWhiteSpace($pass)) { return $false }
$out = & $mysql -h 127.0.0.1 -P 3306 -u root "-p$pass" --connect-timeout=8 -e "SELECT 'root_ok' AS r" 2>&1 | Out-String
return ($out -match "root_ok")
}
Write-Output "=== resolve local mysql root ==="
$rootPass = $null
$stash = "E:\wwwroot\ops\.mysql_root_stash.tmp"
if (Test-Path $stash) {
$candidate = (Get-Content $stash -Raw).Trim()
if (Test-MysqlRoot $candidate) {
$rootPass = $candidate
Write-Output ("root_from=stash len=" + $rootPass.Length)
}
}
if (-not $rootPass) {
$candidate = [string]$dbCred.mysql_password
if (Test-MysqlRoot $candidate) {
$rootPass = $candidate
Write-Output ("root_from=app_db_cred.mysql_password len=" + $rootPass.Length)
Set-Content -Path $stash -Value $rootPass -Encoding ascii -NoNewline
}
}
if (-not $rootPass) {
# 再试 postgres 口令等同机复用(少数环境)
$candidate = [string]$dbCred.postgres_password
if (Test-MysqlRoot $candidate) {
$rootPass = $candidate
Write-Output ("root_from=app_db_cred.postgres_password len=" + $rootPass.Length)
Set-Content -Path $stash -Value $rootPass -Encoding ascii -NoNewline
}
}
if (-not $rootPass) { throw "local mysql root auth failed" }
Write-Output "MYSQL_ROOT_OK"
$mysqlPass = [string]$secrets.mysql_password
if ([string]::IsNullOrWhiteSpace($mysqlPass)) { throw "missing inquiry_robot mysql_password in secrets json" }
# 写临时 SQL,避免 PowerShell 对反引号/括号的解析问题
$sqlPath = "E:/wwwroot/ops/sql/_run_create_inquiry_robot_mysql.sql"
$sql = @"
CREATE DATABASE IF NOT EXISTS ``inquiry_robot`` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'localhost';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'127.0.0.1';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'%';
FLUSH PRIVILEGES;
SELECT 'mysql_create_ok' AS s;
"@
Set-Content -Path $sqlPath -Value $sql -Encoding ascii
Write-Output "=== create empty MySQL DB/user ==="
$createOut = & $mysql -h 127.0.0.1 -P 3306 -u root "-p$rootPass" --connect-timeout=15 -e "source $sqlPath" 2>&1 | Out-String
$createOut -split "`r?`n" | ForEach-Object {
if ($_ -match 'Using a password|IDENTIFIED BY') { return }
if ($_ -match 'password') { return }
$_
}
if ($createOut -notmatch "mysql_create_ok") { throw "mysql create failed" }
Write-Output "=== smoke as inquiry_robot ==="
$smoke = & $mysql -h 127.0.0.1 -P 3306 -u inquiry_robot "-p$mysqlPass" --connect-timeout=8 inquiry_robot -e "SELECT 'mysql_app_ok' AS s; SHOW TABLES;" 2>&1 | Out-String
$smoke -split "`r?`n" | ForEach-Object {
if ($_ -match 'Using a password') { return }
$_
}
if ($smoke -notmatch "mysql_app_ok") { throw "mysql app smoke failed" }
Write-Output "MYSQL_CREATED_OK"
Write-Output "=== confirm PG app user ==="
$env:PGPASSWORD = [string]$secrets.pg_password
$pgSmoke = & $psql -h 127.0.0.1 -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_app_ok'" 2>&1
Write-Output ("PG=" + (($pgSmoke | ForEach-Object {"$_"}) -join " "))
if (($pgSmoke | Out-String) -notmatch "pg_app_ok") { throw "pg app smoke failed" }
Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue
Write-Output "=== patch .env hosts to 127.0.0.1 ==="
$envPath = "E:\wwwroot\.env"
$lines = Get-Content $envPath
$out = foreach ($line in $lines) {
if ($line -match '^MYSQL_HOST=') { 'MYSQL_HOST=127.0.0.1' }
elseif ($line -match '^PG_HOST=') { 'PG_HOST=127.0.0.1' }
elseif ($line -match '^YTD_MYSQL_URL=') {
'YTD_MYSQL_URL=jdbc:mysql://127.0.0.1:3306/inquiry_robot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true&tinyInt1isBit=false&serverTimezone=Asia/Shanghai'
}
elseif ($line -match '^MYSQL_PASSWORD=') { "MYSQL_PASSWORD=$($secrets.mysql_password)" }
elseif ($line -match '^PG_PASSWORD=') { "PG_PASSWORD=$($secrets.pg_password)" }
else { $line }
}
Set-Content $envPath -Value $out -Encoding UTF8
if (Test-Path "E:\wwwroot\agent\current") {
Copy-Item $envPath "E:\wwwroot\agent\current\.env" -Force
}
# 清理含明文口令的临时 SQL(secrets 已在 json/.env)
Remove-Item $sqlPath -Force -ErrorAction SilentlyContinue
$status = @{
mysqlHost = "127.0.0.1"
mysqlDb = "inquiry_robot"
mysqlCreated = $true
pgHost = "127.0.0.1"
pgDb = "inquiry_robot_runtime"
pgCreated = $true
note = "Empty DBs on APP-SERVER local mysqld/postgres (C:\yutongda\tools), not 10.206.0.14. Tables via Flyway later."
updatedAt = (Get-Date).ToString("o")
needDba = $false
} | ConvertTo-Json
Set-Content "E:\wwwroot\ops\data-plane-status.json" -Value $status -Encoding UTF8
Write-Output $status
Write-Output "CREATE_ALL_DONE"
@@ -1,46 +0,0 @@
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$pgpass = (Get-Content "C:\yutongda\secure\pgpass.txt" -Raw).Trim()
$dbCred = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
$secrets = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
Write-Output "=== find mysql ini ==="
Get-ChildItem "C:\yutongda\tools\mysql-8.0.39-winx64" -Recurse -Include my.ini,my.cnf -EA SilentlyContinue | Select-Object FullName
Get-ChildItem "C:\ProgramData\MySQL" -Recurse -Include my.ini -EA SilentlyContinue | Select-Object -First 5 FullName
Write-Output "=== more local mysql password tries ==="
$tries = @($pgpass, 'Mysql@2026', 'MySQL@2026', 'Ytd@2026', 'yutongda', '123456', '')
foreach ($p in $tries) {
$tag = if ($p -eq '') { 'empty' } elseif ($p -eq $pgpass) { 'pgpass' } else { 'named' }
$arg = if ($p -eq '') { @('-h','127.0.0.1','-P','3306','-u','root','--connect-timeout=5','-e','SELECT 1 AS ok;') } else { @('-h','127.0.0.1','-P','3306','-u','root',"-p$p",'--connect-timeout=5','-e','SELECT 1 AS ok;') }
$out = & $mysql @arg 2>&1
$text = ($out | ForEach-Object {"$_"}) -join ' '
if ($text -match '\bok\b' -or $text -match '^\s*1\s*$' -or $text -match 'ok') {
Write-Output "MYSQL_ROOT_HIT tag=$tag"
} else {
Write-Output "mysql_miss tag=$tag"
}
}
Write-Output "=== CREATE PG inquiry_robot_runtime on LOCAL ==="
$env:PGPASSWORD = $pgpass
$env:PGCONNECT_TIMEOUT = "10"
$pgUserPass = $secrets.pg_password
# create role if not exists
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -v ON_ERROR_STOP=1 -c "DO `$`$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'inquiry_robot_runtime') THEN CREATE ROLE inquiry_robot_runtime LOGIN PASSWORD '$pgUserPass'; ELSE ALTER ROLE inquiry_robot_runtime WITH LOGIN PASSWORD '$pgUserPass'; END IF; END `$`$;" 2>&1 | ForEach-Object { "pgrole=$_" }
$exists = (& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='inquiry_robot_runtime'" 2>$null).Trim()
if ($exists -ne '1') {
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE inquiry_robot_runtime OWNER inquiry_robot_runtime ENCODING 'UTF8' TEMPLATE template0;" 2>&1 | ForEach-Object { "pgdb=$_" }
} else {
Write-Output "PG_DB_EXISTS"
& $psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -c "ALTER DATABASE inquiry_robot_runtime OWNER TO inquiry_robot_runtime;" 2>&1 | ForEach-Object { "pgown=$_" }
}
& $psql -h 127.0.0.1 -p 5432 -U postgres -d inquiry_robot_runtime -v ON_ERROR_STOP=1 -c "GRANT ALL ON SCHEMA public TO inquiry_robot_runtime; ALTER SCHEMA public OWNER TO inquiry_robot_runtime;" 2>&1 | ForEach-Object { "pgschema=$_" }
# smoke as app user
$env:PGPASSWORD = $pgUserPass
$smoke = & $psql -h 127.0.0.1 -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_app_ok'" 2>&1
Write-Output ("PG_SMOKE=" + ($smoke | ForEach-Object {"$_"}))
Write-Output "STEP_DONE"
-11
View File
@@ -1,11 +0,0 @@
Write-Output "local agent:"
cmd /c "curl.exe -s http://127.0.0.1:8910/health"
Write-Output ""
Write-Output "via nginx host header:"
cmd /c "curl.exe -sk -H Host: ai.ytd-scm.com https://127.0.0.1/agent/health"
Write-Output ""
Write-Output "via nginx wecom health:"
cmd /c "curl.exe -sk -H Host: ai.ytd-scm.com https://127.0.0.1/wecom/callback/health"
Write-Output ""
Write-Output "error log tail:"
Get-Content "C:\nginx-1.18.0\logs\error.log" -Tail 20 -ErrorAction SilentlyContinue
-107
View File
@@ -1,107 +0,0 @@
# Remote: publish latest admin dist + switch Nginx /jeecgboot -> 8180
# Do not touch C:\yutongda. On nginx -t failure, restore backup.
$ErrorActionPreference = 'Stop'
$IncomingZip = 'C:\Users\ytd_extdev_0903\incoming\admin-dist.zip'
$IncomingConf = 'C:\Users\ytd_extdev_0903\incoming\ai.conf.cutover-8180'
$Root = 'E:\wwwroot'
$Nginx = 'C:\nginx-1.18.0'
$NginxConf = Join-Path $Nginx 'myconf\ai.conf'
$Stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$RelId = 'admin-' + $Stamp
$RelDist = Join-Path $Root ('admin\releases\' + $RelId + '\dist')
$Current = Join-Path $Root 'admin\current'
$PtrPath = Join-Path $Root 'ops\active-release.json'
if (-not (Test-Path $IncomingZip)) { throw 'missing admin-dist.zip' }
if (-not (Test-Path $IncomingConf)) { throw 'missing ai.conf.cutover-8180' }
$ledger = Get-NetTCPConnection -LocalPort 8180 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $ledger) { throw 'CRITICAL: 8180 not listening' }
$agent = Get-NetTCPConnection -LocalPort 8910 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $agent) { throw 'CRITICAL: 8910 not listening' }
$prod = Get-NetTCPConnection -LocalPort 8080 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $prod) { throw 'CRITICAL: prod 8080 down' }
Write-Output '=== backup nginx ==='
$bak = $NginxConf + '.bak-before-admin-8180-' + $Stamp
Copy-Item $NginxConf $bak -Force
Write-Output ('bak=' + $bak)
Write-Output '=== install release dist ==='
New-Item -ItemType Directory -Force -Path $RelDist | Out-Null
Expand-Archive -Path $IncomingZip -DestinationPath $RelDist -Force
if (-not (Test-Path (Join-Path $RelDist 'index.html'))) {
$inner = Get-ChildItem $RelDist -Directory | Select-Object -First 1
if ($inner -and (Test-Path (Join-Path $inner.FullName 'index.html'))) {
$RelDist = $inner.FullName
}
}
if (-not (Test-Path (Join-Path $RelDist 'index.html'))) { throw 'index.html missing' }
Write-Output '=== switch admin current junction ==='
if (Test-Path $Current) {
cmd /c ('rmdir "' + $Current + '"') | Out-Null
if (Test-Path $Current) { Remove-Item $Current -Recurse -Force }
}
cmd /c ('mklink /J "' + $Current + '" "' + $RelDist + '"')
if (-not (Test-Path (Join-Path $Current 'index.html'))) { throw 'current index missing' }
Write-Output ('CURRENT_OK=' + $Current + ' -> ' + $RelDist)
Write-Output '=== nginx conf no BOM ==='
$bytes = [System.IO.File]::ReadAllBytes($IncomingConf)
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) {
$list = New-Object System.Collections.Generic.List[byte]
for ($i = 3; $i -lt $bytes.Length; $i++) { [void]$list.Add($bytes[$i]) }
$bytes = $list.ToArray()
}
[System.IO.File]::WriteAllBytes($NginxConf, $bytes)
Set-Location $Nginx
& .\nginx.exe -t
if ($LASTEXITCODE -ne 0) {
Copy-Item $bak $NginxConf -Force
throw 'nginx -t failed, restored'
}
Get-Process nginx -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
try {
Start-Service Nginx1.18 -ErrorAction Stop
Write-Output 'SERVICE_STARTED'
} catch {
Start-Process -FilePath (Join-Path $Nginx 'nginx.exe') -WorkingDirectory $Nginx -WindowStyle Hidden
Write-Output 'EXE_STARTED'
}
Start-Sleep -Seconds 2
New-Item -ItemType Directory -Force -Path (Join-Path $Root 'ops') | Out-Null
$prevAgentCurrent = Join-Path $Root 'agent\current'
$prevAgentHome = $null
if (Test-Path $PtrPath) {
try {
$old = Get-Content $PtrPath -Raw | ConvertFrom-Json
if ($old.agentCurrent) { $prevAgentCurrent = [string]$old.agentCurrent }
if ($old.agentHome) { $prevAgentHome = [string]$old.agentHome }
} catch {}
}
$ptr = @{
root = $Root
releaseId = $RelId
adminRelease = $RelDist
adminCurrent = $Current
agentCurrent = $prevAgentCurrent
agentHome = $prevAgentHome
nginxBak = $bak
jeecgbootProxy = 'http://127.0.0.1:8180/jeecgboot/'
updatedAt = (Get-Date).ToString('o')
note = 'admin cutover to Jeecg Vue + ledger 8180'
}
($ptr | ConvertTo-Json) | Out-File -FilePath $PtrPath -Encoding utf8
Write-Output '=== smoke ==='
try {
$h = Invoke-WebRequest -Uri 'http://127.0.0.1:8180/jeecgboot/sys/randomImage/cutover' -UseBasicParsing -TimeoutSec 8
Write-Output ('ledger=' + $h.StatusCode)
} catch {
Write-Output ('ledger_fail=' + $_.Exception.Message)
}
Write-Output 'ADMIN_CUTOVER_OK'
-97
View File
@@ -1,97 +0,0 @@
# Align DB hosts to intranet IP; diagnose MySQL create state. No secret stdout.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$dbCred = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
$sec = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
Write-Output "=== this host intranet addresses ==="
Get-NetIPAddress -AddressFamily IPv4 -EA SilentlyContinue |
Where-Object { $_.IPAddress -notlike '127.*' } |
ForEach-Object { "$($_.InterfaceAlias) $($_.IPAddress)" }
Write-Output "=== credential hosts (from secure json) ==="
Write-Output ("mysql_host=" + $dbCred.mysql_host + " postgres_host=" + $dbCred.postgres_host)
Write-Output "=== .env host lines now ==="
Select-String -Path "E:\wwwroot\.env" -Pattern '^(MYSQL_HOST|PG_HOST|YTD_MYSQL_URL)=' |
ForEach-Object {
$l = $_.Line
if ($l -match 'PASSWORD') { ($l -split '=',2)[0] + '=***' } else { $l }
}
function Test-Mysql([string]$host, [string]$user, [string]$pass, [string]$db) {
$args = @("-h$host","-P3306","-u$user","-p$pass","--connect-timeout=8","--batch","-N")
if ($db) { $args += $db }
$args += @("-e","SELECT 1")
$out = & $mysql @args 2>&1
$text = ($out | ForEach-Object {"$_"}) -join "`n"
if ($text -match "ERROR\s+\d+") {
$err = ($text -split "`n" | Where-Object { $_ -match "ERROR" } | Select-Object -First 1)
return "FAIL $err"
}
$lines = $out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
if ($lines -contains "1") { return "OK" }
return "FAIL no-result"
}
function Test-RootCreate([string]$host, [string]$pass) {
$out = & $mysql -h$host -P3306 -uroot "-p$pass" --connect-timeout=8 --batch -N -e "SELECT 1" 2>&1
$text = ($out | ForEach-Object {"$_"}) -join "`n"
if ($text -match "ERROR") { return "root_fail" }
$lines = $out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
if ($lines -notcontains "1") { return "root_fail" }
$dbs = & $mysql -h$host -P3306 -uroot "-p$pass" --batch -N -e "SHOW DATABASES LIKE 'inquiry_robot'" 2>&1
$has = (($dbs | ForEach-Object {"$_"}) -join " ") -match "inquiry_robot"
return ("root_ok has_db=" + $has)
}
$hosts = @("127.0.0.1", "10.206.0.15", [string]$dbCred.mysql_host)
$hosts = $hosts | Select-Object -Unique
Write-Output "=== inquiry_robot app user smoke ==="
foreach ($h in $hosts) {
Write-Output ("host=$h -> " + (Test-Mysql $h "inquiry_robot" ([string]$sec.mysql_password) "inquiry_robot"))
}
Write-Output "=== root smoke if local secret exists ==="
$rootPass = $null
if (Test-Path "E:\wwwroot\ops\local_mysql_root_secret.json") {
$rootPass = [string](Get-Content "E:\wwwroot\ops\local_mysql_root_secret.json" -Raw | ConvertFrom-Json).root_password
Write-Output "local_mysql_root_secret=present"
} elseif (Test-Path "E:\wwwroot\ops\.mysql_root_stash.tmp") {
$rootPass = (Get-Content "E:\wwwroot\ops\.mysql_root_stash.tmp" -Raw).Trim()
Write-Output "stash=present"
} else {
Write-Output "no_root_secret"
}
if ($rootPass) {
foreach ($h in $hosts) {
Write-Output ("root@$h -> " + (Test-RootCreate $h $rootPass))
}
}
Write-Output "=== ytd_jeecg on data host show dbs like inquiry ==="
$h = [string]$dbCred.mysql_host
$u = [string]$dbCred.mysql_username
$p = [string]$dbCred.mysql_password
& $mysql -h$h -P3306 -u$u "-p$p" --batch -e "SHOW DATABASES LIKE 'inquiry%'; SHOW DATABASES LIKE 'jeecg%';" 2>&1 |
Where-Object { $_ -notmatch "Warning" } | ForEach-Object { "$_" }
Write-Output "=== PG inquiry_robot_runtime ==="
$env:PGPASSWORD = [string]$sec.pg_password
foreach ($h in @("127.0.0.1","10.206.0.15",[string]$dbCred.postgres_host) | Select-Object -Unique) {
$r = & $psql -h $h -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_ok'" 2>&1
Write-Output ("pg@$h -> " + (($r | ForEach-Object {"$_"}) -join " "))
}
# also postgres superuser local
$env:PGPASSWORD = (Get-Content "C:\yutongda\secure\pgpass.txt" -Raw).Trim()
foreach ($h in @("127.0.0.1","10.206.0.15",[string]$dbCred.postgres_host) | Select-Object -Unique) {
$r = & $psql -h $h -p 5432 -U postgres -d postgres -tAc "SELECT datname FROM pg_database WHERE datname='inquiry_robot_runtime'" 2>&1
Write-Output ("pg_super@$h inquiry_robot_runtime=" + (($r | ForEach-Object {"$_"}) -join " ").Trim())
}
Remove-Item Env:PGPASSWORD -EA SilentlyContinue
Write-Output "=== YTD-MySQL service ==="
Get-Service YTD-MySQL | Format-Table Name,Status -AutoSize | Out-String | Write-Output
Write-Output "DONE"
-84
View File
@@ -1,84 +0,0 @@
# Probe 10.206.0.14 only (intranet data host). Avoid foreach var name 'host'.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$dbCred = Get-Content "C:\yutongda\secure\application-database-credentials.json" -Raw | ConvertFrom-Json
$sec = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
$dataHost = [string]$dbCred.mysql_host
Write-Output ("dataHost=" + $dataHost)
Write-Output ("appIntranet=" + (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -like '10.*' } | Select-Object -First 1 -ExpandProperty IPAddress))
Write-Output "=== MySQL ytd_jeecg @ dataHost ==="
$u = [string]$dbCred.mysql_username
$p = [string]$dbCred.mysql_password
& $mysql -h $dataHost -P 3306 -u $u "-p$p" --connect-timeout=10 --batch -e "SELECT CURRENT_USER() AS u; SHOW DATABASES LIKE 'inquiry%'; SHOW GRANTS FOR CURRENT_USER();" 2>&1 |
Where-Object { "$_" -notmatch "Warning" } | ForEach-Object { "$_" }
Write-Output "=== MySQL inquiry_robot @ dataHost ==="
$ir = [string]$sec.mysql_user
$irp = [string]$sec.mysql_password
$out = & $mysql -h $dataHost -P 3306 -u $ir "-p$irp" --connect-timeout=10 --batch -N -e "SELECT 1" 2>&1
$text = ($out | ForEach-Object {"$_"}) -join "`n"
if ($text -match "ERROR") {
($text -split "`n" | Where-Object { $_ -match "ERROR" } | Select-Object -First 1)
} else {
Write-Output "inquiry_robot_login=OK"
}
Write-Output "=== try CREATE DATABASE on dataHost as ytd_jeecg (expect deny) ==="
$c = & $mysql -h $dataHost -P 3306 -u $u "-p$p" --connect-timeout=10 -e "CREATE DATABASE IF NOT EXISTS inquiry_robot" 2>&1
($c | ForEach-Object {"$_"}) | Where-Object { $_ -match "ERROR|Query OK|Rows" } | Select-Object -First 3
Write-Output "=== PG ytd_runtime / inquiry @ dataHost ==="
$env:PGPASSWORD = [string]$dbCred.postgres_password
& $psql -h $dataHost -p 5432 -U ([string]$dbCred.postgres_username) -d ([string]$dbCred.postgres_database) -tAc "SELECT current_user, current_database(); SELECT datname FROM pg_database WHERE datname LIKE 'inquiry%' OR datname LIKE 'ytd%';" 2>&1 |
ForEach-Object { "$_" }
Write-Output "=== PG inquiry_robot_runtime @ dataHost ==="
$env:PGPASSWORD = [string]$sec.pg_password
& $psql -h $dataHost -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'pg_ir_ok'" 2>&1 |
ForEach-Object { "$_" }
Write-Output "=== local-only leftovers (info) ==="
$env:PGPASSWORD = [string]$sec.pg_password
& $psql -h 127.0.0.1 -p 5432 -U inquiry_robot_runtime -d inquiry_robot_runtime -tAc "SELECT 'local_pg_ok'" 2>&1 | ForEach-Object { "local_pg=" + $_ }
Remove-Item Env:PGPASSWORD -EA SilentlyContinue
# ensure .env stays on intranet data host
Write-Output "=== ensure .env hosts = dataHost ==="
$envPath = "E:\wwwroot\.env"
$lines = Get-Content $envPath
$changed = $false
$outLines = foreach ($line in $lines) {
if ($line -match '^MYSQL_HOST=' -and $line -ne "MYSQL_HOST=$dataHost") { $changed = $true; "MYSQL_HOST=$dataHost" }
elseif ($line -match '^PG_HOST=' -and $line -ne "PG_HOST=$dataHost") { $changed = $true; "PG_HOST=$dataHost" }
elseif ($line -match '^YTD_MYSQL_URL=' -and $line -notmatch [regex]::Escape("jdbc:mysql://${dataHost}:3306/inquiry_robot")) {
$changed = $true
"YTD_MYSQL_URL=jdbc:mysql://${dataHost}:3306/inquiry_robot?characterEncoding=UTF-8&useUnicode=true&useSSL=true&requireSSL=true&verifyServerCertificate=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai"
}
else { $line }
}
if ($changed) {
Set-Content $envPath -Value $outLines -Encoding UTF8
if (Test-Path "E:\wwwroot\agent\current") { Copy-Item $envPath "E:\wwwroot\agent\current\.env" -Force }
Write-Output "env_patched=true"
} else {
Write-Output "env_patched=false (already intranet)"
}
$status = @{
mysqlHost = $dataHost
pgHost = $dataHost
appServerIntranet = "10.206.0.15"
mysqlCreatedOnDataHost = $false
pgCreatedOnDataHost = $false
localPgLeftover = $true
note = "Apps must use intranet data host 10.206.0.14 (not 127.0.0.1). Empty DB create needs DBA on 10.206.0.14; app users have no CREATE DATABASE."
needDba = $true
sqlDir = "E:\\wwwroot\\ops\\sql"
updatedAt = (Get-Date).ToString("o")
} | ConvertTo-Json
Set-Content "E:\wwwroot\ops\data-plane-status.json" -Value $status -Encoding UTF8
Write-Output $status
Write-Output "DONE"
-71
View File
@@ -1,71 +0,0 @@
# 部署前状态探测:只读,禁止改现网
# 职责:确认 E:\wwwroot 布局、测试端口、现网端口仍在听
$ErrorActionPreference = 'Continue'
Write-Output '=== host ==='
hostname
Write-Output '=== paths ==='
@(
'E:\wwwroot',
'E:\wwwroot\.env',
'E:\wwwroot\ops\active-release.json',
'E:\wwwroot\agent\current',
'E:\wwwroot\admin\current',
'E:\wwwroot\inquiry-new',
'C:\yutongda',
'C:\yutongda\ops\active-release.json'
) | ForEach-Object { "$_ = $(Test-Path $_)" }
Write-Output '=== wwwroot top ==='
if (Test-Path 'E:\wwwroot') {
Get-ChildItem 'E:\wwwroot' | ForEach-Object { $_.Name }
}
Write-Output '=== active-release ==='
if (Test-Path 'E:\wwwroot\ops\active-release.json') {
Get-Content 'E:\wwwroot\ops\active-release.json' -Raw
}
Write-Output '=== ports ==='
foreach ($x in 8080, 8809, 8810, 8811, 8813, 8180, 8910, 8913) {
$c = Get-NetTCPConnection -LocalPort $x -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if ($c) {
Write-Output "$x LISTEN pid=$($c.OwningProcess)"
} else {
Write-Output "$x down"
}
}
Write-Output '=== health local ==='
foreach ($u in @(
'http://127.0.0.1:8910/health',
'http://127.0.0.1:8180/jeecgboot/',
'http://127.0.0.1:8810/health',
'http://127.0.0.1:8080/jeecg-boot/'
)) {
try {
$r = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 5
Write-Output "OK $($r.StatusCode) $u"
} catch {
Write-Output "FAIL $u :: $($_.Exception.Message)"
}
}
Write-Output '=== agent current sample ==='
if (Test-Path 'E:\wwwroot\agent\current\agent\http_app.py') {
Write-Output 'agent http_app.py present'
} else {
Write-Output 'agent http_app.py MISSING'
}
if (Test-Path 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar') {
$j = Get-Item 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
Write-Output "jar bytes=$($j.Length) mtime=$($j.LastWriteTime)"
} else {
Write-Output 'ledger jar MISSING'
}
if (Test-Path 'E:\wwwroot\admin\current\index.html') {
Write-Output 'admin current index present'
} else {
Write-Output 'admin current index MISSING'
}
Write-Output 'STATUS_PROBE_DONE'
-7
View File
@@ -1,7 +0,0 @@
Get-Content 'E:\wwwroot\.env' | ForEach-Object {
$line = $_.Trim(); if (-not $line -or $line.StartsWith('#')) { return }
$i = $line.IndexOf('='); if ($i -lt 1) { return }
Set-Item -Path ("Env:" + $line.Substring(0,$i).Trim()) -Value $line.Substring($i+1).Trim().Trim('"')
}
$mysql = 'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe'
& $mysql -h 127.0.0.1 -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" $env:MYSQL_DB -e "DESCRIBE sys_permission; SHOW TABLES LIKE 'inq_%'; SELECT COUNT(*) c FROM inq_ticket;"
-41
View File
@@ -1,41 +0,0 @@
$ErrorActionPreference = 'Continue'
Write-Host '=== listening 8180 ==='
Get-NetTCPConnection -LocalPort 8180 -State Listen -EA SilentlyContinue | Select-Object -First 1 OwningProcess
$java = Get-CimInstance Win32_Process -Filter "Name='java.exe'" | Where-Object { $_.CommandLine -like '*inquiry-new*' } | Select-Object -First 1
if ($java) {
Write-Host ("pid=" + $java.ProcessId)
$cl = $java.CommandLine
if ($cl.Length -gt 200) { $cl = $cl.Substring(0,200) }
Write-Host ("cmd=" + $cl)
}
Write-Host '=== fat jar inquiry/poi ==='
$jarCmd = 'C:\yutongda\tools\jdk8\bin\jar.exe'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
Write-Host ("fat_bytes=" + (Get-Item $Fat).Length)
& $jarCmd tf $Fat | Select-String 'jeecg-module-inquiry|poi-ooxml|commons-io'
Write-Host '=== probe urls ==='
$bodyPath = Join-Path $env:TEMP 'login-body.json'
Set-Content $bodyPath '{"username":"admin","password":"123456","captcha":"","checkKey":""}' -Encoding ASCII
$login = Invoke-RestMethod -Uri 'http://127.0.0.1:8180/jeecgboot/sys/login' -Method POST -InFile $bodyPath -ContentType 'application/json;charset=UTF-8'
$h = @{ 'X-Access-Token' = $login.result.token }
foreach ($u in @(
'http://127.0.0.1:8180/jeecgboot/inquiry/quoteTemplate/list?pageNo=1&pageSize=1',
'http://127.0.0.1:8180/inquiry/quoteTemplate/list?pageNo=1&pageSize=1',
'http://127.0.0.1:8180/jeecgboot/sys/permission/getPermCode'
)) {
try {
$r = Invoke-WebRequest -Uri $u -Headers $h -UseBasicParsing -TimeoutSec 15
Write-Host ("OK " + $u.Split('?')[0].Split('/')[-1] + " status=" + $r.StatusCode + " len=" + $r.RawContentLength)
} catch {
$code = $null
try { $code = [int]$_.Exception.Response.StatusCode } catch {}
Write-Host ("FAIL status=" + $code + " url=" + $u)
}
}
Write-Host '=== stdout mapping quoteTemplate ==='
Select-String -Path 'E:\wwwroot\inquiry-new\logs\stdout.log' -Pattern 'quoteTemplate|InquiryQuoteTemplate|Mapped.*inquiry' | Select-Object -Last 15 | ForEach-Object {
$s = $_.Line
if ($s.Length -gt 220) { $s = $s.Substring(0,220) }
Write-Host $s
}
Write-Host 'DIAG_DONE'
-11
View File
@@ -1,11 +0,0 @@
$ErrorActionPreference = 'Continue'
$jarCmd = 'C:\yutongda\tools\jdk8\bin\jar.exe'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
$Incoming = 'C:\Users\ytd_extdev_0903\incoming'
Write-Host ("fat=" + (Get-Item $Fat).Length)
Get-ChildItem $Incoming -Filter 'jeecg*.jar' | ForEach-Object { Write-Host ("incoming " + $_.Name + " " + $_.Length) }
Write-Host '=== fat libs matching inquiry/poi ==='
& $jarCmd tf $Fat 2>&1 | findstr /i "inquiry poi-ooxml poi-4 commons-io"
Write-Host '=== spring factories / component ==='
& $jarCmd tf $Fat 2>&1 | findstr /i "InquiryQuoteTemplate"
Write-Host 'DIAG2_DONE'
-39
View File
@@ -1,39 +0,0 @@
# 诊断并强制拉起 Nginx
$ErrorActionPreference = "Continue"
Set-Location 'C:\nginx-1.18.0'
Write-Output "=== nginx -t ==="
& .\nginx.exe -t 2>&1 | ForEach-Object { "$_" }
Write-Output "=== who owns 80/443 ==="
netstat -ano | findstr "LISTENING" | findstr ":80 "
netstat -ano | findstr "LISTENING" | findstr ":443 "
Write-Output "=== error.log tail ==="
$err = 'C:\nginx-1.18.0\logs\error.log'
if (Test-Path $err) { Get-Content $err -Tail 40 }
Write-Output "=== service config ==="
sc.exe qc Nginx1.18
sc.exe query Nginx1.18
Write-Output "=== try start with capture ==="
Remove-Item 'C:\nginx-1.18.0\logs\nginx-start.out.txt','C:\nginx-1.18.0\logs\nginx-start.err.txt' -Force -EA SilentlyContinue
$p = Start-Process -FilePath 'C:\nginx-1.18.0\nginx.exe' -WorkingDirectory 'C:\nginx-1.18.0' -PassThru -RedirectStandardOutput 'C:\nginx-1.18.0\logs\nginx-start.out.txt' -RedirectStandardError 'C:\nginx-1.18.0\logs\nginx-start.err.txt' -WindowStyle Hidden
Start-Sleep -Seconds 3
Write-Output "STARTED_PID=$($p.Id) HAS_EXITED=$($p.HasExited)"
if (Test-Path 'C:\nginx-1.18.0\logs\nginx-start.err.txt') { Get-Content 'C:\nginx-1.18.0\logs\nginx-start.err.txt' }
if (Test-Path 'C:\nginx-1.18.0\logs\nginx-start.out.txt') { Get-Content 'C:\nginx-1.18.0\logs\nginx-start.out.txt' }
Get-Process nginx -EA SilentlyContinue | Format-Table Id,Path -AutoSize
Get-Content $err -Tail 20
Write-Output "=== ai.conf root/admin exists? ==="
Test-Path 'E:\wwwroot\admin\dist\index.html'
Select-String -Path 'C:\nginx-1.18.0\myconf\ai.conf' -Pattern 'root |ssl_certificate' | ForEach-Object { $_.Line.Trim() }
Test-Path 'C:\nginx-1.18.0\cert\ai.ytd-scm.com.crt'
Test-Path 'C:\nginx-1.18.0\cert\ai.ytd-scm.com.key'
Write-Output "=== main nginx.conf includes ==="
Select-String -Path 'C:\nginx-1.18.0\conf\nginx.conf' -Pattern 'include|myconf' | ForEach-Object { $_.Line.Trim() }
Write-Output "DIAG_DONE"
-47
View File
@@ -1,47 +0,0 @@
# 诊断 Redis 池;不打印密码明文
$ErrorActionPreference = 'Continue'
$java = Get-CimInstance Win32_Process -Filter "Name='java.exe'" | Where-Object { $_.CommandLine -like '*inquiry-new*' } | Select-Object -First 1
if (-not $java) { Write-Host 'no_ledger_java'; exit 1 }
Write-Host ("pid=" + $java.ProcessId)
foreach ($line in (Get-Content 'E:\wwwroot\.env')) {
$t = $line.Trim()
if (-not $t -or $t.StartsWith('#')) { continue }
$i = $t.IndexOf('=')
if ($i -lt 1) { continue }
$k = $t.Substring(0, $i).Trim()
$v = $t.Substring($i + 1).Trim().Trim('"')
if ($k -match 'REDIS|YTD_REDIS') {
$pref = if ($v.Length -ge 12) { $v.Substring(0,12) + '...' } else { '***' }
Write-Host ("envfile $k len=$($v.Length) prefix=$pref")
}
}
$logDir = 'E:\wwwroot\inquiry-new\logs'
Get-ChildItem $logDir -Filter '*.log' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 2 | ForEach-Object {
Write-Host ("log=$($_.Name) size=$($_.Length)")
Select-String -Path $_.FullName -Pattern 'Could not get a resource from the pool|JedisConnectionException|NOAUTH|WRONGPASS' | Select-Object -Last 6 | ForEach-Object {
$s = $_.Line
if ($s.Length -gt 200) { $s = $s.Substring(0,200) }
Write-Host (" $s")
}
}
$login = Invoke-RestMethod -Uri 'http://127.0.0.1:8180/jeecgboot/sys/login' -Method POST -Body '{"username":"admin","password":"123456","captcha":"","checkKey":""}' -ContentType 'application/json;charset=UTF-8'
$h = @{ 'X-Access-Token' = $login.result.token }
foreach ($u in @(
'http://127.0.0.1:8180/jeecgboot/sys/permission/getPermCode',
'http://127.0.0.1:8180/jeecgboot/inquiry/quoteTemplate/agent/listEnabled',
'http://127.0.0.1:8180/jeecgboot/sys/user/list?pageNo=1&pageSize=1'
)) {
try {
$r = Invoke-WebRequest -Uri $u -Headers $h -UseBasicParsing -TimeoutSec 15
$j = $r.Content | ConvertFrom-Json
$msg = [string]$j.message
if ($msg.Length -gt 60) { $msg = $msg.Substring(0,60) }
Write-Host ("API $($u.Split('?')[0].Split('/')[-1]) success=$($j.success) code=$($j.code) msg=$msg")
} catch {
Write-Host ("API fail $u $($_.Exception.Message)")
}
}
Write-Host 'REDIS_DIAG_DONE'
-58
View File
@@ -1,58 +0,0 @@
# Drop Jeecg demo/sample tables from inquiry_robot; keep sys_*/onl_*/QRTZ_*/jimu_*.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"; $user = "inquiry_robot"; $pass = $null; $db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
if ($db -ne "inquiry_robot") { throw "refuse db=$db" }
$drop = @(
"ceshi_note",
"demo",
"demo_field_def_val_main",
"demo_field_def_val_sub",
"sys_gateway_route",
"test_demo",
"test_enhance_select",
"test_note",
"test_order_customer",
"test_order_main",
"test_order_product",
"test_shoptype_tree",
"test_v3_hello",
"jeecg_monthly_growth_analysis",
"jeecg_order_customer",
"jeecg_order_main",
"jeecg_order_ticket",
"jeecg_project_nature_income",
"joa_demo",
"tmp_report_data_1",
"tmp_report_data_income"
)
$sql = "SET FOREIGN_KEY_CHECKS=0;`n"
foreach ($t in $drop) {
$sql += "DROP TABLE IF EXISTS ``$t``;`n"
}
$sql += "SET FOREIGN_KEY_CHECKS=1;`n"
$sql += "SELECT COUNT(*) AS table_count FROM information_schema.tables WHERE table_schema=DATABASE();`n"
$sqlFile = "E:\wwwroot\ops\sql\_drop_jeecg_demo.sql"
Set-Content $sqlFile -Value $sql -Encoding ascii
$out = & $mysql -h $hostn -P 3306 -u $user "-p$pass" $db -e "source $($sqlFile -replace '\\','/')" 2>&1
$out | ForEach-Object {
if ($_ -match "Warning|password") { return }
"$_"
}
# recount classes
$tables = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
Write-Output ("remaining_total=" + @($tables).Count)
$tables | ForEach-Object { $_ }
Write-Output "CLEAN_OK"
-15
View File
@@ -1,15 +0,0 @@
# Drop leftover report demo tables.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"; $user = "inquiry_robot"; $pass = $null; $db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
$drop = @("rep_demo_dxtj","rep_demo_employee","rep_demo_gongsi","rep_demo_jianpiao")
$sql = "SET FOREIGN_KEY_CHECKS=0; " + (($drop | ForEach-Object { "DROP TABLE IF EXISTS ``$_``;" }) -join " ") + " SET FOREIGN_KEY_CHECKS=1; SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE();"
& $mysql -h $hostn -P 3306 -u $user "-p$pass" $db -e $sql 2>&1 | Where-Object { $_ -notmatch "Warning|password" }
Write-Output "DONE"
-28
View File
@@ -1,28 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Host "=== run-ledger-inner.ps1 ==="
Get-Content "E:\wwwroot\ops\run-ledger-inner.ps1"
Write-Host "=== config redis lines ==="
Get-ChildItem "E:\wwwroot\inquiry-new\config" -Recurse -ErrorAction SilentlyContinue | ForEach-Object { Write-Host ("cfgfile=" + $_.FullName) }
Select-String -Path "E:\wwwroot\inquiry-new\config\*.yml","E:\wwwroot\inquiry-new\config\*.yaml","E:\wwwroot\inquiry-new\config\*.properties" -Pattern "redis" -ErrorAction SilentlyContinue | ForEach-Object { Write-Host ($_.Filename + ":" + $_.LineNumber + ":" + $_.Line.Trim()) }
Write-Host "=== simulate parse lens only ==="
Get-Content "E:\wwwroot\.env" | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith("#")) { return }
$i = $line.IndexOf("=")
if ($i -lt 1) { return }
Set-Item -Path ("Env:" + $line.Substring(0, $i).Trim()) -Value $line.Substring($i + 1).Trim().Trim('"')
}
Write-Host ("from_env user=" + $env:YTD_REDIS_USERNAME + " user_len=" + $env:YTD_REDIS_USERNAME.Length)
Write-Host ("url_len=" + $env:REDIS_URL.Length)
if ($env:REDIS_URL -match "redis://:([^@]+)@([^:/]+)(?::(\d+))?(?:/(\d+))?") {
Write-Host ("form=pass_only host=" + $Matches[2] + " pw_len=" + $Matches[1].Length)
} elseif ($env:REDIS_URL -match "redis://([^:/@]+):([^@]+)@([^:/]+)(?::(\d+))?(?:/(\d+))?") {
Write-Host ("form=user_pass user=" + $Matches[1] + " user_len=" + $Matches[1].Length + " pw_len=" + $Matches[2].Length + " host=" + $Matches[3] + " port=" + $Matches[4] + " db=" + $Matches[5])
} else {
Write-Host "NO_MATCH"
# show sanitized url structure
$u = $env:REDIS_URL
$safe = $u -replace "://[^@]+@", "://***:***@"
Write-Host ("url_safe=" + $safe)
}
Write-Host "DUMP_DONE"
-28
View File
@@ -1,28 +0,0 @@
$ErrorActionPreference = 'Continue'
$candidates = @(
'E:\wwwroot\tools\apache-maven-3.9.9\bin\mvn.cmd',
'C:\yutongda\tools\apache-maven-3.9.9\bin\mvn.cmd',
'C:\Program Files\Apache\maven\bin\mvn.cmd'
)
foreach ($c in $candidates) {
if (Test-Path $c) {
Write-Host "FOUND=$c"
& $c -v
exit 0
}
}
Write-Host 'NO_LOCAL_MAVEN'
# install under E:\wwwroot\tools
$tools = 'E:\wwwroot\tools'
New-Item -ItemType Directory -Force -Path $tools | Out-Null
$mvnHome = Join-Path $tools 'apache-maven-3.9.9'
$mvnCmd = Join-Path $mvnHome 'bin\mvn.cmd'
if (Test-Path $mvnCmd) { Write-Host "FOUND=$mvnCmd"; & $mvnCmd -v; exit 0 }
$zip = Join-Path $tools 'apache-maven-3.9.9-bin.zip'
$url2 = 'https://archive.apache.org/dist/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip'
Write-Host 'downloading maven on remote...'
Invoke-WebRequest -Uri $url2 -OutFile $zip -UseBasicParsing
Expand-Archive -Path $zip -DestinationPath $tools -Force
if (-not (Test-Path $mvnCmd)) { throw 'maven extract failed' }
Write-Host "FOUND=$mvnCmd"
& $mvnCmd -v
-52
View File
@@ -1,52 +0,0 @@
# Diagnose E:\wwwroot\.env encoding without printing secret values
$ErrorActionPreference = 'Stop'
$path = 'E:\wwwroot\.env'
$bytes = [System.IO.File]::ReadAllBytes($path)
Write-Output ("bytes=" + $bytes.Length)
Write-Output ("bom_utf8=" + ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191))
Write-Output ("bom_utf16le=" + ($bytes.Length -ge 2 -and $bytes[0] -eq 255 -and $bytes[1] -eq 254))
function Show-Head([string]$label, [string]$text) {
$lines = $text -split "`r?`n" | Select-Object -First 8
Write-Output ("=== " + $label + " ===")
foreach ($line in $lines) {
if ($line -match '^(#|YTD_ENV=|PUBLIC_BASE_URL=|WECOM_CALLBACK_REPLY_TEXT=)') {
if ($line -match '^WECOM_CALLBACK_REPLY_TEXT=') {
$v = $line.Substring($line.IndexOf('=') + 1)
Write-Output ("WECOM_CALLBACK_REPLY_TEXT len=" + $v.Length + " sample=" + $v.Substring(0, [Math]::Min(24, $v.Length)))
} else {
Write-Output $line
}
} elseif ($line -match '^[A-Z0-9_]+=') {
$k = $line.Substring(0, $line.IndexOf('='))
Write-Output ($k + "=***")
} else {
Write-Output $line
}
}
}
$utf8 = [System.Text.Encoding]::UTF8.GetString($bytes)
Show-Head 'as_utf8' $utf8
$gbk = [System.Text.Encoding]::GetEncoding(936).GetString($bytes)
Show-Head 'as_gbk' $gbk
# try: utf8 mis-decoded as gbk then saved as utf8 -> recover by encode gbk getbytes then utf8 getstring
try {
$rec1 = [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(936).GetBytes($utf8))
Show-Head 'recover_utf8_via_gbk_bytes' $rec1
} catch {
Write-Output 'recover1_fail'
}
# try: latin1/cp1252 roundtrip
try {
$latin = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
$rec2 = [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(1252).GetBytes($latin))
Show-Head 'recover_cp1252_to_utf8' $rec2
} catch {
Write-Output 'recover2_fail'
}
Write-Output 'ENV_DIAG_DONE'
-16
View File
@@ -1,16 +0,0 @@
Write-Output "=== layout ==="
Test-Path "E:\wwwroot\ops\active-release.json"
Test-Path "C:\ytd-test"
Get-ChildItem "C:\" -Directory | Where-Object { $_.Name -like "ytd-test*" } | Select-Object Name
Get-Content "E:\wwwroot\ops\active-release.json"
Write-Output "=== agent cwd ==="
$p = (Get-NetTCPConnection -LocalPort 8910 -State Listen -EA SilentlyContinue | Select-Object -First 1).OwningProcess
if ($p) {
Get-CimInstance Win32_Process -Filter "ProcessId=$p" | Select-Object ProcessId, ExecutablePath, CommandLine | Format-List
}
Write-Output "=== ports ==="
foreach ($x in 8910,8080,8810,8180,8913) {
$c = Get-NetTCPConnection -LocalPort $x -State Listen -EA SilentlyContinue | Select-Object -First 1
if ($c) { "$x LISTEN pid=$($c.OwningProcess)" } else { "$x down" }
}
Write-Output "FINAL_OK"
-20
View File
@@ -1,20 +0,0 @@
$ErrorActionPreference = "Continue"
Select-String -Path "E:\wwwroot\inquiry-new\logs\stdout.log" -Pattern "redis_mode=" | Select-Object -Last 2 | ForEach-Object { Write-Host $_.Line }
$bodyPath = Join-Path $env:TEMP "login-body.json"
Set-Content -Path $bodyPath -Value '{"username":"admin","password":"123456","captcha":"","checkKey":""}' -Encoding ASCII
$login = Invoke-RestMethod -Uri "http://127.0.0.1:8180/jeecgboot/sys/login" -Method POST -InFile $bodyPath -ContentType "application/json;charset=UTF-8"
$h = @{ "X-Access-Token" = $login.result.token }
$a = Invoke-RestMethod -Uri "http://127.0.0.1:8180/jeecgboot/inquiry/quoteTemplate/agent/listEnabled" -Headers $h
Write-Host ("agent_enabled=" + @($a.result).Count + " login_captcha_ok=" + $login.success)
# agent process?
$agent = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and ($_.CommandLine -like '*inquiry-agent*' -or $_.CommandLine -like '*uvicorn*' -or $_.CommandLine -like '*8910*') } | Select-Object -First 5
if ($agent) { $agent | ForEach-Object { Write-Host ("proc pid=" + $_.ProcessId + " " + $_.CommandLine.Substring(0,[Math]::Min(120,$_.CommandLine.Length))) } }
else { Write-Host "agent_proc_not_found_in_wmi_sample" }
# health if any
foreach ($u in @("http://127.0.0.1:8910/health","http://127.0.0.1:8810/health","http://127.0.0.1:8910/")) {
try {
$r = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 3
Write-Host ("health " + $u + " " + $r.StatusCode)
} catch { Write-Host ("health " + $u + " fail") }
}
Write-Host "FINAL_SMOKE_DONE"
-19
View File
@@ -1,19 +0,0 @@
$ErrorActionPreference = "Continue"
$Dest = "E:\wwwroot\tools\jdk-17"
$java = "$Dest\bin\java.exe"
New-Item -ItemType Directory -Force -Path "E:\wwwroot\tools","E:\wwwroot\ops" | Out-Null
@(
"@echo off",
"set JAVA_HOME=$Dest",
"set PATH=%JAVA_HOME%\bin;%PATH%"
) | Set-Content -Path "E:\wwwroot\tools\use-jdk17.cmd" -Encoding ASCII
"{`"vendor`":`"Microsoft OpenJDK`",`"version`":`"17.0.16`",`"home`":`"E:\\wwwroot\\tools\\jdk-17`",`"javaExe`":`"E:\\wwwroot\\tools\\jdk-17\\bin\\java.exe`"}" | Set-Content "E:\wwwroot\ops\jdk17.json" -Encoding ASCII
try {
[Environment]::SetEnvironmentVariable("JDK17_HOME", $Dest, "User")
[Environment]::SetEnvironmentVariable("JAVA17_HOME", $Dest, "User")
"USER_ENV_SET"
} catch {
"USER_ENV_FAIL=$_"
}
cmd /c "`"$java`" -version"
"FINAL_OK"
-43
View File
@@ -1,43 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== search mysql/postgres root hints (filenames + key names only) ==="
Get-ChildItem "C:\yutongda\secure","C:\yutongda\config","C:\yutongda\ops" -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match 'mysql|postgres|root|dba|admin|credential|pass' } |
Select-Object -ExpandProperty FullName
Write-Output "=== try pg superuser with pgpass.txt against data host ==="
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
$raw = (Get-Content "C:\yutongda\secure\pgpass.txt" -Raw).Trim()
# pgpass may be plain password or host:port:db:user:pass
$pgPass = $raw
$pgUser = "postgres"
if ($raw -match ':') {
$parts = $raw -split ':'
if ($parts.Length -ge 5) {
$pgUser = $parts[3]
$pgPass = $parts[4]
"pgpass_format=libpq parts_user=$pgUser"
} else {
"pgpass_format=colon_but_not_5"
}
} else {
"pgpass_format=plain_password"
}
$env:PGPASSWORD = $pgPass
$env:PGCONNECT_TIMEOUT = "8"
& $psql -h 10.206.0.14 -p 5432 -U $pgUser -d postgres -c "SELECT current_user, rolsuper FROM pg_roles WHERE rolname = current_user;" 2>&1 | ForEach-Object { "$_" }
Write-Output "=== redis old cli auth ==="
$redisCred = Get-Content "C:\yutongda\secure\redis-credentials.json" -Raw | ConvertFrom-Json
$rcli = "C:\yutongda\tools\redis-5.0.14.1\redis-cli.exe"
# try AUTH after -a only
$env:REDISCLI_AUTH = $redisCred.application_password
& $rcli -h $redisCred.host -p $redisCred.port -a $redisCred.application_password -n 1 --no-auth-warning PING 2>&1 | ForEach-Object { if ($_ -notmatch 'Warning') { "app=$($_)" } }
& $rcli -h $redisCred.host -p $redisCred.port -a $redisCred.operations_password -n 1 --no-auth-warning PING 2>&1 | ForEach-Object { if ($_ -notmatch 'Warning') { "ops=$($_)" } }
Write-Output "=== minio root bucket list via python urllib? ==="
# just check endpoint responds
curl.exe -s -o NUL -w "minio_http=%{http_code}" http://127.0.0.1:9000/minio/health/live
Write-Output ""
curl.exe -s -o NUL -w "minio_console=%{http_code}" http://127.0.0.1:9001/
Write-Output ""
Write-Output "SEARCH_DONE"
-58
View File
@@ -1,58 +0,0 @@
# Find any DBA/admin secrets usable on 10.206.0.14; never print values.
$ErrorActionPreference = "Continue"
Write-Output "=== candidate secret files ==="
$paths = @(
"E:\wwwroot\ops\admin-secrets.env",
"E:\wwwroot\ops\*root*",
"E:\wwwroot\ops\*admin*",
"C:\yutongda\secure\*",
"C:\yutongda\config\*mysql*",
"C:\yutongda\config\*db*",
"C:\yutongda\config\*postgres*",
"C:\yutongda\config\*pgsql*"
)
foreach ($p in $paths) {
Get-ChildItem $p -EA SilentlyContinue | ForEach-Object { $_.FullName }
}
Write-Output "=== key names in env-like files ==="
$files = @(
"E:\wwwroot\ops\admin-secrets.env",
"C:\yutongda\secure\e2e-business-20260826-205407.env",
"C:\yutongda\config\minio.env"
)
Get-ChildItem "C:\yutongda\secure" -File -EA SilentlyContinue | ForEach-Object { $files += $_.FullName }
Get-ChildItem "E:\wwwroot\ops" -File -EA SilentlyContinue | Where-Object { $_.Extension -match '\.(env|json|txt)$' } | ForEach-Object { $files += $_.FullName }
foreach ($f in ($files | Select-Object -Unique)) {
if (-not (Test-Path $f)) { continue }
Write-Output ("FILE=" + $f)
if ($f -match '\.json$') {
try {
$j = Get-Content $f -Raw | ConvertFrom-Json
foreach ($p in $j.PSObject.Properties) {
$len = if ($p.Value -is [string]) { $p.Value.Length } else { "-" }
Write-Output (" key=" + $p.Name + " len=" + $len)
}
} catch { Write-Output " json_parse_fail" }
} else {
Get-Content $f -EA SilentlyContinue | ForEach-Object {
if ($_ -match '^\s*#' -or $_ -notmatch '=') { return }
$k = ($_ -split '=',2)[0].Trim()
$v = ($_ -split '=',2)[1]
if ($k -match '(?i)pass|secret|pwd|token|key') {
Write-Output (" key=" + $k + " len=" + $v.Trim().Length)
} else {
Write-Output (" key=" + $k + " val=" + $v.Trim())
}
}
}
}
Write-Output "=== sql ready? ==="
Get-ChildItem "E:\wwwroot\ops\sql" -EA SilentlyContinue | ForEach-Object { $_.Name + " " + $_.Length }
Write-Output "=== ssh to 10.206.0.14? ==="
ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new ytd_extdev_0903@10.206.0.14 "echo ssh_ok & hostname" 2>&1 | Select-Object -First 5
Write-Output "DONE"
-13
View File
@@ -1,13 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== my.ini (no password lines expected) ==="
Get-Content "C:\yutongda\tools\mysql-8.0.39-winx64\my.ini" | ForEach-Object {
if ($_ -match 'password') { 'REDACTED' } else { $_ }
}
Write-Output "=== search mysql root/pass in ops/tools ==="
Get-ChildItem "C:\yutongda\ops","C:\yutongda\tools","C:\yutongda\incoming" -Recurse -Include *.ps1,*.cmd,*.bat,*.env,*.txt,*.md -EA SilentlyContinue -Depth 3 |
Select-String -Pattern "mysqld|mysql.*root|MYSQL_ROOT|--initialize" -EA SilentlyContinue |
Select-Object -First 40 @{n='F';e={$_.Filename}}, LineNumber, @{n='L';e={
$t=$_.Line.Trim()
if ($t -match 'password|passwd|pwd\s*=') { 'REDACTED' } else { $t.Substring(0,[Math]::Min(140,$t.Length)) }
}}
Write-Output "SEARCH_DONE"
-18
View File
@@ -1,18 +0,0 @@
# Find who locks old agent release dirs
$ErrorActionPreference = 'Continue'
Write-Output '=== processes mentioning releases ==='
Get-CimInstance Win32_Process | ForEach-Object {
$cl = $_.CommandLine
if ($cl -and ($cl -like '*agent\\releases*' -or $cl -like '*agent/releases*' -or $cl -like '*wwwroot*agent*')) {
Write-Output ("pid=$($_.ProcessId) name=$($_.Name)")
Write-Output (" " + $cl.Substring(0, [Math]::Min(300, $cl.Length)))
}
}
Write-Output '=== netstat 8910 owner tree ==='
$p = (Get-NetTCPConnection -LocalPort 8910 -State Listen -EA SilentlyContinue | Select-Object -First 1).OwningProcess
if ($p) {
$proc = Get-CimInstance Win32_Process -Filter "ProcessId=$p"
Write-Output ("listen_pid=$p parent=$($proc.ParentProcessId)")
Write-Output ($proc.CommandLine)
}
Write-Output 'LOCKERS_DONE'
-9
View File
@@ -1,9 +0,0 @@
$ErrorActionPreference = "Continue"
Write-Output "=== secure files ==="
cmd /c "dir /b C:\yutongda\secure"
Write-Output "=== find minio.env ==="
cmd /c "dir /s /b C:\yutongda\minio.env C:\yutongda\*minio* 2>nul"
Get-ChildItem -Path C:\yutongda -Filter "minio*.env" -Recurse -ErrorAction SilentlyContinue -Depth 6 | Select-Object FullName
Write-Output "=== find mc.exe ==="
Get-ChildItem -Path C:\yutongda,C:\ -Filter "mc.exe" -Recurse -ErrorAction SilentlyContinue -Depth 4 | Select-Object -First 5 FullName
Write-Output "LIST_DONE"
-21
View File
@@ -1,21 +0,0 @@
# 只读:找 C:\ytd-test 硬编码路径与相关任务
$ErrorActionPreference = "Continue"
Write-Output "=== grep ytd-test under tree ==="
Get-ChildItem 'C:\ytd-test' -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.Extension -match '\.(cmd|ps1|json|env|bat|txt|md)$' -or $_.Name -eq '.env' } |
ForEach-Object {
$hits = Select-String -Path $_.FullName -Pattern 'C:\\ytd-test|C:/ytd-test' -SimpleMatch:$false -ErrorAction SilentlyContinue
if ($hits) {
Write-Output $_.FullName
$hits | ForEach-Object { " L$($_.LineNumber): $($_.Line.Trim())" }
}
}
Write-Output "=== task actions ==="
foreach ($n in @('WinAgentKeepAlive','SpaceAgentTask','YTD-Inquiry-Agent','YTD-WeCom-Callback')) {
$t = Get-ScheduledTask -TaskName $n -ErrorAction SilentlyContinue
if (-not $t) { continue }
Write-Output "---- $n state=$($t.State) ----"
$t.Actions | ForEach-Object { "Exec=$($_.Execute) Args=$($_.Arguments) Work=$($_.WorkingDirectory)" }
}
Write-Output "=== E wwwroot empty? ==="
(Get-ChildItem 'E:\wwwroot' -Force | Measure-Object).Count
-54
View File
@@ -1,54 +0,0 @@
$ErrorActionPreference = "Continue"
# prod java parent / cmdline full redis-related flags (mask password values)
$prod = Get-CimInstance Win32_Process -Filter "Name='java.exe'" | Where-Object { $_.CommandLine -like '*server.port=8080*' } | Select-Object -First 1
if ($prod) {
$cl = $prod.CommandLine
Write-Host ("prod_pid=" + $prod.ProcessId)
# mask --spring.redis.password=...
$masked = [regex]::Replace($cl, "(--spring\.redis\.password=)(\S+)", '${1}***')
$masked = [regex]::Replace($masked, "(password=)([^,\s]+)", '${1}***')
Write-Host ("prod_cmd_len=" + $cl.Length)
# extract redis-related tokens
$tokens = $cl.Split(" ") | Where-Object { $_ -match "redis|REDIS|YTD_REDIS" }
foreach ($t in $tokens) {
$m = $t
if ($m -match "password=") { $m = ($m -replace "(=).+","=`$1***") }
Write-Host (" token=" + $m)
}
}
# agent short redis url
$agentEnv = "C:\yutongda\apps\inquiry-agent\.env"
if (Test-Path $agentEnv) {
Get-Content $agentEnv | ForEach-Object {
if ($_ -match "REDIS") {
$line = $_
if ($line -match "REDIS_URL=(.+)") {
$u = $Matches[1].Trim().Trim('"')
$safe = $u -replace "://[^@]+@", "://***@"
if ($safe -eq $u -and $u.Length -gt 20) { $safe = $u.Substring(0,12) + "...(len=" + $u.Length + ")" }
Write-Host ("agent_REDIS_URL_safe=" + $safe + " len=" + $u.Length)
} else {
Write-Host ("agent_" + $line)
}
}
}
}
# Try AUTH without username using password from URL via System.Uri
$www = Get-Content "E:\wwwroot\.env" | Where-Object { $_ -match "^REDIS_URL=" }
$url = ($www -replace "^REDIS_URL=","").Trim().Trim('"')
try {
# redis URL is not always valid System.Uri because of scheme; hack
$tmp = $url -replace "^redis://","http://"
$uri = [Uri]$tmp
Write-Host ("uri_userinfo_len=" + $uri.UserInfo.Length + " host=" + $uri.Host + " port=" + $uri.Port)
$ui = $uri.UserInfo
$up = $ui.Split(":",2)
Write-Host ("uri_user=" + $up[0] + " uri_pw_len=" + $up[1].Length)
} catch {
Write-Host ("uri_err=" + $_.Exception.Message)
}
# Does empty username + password work? Check lettuce docs - try starting a one-off with only password
# Use jedis from a small java snippet if jdk present
$java = "C:\yutongda\tools\jdk8\bin\java.exe"
Write-Host ("java_exists=" + (Test-Path $java))
Write-Host "FIND_DONE"
-36
View File
@@ -1,36 +0,0 @@
# 远端:确认 8180/8910/8080,然后执行 admin cutover(依赖已上传的 admin-dist.zip)
$ErrorActionPreference = 'Continue'
function Port-Up([int]$p) {
return [bool](Get-NetTCPConnection -LocalPort $p -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1)
}
Write-Output ("8180=" + (Port-Up 8180))
Write-Output ("8910=" + (Port-Up 8910))
Write-Output ("8080=" + (Port-Up 8080))
Write-Output ("zip=" + (Test-Path 'C:\Users\ytd_extdev_0903\incoming\admin-dist.zip'))
Write-Output ("conf=" + (Test-Path 'C:\Users\ytd_extdev_0903\incoming\ai.conf.cutover-8180'))
if (-not (Port-Up 8180)) {
Write-Output 'START_LEDGER'
& powershell -NoProfile -ExecutionPolicy Bypass -File 'C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1'
}
if (-not (Port-Up 8910)) {
Write-Output 'START_AGENT'
& powershell -NoProfile -ExecutionPolicy Bypass -File 'C:\Users\ytd_extdev_0903\incoming\_remote_safe_deploy_agent.ps1'
}
# 再等一会儿 8180
for ($i = 0; $i -lt 24; $i++) {
if (Port-Up 8180) { break }
Start-Sleep -Seconds 5
}
Write-Output ("8180_final=" + (Port-Up 8180))
Write-Output ("8910_final=" + (Port-Up 8910))
Write-Output ("8080_final=" + (Port-Up 8080))
if (-not (Port-Up 8180)) { throw '8180 still down' }
if (-not (Port-Up 8910)) { throw '8910 still down' }
if (-not (Port-Up 8080)) { throw '8080 still down' }
$ErrorActionPreference = 'Stop'
& powershell -NoProfile -ExecutionPolicy Bypass -File 'C:\Users\ytd_extdev_0903\incoming\_remote_cutover_admin_8180.ps1'
Write-Output 'ALL_DONE'
-80
View File
@@ -1,80 +0,0 @@
# Step1: verify/fix local MySQL root + create inquiry_robot; smoke 127 and intranet.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$ops = "E:\wwwroot\ops"
$sec = Get-Content "$ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json
$mysqlPass = [string]$sec.mysql_password
$intranet = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -like '10.*' } | Select-Object -First 1 -ExpandProperty IPAddress)
Write-Output ("intranet=" + $intranet)
function Mysql-Ok([string]$h, [string]$u, [string]$p, [string]$db) {
$a = New-Object System.Collections.Generic.List[string]
[void]$a.Add("-h$h"); [void]$a.Add("-P3306"); [void]$a.Add("-u$u"); [void]$a.Add("-p$p")
[void]$a.Add("--connect-timeout=8"); [void]$a.Add("--batch"); [void]$a.Add("-N")
if ($db) { [void]$a.Add($db) }
[void]$a.Add("-e"); [void]$a.Add("SELECT 1")
$out = & $mysql $a.ToArray() 2>&1
$text = ($out | ForEach-Object {"$_"}) -join "`n"
if ($text -match "ERROR") { return $false }
$lines = $out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
return ($lines -contains "1")
}
$rootPass = $null
$sources = @()
if (Test-Path "$ops\local_mysql_root_secret.json") {
$sources += ,[pscustomobject]@{n="json"; p=[string](Get-Content "$ops\local_mysql_root_secret.json" -Raw | ConvertFrom-Json).root_password}
}
if (Test-Path "$ops\.mysql_root_stash.tmp") {
$sources += ,[pscustomobject]@{n="stash"; p=(Get-Content "$ops\.mysql_root_stash.tmp" -Raw).Trim()}
}
foreach ($s in $sources) {
Write-Output ("try_root src=$($s.n) len=$($s.p.Length)")
if (Mysql-Ok "127.0.0.1" "root" $s.p $null) {
$rootPass = $s.p
Write-Output "ROOT_OK_127"
break
}
if (Mysql-Ok "localhost" "root" $s.p $null) {
$rootPass = $s.p
Write-Output "ROOT_OK_LOCALHOST"
break
}
}
if (-not $rootPass) {
Write-Output "ROOT_FAIL; check service and redo skip-grant"
Get-Service YTD-MySQL | Format-List Name,Status | Out-String | Write-Output
# show bind
Select-String -Path "C:\yutongda\tools\mysql-8.0.39-winx64\my.ini" -Pattern "bind-address|port=" | ForEach-Object { $_.Line }
exit 2
}
$sql = @"
CREATE DATABASE IF NOT EXISTS ``inquiry_robot`` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'$intranet' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'localhost' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'127.0.0.1' IDENTIFIED BY '$mysqlPass';
ALTER USER 'inquiry_robot'@'$intranet' IDENTIFIED BY '$mysqlPass';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'%';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'localhost';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'127.0.0.1';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'$intranet';
FLUSH PRIVILEGES;
SELECT 'mysql_ok' AS s;
"@
$sqlPath = "$ops\sql\_run_ir_mysql.sql"
Set-Content $sqlPath -Value $sql -Encoding ascii
$o = & $mysql -h127.0.0.1 -P3306 -uroot "-p$rootPass" -e "source $($sqlPath -replace '\\','/')" 2>&1 | Out-String
Write-Output (($o -split "`r?`n" | Where-Object { $_ -notmatch "password|IDENTIFIED" }) -join "`n")
Remove-Item $sqlPath -Force -EA SilentlyContinue
if ($o -notmatch "mysql_ok") { exit 3 }
Write-Output ("smoke127=" + (Mysql-Ok "127.0.0.1" "inquiry_robot" $mysqlPass "inquiry_robot"))
Write-Output ("smokeIntranet=" + (Mysql-Ok $intranet "inquiry_robot" $mysqlPass "inquiry_robot"))
Write-Output "MYSQL_STEP_DONE"
-85
View File
@@ -1,85 +0,0 @@
# ASCII-only script: rewrite .env as UTF-8 BOM; Chinese via unicode escapes
$ErrorActionPreference = 'Stop'
$path = 'E:\wwwroot\.env'
$bak = 'E:\wwwroot\.env.bak-encoding-' + (Get-Date -Format 'yyyyMMdd-HHmmss')
Copy-Item $path $bak -Force
Write-Output ('backup=' + $bak)
function U([string]$escaped) {
return [System.Text.RegularExpressions.Regex]::Unescape($escaped)
}
$utf8BomEnc = New-Object System.Text.UTF8Encoding $true
$raw = [System.IO.File]::ReadAllText($path, $utf8BomEnc)
$map = [ordered]@{}
foreach ($line in ($raw -split "`r?`n")) {
$t = $line.Trim()
if (-not $t -or $t.StartsWith('#')) { continue }
$i = $t.IndexOf('=')
if ($i -lt 1) { continue }
$k = $t.Substring(0, $i).Trim()
$v = $t.Substring($i + 1)
if (-not $map.Contains($k)) { $map[$k] = $v }
}
# "询价智能体接通成功。已收到:{content}"
$goodReply = U '\u8be2\u4ef7\u667a\u80fd\u4f53\u63a5\u901a\u6210\u529f\u3002\u5df2\u6536\u5230\uff1a{content}'
$needFix = $true
if ($map.Contains('WECOM_CALLBACK_REPLY_TEXT')) {
$rt = [string]$map['WECOM_CALLBACK_REPLY_TEXT']
if ($rt -match '\{content\}' -and $rt.Contains([char]0x8BE2) -and $rt.Contains([char]0x4EF7)) {
$needFix = $false
}
}
if ($needFix) {
$map['WECOM_CALLBACK_REPLY_TEXT'] = $goodReply
Write-Output 'fixed_reply_text'
}
function V([string]$k, [string]$default = '') {
if ($map.Contains($k)) { return [string]$map[$k] }
return $default
}
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add((U '# \u53cb\u901a\u8fbe\u8be2\u4ef7\u667a\u80fd\u4f53 \u00b7 \u73af\u5883\u53d8\u91cf\uff08\u670d\u52a1\u5668 E:\\wwwroot\\.env\uff09'))
$lines.Add((U '# \u7f16\u7801\uff1aUTF-8\uff08\u5e26 BOM\uff0c\u4fbf\u4e8e\u8bb0\u4e8b\u672c\u6b63\u786e\u6253\u5f00\uff09\u3002\u7981\u6b62\u63d0\u4ea4 Git\u3002'))
$lines.Add((U '# \u5bf9\u7167\uff1aprompt/13-\u73af\u5883\u5bf9\u7167.md'))
$lines.Add('')
$lines.Add('YTD_ENV=' + (V 'YTD_ENV' 'test'))
$lines.Add('')
$lines.Add((U '# \u516c\u7f51\u4e0e\u4f01\u5fae\uff08\u57df\u540d\u4e0e\u6b63\u5f0f\u76f8\u540c\uff09'))
$lines.Add('PUBLIC_BASE_URL=' + (V 'PUBLIC_BASE_URL'))
$lines.Add('WECOM_CALLBACK_URL=' + (V 'WECOM_CALLBACK_URL'))
$lines.Add('INQUIRY_FORM_PUBLIC_BASE_URL=' + (V 'INQUIRY_FORM_PUBLIC_BASE_URL'))
$lines.Add('WECOM_CORP_ID=' + (V 'WECOM_CORP_ID'))
$lines.Add('WECOM_AGENT_ID=' + (V 'WECOM_AGENT_ID'))
$lines.Add('WECOM_SECRET=' + (V 'WECOM_SECRET'))
$lines.Add('WECOM_CALLBACK_TOKEN=' + (V 'WECOM_CALLBACK_TOKEN'))
$lines.Add('WECOM_ENCODING_AES_KEY=' + (V 'WECOM_ENCODING_AES_KEY'))
$lines.Add('WECOM_CALLBACK_REPLY_TEXT=' + (V 'WECOM_CALLBACK_REPLY_TEXT' $goodReply))
$lines.Add('WECOM_OPS_AGENT_ID=' + (V 'WECOM_OPS_AGENT_ID'))
$lines.Add('DEV_INJECT_ENABLED=' + (V 'DEV_INJECT_ENABLED' 'false'))
$lines.Add('')
$lines.Add((U '# \u5176\u4f59\u914d\u7f6e\uff08\u7aef\u53e3 / \u5e93 / Redis / \u6a21\u578b\u7b49\uff09'))
$written = @(
'YTD_ENV','PUBLIC_BASE_URL','WECOM_CALLBACK_URL','INQUIRY_FORM_PUBLIC_BASE_URL',
'WECOM_CORP_ID','WECOM_AGENT_ID','WECOM_SECRET','WECOM_CALLBACK_TOKEN',
'WECOM_ENCODING_AES_KEY','WECOM_CALLBACK_REPLY_TEXT','WECOM_OPS_AGENT_ID','DEV_INJECT_ENABLED'
)
foreach ($k in $map.Keys) {
if ($written -contains $k) { continue }
$lines.Add($k + '=' + $map[$k])
}
$text = [string]::Join("`r`n", $lines.ToArray()) + "`r`n"
[System.IO.File]::WriteAllText($path, $text, $utf8BomEnc)
$check = [System.IO.File]::ReadAllText($path, $utf8BomEnc)
$first = ($check -split "`r?`n")[0]
Write-Output ('first_line=' + $first)
Write-Output ('keys=' + $map.Count)
Write-Output ('reply_has_cn=' + ($check.Contains([char]0x8BE2) -and $check.Contains('{content}')))
Write-Output 'ENV_REWRITE_OK'
-50
View File
@@ -1,50 +0,0 @@
$ErrorActionPreference = "Stop"
$Incoming = "C:\Users\ytd_extdev_0903\incoming\ai.conf.cutover-8910"
$Ai = "C:\nginx-1.18.0\myconf\ai.conf"
$Stamp = Get-Date -Format "yyyyMMdd-HHmmss"
if (-not (Test-Path $Incoming)) { throw "missing incoming conf" }
Copy-Item $Ai "$Ai.bak-before-ascii-$Stamp" -Force
$bytes = [System.IO.File]::ReadAllBytes($Incoming)
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) {
$list = New-Object System.Collections.Generic.List[byte]
for ($i = 3; $i -lt $bytes.Length; $i++) { [void]$list.Add($bytes[$i]) }
$bytes = $list.ToArray()
}
[System.IO.File]::WriteAllBytes($Ai, $bytes)
Write-Output "WROTE_AI_CONF_NO_BOM"
Set-Location "C:\nginx-1.18.0"
& .\nginx.exe -t
if ($LASTEXITCODE -ne 0) { throw "nginx -t failed" }
Get-Process nginx -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
$started = $false
try {
Start-Service Nginx1.18 -ErrorAction Stop
Start-Sleep -Seconds 2
if ((Get-Service Nginx1.18).Status -eq "Running") {
$started = $true
Write-Output "SERVICE_RUNNING"
}
} catch {
Write-Output "SERVICE_FAIL"
}
if (-not $started) {
Start-Process -FilePath "C:\nginx-1.18.0\nginx.exe" -WorkingDirectory "C:\nginx-1.18.0" -WindowStyle Hidden
Start-Sleep -Seconds 2
if (-not (Get-Process nginx -ErrorAction SilentlyContinue)) { throw "nginx still not running" }
Write-Output "EXE_RUNNING"
}
Get-Service Nginx1.18 | Format-List Name, Status
Get-Process nginx | Select-Object Id | Format-Table -AutoSize
cmd /c "curl.exe -sk -H `"Host: ai.ytd-scm.com`" https://127.0.0.1/agent/health"
Write-Output ""
cmd /c "curl.exe -sk -o NUL -w root:%{http_code} -H `"Host: ai.ytd-scm.com`" https://127.0.0.1/"
Write-Output ""
Write-Output "NGINX_FIXED"
-17
View File
@@ -1,17 +0,0 @@
# Fix active-release pointer after admin cutover (ASCII only)
$ErrorActionPreference = 'Stop'
New-Item -ItemType Directory -Force -Path 'E:\wwwroot\ops' | Out-Null
$obj = [ordered]@{
root = 'E:\wwwroot'
releaseId = 'admin-20260913-154002'
adminCurrent = 'E:\wwwroot\admin\current'
adminRelease = 'E:\wwwroot\admin\releases\admin-20260913-154002\dist'
agentCurrent = 'E:\wwwroot\agent\current'
agentHome = 'E:\wwwroot\agent\releases\agent-20260913-143916\agent'
jeecgbootProxy = 'http://127.0.0.1:8180/jeecgboot/'
updatedAt = (Get-Date).ToString('o')
note = 'admin cutover Jeecg Vue + ledger 8180'
}
($obj | ConvertTo-Json) | Out-File -FilePath 'E:\wwwroot\ops\active-release.json' -Encoding utf8
Get-Content 'E:\wwwroot\ops\active-release.json'
Write-Output 'POINTER_OK'
-34
View File
@@ -1,34 +0,0 @@
# Force remove stale agent releases (not current)
$ErrorActionPreference = 'Continue'
$keepName = 'agent-20260913-210940'
Get-ChildItem 'E:\wwwroot\agent\releases' | Where-Object { $_.PSIsContainer } | ForEach-Object {
$name = $_.Name
$full = $_.FullName
if ($name -eq $keepName) {
Write-Output ('KEEP ' + $name)
return
}
Write-Output ('CLEAN ' + $name)
Get-CimInstance Win32_Process | ForEach-Object {
$cl = $_.CommandLine
if ($cl -and $cl.Contains($full)) {
Write-Output ('kill pid=' + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 1
cmd /c ("rmdir /s /q `"$full`"") | Out-Null
if (Test-Path $full) {
try {
Remove-Item $full -Recurse -Force -ErrorAction Stop
Write-Output ('REMOVED_PS ' + $name)
} catch {
Write-Output ('FAIL ' + $name + ' ' + $_.Exception.Message)
}
} else {
Write-Output ('REMOVED ' + $name)
}
}
Write-Output '=== left ==='
Get-ChildItem 'E:\wwwroot\agent\releases' | ForEach-Object { $_.Name }
Write-Output 'FORCE_CLEAN_OK'
-104
View File
@@ -1,104 +0,0 @@
# Force true UTF-8 body (not GBK) with BOM; ASCII-only script
$ErrorActionPreference = 'Stop'
$path = 'E:\wwwroot\.env'
$bak = 'E:\wwwroot\.env.bak-encoding2-' + (Get-Date -Format 'yyyyMMdd-HHmmss')
Copy-Item $path $bak -Force
function U([string]$escaped) {
return [System.Text.RegularExpressions.Regex]::Unescape($escaped)
}
# Read previous values using BOTH encodings; prefer lines that parse as KEY=VALUE ascii
function Load-Map([byte[]]$bytes) {
$map = [ordered]@{}
foreach ($encName in @('utf-8', 'gbk')) {
$enc = if ($encName -eq 'utf-8') { New-Object System.Text.UTF8Encoding $false } else { [System.Text.Encoding]::GetEncoding(936) }
$start = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) { $start = 3 }
$text = $enc.GetString($bytes, $start, $bytes.Length - $start)
foreach ($line in ($text -split "`r?`n")) {
$t = $line.Trim()
if (-not $t -or $t.StartsWith('#')) { continue }
$i = $t.IndexOf('=')
if ($i -lt 1) { continue }
$k = $t.Substring(0, $i).Trim()
$v = $t.Substring($i + 1)
if ($k -notmatch '^[A-Z0-9_]+$') { continue }
if (-not $map.Contains($k)) { $map[$k] = $v }
}
}
return $map
}
$bytes = [System.IO.File]::ReadAllBytes($path)
$map = Load-Map $bytes
Write-Output ('keys=' + $map.Count)
$goodReply = U '\u8be2\u4ef7\u667a\u80fd\u4f53\u63a5\u901a\u6210\u529f\u3002\u5df2\u6536\u5230\uff1a{content}'
$map['WECOM_CALLBACK_REPLY_TEXT'] = $goodReply
function V([string]$k, [string]$d = '') {
if ($map.Contains($k)) { return [string]$map[$k] }
return $d
}
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add((U '# \u53cb\u901a\u8fbe\u8be2\u4ef7\u667a\u80fd\u4f53 \u00b7 \u73af\u5883\u53d8\u91cf\uff08E:\\wwwroot\\.env\uff09'))
$lines.Add((U '# \u7f16\u7801 UTF-8 BOM\uff1b\u8bb0\u4e8b\u672c\u8bf7\u9009 UTF-8\u3002\u7981\u6b62\u63d0\u4ea4 Git\u3002'))
$lines.Add((U '# \u5bf9\u7167 prompt/13'))
$lines.Add('')
$lines.Add('YTD_ENV=' + (V 'YTD_ENV' 'test'))
$lines.Add('')
$lines.Add((U '# \u516c\u7f51\u4e0e\u4f01\u5fae'))
$lines.Add('PUBLIC_BASE_URL=' + (V 'PUBLIC_BASE_URL'))
$lines.Add('WECOM_CALLBACK_URL=' + (V 'WECOM_CALLBACK_URL'))
$lines.Add('INQUIRY_FORM_PUBLIC_BASE_URL=' + (V 'INQUIRY_FORM_PUBLIC_BASE_URL'))
$lines.Add('WECOM_CORP_ID=' + (V 'WECOM_CORP_ID'))
$lines.Add('WECOM_AGENT_ID=' + (V 'WECOM_AGENT_ID'))
$lines.Add('WECOM_SECRET=' + (V 'WECOM_SECRET'))
$lines.Add('WECOM_CALLBACK_TOKEN=' + (V 'WECOM_CALLBACK_TOKEN'))
$lines.Add('WECOM_ENCODING_AES_KEY=' + (V 'WECOM_ENCODING_AES_KEY'))
$lines.Add('WECOM_CALLBACK_REPLY_TEXT=' + $goodReply)
$lines.Add('WECOM_OPS_AGENT_ID=' + (V 'WECOM_OPS_AGENT_ID'))
$lines.Add('DEV_INJECT_ENABLED=' + (V 'DEV_INJECT_ENABLED' 'false'))
$lines.Add('')
$lines.Add((U '# \u5176\u4f59\u914d\u7f6e'))
$skip = @('YTD_ENV','PUBLIC_BASE_URL','WECOM_CALLBACK_URL','INQUIRY_FORM_PUBLIC_BASE_URL','WECOM_CORP_ID','WECOM_AGENT_ID','WECOM_SECRET','WECOM_CALLBACK_TOKEN','WECOM_ENCODING_AES_KEY','WECOM_CALLBACK_REPLY_TEXT','WECOM_OPS_AGENT_ID','DEV_INJECT_ENABLED')
foreach ($k in $map.Keys) {
if ($skip -contains $k) { continue }
$lines.Add($k + '=' + $map[$k])
}
$text = [string]::Join("`r`n", $lines.ToArray()) + "`r`n"
# Write UTF-8 BOM explicitly via bytes
$utf8 = New-Object System.Text.UTF8Encoding $false
$body = $utf8.GetBytes($text)
$bom = [byte[]](0xEF, 0xBB, 0xBF)
$all = New-Object byte[] ($bom.Length + $body.Length)
[Array]::Copy($bom, 0, $all, 0, 3)
[Array]::Copy($body, 0, $all, 3, $body.Length)
[System.IO.File]::WriteAllBytes($path, $all)
# Prove first Chinese char "友" is UTF-8 E5 8F 8B not GBK D3 D1
$nb = [System.IO.File]::ReadAllBytes($path)
# find first non-ascii after BOM
$i = 3
while ($i -lt $nb.Length -and $nb[$i] -lt 128) { $i++ }
$hex = ($nb[$i..([Math]::Min($i+2, $nb.Length-1))] | ForEach-Object { $_.ToString('X2') }) -join ' '
Write-Output ('first_non_ascii_hex=' + $hex)
Write-Output ('expect_utf8_you=E5 8F 8B')
Write-Output ('is_utf8_you=' + ($hex -eq 'E5 8F 8B'))
# decode check without console encoding issues: look for UTF-8 sequence of 询
$needle = $utf8.GetBytes((U '\u8be2\u4ef7'))
$found = $false
for ($p = 0; $p -le $nb.Length - $needle.Length; $p++) {
$ok = $true
for ($j = 0; $j -lt $needle.Length; $j++) {
if ($nb[$p + $j] -ne $needle[$j]) { $ok = $false; break }
}
if ($ok) { $found = $true; break }
}
Write-Output ('has_utf8_xunjia=' + $found)
Write-Output 'ENV_UTF8_OK'
-27
View File
@@ -1,27 +0,0 @@
# 在应用机把询价后台表导入 inquiry_robot(只动新库)
$ErrorActionPreference = 'Stop'
Get-Content 'E:\wwwroot\.env' | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith('#')) { return }
$i = $line.IndexOf('=')
if ($i -lt 1) { return }
$k = $line.Substring(0, $i).Trim()
$v = $line.Substring($i + 1).Trim().Trim('"')
Set-Item -Path "Env:$k" -Value $v
}
$mysql = 'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe'
$hostName = if ($env:MYSQL_HOST) { $env:MYSQL_HOST } else { '127.0.0.1' }
# 本机有 mysqld 时优先连本机
$tcp = New-Object System.Net.Sockets.TcpClient
try { $null = $tcp.ConnectAsync('127.0.0.1',3306).Wait(1000); if ($tcp.Connected) { $hostName = '127.0.0.1' } } catch {} finally { $tcp.Close() }
Write-Host "import host=$hostName db=$env:MYSQL_DB"
foreach ($f in @(
'C:\Users\ytd_extdev_0903\incoming\inquiry_admin_v1.sql',
'C:\Users\ytd_extdev_0903\incoming\inquiry_admin_menu_seed_v1.sql'
)) {
Write-Host "import $f"
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" --default-character-set=utf8mb4 $env:MYSQL_DB -e "source $($f.Replace('\','/'))"
if ($LASTEXITCODE -ne 0) { throw "fail $f code=$LASTEXITCODE" }
}
Write-Host 'SQL_OK'
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" $env:MYSQL_DB -e "SHOW TABLES LIKE 'inq_%'; SELECT COUNT(*) AS tickets FROM inq_ticket;"
-82
View File
@@ -1,82 +0,0 @@
# Import official Jeecg SQL into inquiry_robot only (strip CREATE/USE jeecg-boot).
$ErrorActionPreference = "Stop"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$srcSql = "C:\Users\ytd_extdev_0903\incoming\jeecgboot-mysql-5.7.sql"
$opsDir = "E:\wwwroot\ops\sql"
New-Item -ItemType Directory -Force -Path $opsDir | Out-Null
if (-not (Test-Path $srcSql)) { throw "missing incoming sql" }
$patched = Join-Path $opsDir "jeecgboot-mysql-5.7-inquiry_robot.sql"
Write-Output "patching SQL for inquiry_robot..."
$raw = [System.IO.File]::ReadAllText($srcSql)
$raw = [regex]::Replace($raw, '(?im)^\s*CREATE\s+database\s+if\s+NOT\s+EXISTS\s+`jeecg-boot`[^;]*;\s*', '')
$raw = [regex]::Replace($raw, '(?im)^\s*USE\s+`jeecg-boot`\s*;\s*', '')
[System.IO.File]::WriteAllText($patched, $raw)
Write-Output ("patched_bytes=" + (Get-Item $patched).Length)
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"
$user = "inquiry_robot"
$pass = $null
$db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
if ([string]::IsNullOrWhiteSpace($pass)) { throw "MYSQL_PASSWORD empty" }
if ($db -ne "inquiry_robot") { throw "refuse db=$db" }
Write-Output ("import host=$hostn db=$db user=$user")
$ErrorActionPreference = "Continue"
function Mysql-Scalar([string]$query) {
$out = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --connect-timeout=15 --batch -N $db -e $query 2>&1
$err = ($out | ForEach-Object {"$_"}) | Where-Object { $_ -match "ERROR\s+\d+" } | Select-Object -First 1
if ($err) { throw $err }
return ($out | ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" } | Select-Object -Last 1)
}
Write-Output ("connected db=" + (Mysql-Scalar "SELECT DATABASE()"))
$cnt = Mysql-Scalar "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='sys_user'"
Write-Output ("has_sys_user=$cnt")
if ($cnt -eq "1") {
Write-Output "SKIP_ALREADY_IMPORTED"
exit 0
}
$cnf = Join-Path $opsDir "_mysql_import.cnf"
@"
[client]
host=$hostn
port=3306
user=$user
password=$pass
default-character-set=utf8mb4
"@ | Set-Content $cnf -Encoding ascii
Write-Output "running import..."
$errLog = Join-Path $opsDir "_import_err.txt"
$outLog = Join-Path $opsDir "_import_out.txt"
$p = Start-Process -FilePath $mysql `
-ArgumentList @("--defaults-extra-file=$cnf", $db) `
-RedirectStandardInput $patched `
-RedirectStandardError $errLog `
-RedirectStandardOutput $outLog `
-Wait -PassThru -NoNewWindow
Remove-Item $cnf -Force -ErrorAction SilentlyContinue
Write-Output ("mysql_exit=" + $p.ExitCode)
if ($p.ExitCode -ne 0) {
Get-Content $errLog -Tail 40 -ErrorAction SilentlyContinue
throw "import exit=$($p.ExitCode)"
}
$cnt2 = Mysql-Scalar "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='sys_user'"
Write-Output ("after_has_sys_user=$cnt2")
if ($cnt2 -ne "1") {
Get-Content $errLog -Tail 50 -ErrorAction SilentlyContinue
throw "import did not create sys_user"
}
Write-Output ("table_count=" + (Mysql-Scalar "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE()"))
Write-Output "IMPORT_OK"
@@ -1,30 +0,0 @@
# 仅导入报价模板表到 inquiry_robot(禁止动 jeecg-boot)
$ErrorActionPreference = 'Stop'
Get-Content 'E:\wwwroot\.env' | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith('#')) { return }
$i = $line.IndexOf('=')
if ($i -lt 1) { return }
$k = $line.Substring(0, $i).Trim()
$v = $line.Substring($i + 1).Trim().Trim('"')
Set-Item -Path "Env:$k" -Value $v
}
$mysql = 'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe'
$hostName = if ($env:MYSQL_HOST) { $env:MYSQL_HOST } else { '127.0.0.1' }
$tcp = New-Object System.Net.Sockets.TcpClient
try {
$null = $tcp.ConnectAsync('127.0.0.1', 3306).Wait(1000)
if ($tcp.Connected) { $hostName = '127.0.0.1' }
} catch {
} finally {
$tcp.Close()
}
Write-Host "import host=$hostName db=$env:MYSQL_DB"
$f = 'C:\Users\ytd_extdev_0903\incoming\inquiry_quote_template_v1.sql'
if (-not (Test-Path $f)) { throw "missing $f" }
Write-Host "import $f"
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" --default-character-set=utf8mb4 $env:MYSQL_DB -e "source $($f.Replace('\','/'))"
if ($LASTEXITCODE -ne 0) { throw "fail sql code=$LASTEXITCODE" }
Write-Host 'SQL_OK'
& $mysql -h $hostName -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" $env:MYSQL_DB -e "SHOW TABLES LIKE 'inq_quote_template%';"
Write-Host 'VERIFY_DONE'
-14
View File
@@ -1,14 +0,0 @@
$ErrorActionPreference = 'Stop'
Get-Content 'E:\wwwroot\.env' | ForEach-Object {
$line = $_.Trim()
if (-not $line -or $line.StartsWith('#')) { return }
$i = $line.IndexOf('=')
if ($i -lt 1) { return }
Set-Item -Path ("Env:" + $line.Substring(0, $i).Trim()) -Value $line.Substring($i + 1).Trim().Trim('"')
}
$mysql = 'C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe'
$file = 'C:\Users\ytd_extdev_0903\incoming\inquiry_admin_menu_seed_slim_v1.sql'
& $mysql -h 127.0.0.1 -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" --default-character-set=utf8mb4 inquiry_robot -e "source $($file.Replace('\','/'))"
if ($LASTEXITCODE -ne 0) { throw "seed failed $LASTEXITCODE" }
& $mysql -h 127.0.0.1 -P 3306 -u $env:MYSQL_USER "--password=$env:MYSQL_PASSWORD" inquiry_robot -e "SELECT COUNT(*) AS tickets FROM inq_ticket; SELECT COUNT(*) AS menus FROM sys_permission WHERE id LIKE 'b100%';"
Write-Host 'SEED_OK'
-21
View File
@@ -1,21 +0,0 @@
Write-Output "=== java ==="
Get-Command java -ErrorAction SilentlyContinue | Format-List
java -version 2>&1
Write-Output "=== java homes ==="
@(
'C:\Program Files\Java',
'C:\Program Files\Eclipse Adoptium',
'C:\Program Files\Microsoft',
'C:\Program Files\Amazon Corretto',
'C:\yutongda\tools'
) | ForEach-Object {
if (Test-Path $_) {
Write-Output "DIR $_"
Get-ChildItem $_ -ErrorAction SilentlyContinue | Select-Object Name
}
}
Write-Output "=== tools ==="
Get-Command winget, choco, scoop -ErrorAction SilentlyContinue | Select-Object Name, Source
Write-Output "=== free space E/C ==="
Get-PSDrive C,E -ErrorAction SilentlyContinue | Format-Table Name, @{n='FreeGB';e={[math]::Round($_.Free/1GB,1)}}
Write-Output "DONE"
-30
View File
@@ -1,30 +0,0 @@
Write-Output "=== drives ==="
Get-PSDrive -PSProvider FileSystem | Format-Table Name, Root -AutoSize
Write-Output "=== volumes ==="
Get-Volume | Where-Object { $_.DriveLetter } | Select-Object DriveLetter, FileSystemLabel, @{n='FreeGB';e={[math]::Round($_.SizeRemaining/1GB,1)}}, @{n='SizeGB';e={[math]::Round($_.Size/1GB,1)}} | Format-Table -AutoSize
Write-Output "=== paths ==="
@(
'E:\wwwroot',
'D:\wwwroot',
'C:\ytd-test',
'C:\yutongda',
'C:\nginx-1.18.0\myconf\ai.conf'
) | ForEach-Object {
"$_ exists=$(Test-Path $_)"
}
Write-Output "=== ytd-test tree ==="
if (Test-Path 'C:\ytd-test') {
Get-ChildItem 'C:\ytd-test' | Select-Object Name, Mode
if (Test-Path 'C:\ytd-test\ops\active-release.json') {
Get-Content 'C:\ytd-test\ops\active-release.json' -Raw
}
}
Write-Output "=== nginx root line ==="
if (Test-Path 'C:\nginx-1.18.0\myconf\ai.conf') {
Select-String -Path 'C:\nginx-1.18.0\myconf\ai.conf' -Pattern 'root |8910|8180|ytd-test|wwwroot'
}
Write-Output "=== listen ports ==="
foreach ($p in 8910,8180,8913,8080,8810) {
$c = Get-NetTCPConnection -LocalPort $p -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
if ($c) { "$p LISTEN pid=$($c.OwningProcess)" } else { "$p down" }
}
-21
View File
@@ -1,21 +0,0 @@
Write-Output "=== E:\wwwroot ==="
Get-ChildItem 'E:\wwwroot' -Force | Select-Object Mode, Length, Name | Format-Table -AutoSize
Write-Output "=== C:\ytd-test deep ==="
Get-ChildItem 'C:\ytd-test' -Recurse -Depth 2 | Select-Object FullName | ForEach-Object { $_.FullName }
Write-Output "=== ops scripts ==="
if (Test-Path 'C:\ytd-test\ops') {
Get-ChildItem 'C:\ytd-test\ops' | Format-Table Name, Length -AutoSize
Get-ChildItem 'C:\ytd-test\ops\*.cmd','C:\ytd-test\ops\*.ps1','C:\ytd-test\ops\*.json' -ErrorAction SilentlyContinue | ForEach-Object {
Write-Output "---- $($_.FullName) ----"
Get-Content $_.FullName -TotalCount 40
}
}
Write-Output "=== scheduled tasks ytd ==="
Get-ScheduledTask | Where-Object { $_.TaskName -match 'ytd|agent|8910|inquiry' } | Select-Object TaskName, State | Format-Table -AutoSize
Write-Output "=== nginx root snippet ==="
Select-String -Path 'C:\nginx-1.18.0\myconf\ai.conf' -Pattern 'root |proxy_pass|ytd-test|wwwroot' | ForEach-Object { $_.Line.Trim() }
Write-Output "=== pid 8910 ==="
$p = Get-NetTCPConnection -LocalPort 8910 -State Listen -EA SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess
if ($p) {
Get-CimInstance Win32_Process -Filter "ProcessId=$p" | Select-Object ProcessId, CommandLine, ExecutablePath | Format-List
}
-56
View File
@@ -1,56 +0,0 @@
# 服务器侧:发布新后台静态到 admin\releases\<id>\dist,并切换 admin\current 联接
# 根目录:E:\wwwroot。禁止动 C:\yutongda。Nginx conf 必须无 BOM。
$ErrorActionPreference = "Stop"
$IncomingZip = "C:\Users\ytd_extdev_0903\incoming\admin-dist.zip"
$IncomingConf = "C:\Users\ytd_extdev_0903\incoming\ai.conf.cutover-8910"
$Root = "E:\wwwroot"
$NginxConf = "C:\nginx-1.18.0\myconf\ai.conf"
$Stamp = Get-Date -Format "yyyyMMdd-HHmmss"
$RelId = "admin-$Stamp"
$RelDist = Join-Path $Root "admin\releases\$RelId\dist"
$Current = Join-Path $Root "admin\current"
if (-not (Test-Path $IncomingZip)) { throw "missing $IncomingZip" }
if (-not (Test-Path $IncomingConf)) { throw "missing $IncomingConf" }
Write-Output "=== backup nginx ==="
Copy-Item $NginxConf "$NginxConf.bak-before-admin-$Stamp" -Force
Write-Output "=== install release dist ==="
New-Item -ItemType Directory -Force -Path $RelDist | Out-Null
Expand-Archive -Path $IncomingZip -DestinationPath $RelDist -Force
if (-not (Test-Path (Join-Path $RelDist "index.html"))) { throw "index.html missing" }
Write-Output "=== switch admin\\current junction ==="
if (Test-Path $Current) {
cmd /c "rmdir `"$Current`"" | Out-Null
if (Test-Path $Current) { Remove-Item $Current -Recurse -Force }
}
cmd /c "mklink /J `"$Current`" `"$RelDist`""
if (-not (Test-Path (Join-Path $Current "index.html"))) { throw "current index missing" }
Write-Output "CURRENT_OK=$Current -> $RelDist"
Write-Output "=== nginx conf no BOM ==="
$bytes = [System.IO.File]::ReadAllBytes($IncomingConf)
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) {
$list = New-Object System.Collections.Generic.List[byte]
for ($i = 3; $i -lt $bytes.Length; $i++) { [void]$list.Add($bytes[$i]) }
$bytes = $list.ToArray()
}
[System.IO.File]::WriteAllBytes($NginxConf, $bytes)
Set-Location "C:\nginx-1.18.0"
& .\nginx.exe -t
if ($LASTEXITCODE -ne 0) { throw "nginx -t failed" }
Get-Process nginx -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
try {
Start-Service Nginx1.18 -ErrorAction Stop
Write-Output "SERVICE_STARTED"
} catch {
Start-Process -FilePath "C:\nginx-1.18.0\nginx.exe" -WorkingDirectory "C:\nginx-1.18.0" -WindowStyle Hidden
Write-Output "EXE_STARTED"
}
Start-Sleep -Seconds 2
Write-Output "DONE"
-27
View File
@@ -1,27 +0,0 @@
# 安装已上传完整的 CAPTCHA fat jar,并重启 8180 主账。禁止动现网 8080。
$ErrorActionPreference = 'Stop'
$Src = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.CAPTCHA.jar'
$Incoming = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.jar'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
$Expect = 177074039
if (-not (Test-Path $Src)) { throw "missing $Src" }
$len = (Get-Item $Src).Length
Write-Host ("src_bytes=" + $len)
if ($len -ne $Expect) { throw ("size mismatch expect=" + $Expect + " got=" + $len) }
Get-CimInstance Win32_Process | ForEach-Object {
if ($_.CommandLine -and ($_.CommandLine -like '*inquiry-new*jeecg*' -or $_.CommandLine -like '*run-ledger*')) {
Write-Host ("killing=" + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 3
Copy-Item $Src $Incoming -Force
Copy-Item $Src $Fat -Force
Write-Host ("fat_bytes=" + (Get-Item $Fat).Length)
Write-Host 'COPIED_CAPTCHA_JAR'
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1
Write-Host 'INSTALL_CAPTCHA_DONE'
-30
View File
@@ -1,30 +0,0 @@
# Install COMMONSIO fat jar and restart 8180
$ErrorActionPreference = 'Stop'
$Src = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.COMMONSIO.jar'
$Incoming = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.jar'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
$Expect = 177186821
if (-not (Test-Path $Src)) { throw "missing $Src" }
$len = (Get-Item $Src).Length
Write-Host ("src_bytes=" + $len)
if ($len -lt 170000000) { throw 'src too small' }
$jarCmd = 'C:\yutongda\tools\jdk8\bin\jar.exe'
Write-Host '=== commons-io in src ==='
& $jarCmd tf $Src | Select-String 'commons-io'
Get-CimInstance Win32_Process | ForEach-Object {
if ($_.CommandLine -and ($_.CommandLine -like '*inquiry-new*jeecg*' -or $_.CommandLine -like '*run-ledger*')) {
Write-Host ("killing=" + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 3
Copy-Item $Src $Incoming -Force
Copy-Item $Src $Fat -Force
Write-Host ("fat_bytes=" + (Get-Item $Fat).Length)
Write-Host 'COPIED_COMMONSIO'
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1
Write-Host 'INSTALL_COMMONSIO_DONE'
-62
View File
@@ -1,62 +0,0 @@
# Install Temurin JDK 17 portable under E:\wwwroot\tools (do not replace jdk8)
$ErrorActionPreference = "Stop"
$Tools = "E:\wwwroot\tools"
$Zip = Join-Path $Tools "OpenJDK17-windows-x64.zip"
$Dest = Join-Path $Tools "jdk-17"
$Url = "https://api.adoptium.net/v3/binary/latest/17/ga/windows/x64/jdk/hotspot/normal/eclipse?project=jdk"
New-Item -ItemType Directory -Force -Path $Tools | Out-Null
if (-not (Test-Path (Join-Path $Dest "bin\java.exe"))) {
Write-Output "=== download ==="
if (Test-Path $Zip) { Remove-Item $Zip -Force }
# TLS
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest -Uri $Url -OutFile $Zip -UseBasicParsing -TimeoutSec 600
Write-Output ("ZIP_BYTES=" + (Get-Item $Zip).Length)
Write-Output "=== expand ==="
$stage = Join-Path $Tools ("jdk17-stage-" + (Get-Date -Format "yyyyMMddHHmmss"))
New-Item -ItemType Directory -Force -Path $stage | Out-Null
Expand-Archive -Path $Zip -DestinationPath $stage -Force
$jdkRoot = Get-ChildItem $stage -Directory | Select-Object -First 1
if (-not $jdkRoot) { throw "no jdk folder in zip" }
if (Test-Path $Dest) { Remove-Item $Dest -Recurse -Force }
Move-Item $jdkRoot.FullName $Dest
Remove-Item $stage -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $Zip -Force -ErrorAction SilentlyContinue
} else {
Write-Output "JDK_ALREADY_PRESENT"
}
$java = Join-Path $Dest "bin\java.exe"
if (-not (Test-Path $java)) { throw "java.exe missing" }
& $java -version 2>&1 | ForEach-Object { "$_" }
# Machine-level JDK17_HOME for new ledger; do NOT overwrite JAVA_HOME if jdk8 services rely on it
[Environment]::SetEnvironmentVariable("JDK17_HOME", $Dest, "Machine")
[Environment]::SetEnvironmentVariable("JAVA17_HOME", $Dest, "Machine")
# Write helper for ops
$cmd = @"
@echo off
REM New-system JDK17 only. Do not use for legacy Jeecg (jdk8).
set JAVA_HOME=$Dest
set PATH=%JAVA_HOME%\bin;%PATH%
"@
Set-Content -Path (Join-Path $Tools "use-jdk17.cmd") -Value $cmd -Encoding ASCII
$info = @{
vendor = "Eclipse Temurin"
major = 17
home = $Dest
javaExe = $java
installedAt = (Get-Date).ToString("o")
note = "Alongside C:\yutongda\tools\jdk8; legacy JAVA_HOME untouched"
} | ConvertTo-Json
Set-Content -Path (Join-Path $Tools "jdk17.json") -Value $info -Encoding UTF8
Set-Content -Path "E:\wwwroot\ops\jdk17.json" -Value $info -Encoding UTF8
Write-Output "JDK17_HOME=$Dest"
Write-Output "INSTALL_OK"
-52
View File
@@ -1,52 +0,0 @@
# Install Microsoft JDK 17 from pre-uploaded zip (no internet required)
$ErrorActionPreference = "Stop"
$Tools = "E:\wwwroot\tools"
$Zip = "C:\Users\ytd_extdev_0903\incoming\microsoft-jdk-17-windows-x64.zip"
$Dest = Join-Path $Tools "jdk-17"
if (-not (Test-Path $Zip)) { throw "missing $Zip" }
New-Item -ItemType Directory -Force -Path $Tools | Out-Null
Write-Output ("ZIP_BYTES=" + (Get-Item $Zip).Length)
if (Test-Path $Dest) {
Rename-Item $Dest ("jdk-17.bak-" + (Get-Date -Format "yyyyMMddHHmmss"))
}
$stage = Join-Path $Tools ("jdk17-stage-" + (Get-Date -Format "yyyyMMddHHmmss"))
New-Item -ItemType Directory -Force -Path $stage | Out-Null
Write-Output "=== expand ==="
Expand-Archive -Path $Zip -DestinationPath $stage -Force
$jdkRoot = Get-ChildItem $stage -Directory | Select-Object -First 1
if (-not $jdkRoot) { throw "no jdk root in zip" }
Move-Item $jdkRoot.FullName $Dest
Remove-Item $stage -Recurse -Force -ErrorAction SilentlyContinue
$java = Join-Path $Dest "bin\java.exe"
if (-not (Test-Path $java)) { throw "java.exe missing at $java" }
& $java -version 2>&1 | ForEach-Object { "$_" }
[Environment]::SetEnvironmentVariable("JDK17_HOME", $Dest, "Machine")
[Environment]::SetEnvironmentVariable("JAVA17_HOME", $Dest, "Machine")
$cmd = @"
@echo off
REM New-system JDK17 only. Do not use for legacy Jeecg (jdk8).
set JAVA_HOME=$Dest
set PATH=%JAVA_HOME%\bin;%PATH%
"@
Set-Content -Path (Join-Path $Tools "use-jdk17.cmd") -Value $cmd -Encoding ASCII
$info = @{
vendor = "Microsoft OpenJDK"
major = 17
home = $Dest
javaExe = $java
installedAt = (Get-Date).ToString("o")
note = "Alongside C:\yutongda\tools\jdk8; legacy JAVA_HOME untouched"
} | ConvertTo-Json
Set-Content -Path (Join-Path $Tools "jdk17.json") -Value $info -Encoding UTF8
New-Item -ItemType Directory -Force -Path "E:\wwwroot\ops" | Out-Null
Set-Content -Path "E:\wwwroot\ops\jdk17.json" -Value $info -Encoding UTF8
Write-Output "JDK17_HOME=$Dest"
Write-Output "INSTALL_OK"
-27
View File
@@ -1,27 +0,0 @@
# Install portable Maven under E:\wwwroot\tools if missing.
$ErrorActionPreference = "Stop"
$tools = "E:\wwwroot\tools"
New-Item -ItemType Directory -Force -Path $tools | Out-Null
$mvnHome = Join-Path $tools "apache-maven-3.9.9"
$mvnCmd = Join-Path $mvnHome "bin\mvn.cmd"
if (Test-Path $mvnCmd) {
Write-Output ("maven_exists=" + $mvnHome)
& $mvnCmd -v
exit 0
}
$zip = Join-Path $tools "apache-maven-3.9.9-bin.zip"
$url = "https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip"
# fallback archive
$url2 = "https://archive.apache.org/dist/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip"
Write-Output "downloading maven..."
try {
Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing
} catch {
Write-Output "primary failed, try archive..."
Invoke-WebRequest -Uri $url2 -OutFile $zip -UseBasicParsing
}
Expand-Archive -Path $zip -DestinationPath $tools -Force
if (-not (Test-Path $mvnCmd)) { throw "maven extract failed" }
Write-Output "MAVEN_OK"
& $mvnCmd -v
-19
View File
@@ -1,19 +0,0 @@
$ErrorActionPreference='Stop'
$New='C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.NEW.jar'
$Incoming='C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.jar'
$Fat='E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
if(-not (Test-Path $New)){ throw "missing $New" }
$len=(Get-Item $New).Length
Write-Host ("new_bytes="+$len)
if($len -lt 170000000){ throw "new jar too small, incomplete upload" }
# stop loops
Get-CimInstance Win32_Process | ForEach-Object {
if($_.CommandLine -and ($_.CommandLine -like '*inquiry-new*jeecg*' -or $_.CommandLine -like '*run-ledger*')){
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 2
Copy-Item $New $Incoming -Force
Copy-Item $New $Fat -Force
Write-Host 'COPIED_NEW_JAR'
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1
-29
View File
@@ -1,29 +0,0 @@
# Install POI412 fat jar and restart 8180
$ErrorActionPreference = 'Stop'
$Src = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.POI412.jar'
$Incoming = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.jar'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
if (-not (Test-Path $Src)) { throw "missing $Src" }
$len = (Get-Item $Src).Length
Write-Host ("src_bytes=" + $len)
if ($len -lt 160000000) { throw 'src too small' }
$jarCmd = 'C:\yutongda\tools\jdk8\bin\jar.exe'
Write-Host '=== poi entries ==='
& $jarCmd tf $Src | Select-String 'poi-'
Get-CimInstance Win32_Process | ForEach-Object {
if ($_.CommandLine -and ($_.CommandLine -like '*inquiry-new*jeecg*' -or $_.CommandLine -like '*run-ledger*')) {
Write-Host ("killing=" + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 3
Copy-Item $Src $Incoming -Force
Copy-Item $Src $Fat -Force
Write-Host ("fat_bytes=" + (Get-Item $Fat).Length)
Write-Host 'COPIED_POI412'
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1
Write-Host 'INSTALL_POI412_DONE'
@@ -1,37 +0,0 @@
# Force install local-built POI412 jar that contains QuoteTemplateController
$ErrorActionPreference = 'Stop'
$Src = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.POI412.jar'
$Incoming = 'C:\Users\ytd_extdev_0903\incoming\jeecg-system-start-3.5.3.jar'
$Fat = 'E:\wwwroot\inquiry-new\jeecg-system-start-3.5.3.jar'
$Expect = 170763133
if (-not (Test-Path $Src)) { throw "missing $Src" }
$len = (Get-Item $Src).Length
Write-Host ("src_bytes=" + $len)
if ($len -ne $Expect) { Write-Host ("WARN size expect=" + $Expect + " got=" + $len) }
$work = Join-Path $env:TEMP 'verify-qt-class'
if (Test-Path $work) { Remove-Item $work -Recurse -Force }
New-Item -ItemType Directory $work | Out-Null
$jarCmd = 'C:\yutongda\tools\jdk8\bin\jar.exe'
Push-Location $work
& $jarCmd xf $Src 'BOOT-INF/lib/jeecg-module-inquiry-3.5.3.jar'
$has = (& $jarCmd tf 'BOOT-INF/lib/jeecg-module-inquiry-3.5.3.jar' | Select-String 'InquiryQuoteTemplateController').Count
Write-Host ("src_has_QuoteTemplateController=" + ($has -gt 0))
if ($has -lt 1) { throw 'source jar missing QuoteTemplateController' }
Pop-Location
Get-CimInstance Win32_Process | ForEach-Object {
if ($_.CommandLine -and ($_.CommandLine -like '*inquiry-new*jeecg*' -or $_.CommandLine -like '*run-ledger*')) {
Write-Host ("killing=" + $_.ProcessId)
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 3
Copy-Item $Src $Incoming -Force
Copy-Item $Src $Fat -Force
Write-Host ("fat_bytes=" + (Get-Item $Fat).Length)
Write-Host 'COPIED_POI412_VERIFIED'
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\ytd_extdev_0903\incoming\_remote_wmi_start_ledger.ps1
Write-Host 'INSTALL_VERIFIED_DONE'
-44
View File
@@ -1,44 +0,0 @@
# Keep only 5 RBAC tables.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"
$user = "inquiry_robot"
$pass = $null
$db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
if ($db -ne "inquiry_robot") { throw "refuse db=$db" }
$keepSet = New-Object 'System.Collections.Generic.HashSet[string]'
@('sys_user','sys_role','sys_user_role','sys_permission','sys_role_permission') | ForEach-Object { [void]$keepSet.Add($_) }
$tables = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
$drop = New-Object System.Collections.Generic.List[string]
foreach ($t in $tables) {
if (-not $keepSet.Contains($t)) { [void]$drop.Add($t) }
}
Write-Output ("before=" + @($tables).Count + " drop=" + $drop.Count)
$sb = New-Object System.Text.StringBuilder
[void]$sb.AppendLine("SET FOREIGN_KEY_CHECKS=0;")
foreach ($t in $drop) { [void]$sb.AppendLine("DROP TABLE IF EXISTS ``$t``;") }
[void]$sb.AppendLine("SET FOREIGN_KEY_CHECKS=1;")
$sqlFile = "E:\wwwroot\ops\sql\_keep_rbac_only.sql"
[System.IO.File]::WriteAllText($sqlFile, $sb.ToString())
& $mysql -h $hostn -P 3306 -u $user "-p$pass" $db -e "source $($sqlFile -replace '\\','/')" 2>&1 |
Where-Object { $_ -notmatch "Warning|password" } | Out-Null
$left = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
Write-Output ("after_total=" + @($left).Count)
$left | ForEach-Object { $_ }
Write-Output "RBAC_ONLY_OK"
-48
View File
@@ -1,48 +0,0 @@
# inquiry_robot: keep only admin-related sys_* tables; drop the rest.
$ErrorActionPreference = "Continue"
$mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
$envFile = "E:\wwwroot\.env"
$hostn = "10.206.0.15"; $user = "inquiry_robot"; $pass = $null; $db = "inquiry_robot"
Get-Content $envFile | ForEach-Object {
if ($_ -match '^MYSQL_HOST=(.+)$') { $hostn = $Matches[1].Trim() }
if ($_ -match '^MYSQL_USER=(.+)$') { $user = $Matches[1].Trim() }
if ($_ -match '^MYSQL_PASSWORD=(.+)$') { $pass = $Matches[1].Trim() }
if ($_ -match '^MYSQL_DB=(.+)$') { $db = $Matches[1].Trim() }
}
if ($db -ne "inquiry_robot") { throw "refuse db=$db" }
$tables = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
$keep = @()
$drop = @()
foreach ($t in $tables) {
# 只要管理员体系:用户/角色/菜单/部门/权限/字典/租户/日志等 sys_*
if ($t -match '^sys_') { $keep += $t } else { $drop += $t }
}
Write-Output ("before=" + $tables.Count + " keep=" + $keep.Count + " drop=" + $drop.Count)
Write-Output "=== keep ==="
$keep | ForEach-Object { $_ }
Write-Output "=== drop ==="
$drop | ForEach-Object { $_ }
if ($drop.Count -eq 0) {
Write-Output "NOTHING_TO_DROP"
exit 0
}
$sql = "SET FOREIGN_KEY_CHECKS=0;`n"
foreach ($t in $drop) { $sql += "DROP TABLE IF EXISTS ``$t``;`n" }
$sql += "SET FOREIGN_KEY_CHECKS=1;`n"
$sql += "SELECT COUNT(*) AS c FROM information_schema.tables WHERE table_schema=DATABASE();`n"
$sqlFile = "E:\wwwroot\ops\sql\_keep_sys_only.sql"
Set-Content $sqlFile -Value $sql -Encoding ascii
& $mysql -h $hostn -P 3306 -u $user "-p$pass" $db -e "source $($sqlFile -replace '\\','/')" 2>&1 |
Where-Object { $_ -notmatch "Warning|password" }
$left = & $mysql -h $hostn -P 3306 -u $user "-p$pass" --batch -N $db -e "SHOW TABLES" 2>&1 |
ForEach-Object {"$_".Trim()} | Where-Object { $_ -ne "" -and $_ -notmatch "Warning" }
Write-Output ("after_total=" + @($left).Count)
$left | ForEach-Object { $_ }
Write-Output "SYS_ONLY_OK"
-14
View File
@@ -1,14 +0,0 @@
# 结束卡住的迁移脚本(Restart-Service Nginx 挂死)
$ErrorActionPreference = "Continue"
Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" | ForEach-Object {
if ($_.CommandLine -and ($_.CommandLine -match 'migrate_to_wwwroot|Restart-Service')) {
Write-Output "KILL_PS=$($_.ProcessId)"
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
}
# Restart-Service 卡住时服务控制也可能僵住;先杀 nginx 进程便于 bounce
Get-Process nginx -ErrorAction SilentlyContinue | ForEach-Object {
Write-Output "KILL_NGINX=$($_.Id)"
Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue
}
Write-Output "KILL_DONE"
-18
View File
@@ -1,18 +0,0 @@
$ErrorActionPreference = 'Continue'
Write-Host '=== wwwroot ==='
Get-ChildItem E:\wwwroot -ErrorAction SilentlyContinue | Select-Object Name,Mode | Format-Table -AutoSize
Write-Host '=== yutongda ==='
Get-ChildItem C:\yutongda -ErrorAction SilentlyContinue | Select-Object Name,Mode | Format-Table -AutoSize
Write-Host '=== env exists ==='
@(
'E:\wwwroot\.env',
'E:\wwwroot\ops\.env',
'C:\yutongda\.env'
) | ForEach-Object { Write-Host "$_ = $(Test-Path $_)" }
Write-Host '=== java ==='
Get-ChildItem 'C:\Program Files\Java','C:\yutongda\tools' -ErrorAction SilentlyContinue | Select-Object FullName
where.exe java 2>$null
where.exe mvn 2>$null
where.exe node 2>$null
Write-Host '=== inquiry_robot dirs ==='
Get-ChildItem E:\wwwroot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'inquiry|jeecg|admin' } | Select-Object FullName
-34
View File
@@ -1,34 +0,0 @@
# 读取主账启动失败原因(不打印密钥)
$ErrorActionPreference = 'Continue'
$Err = 'E:\wwwroot\inquiry-new\logs\stderr.log'
$Out = 'E:\wwwroot\inquiry-new\logs\stdout.log'
Write-Output '=== process ==='
Get-CimInstance Win32_Process -Filter "Name='java.exe'" | ForEach-Object {
if ($_.CommandLine -like '*inquiry-new*') {
"pid=$($_.ProcessId) alive"
}
}
Write-Output '=== port 8180 ==='
$c = Get-NetTCPConnection -LocalPort 8180 -State Listen -EA SilentlyContinue | Select-Object -First 1
if ($c) { "LISTEN pid=$($c.OwningProcess)" } else { 'down' }
Write-Output '=== stderr tail ==='
if (Test-Path $Err) { Get-Content $Err -Tail 80 } else { 'no stderr' }
Write-Output '=== stdout tail ==='
if (Test-Path $Out) { Get-Content $Out -Tail 80 } else { 'no stdout' }
Write-Output '=== try health variants ==='
foreach ($u in @(
'http://127.0.0.1:8180/jeecgboot/',
'http://127.0.0.1:8180/jeecg-boot/',
'http://127.0.0.1:8180/actuator/health',
'http://127.0.0.1:8180/'
)) {
try {
$r = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 5
"OK $($r.StatusCode) $u"
} catch {
"FAIL $u"
}
}
Write-Output 'LEDGER_DIAG_DONE'

Some files were not shown because too many files have changed in this diff Show More