From 3e49c3d80a0d94685b648a2f7370dc8378d603e4 Mon Sep 17 00:00:00 2001
From: v_xugzhou <941071842@qq.com>
Date: Thu, 12 Dec 2024 14:49:25 +0800
Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=E7=AC=AC=E4=B8=89=E6=96=B9=E6=8F=92?=
=?UTF-8?q?=E4=BB=B6=E6=89=A7=E8=A1=8C=E4=B8=AD=E8=B0=83=E7=94=A8=20detail?=
=?UTF-8?q?=20=E6=8E=A5=E5=8F=A3=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=20--story=3D120926155=20#=20Reviewed,=20tran?=
=?UTF-8?q?saction=20id:=2026577?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/desktop/src/pages/task/TaskExecute/ExecuteInfo.vue | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/frontend/desktop/src/pages/task/TaskExecute/ExecuteInfo.vue b/frontend/desktop/src/pages/task/TaskExecute/ExecuteInfo.vue
index 0bd5be39e..3a82ba6ba 100644
--- a/frontend/desktop/src/pages/task/TaskExecute/ExecuteInfo.vue
+++ b/frontend/desktop/src/pages/task/TaskExecute/ExecuteInfo.vue
@@ -684,7 +684,7 @@
},
// 补充记录缺少的字段
async setFillRecordField (record) {
- const { version, component_code: componentCode } = this.nodeDetailConfig
+ const { version, component_code: componentCode, componentData = {} } = this.nodeDetailConfig
const { inputs, state } = record
let outputs = record.outputs
// 执行记录的outputs可能为Object格式,需要转为Array格式
@@ -721,7 +721,8 @@
const keys = Object.keys(inputs)
this.renderConfig = renderConfig.filter(item => keys.includes(item.tag_code))
} else if (componentCode) { // 任务节点需要加载标准插件
- await this.getNodeConfig(componentCode, version, inputs.plugin_version)
+ const pluginVersion = componentData.plugin_version?.value
+ await this.getNodeConfig(componentCode, version, pluginVersion)
}
inputsInfo = Object.keys(inputs).reduce((acc, cur) => {
const scheme = Array.isArray(this.renderConfig) ? this.renderConfig.find(item => item.tag_code === cur) : null
From b4fa7f1fc249fc937902d57672da69bbff88e710 Mon Sep 17 00:00:00 2001
From: waylon <1158341873@qq.com>
Date: Wed, 18 Dec 2024 11:28:14 +0800
Subject: [PATCH 2/5] feat: release V3.32.1-p3 #7567
---
app.yml | 2 +-
app_desc.yaml | 2 +-
config/default.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app.yml b/app.yml
index 1dedbf048..0b1123cff 100644
--- a/app.yml
+++ b/app.yml
@@ -6,7 +6,7 @@ is_use_celery: True
author: 蓝鲸智云
introduction: 标准运维是通过一套成熟稳定的任务调度引擎,把在多系统间的工作整合到一个流程,助力运维实现跨系统调度自动化的SaaS应用。
introduction_en: SOPS is a SaaS application that utilizes a set of mature and stable task scheduling engines to help realize cross-system scheduling automation, and integrates the work among multiple systems into a single process.
-version: 3.32.1-p2
+version: 3.32.1-p3
category: 运维工具
language_support: 中文
desktop:
diff --git a/app_desc.yaml b/app_desc.yaml
index 4ebea3fc0..53476dd44 100644
--- a/app_desc.yaml
+++ b/app_desc.yaml
@@ -1,5 +1,5 @@
spec_version: 2
-app_version: "3.32.1-p2"
+app_version: "3.32.1-p3"
app:
region: default
bk_app_code: bk_sops
diff --git a/config/default.py b/config/default.py
index ba5c58e90..2e1e75557 100644
--- a/config/default.py
+++ b/config/default.py
@@ -214,7 +214,7 @@
# mako模板中:
# 如果静态资源修改了以后,上线前改这个版本号即可
-STATIC_VERSION = "3.32.1-p2"
+STATIC_VERSION = "3.32.1-p3"
DEPLOY_DATETIME = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
From 97cbdfb301489b4b490db8ae34e1349486d8b270 Mon Sep 17 00:00:00 2001
From: guohelu <19503896967@163.com>
Date: Wed, 18 Dec 2024 18:47:39 +0800
Subject: [PATCH 3/5] =?UTF-8?q?feat:=20sops=20=E5=9B=9E=E8=B0=83=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD=E5=90=8C=E6=AD=A5=E4=BB=A3=E7=A0=81=20--story=3D12088?=
=?UTF-8?q?3063?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gcloud/apigw/views/create_task.py | 9 +++++-
gcloud/taskflow3/domains/callback.py | 9 ++++--
gcloud/taskflow3/models.py | 2 ++
gcloud/taskflow3/signals/handlers.py | 41 ++++++++++++++++------------
4 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/gcloud/apigw/views/create_task.py b/gcloud/apigw/views/create_task.py
index 30335a038..e27b2b8c8 100644
--- a/gcloud/apigw/views/create_task.py
+++ b/gcloud/apigw/views/create_task.py
@@ -100,6 +100,7 @@ def create_task(request, template_id, project_id):
"code": err_code.REQUEST_PARAM_INVALID.code,
"message": f"callback_url format error, must match {CALLBACK_URL_PATTERN}",
}
+ callback_version = params.get("callback_version", None)
# 兼容老版本的接口调用
if template_source in NON_COMMON_TEMPLATE_TYPES:
@@ -214,7 +215,13 @@ def create_task(request, template_id, project_id):
# create callback url record
if callback_url:
- TaskCallBackRecord.objects.create(task_id=task.id, url=callback_url)
+ record_kwargs = {
+ "task_id": task.id,
+ "url": callback_url,
+ }
+ if callback_version:
+ record_kwargs["extra_info"] = json.dumps({"callback_version": callback_version})
+ TaskCallBackRecord.objects.create(**record_kwargs)
# crete auto retry strategy
arn_creator = AutoRetryNodeStrategyCreator(taskflow_id=task.id, root_pipeline_id=task.pipeline_instance.instance_id)
diff --git a/gcloud/taskflow3/domains/callback.py b/gcloud/taskflow3/domains/callback.py
index 043b82966..842f279ff 100644
--- a/gcloud/taskflow3/domains/callback.py
+++ b/gcloud/taskflow3/domains/callback.py
@@ -32,7 +32,8 @@ class TaskCallBacker:
def __init__(self, task_id, *args, **kwargs):
self.task_id = task_id
self.record = TaskCallBackRecord.objects.filter(task_id=self.task_id).first()
- self.extra_info = {"task_id": self.task_id, **json.loads(self.record.extra_info), **kwargs}
+ self.record_extra_info = json.loads(self.record.extra_info)
+ self.extra_info = {"task_id": self.task_id, **self.record_extra_info, **kwargs}
def check_record_existence(self):
return True if self.record else False
@@ -96,9 +97,13 @@ def _url_callback(self):
logger.error(f"[TaskCallBacker _url_callback] get lock error: {err}")
return None
url = self.record.url
+ callback_version = self.record_extra_info.get("callback_version")
response = None
try:
- response = requests.post(url, data=self.extra_info)
+ if callback_version == TaskCallBackRecord.CALLBACK_VERSION_V2:
+ response = requests.post(url, json=self.extra_info)
+ else:
+ response = requests.post(url, data=self.extra_info)
response.raise_for_status()
except HTTPError as e:
message = (
diff --git a/gcloud/taskflow3/models.py b/gcloud/taskflow3/models.py
index 20fb804e8..b0df2c954 100644
--- a/gcloud/taskflow3/models.py
+++ b/gcloud/taskflow3/models.py
@@ -1356,6 +1356,8 @@ class Meta:
class TaskCallBackRecord(models.Model):
+ CALLBACK_VERSION_V2 = "v2"
+
id = models.BigAutoField(verbose_name="ID", primary_key=True)
task_id = models.BigIntegerField(verbose_name=_("任务ID"), db_index=True)
url = models.TextField(verbose_name=_("回调地址"))
diff --git a/gcloud/taskflow3/signals/handlers.py b/gcloud/taskflow3/signals/handlers.py
index 7788dea64..c21a6d3ba 100644
--- a/gcloud/taskflow3/signals/handlers.py
+++ b/gcloud/taskflow3/signals/handlers.py
@@ -47,25 +47,23 @@
def _finish_taskflow_and_send_signal(instance_id, sig, task_success=False):
- qs = TaskFlowInstance.objects.filter(pipeline_instance__instance_id=instance_id).only("id")
- if not qs:
+ task = TaskFlowInstance.objects.filter(pipeline_instance__instance_id=instance_id).first()
+ if not task:
logger.error("pipeline archive handler get taskflow error, pipeline_instance_id={}".format(instance_id))
return
- task_id = qs[0].id
-
- TaskFlowInstance.objects.filter(id=task_id).update(current_flow="finished")
- sig.send(TaskFlowInstance, task_id=task_id)
+ TaskFlowInstance.objects.filter(id=task.id).update(current_flow="finished")
+ sig.send(TaskFlowInstance, task_id=task.id)
if task_success:
- _check_and_callback(task_id, task_success=task_success, task=qs[0])
+ _check_and_callback(task, task_success=task_success)
try:
- send_taskflow_message.delay(task_id=task_id, msg_type=TASK_FINISHED)
+ send_taskflow_message.delay(task_id=task.id, msg_type=TASK_FINISHED)
except Exception as e:
- logger.exception("send_taskflow_message[taskflow_id=%s] task delay error: %s" % (task_id, e))
+ logger.exception("send_taskflow_message[taskflow_id=%s] task delay error: %s" % (task.id, e))
if sig is taskflow_revoked:
- _check_and_callback(task_id, task_success=False, task=qs[0])
+ _check_and_callback(task, task_success=False)
def _send_node_fail_message(node_id, pipeline_id):
@@ -74,7 +72,7 @@ def _send_node_fail_message(node_id, pipeline_id):
except TaskFlowInstance.DoesNotExist:
logger.error("pipeline finished handler get taskflow error, pipeline_instance_id=%s" % pipeline_id)
return
- _check_and_callback(taskflow.id, task_success=False, task=taskflow)
+ _check_and_callback(taskflow, task_success=False)
if taskflow.is_child_taskflow is False:
try:
@@ -85,15 +83,24 @@ def _send_node_fail_message(node_id, pipeline_id):
logger.exception("pipeline_fail_handler[taskflow_id=%s] task delay error: %s" % (taskflow.id, e))
-def _check_and_callback(taskflow_id, *args, **kwargs):
- if not TaskCallBackRecord.objects.filter(task_id=taskflow_id).exists():
+def _check_and_callback(task, *args, **kwargs):
+ record = TaskCallBackRecord.objects.filter(task_id=task.id).first()
+ if not record:
return
try:
- if kwargs.get("task"):
- task = kwargs.pop("task")
- kwargs["task_outputs"] = json.dumps(task.get_task_detail()["outputs"])
+ if (
+ record.url
+ and json.loads(record.extra_info).get("callback_version") == TaskCallBackRecord.CALLBACK_VERSION_V2
+ ):
+ # 检查任务的输出是否可以被json序列化,如果可以则将输出作为参数传给回调函数,否则不做处理
+ try:
+ task_outputs = task.get_task_detail()["outputs"]
+ json.dumps(task_outputs)
+ kwargs["task_outputs"] = task_outputs
+ except Exception as e:
+ logger.exception(f"[task {task.id}] outputs data serialize error: {e}")
task_callback.apply_async(
- kwargs=dict(task_id=taskflow_id, **kwargs),
+ kwargs=dict(task_id=task.id, **kwargs),
queue="task_callback",
routing_key="task_callback",
)
From dd2f303d9b5a90227b1345ea9ba9e6509d4478e3 Mon Sep 17 00:00:00 2001
From: v_xugzhou <941071842@qq.com>
Date: Mon, 23 Dec 2024 12:04:02 +0800
Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=E5=8F=98=E9=87=8F=E7=BC=96=E8=BE=91?=
=?UTF-8?q?--GSEKit=20ip=E9=80=89=E6=8B=A9=E5=99=A8=E5=8F=98=E9=87=8F?=
=?UTF-8?q?=E5=88=87ip=E9=80=89=E6=8B=A9=E5=99=A8=E5=90=8E=E6=97=A0?=
=?UTF-8?q?=E6=B3=95=E6=AD=A3=E5=B8=B8=E6=93=8D=E4=BD=9C=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=20--story=3D121335817=20#=20Reviewed,=20tran?=
=?UTF-8?q?saction=20id:=2027466?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../TemplateSetting/TabGlobalVariables/VariableEdit.vue | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/frontend/desktop/src/pages/template/TemplateEdit/TemplateSetting/TabGlobalVariables/VariableEdit.vue b/frontend/desktop/src/pages/template/TemplateEdit/TemplateSetting/TabGlobalVariables/VariableEdit.vue
index 5dc8fa80d..868231553 100644
--- a/frontend/desktop/src/pages/template/TemplateEdit/TemplateSetting/TabGlobalVariables/VariableEdit.vue
+++ b/frontend/desktop/src/pages/template/TemplateEdit/TemplateSetting/TabGlobalVariables/VariableEdit.vue
@@ -658,9 +658,10 @@
},
// 变量类型切换
onValTypeChange (val, oldValue) {
- // 将上一个类型的填写的数据存起来("集群模块IP选择器"的code与"ip选择器"code相同,需要单独处理)
- const valData = oldValue === 'set_module_ip_selector'
- ? { set_module_ip_selector: tools.deepClone(this.renderData['ip_selector']) }
+ // 将上一个类型的填写的数据存起来("集群模块IP选择器"和"GSEKit IP选择器"的code与"ip选择器"code相同,需要单独处理)
+ const sameIpSelectorCode = ['set_module_ip_selector', 'gse_kit_ip_selector']
+ const valData = sameIpSelectorCode.includes(oldValue)
+ ? { [oldValue]: tools.deepClone(this.renderData['ip_selector']) }
: tools.deepClone(this.renderData)
Object.assign(this.varTypeData, valData)
// 将input textarea类型正则存起来
@@ -677,7 +678,7 @@
})
if (val in this.varTypeData) {
const value = this.varTypeData[val]
- this.renderData = { [val === 'set_module_ip_selector' ? 'ip_selector' : val]: value }
+ this.renderData = { [sameIpSelectorCode.includes(val) ? 'ip_selector' : val]: value }
} else {
this.renderData = {}
}
From cc7ed72eb92f75ff6c2df557579d6321e8300d22 Mon Sep 17 00:00:00 2001
From: waylon <1158341873@qq.com>
Date: Fri, 27 Dec 2024 18:47:59 +0800
Subject: [PATCH 5/5] feat: release V3.32.1-p4 #7567
---
app.yml | 2 +-
app_desc.yaml | 2 +-
config/default.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app.yml b/app.yml
index 0b1123cff..83131947a 100644
--- a/app.yml
+++ b/app.yml
@@ -6,7 +6,7 @@ is_use_celery: True
author: 蓝鲸智云
introduction: 标准运维是通过一套成熟稳定的任务调度引擎,把在多系统间的工作整合到一个流程,助力运维实现跨系统调度自动化的SaaS应用。
introduction_en: SOPS is a SaaS application that utilizes a set of mature and stable task scheduling engines to help realize cross-system scheduling automation, and integrates the work among multiple systems into a single process.
-version: 3.32.1-p3
+version: 3.32.1-p4
category: 运维工具
language_support: 中文
desktop:
diff --git a/app_desc.yaml b/app_desc.yaml
index 53476dd44..7954c0735 100644
--- a/app_desc.yaml
+++ b/app_desc.yaml
@@ -1,5 +1,5 @@
spec_version: 2
-app_version: "3.32.1-p3"
+app_version: "3.32.1-p4"
app:
region: default
bk_app_code: bk_sops
diff --git a/config/default.py b/config/default.py
index 7bb4b5667..5c1599623 100644
--- a/config/default.py
+++ b/config/default.py
@@ -215,7 +215,7 @@
# mako模板中:
# 如果静态资源修改了以后,上线前改这个版本号即可
-STATIC_VERSION = "3.32.1-p3"
+STATIC_VERSION = "3.32.1-p4"
DEPLOY_DATETIME = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]