主仓只保留代码:移出 contracts/deploy/docs 与模板监听包/原型图,并提交后台工单页改动。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+10
@@ -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
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -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结构、非空、条件激活、权限、版本与幂等;字段内容格式、规范性和是否适合报价由模型与下游报价服务负责。"
|
||||
]
|
||||
}
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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` 回到现网行为。
|
||||
@@ -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 账号登录'
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
@@ -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%
|
||||
@@ -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%
|
||||
@@ -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
|
||||
@@ -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
|
||||
- 不要把私钥打进这个压缩包
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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' }
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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)" }
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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") }
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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;"
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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;"
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user