update pre_add_web follow base

This commit is contained in:
cdllp2 2022-11-23 17:01:10 +08:00
parent 664268408e
commit 27bbc65e4d
13 changed files with 168 additions and 59 deletions

View File

@ -181,7 +181,7 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
"sqllchemy_uri":StringField(
_(datamodel.obj.lab('sqllchemy_uri')),
default="",
description='链接串地址: <br> mysql+pymysql://root:admin@host.docker.internal:3306/db_name?charset=utf8 <br> postgresql+psycopg2://root:admin@host.docker.internal:5432/db_name',
description='链接串地址: <br> 示例mysql+pymysql://$账号:$密码@$ip:$端口/$库名?charset=utf8 <br> 示例postgresql+psycopg2://$账号:$密码@$ip:$端口/$库名',
widget=BS3TextFieldWidget(),
validators=[DataRequired(),Regexp("^(mysql\+pymysql|postgresql\+psycopg2)")]
),
@ -249,7 +249,8 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
if not item.owner or g.user.username not in item.owner:
item.owner = g.user.username if not item.owner else item.owner + "," + g.user.username
flash('添加或修改字段类型,需要点击创建远程表,已实现在远程数据库上建表','warning')
flash('添加或修改字段类型,需要点击创建远程表,以实现在远程数据库上建表','warning')
def pre_update(self, item):
if not item.sqllchemy_uri:
item.sqllchemy_uri=self.src_item_json.get('sqllchemy_uri','')
@ -257,7 +258,7 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
# 转换为前端list
def pre_get(self,_response):
def pre_show_res(self,_response):
data = _response['data']
columns=json.loads(data.get('columns','{}'))
columns_list=[]
@ -268,8 +269,8 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
data['columns']=columns_list
# 将前端columns list转化为字段存储
def pre_json_load(self, req_json=None):
# 添加或者更新前将前端columns list转化为字段存储
def pre_add_req(self, req_json=None):
if req_json and 'columns' in req_json:
columns={}
for col in req_json.get('columns',[]):
@ -277,6 +278,8 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
req_json['columns'] = json.dumps(columns,indent=4,ensure_ascii=False)
return req_json
pre_update_req=pre_add_req
# 获取指定维表里面的数据
@staticmethod
def get_dim_target_data(dim_id):
@ -324,7 +327,7 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
sqllchemy_uri = item.sqllchemy_uri
if sqllchemy_uri:
# 创建数据库的sql(如果数据库存在就不创建,防止异常)
if 'postgresql' in item.sqllchemy_uri:
if 'postgresql' in sqllchemy_uri:
# 创建pg表
import sqlalchemy.engine.url as url
@ -388,7 +391,7 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
# 创建数据库的sql(如果数据库存在就不创建,防止异常)
if 'mysql' in item.sqllchemy_uri:
if 'mysql' in sqllchemy_uri:
# 创建mysql表
import sqlalchemy.engine.url as url
uri = url.make_url(sqllchemy_uri)
@ -454,6 +457,10 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
dbsession.close()
# 如果远程有表,就增加字段
all_dimension = conf.get('all_dimension_instance', {})
if "dimension_%s"%dim_id in all_dimension:
del all_dimension["dimension_%s"%dim_id]
url_path = conf.get('MODEL_URLS', {}).get("dimension")+'?targetId='+dim_id
return redirect(url_path)
@ -511,10 +518,13 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
search_columns = []
label_columns={}
add_columns=[]
edit_columns=[]
show_columns=[]
list_columns=[]
description_columns={}
add_form_extra_fields={}
add_form_query_rel_fields={}
validators_columns={}
order_columns=[]
cols_width = {
}
@ -573,14 +583,16 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
label_columns[column_name]=columns[column_name]['describe']
description_columns[column_name] = columns[column_name]['describe']
add_columns.append(column_name)
if not int(columns[column_name].get('primary_key',False)):
add_columns.append(column_name)
show_columns.append(column_name)
list_columns.append(column_name)
if not int(columns[column_name].get('primary_key', False)):
list_columns.append(column_name)
if column_type == 'string' or column_type=='text' or column_type=='int':
if not int(columns[column_name].get('primary_key',False)):
search_columns.append(column_name)
if column_type == 'int':
order_columns.append(column_name)
# if column_type == 'int':
order_columns.append(column_name)
bind_key = 'dimension_%s' % dim.id
# SQLALCHEMY_BINDS = conf.get('SQLALCHEMY_BINDS', {})
@ -702,7 +714,7 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
elif cols.get(key,{}).get('column_type','text')=='double':
data[key]=float(data[key]) if data[key] else None
else:
data[key]=str(data[key])
data[key]=str(data[key]).replace('\n',' ')
except Exception as e:
print(e)
data[key] = None
@ -755,6 +767,36 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
)
@action("copy_row", __("Copy"), __("复制所选记录 all Really?"), "fa-trash", single=False)
# @pysnooper.snoop(watch_explode=('items'))
def copy_row(self, items):
if not items:
abort(404)
success = []
fail = []
for item in items:
try:
req_json = item.to_json()
if 'id' in req_json:
del req_json["id"]
json_data = self.pre_add_req(req_json)
new_item = self.add_model_schema.load(json_data)
self.pre_add(new_item.data)
self.datamodel.add(new_item.data, raise_exception=True)
self.post_add(new_item.data)
result_data = self.add_model_schema.dump(new_item.data, many=False).data
success.append(item.to_json())
except Exception as e:
flash(str(e), "danger")
fail.append(item.to_json())
db.session.commit()
return json.dumps(
{
"success": success,
"fail": fail
}, indent=4, ensure_ascii=False
)
view_class = type(
"Dimension_%s_ModelView_Api"%dim.id, (MyappModelRestApi,),
dict(
@ -765,12 +807,14 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
spec_label_columns=spec_label_columns,
search_columns=search_columns,
order_columns=order_columns,
add_columns=add_columns,
label_title = dim.label,
base_permissions = ['can_list','can_add','can_delete','can_edit','can_show'],
pre_add=pre_add,
pre_update=pre_update,
upload=upload,
muldelete=muldelete,
copy_row=copy_row,
dim_id=dim_id,
import_data=True,
download_data=True,
@ -792,9 +836,9 @@ class Dimension_remote_table_ModelView_Api(MyappModelRestApi):
@expose("/<dim_id>/api/<int:pk>", methods=["GET"])
def dim_api_get(self, dim_id,pk, **kwargs):
def dim_api_show(self, dim_id,pk, **kwargs):
view_instance = self.set_model(dim_id)
return view_instance.api_get(pk,**kwargs)
return view_instance.api_show(pk,**kwargs)
@expose("/<dim_id>/api/", methods=["GET"])
def dim_api_list(self,dim_id, **kwargs):

View File

@ -98,7 +98,7 @@ class Docker_ModelView_Base():
}
edit_form_extra_fields=add_form_extra_fields
# @pysnooper.snoop()
def pre_add_get(self,docker=None):
def pre_add_web(self,docker=None):
self.add_form_extra_fields['target_image']=StringField(
_(self.datamodel.obj.lab('target_image')),
default=conf.get('REPOSITORY_ORG')+g.user.username+":"+datetime.datetime.now().strftime('%Y.%m.%d'+".1"),
@ -111,7 +111,7 @@ class Docker_ModelView_Base():
self.edit_form_extra_fields = self.add_form_extra_fields
pre_update_get=pre_add_get
pre_update_web=pre_add_web
def pre_add(self,item):
image_org=conf.get('REPOSITORY_ORG')+g.user.username+":"

View File

@ -79,7 +79,7 @@ class Repository_ModelView_Base():
validators=[Regexp("^[a-z][a-z0-9\-]*[a-z0-9]$"), Length(1, 54),DataRequired()]
)
pre_add_get = set_column
pre_add_web = set_column
# create hubsecret
# @pysnooper.snoop()

View File

@ -316,7 +316,7 @@ class InferenceService_ModelView_base():
edit_fieldsets = add_fieldsets
def pre_add_get(self):
def pre_add_web(self):
self.default_filter = {
"created_by": g.user.id
}
@ -620,7 +620,7 @@ output %s
# 修改了名称的话,要把之前的删掉
self.use_expand(item)
# 如果模型版本和名称变了,需要把之前的服务删除掉
# 如果模型版本和模型名称变了,需要把之前的服务删除掉
if self.src_item_json.get('name','') and item.name!=self.src_item_json.get('name',''):
self.delete_old_service(self.src_item_json.get('name',''), item.project.cluster)
flash('发现模型服务变更,启动清理服务%s:%s'%(self.src_item_json.get('model_name',''),self.src_item_json.get('model_version','')),'success')
@ -782,14 +782,15 @@ output %s
pod_env = service.env
pod_env+="\nKUBEFLOW_ENV="+env
pod_env+='\nKUBEFLOW_MODEL_PATH='+service.model_path if service.model_path else ''
pod_env+='\nKUBEFLOW_MODEL_VERSION='+service.model_version
pod_env+='\nKUBEFLOW_MODEL_IMAGES='+service.images
pod_env+='\nKUBEFLOW_MODEL_NAME='+service.model_name
pod_env += '\nKUBEFLOW_AREA=' + json.loads(service.project.expand).get('area','guangzhou')
pod_env=pod_env.strip(',')
pod_env += "\nKUBEFLOW_ENV=" + env
pod_env += '\nKUBEFLOW_MODEL_PATH=' + service.model_path if service.model_path else ''
pod_env += '\nKUBEFLOW_MODEL_VERSION=' + service.model_version
pod_env += '\nKUBEFLOW_MODEL_IMAGES=' + service.images
pod_env += '\nKUBEFLOW_MODEL_NAME=' + service.model_name
pod_env += '\nKUBEFLOW_AREA=' + json.loads(service.project.expand).get('area', 'guangzhou')
pod_env += "\nRESOURCE_CPU=" + service.resource_cpu
pod_env += "\nRESOURCE_MEMORY=" + service.resource_memory
pod_env = pod_env.strip(',')
if env=='test' or env =='debug':
try:

View File

@ -234,9 +234,7 @@ class Metadata_table_ModelView_base():
# @event_logger.log_this
@action(
"ddl", __("创建远程hive表"), __("ddl 保存修改"), "fa-save", multiple=False, single=True
)
@action("ddl", __("更新到远程hive表"), __("ddl 保存修改"), "fa-save", multiple=False, single=True)
def ddl(self, item):
pass
# 自己实现更新到hive表
@ -249,18 +247,19 @@ class Metadata_table_ModelView_Api(Metadata_table_ModelView_base,MyappModelRestA
# @pysnooper.snoop()
def pre_add_get(self):
def pre_add_web(self):
self.default_filter = {
"owner": g.user.username
}
# @pysnooper.snoop()
def pre_get_list(self,result):
def pre_list_res(self,result):
data = result['data']
for item in data:
storage_cost = item.get('storage_cost',0)
if storage_cost:
item['storage_cost']=round(float(storage_cost), 6)
return result
# # 在info信息中添加特定参数
# @pysnooper.snoop()

View File

@ -323,8 +323,8 @@ class NNI_ModelView_Base():
pre_add_get=set_column
pre_update_get=set_column
pre_add_web=set_column
pre_update_web=set_column
# 处理form请求
def process_form(self, form, is_created):

View File

@ -15,14 +15,14 @@ from wtforms.validators import DataRequired, Length, Regexp
from wtforms import SelectField, StringField
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget, Select2Widget
from myapp.forms import MySelect2Widget, MyBS3TextFieldWidget
from flask import Markup
from myapp.utils.py.py_k8s import K8s
from flask import (
abort,
flash,
g,
redirect,
request,
request, make_response,
)
from .baseApi import (
MyappModelRestApi
@ -264,8 +264,8 @@ class Notebook_ModelView_Base():
# self.add_template, title=self.add_title, widgets=widget
# )
pre_update_get=set_column
pre_add_get=set_column
pre_update_web=set_column
pre_add_web=set_column
# @pysnooper.snoop(watch_explode=('notebook'))

View File

@ -3,6 +3,7 @@ from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
import uuid
import urllib.parse
from sqlalchemy.exc import InvalidRequestError
from myapp.models.model_job import Task,Pipeline,Workflow, RunHistory
from myapp.models.model_team import Project
@ -40,6 +41,7 @@ from flask import (
from myapp import security_manager
from myapp.views.view_team import filter_join_org_project
import kfp
import pysnooper
from kubernetes import client
from .base import (
DeleteMixin,
@ -574,7 +576,7 @@ class Pipeline_ModelView_Base():
cols_width={
"id":{"type": "ellip2", "width": 100},
"project": {"type": "ellip2", "width": 200},
"pipeline_url":{"type": "ellip2", "width": 500},
"pipeline_url":{"type": "ellip2", "width": 400},
"modified": {"type": "ellip2", "width": 150}
}
add_columns = ['project','name','describe']
@ -698,6 +700,43 @@ class Pipeline_ModelView_Base():
related_views = [Task_ModelView, ]
def delete_task_run(self,task):
from myapp.utils.py.py_k8s import K8s
k8s_client = K8s(task.pipeline.project.cluster.get('KUBECONFIG',''))
namespace = conf.get('PIPELINE_NAMESPACE')
# 删除运行时容器
pod_name = "run-" + task.pipeline.name.replace('_', '-') + "-" + task.name.replace('_', '-')
pod_name = pod_name.lower()[:60].strip('-')
pod = k8s_client.get_pods(namespace=namespace, pod_name=pod_name)
# print(pod)
if pod:
pod = pod[0]
# 有历史,直接删除
if pod:
k8s_client.delete_pods(namespace=namespace,pod_name=pod['name'])
run_id = pod['labels'].get('run-id', '')
if run_id:
k8s_client.delete_workflow(all_crd_info = conf.get("CRD_INFO", {}), namespace=namespace,run_id=run_id)
k8s_client.delete_pods(namespace=namespace, labels={"run-id": run_id})
time.sleep(2)
# 删除debug容器
pod_name = "debug-" + task.pipeline.name.replace('_', '-') + "-" + task.name.replace('_', '-')
pod_name = pod_name.lower()[:60].strip('-')
pod = k8s_client.get_pods(namespace=namespace, pod_name=pod_name)
# print(pod)
if pod:
pod = pod[0]
# 有历史,直接删除
if pod:
k8s_client.delete_pods(namespace=namespace, pod_name=pod['name'])
run_id = pod['labels'].get('run-id','')
if run_id:
k8s_client.delete_workflow(all_crd_info = conf.get("CRD_INFO", {}), namespace=namespace,run_id=run_id)
k8s_client.delete_pods(namespace=namespace, labels={"run-id":run_id})
time.sleep(2)
# 检测是否具有编辑权限只有creator和admin可以编辑
def check_edit_permission(self, item):
@ -835,12 +874,13 @@ class Pipeline_ModelView_Base():
flash('无法保障公共集群的稳定性,定时任务请选择专门的日更集群项目组','warning')
def pre_update_get(self,item):
def pre_update_web(self,item):
item.dag_json = item.fix_dag_json()
item.expand = json.dumps(item.fix_expand(),indent=4,ensure_ascii=False)
db.session.commit()
# 删除前先把下面的task删除了
# 删除前先把下面的task删除了把里面的运行实例也删除了
# @pysnooper.snoop()
def pre_delete(self, pipeline):
tasks = pipeline.get_tasks()
@ -854,6 +894,14 @@ class Pipeline_ModelView_Base():
pipeline.dag_json="{}"
db.session.commit()
back_crds = pipeline.get_workflow()
self.delete_bind_crd(back_crds)
# 删除task启动的所有实例
for task in tasks:
self.delete_task_run(task)
@expose("/my/list/")
def my(self):
@ -942,7 +990,7 @@ class Pipeline_ModelView_Base():
return wraps
# # @event_logger.log_this
# @event_logger.log_this
@expose("/run_pipeline/<pipeline_id>", methods=["GET", "POST"])
@check_pipeline_perms
def run_pipeline(self,pipeline_id):
@ -986,6 +1034,13 @@ class Pipeline_ModelView_Base():
# not_running_crds = back_crds # [crd for crd in back_crds if 'running' not in crd['status'].lower()]
self.delete_bind_crd(back_crds)
# 删除task启动的所有实例
for task in tasks:
self.delete_task_run(task)
# running_crds = [1 for crd in back_crds if 'running' in crd['status'].lower()]
# if len(running_crds)>0:
# flash("发现当前运行实例 %s 个目前集群仅支持每个任务流1个运行实例若要重新发起实例请先stop旧实例"%len(running_crds),category='warning')
@ -1217,7 +1272,7 @@ class Pipeline_ModelView_Api(Pipeline_ModelView_Base,MyappModelRestApi):
related_views = [Task_ModelView_Api,]
def pre_add_get(self):
def pre_add_web(self):
self.default_filter = {
"created_by": g.user.id
}

View File

@ -49,7 +49,7 @@ class Service_Filter(MyappFilter):
class Service_ModelView_base():
datamodel = SQLAInterface(Service)
show_columns = ['project','name', 'label','images','volume_mount','working_dir','command','env','resource_memory','resource_cpu','resource_gpu','replicas','ports','host_url']
show_columns = ['project','name', 'label','images','volume_mount','working_dir','command','env','resource_memory','resource_cpu','resource_gpu','replicas','ports','host']
add_columns = ['project','name', 'label','images','working_dir','command','env','resource_memory','resource_cpu','resource_gpu','replicas','ports','host']
list_columns = ['project','name_url','host_url','ip','deploy','creator','modified']
cols_width={
@ -70,7 +70,7 @@ class Service_ModelView_base():
"project": [["name", Project_Join_Filter, 'org']]
}
edit_form_query_rel_fields = add_form_query_rel_fields
host_rule = ",".join([cluster + "集群:*." + conf.get('CLUSTERS')[cluster].get("SERVICE_DOMAIN", conf.get('SERVICE_DOMAIN','')) for cluster in conf.get('CLUSTERS') if conf.get('CLUSTERS')[cluster].get("SERVICE_DOMAIN", conf.get('SERVICE_DOMAIN',''))])
host_rule = ", ".join([cluster + "集群:*." + conf.get('CLUSTERS')[cluster].get("SERVICE_DOMAIN", conf.get('SERVICE_DOMAIN','')) for cluster in conf.get('CLUSTERS') if conf.get('CLUSTERS')[cluster].get("SERVICE_DOMAIN", conf.get('SERVICE_DOMAIN',''))])
add_form_extra_fields={
"project": QuerySelectField(
_(datamodel.obj.lab('project')),
@ -156,6 +156,10 @@ class Service_ModelView_base():
volume_mount = service.volume_mount
labels = {"app":service.name,"user":service.created_by.username,"pod-type":"service"}
env = service.env
env+="\nRESOURCE_CPU="+service.resource_cpu
env += "\nRESOURCE_MEMORY=" + service.resource_memory
k8s_client.create_deployment(namespace=namespace,
name=service.name,
replicas=service.replicas,
@ -172,7 +176,7 @@ class Service_ModelView_base():
image_pull_secrets=image_secrets,
image=service.images,
hostAliases=conf.get('HOSTALIASES',''),
env=service.env,
env=env,
privileged=False,
accounts=None,
username=service.created_by.username,

View File

@ -361,6 +361,8 @@ class Task_ModelView_Base():
def pre_delete(self, item):
self.check_redirect_list_url = '/pipeline_modelview/edit/' + str(item.pipeline.id)
self.pipeline = item.pipeline
# 删除task启动的所有实例
self.delete_task_run(item)
widget_config = {
@ -647,15 +649,10 @@ class Task_ModelView_Base():
return redirect("/myapp/web/log/%s/%s/%s" % (task.pipeline.project.cluster['NAME'],namespace, pod_name))
@expose("/clear/<task_id>", methods=["GET", "POST"])
def clear_task(self,task_id):
task = db.session.query(Task).filter_by(id=task_id).first()
def delete_task_run(self,task):
from myapp.utils.py.py_k8s import K8s
k8s_client = K8s(task.pipeline.project.cluster.get('KUBECONFIG',''))
namespace = conf.get('PIPELINE_NAMESPACE')
# 删除运行时容器
pod_name = "run-" + task.pipeline.name.replace('_', '-') + "-" + task.name.replace('_', '-')
pod_name = pod_name.lower()[:60].strip('-')
@ -688,6 +685,12 @@ class Task_ModelView_Base():
k8s_client.delete_workflow(all_crd_info = conf.get("CRD_INFO", {}), namespace=namespace,run_id=run_id)
k8s_client.delete_pods(namespace=namespace, labels={"run-id":run_id})
time.sleep(2)
@expose("/clear/<task_id>", methods=["GET", "POST"])
def clear_task(self,task_id):
task = db.session.query(Task).filter_by(id=task_id).first()
self.delete_task_run(task)
flash("删除完成",category='success')
# self.update_redirect()
return redirect('/pipeline_modelview/web/%s' % str(task.pipeline.id))

View File

@ -139,7 +139,7 @@ class Project_ModelView_Base():
# @pysnooper.snoop()
def pre_add_get(self):
def pre_add_web(self):
self.edit_form_extra_fields['type'] = StringField(
_(self.datamodel.obj.lab('type')),
description="项目分组",
@ -162,8 +162,8 @@ class Project_ModelView_Base():
raise MyappException('just creator can add/edit')
# before update, check permission
def pre_update_get(self, item):
self.pre_add_get()
def pre_update_web(self, item):
self.pre_add_web()
self.check_item_permissions(item)
if not self.user_permissions['edit']:
flash('just creator can add/edit user','warning')

View File

@ -195,7 +195,7 @@ class Training_Model_ModelView_Base():
class Training_Model_ModelView(Training_Model_ModelView_Base,MyappModelView,DeleteMixin):
datamodel = SQLAInterface(Training_Model)
appbuilder.add_view(Training_Model_ModelView,"模型管理",icon = 'fa-hdd-o',category = '服务化',category_icon = 'fa-tasks')
appbuilder.add_view_no_menu(Training_Model_ModelView)

View File

@ -103,6 +103,9 @@ class Crd_ModelView_Base():
db.session.commit()
# 个性化删除操作
def delete_more(self,item):
pass
# 基础批量删除
# @pysnooper.snoop()
@ -110,6 +113,7 @@ class Crd_ModelView_Base():
if not items:
abort(404)
for item in items:
self.delete_more(item)
if item:
try:
labels = json.loads(item.labels) if item.labels else {}
@ -200,7 +204,7 @@ class Workflow_ModelView_Base(Crd_ModelView_Base):
# 删除之前的 workflow和相关容器
# @pysnooper.snoop()
def delete_workflow(self, workflow):
def delete_more(self, workflow):
try:
k8s_client = py_k8s.K8s(workflow.pipeline.project.cluster.get('KUBECONFIG',''))
k8s_client.delete_workflow(
@ -214,11 +218,10 @@ class Workflow_ModelView_Base(Crd_ModelView_Base):
except Exception as e:
print(e)
@expose("/stop/<crd_id>")
def stop(self, crd_id):
workflow = db.session.query(self.datamodel.obj).filter_by(id=crd_id).first()
self.delete_workflow(workflow)
self.delete_more(workflow)
flash('清理完成','success')
url = conf.get('MODEL_URLS',{}).get('workflow','')