feat: Initializer of admin, anonymous account and workflows. (#6)
* feat: Tools from metrics 0-14 * feat: Tools from metrics 15-30 * feat: Tools from metrics 31-41. Fill with '.*' when param is empty. * feat: Initialize the administrator account. * feat: Initializer of anonymous and workflows.pull/17608/head
parent
afac446656
commit
b15a8af990
@ -0,0 +1,48 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from configs import dify_config
|
||||
from core.tools.builtin_tool.tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from libs.apo_utils import APOUtils
|
||||
|
||||
|
||||
class ContainerCpuThrottleContainerdSecondsTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
conversation_id: Optional[str] = None,
|
||||
app_id: Optional[str] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Generator[ToolInvokeMessage, None, None]:
|
||||
cadvisor_job_name = tool_parameters.get('cadvisor_job_name', '.*')
|
||||
namespace = tool_parameters.get('namespace', '.*')
|
||||
pod = tool_parameters.get('pod', '.*')
|
||||
start_time = tool_parameters.get("startTime")
|
||||
end_time = tool_parameters.get("endTime")
|
||||
params = {
|
||||
'metricName': '基础设施情况 - 容器CPU - 容器CPU节流时间 - Containerd',
|
||||
'params': {
|
||||
'cadvisor_job_name': cadvisor_job_name,
|
||||
'namespace': namespace,
|
||||
'pod': pod
|
||||
},
|
||||
'startTime': start_time,
|
||||
'endTime': end_time,
|
||||
'step': APOUtils.get_step(start_time, end_time),
|
||||
}
|
||||
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
|
||||
list = resp.json()['result']
|
||||
list = json.dumps({
|
||||
'type': 'metric',
|
||||
'display': True,
|
||||
'unit': list['unit'],
|
||||
'data': {
|
||||
'timeseries': list['timeseries']
|
||||
}
|
||||
})
|
||||
yield self.create_text_message(list)
|
||||
@ -0,0 +1,75 @@
|
||||
identity:
|
||||
name: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
|
||||
author: APO
|
||||
label:
|
||||
en_US: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
|
||||
zh_Hans: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
|
||||
description:
|
||||
human:
|
||||
en_US: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
|
||||
zh_Hans: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
|
||||
llm: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
|
||||
display:
|
||||
type: metric
|
||||
title: 基础设施情况 - 容器CPU - 容器CPU节流时间 - Containerd
|
||||
unit: "s"
|
||||
parameters:
|
||||
- name: cadvisor_job_name
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: cAdvisor job name
|
||||
zh_Hans: cAdvisor任务名称
|
||||
human_description:
|
||||
en_US: cAdvisor job name
|
||||
zh_Hans: cAdvisor任务名称
|
||||
llm_description: cAdvisor job name
|
||||
form: llm
|
||||
- name: namespace
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Namespace
|
||||
zh_Hans: 命名空间
|
||||
human_description:
|
||||
en_US: Namespace
|
||||
zh_Hans: 命名空间
|
||||
llm_description: Namespace
|
||||
form: llm
|
||||
- name: pod
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Pod name
|
||||
zh_Hans: Pod名称
|
||||
human_description:
|
||||
en_US: Pod name
|
||||
zh_Hans: Pod名称
|
||||
llm_description: Pod name
|
||||
form: llm
|
||||
- name: startTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: startTime
|
||||
zh_Hans: startTime
|
||||
pt_BR: startTime
|
||||
human_description:
|
||||
en_US: Data query start time
|
||||
zh_Hans: 开始时间 (微秒)
|
||||
pt_BR: Data query start time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
- name: endTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: endTime
|
||||
zh_Hans: endTime
|
||||
pt_BR: endTime
|
||||
human_description:
|
||||
en_US: Data query end time
|
||||
zh_Hans: 结束时间 (微秒)
|
||||
pt_BR: Data query end time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
@ -0,0 +1,44 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from configs import dify_config
|
||||
from core.tools.builtin_tool.tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from libs.apo_utils import APOUtils
|
||||
|
||||
|
||||
class LinuxNetworkDroppedPacketsReceiveTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
conversation_id: Optional[str] = None,
|
||||
app_id: Optional[str] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Generator[ToolInvokeMessage, None, None]:
|
||||
cluster = tool_parameters.get('cluster', '.*')
|
||||
start_time = tool_parameters.get("startTime")
|
||||
end_time = tool_parameters.get("endTime")
|
||||
params = {
|
||||
'metricName': '集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (receive)',
|
||||
'params': {
|
||||
'cluster': cluster
|
||||
},
|
||||
'startTime': start_time,
|
||||
'endTime': end_time,
|
||||
'step': APOUtils.get_step(start_time, end_time),
|
||||
}
|
||||
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
|
||||
list = resp.json()['result']
|
||||
list = json.dumps({
|
||||
'type': 'metric',
|
||||
'display': True,
|
||||
'unit': list['unit'],
|
||||
'data': {
|
||||
'timeseries': list['timeseries']
|
||||
}
|
||||
})
|
||||
yield self.create_text_message(list)
|
||||
@ -0,0 +1,53 @@
|
||||
identity:
|
||||
name: Linux集群网络接收丢包数
|
||||
author: APO
|
||||
label:
|
||||
en_US: Linux cluster network receive packet drops
|
||||
zh_Hans: Linux集群网络接收丢包数
|
||||
description:
|
||||
human:
|
||||
en_US: Linux cluster network receive packet drops
|
||||
zh_Hans: Linux集群网络接收丢包数
|
||||
llm: Linux cluster network receive packet drops
|
||||
display:
|
||||
type: metric
|
||||
title: 集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (receive)
|
||||
unit: "short"
|
||||
parameters:
|
||||
- name: cluster
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
human_description:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
llm_description: Cluster name
|
||||
form: llm
|
||||
- name: startTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: startTime
|
||||
zh_Hans: startTime
|
||||
pt_BR: startTime
|
||||
human_description:
|
||||
en_US: Data query start time
|
||||
zh_Hans: 开始时间 (微秒)
|
||||
pt_BR: Data query start time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
- name: endTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: endTime
|
||||
zh_Hans: endTime
|
||||
pt_BR: endTime
|
||||
human_description:
|
||||
en_US: Data query end time
|
||||
zh_Hans: 结束时间 (微秒)
|
||||
pt_BR: Data query end time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
@ -0,0 +1,44 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from configs import dify_config
|
||||
from core.tools.builtin_tool.tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from libs.apo_utils import APOUtils
|
||||
|
||||
|
||||
class LinuxNetworkDroppedPacketsTransmitTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
conversation_id: Optional[str] = None,
|
||||
app_id: Optional[str] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Generator[ToolInvokeMessage, None, None]:
|
||||
cluster = tool_parameters.get('cluster', '.*')
|
||||
start_time = tool_parameters.get("startTime")
|
||||
end_time = tool_parameters.get("endTime")
|
||||
params = {
|
||||
'metricName': '集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (transmit)',
|
||||
'params': {
|
||||
'cluster': cluster
|
||||
},
|
||||
'startTime': start_time,
|
||||
'endTime': end_time,
|
||||
'step': APOUtils.get_step(start_time, end_time),
|
||||
}
|
||||
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
|
||||
list = resp.json()['result']
|
||||
list = json.dumps({
|
||||
'type': 'metric',
|
||||
'display': True,
|
||||
'unit': list['unit'],
|
||||
'data': {
|
||||
'timeseries': list['timeseries']
|
||||
}
|
||||
})
|
||||
yield self.create_text_message(list)
|
||||
@ -0,0 +1,53 @@
|
||||
identity:
|
||||
name: Linux集群网络发送丢包数
|
||||
author: APO
|
||||
label:
|
||||
en_US: Linux cluster network transmit packet drops
|
||||
zh_Hans: Linux集群网络发送丢包数
|
||||
description:
|
||||
human:
|
||||
en_US: Linux cluster network transmit packet drops
|
||||
zh_Hans: Linux集群网络发送丢包数
|
||||
llm: Linux cluster network transmit packet drops
|
||||
display:
|
||||
type: metric
|
||||
title: 集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (transmit)
|
||||
unit: "short"
|
||||
parameters:
|
||||
- name: cluster
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
human_description:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
llm_description: Cluster name
|
||||
form: llm
|
||||
- name: startTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: startTime
|
||||
zh_Hans: startTime
|
||||
pt_BR: startTime
|
||||
human_description:
|
||||
en_US: Data query start time
|
||||
zh_Hans: 开始时间 (微秒)
|
||||
pt_BR: Data query start time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
- name: endTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: endTime
|
||||
zh_Hans: endTime
|
||||
pt_BR: endTime
|
||||
human_description:
|
||||
en_US: Data query end time
|
||||
zh_Hans: 结束时间 (微秒)
|
||||
pt_BR: Data query end time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
@ -0,0 +1,44 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from configs import dify_config
|
||||
from core.tools.builtin_tool.tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from libs.apo_utils import APOUtils
|
||||
|
||||
|
||||
class NodeCpuUtilizationLinuxTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
conversation_id: Optional[str] = None,
|
||||
app_id: Optional[str] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Generator[ToolInvokeMessage, None, None]:
|
||||
cluster = tool_parameters.get('cluster', '.*')
|
||||
start_time = tool_parameters.get("startTime")
|
||||
end_time = tool_parameters.get("endTime")
|
||||
params = {
|
||||
'metricName': '集群总览 - 节点资源使用 - 节点CPU使用率 - Linux',
|
||||
'params': {
|
||||
'cluster': cluster
|
||||
},
|
||||
'startTime': start_time,
|
||||
'endTime': end_time,
|
||||
'step': APOUtils.get_step(start_time, end_time),
|
||||
}
|
||||
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
|
||||
list = resp.json()['result']
|
||||
list = json.dumps({
|
||||
'type': 'metric',
|
||||
'display': True,
|
||||
'unit': list['unit'],
|
||||
'data': {
|
||||
'timeseries': list['timeseries']
|
||||
}
|
||||
})
|
||||
yield self.create_text_message(list)
|
||||
@ -0,0 +1,53 @@
|
||||
identity:
|
||||
name: Linux节点CPU使用率
|
||||
author: APO
|
||||
label:
|
||||
en_US: Linux node CPU utilization rate
|
||||
zh_Hans: Linux节点CPU使用率
|
||||
description:
|
||||
human:
|
||||
en_US: Linux node CPU utilization rate
|
||||
zh_Hans: Linux节点CPU使用率
|
||||
llm: Linux node CPU utilization rate
|
||||
display:
|
||||
type: metric
|
||||
title: 集群总览 - 节点资源使用 - 节点CPU使用率 - Linux
|
||||
unit: "percentunit"
|
||||
parameters:
|
||||
- name: cluster
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
human_description:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
llm_description: Cluster name
|
||||
form: llm
|
||||
- name: startTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: startTime
|
||||
zh_Hans: startTime
|
||||
pt_BR: startTime
|
||||
human_description:
|
||||
en_US: Data query start time
|
||||
zh_Hans: 开始时间 (微秒)
|
||||
pt_BR: Data query start time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
- name: endTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: endTime
|
||||
zh_Hans: endTime
|
||||
pt_BR: endTime
|
||||
human_description:
|
||||
en_US: Data query end time
|
||||
zh_Hans: 结束时间 (微秒)
|
||||
pt_BR: Data query end time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
@ -0,0 +1,44 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from configs import dify_config
|
||||
from core.tools.builtin_tool.tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from libs.apo_utils import APOUtils
|
||||
|
||||
|
||||
class NodeMemoryUsageLinuxTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
conversation_id: Optional[str] = None,
|
||||
app_id: Optional[str] = None,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Generator[ToolInvokeMessage, None, None]:
|
||||
cluster = tool_parameters.get('cluster', '.*')
|
||||
start_time = tool_parameters.get("startTime")
|
||||
end_time = tool_parameters.get("endTime")
|
||||
params = {
|
||||
'metricName': '集群总览 - 节点资源使用 - 节点内存使用量 - Linux',
|
||||
'params': {
|
||||
'cluster': cluster
|
||||
},
|
||||
'startTime': start_time,
|
||||
'endTime': end_time,
|
||||
'step': APOUtils.get_step(start_time, end_time),
|
||||
}
|
||||
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
|
||||
list = resp.json()['result']
|
||||
list = json.dumps({
|
||||
'type': 'metric',
|
||||
'display': True,
|
||||
'unit': list['unit'],
|
||||
'data': {
|
||||
'timeseries': list['timeseries']
|
||||
}
|
||||
})
|
||||
yield self.create_text_message(list)
|
||||
@ -0,0 +1,53 @@
|
||||
identity:
|
||||
name: Linux节点内存使用字节数
|
||||
author: APO
|
||||
label:
|
||||
en_US: Linux node memory usage in bytes
|
||||
zh_Hans: Linux节点内存使用字节数
|
||||
description:
|
||||
human:
|
||||
en_US: Linux node memory usage in bytes
|
||||
zh_Hans: Linux节点内存使用字节数
|
||||
llm: Linux node memory usage in bytes
|
||||
display:
|
||||
type: metric
|
||||
title: 集群总览 - 节点资源使用 - 节点内存使用量 - Linux
|
||||
unit: "bytes"
|
||||
parameters:
|
||||
- name: cluster
|
||||
type: string
|
||||
required: False
|
||||
label:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
human_description:
|
||||
en_US: Cluster name
|
||||
zh_Hans: 集群名称
|
||||
llm_description: Cluster name
|
||||
form: llm
|
||||
- name: startTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: startTime
|
||||
zh_Hans: startTime
|
||||
pt_BR: startTime
|
||||
human_description:
|
||||
en_US: Data query start time
|
||||
zh_Hans: 开始时间 (微秒)
|
||||
pt_BR: Data query start time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
- name: endTime
|
||||
type: number
|
||||
required: true
|
||||
label:
|
||||
en_US: endTime
|
||||
zh_Hans: endTime
|
||||
pt_BR: endTime
|
||||
human_description:
|
||||
en_US: Data query end time
|
||||
zh_Hans: 结束时间 (微秒)
|
||||
pt_BR: Data query end time
|
||||
llm_description: Data query start time
|
||||
form: llm
|
||||
@ -0,0 +1,11 @@
|
||||
from flask import Flask
|
||||
from . import (
|
||||
account,
|
||||
workflow
|
||||
)
|
||||
from .decorator import _initializers
|
||||
|
||||
def run_initializers(app: Flask):
|
||||
with app.app_context():
|
||||
for func, _ in sorted(_initializers, key=lambda x: x[1]):
|
||||
func()
|
||||
@ -0,0 +1,28 @@
|
||||
from models import Account
|
||||
from extensions.ext_database import db
|
||||
from services.account_service import RegisterService, AccountService, TenantService
|
||||
from .decorator import initializer
|
||||
from .admin import get_admin
|
||||
|
||||
|
||||
@initializer(priority=1)
|
||||
def init_admin_account():
|
||||
if db.session.query(Account).filter_by(name="admin").first():
|
||||
return
|
||||
|
||||
registerService = RegisterService()
|
||||
registerService.setup("admin@apo.com", "admin", "APO2024@admin", "")
|
||||
|
||||
|
||||
@initializer(priority=2)
|
||||
def init_anonymous_account():
|
||||
if db.session.query(Account).filter_by(name="anonymous").first():
|
||||
return
|
||||
|
||||
accountService = AccountService()
|
||||
anonymous = accountService.create_account("anonymous@apo.com", "anonymous", "en-US", "APO2024@anonymous", True)
|
||||
|
||||
admin = get_admin()
|
||||
tenantService = TenantService()
|
||||
tenant = tenantService.get_current_tenant_by_account(admin)
|
||||
tenantService.create_tenant_member(tenant, anonymous)
|
||||
@ -0,0 +1,11 @@
|
||||
from extensions.ext_database import db
|
||||
from models import Account, Tenant, TenantAccountJoin, TenantAccountRole
|
||||
|
||||
def get_admin() -> Account:
|
||||
admin = db.session.query(Account).filter_by(name="admin").first()
|
||||
tenant_account_join = db.session.query(TenantAccountJoin).filter_by(account_id=admin.id, role=TenantAccountRole.OWNER).first()
|
||||
tenant = db.session.query(Tenant).filter_by(id=tenant_account_join.tenant_id).first()
|
||||
admin.current_tenant = tenant
|
||||
admin.current_tenant_id = tenant.id
|
||||
return admin
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
from typing import Callable, List, Tuple
|
||||
|
||||
_initializers: List[Tuple[Callable, int]] = []
|
||||
|
||||
def initializer(priority: int = 10) -> Callable:
|
||||
def decorator(func: Callable) -> Callable:
|
||||
_initializers.append((func, priority))
|
||||
return func
|
||||
return decorator
|
||||
@ -0,0 +1,203 @@
|
||||
import os
|
||||
import yaml
|
||||
import logging
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from services.app_dsl_service import AppDslService
|
||||
from services.workflow_service import WorkflowService
|
||||
from extensions.ext_database import db
|
||||
from .decorator import initializer
|
||||
from .admin import get_admin
|
||||
from models import App, ApiToken, Workflow, InstalledApp
|
||||
from contexts import tenant_id
|
||||
from configs.app_config import APOConfig
|
||||
from typing import Union
|
||||
|
||||
@initializer(priority=3)
|
||||
def init_workflow():
|
||||
apo_config = APOConfig()
|
||||
initial_language = apo_config.INITIAL_LANGUAGE
|
||||
workflow_dir = apo_config.WORKFLOW_DIR
|
||||
|
||||
sub_dir = ''
|
||||
if initial_language == 'en-US':
|
||||
sub_dir = 'en'
|
||||
elif initial_language == 'zh-Hans':
|
||||
sub_dir = 'zh'
|
||||
workflows = []
|
||||
dir = f'{workflow_dir}/{sub_dir}'
|
||||
if not os.path.isdir(dir):
|
||||
raise ValueError(f"Invalid directory: {dir}")
|
||||
|
||||
for file_entry in os.scandir(dir):
|
||||
if not file_entry.name.endswith('.yaml') and not file_entry.name.endswith('.yml') or file_entry.name.startswith('.'):
|
||||
continue
|
||||
try:
|
||||
with open(file_entry.path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
workflows.append(content)
|
||||
except Exception as e:
|
||||
logging.ERROR(f"Failed to read file: {file_entry.path}")
|
||||
|
||||
admin = get_admin()
|
||||
try:
|
||||
original_token = tenant_id.set(admin.current_tenant_id)
|
||||
for w in workflows:
|
||||
result = _check_workflow_to_update(db.session, w, admin)
|
||||
|
||||
if result is False:
|
||||
continue
|
||||
|
||||
import_service = AppDslService(db.session)
|
||||
workflow_service = WorkflowService()
|
||||
|
||||
'''Import an app or update existing app'''
|
||||
imp = import_service.import_app(
|
||||
account=admin,
|
||||
import_mode="yaml-content",
|
||||
yaml_content=w,
|
||||
app_id=result if result else None
|
||||
)
|
||||
|
||||
app_model = (
|
||||
db.session.query(App)
|
||||
.filter(
|
||||
App.id == imp.app_id,
|
||||
App.tenant_id == admin.current_tenant_id,
|
||||
App.status == "normal"
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
workflow_service.publish_workflow(app_model=app_model, account=admin)
|
||||
if result is None:
|
||||
_generate_api_key(db.session, imp.app_id, admin)
|
||||
db.session.commit()
|
||||
_adjust_workflows(initial_language)
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise
|
||||
finally:
|
||||
tenant_id.reset(original_token)
|
||||
|
||||
def _check_workflow_to_update(session, content, account) -> Union[str, bool, None]:
|
||||
"""Check if the workflow needs to be updated or created.
|
||||
- None: Need to create a new App.
|
||||
- str(app_id): Need to update the existing App.
|
||||
- False: No need to update.
|
||||
"""
|
||||
try:
|
||||
content_dict = yaml.safe_load(content)
|
||||
app_name = content_dict.get('app', {}).get('name')
|
||||
graph = content_dict.get('workflow', {}).get('graph')
|
||||
features = content_dict.get('workflow', {}).get('features')
|
||||
|
||||
app_model = (
|
||||
session.query(App)
|
||||
.filter(
|
||||
App.name == app_name,
|
||||
App.tenant_id == account.current_tenant_id,
|
||||
App.status == "normal",
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not app_model:
|
||||
return None
|
||||
|
||||
workflow = (
|
||||
session.query(Workflow)
|
||||
.filter(
|
||||
Workflow.graph == graph,
|
||||
Workflow.features == features,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if workflow:
|
||||
return False
|
||||
else:
|
||||
return app_model.id
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to check workflow: {str(e)}")
|
||||
return False
|
||||
|
||||
def _generate_api_key(session, app_id, account, key=None):
|
||||
if not app_id or not account:
|
||||
return
|
||||
|
||||
key = key or ApiToken.generate_api_key('app-', 24)
|
||||
api_token = ApiToken(
|
||||
app_id=app_id,
|
||||
tenant_id=account.current_tenant_id,
|
||||
token=key,
|
||||
type='app'
|
||||
)
|
||||
session.add(api_token)
|
||||
|
||||
|
||||
def _adjust_workflows(language):
|
||||
to_adjust = {
|
||||
"zh-Hans": {
|
||||
"告警有效性分析": {
|
||||
"app_id": "dcfeddd2-d6e7-4dc4-a284-e48ab56bf6af",
|
||||
"api_token": "app-x0mOJKUvhr35BOISSeNmsfXj"
|
||||
},
|
||||
"告警简单根因分析": {
|
||||
"app_id": "a2d4d3aa-3401-4393-859e-df051bdd5cd1"
|
||||
}
|
||||
},
|
||||
"en-US": {
|
||||
"alert validity confirmation": {
|
||||
"app_id": "dcfeddd2-d6e7-4dc4-a284-e48ab56bf6af",
|
||||
"api_token": "app-x0mOJKUvhr35BOISSeNmsfXj"
|
||||
},
|
||||
"alert simple root cause analysis": {
|
||||
"app_id": "a2d4d3aa-3401-4393-859e-df051bdd5cd1"
|
||||
}
|
||||
}
|
||||
}
|
||||
try:
|
||||
config = to_adjust.get(language)
|
||||
for app_name, field_config in config.items():
|
||||
app = db.session.query(App).filter_by(name=app_name).first()
|
||||
new_app_id = field_config["app_id"]
|
||||
if not app:
|
||||
continue
|
||||
|
||||
if app.id == new_app_id:
|
||||
continue
|
||||
|
||||
origin_app_id = app.id
|
||||
update_mappings = [
|
||||
(ApiToken, {"app_id": new_app_id}),
|
||||
(Workflow, {"app_id": new_app_id}),
|
||||
(InstalledApp, {"app_id": new_app_id})
|
||||
]
|
||||
|
||||
for model, update_values in update_mappings:
|
||||
db.session.query(model)\
|
||||
.filter_by(app_id=origin_app_id)\
|
||||
.update(update_values, synchronize_session=False)
|
||||
|
||||
app.id = new_app_id
|
||||
db.session.merge(app)
|
||||
|
||||
if "api_token" in field_config:
|
||||
new_token = field_config["api_token"]
|
||||
db.session.query(ApiToken)\
|
||||
.filter_by(app_id=new_app_id)\
|
||||
.update({"token": new_token}, synchronize_session=False)
|
||||
|
||||
db.session.commit()
|
||||
print(f"Successfully updated {app_name} (ID: {origin_app_id} → {new_app_id})")
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
logging.ERROR(f"Database error occurred: {str(e)}")
|
||||
raise
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
logging.ERROR(f"Unexpected error: {str(e)}")
|
||||
raise
|
||||
Loading…
Reference in New Issue