remove invalid comments

This commit is contained in:
FerdinandWard 2022-08-11 10:47:08 +08:00
parent be6f5fb9c2
commit 875c597a21
23 changed files with 46 additions and 581 deletions

View File

@ -25,7 +25,7 @@ from .model_team import Project
from myapp import app,db
from myapp.models.helpers import ImportMixin
# from myapp.models.base import MyappModel
# 添加自定义model
from sqlalchemy import Column, Integer, String, ForeignKey ,Date,DateTime
from flask_appbuilder.models.decorators import renders
from flask import Markup
@ -38,7 +38,7 @@ import re
from myapp.utils.py import py_k8s
import pysnooper
# 定义model
class ETL_Pipeline(Model,ImportMixin,AuditMixinNullable,MyappModelBase):
__tablename__ = 'etl_pipeline'
id = Column(Integer, primary_key=True)
@ -103,7 +103,7 @@ class ETL_Pipeline(Model,ImportMixin,AuditMixinNullable,MyappModelBase):
expand=self.expand,
)
# 定义model
class ETL_Task(Model,ImportMixin,AuditMixinNullable,MyappModelBase):
__tablename__ = 'etl_task'
id = Column(Integer, primary_key=True)

View File

@ -491,7 +491,7 @@ class Pipeline(Model,ImportMixin,AuditMixinNullable,MyappModelBase):
)
# 定义model
class Task(Model,ImportMixin,AuditMixinNullable,MyappModelBase):
__tablename__ = 'task'
id = Column(Integer, primary_key=True)
@ -708,7 +708,7 @@ class Crd:
def stop(self):
return Markup(f'<a href="../stop/{self.id}">停止</a>')
# 定义model
class Workflow(Model,Crd,MyappModelBase):
__tablename__ = 'workflow'
@ -864,7 +864,7 @@ class Workflow(Model,Crd,MyappModelBase):
def stop(self):
return Markup(f'<a href="/workflow_modelview/stop/{self.id}">停止</a>')
# 定义model
class Tfjob(Model,Crd,MyappModelBase):
__tablename__ = 'tfjob'
@ -894,11 +894,11 @@ class Tfjob(Model,Crd,MyappModelBase):
return Markup(f'未知')
# 定义model
class Xgbjob(Model,Crd,MyappModelBase):
__tablename__ = 'xgbjob'
# 定义model
class Pytorchjob(Model,Crd,MyappModelBase):
__tablename__ = 'pytorchjob'

View File

@ -1,156 +0,0 @@
from flask_appbuilder import Model
from sqlalchemy import Column, Integer, String, ForeignKey,Float
from sqlalchemy.orm import relationship
import datetime,time,json
from sqlalchemy import (
Boolean,
Column,
create_engine,
DateTime,
ForeignKey,
Integer,
MetaData,
String,
Table,
Text,
Enum,
)
from myapp.utils import core
import re
from myapp.models.base import MyappModelBase
from myapp.models.helpers import AuditMixinNullable, ImportMixin
from flask import escape, g, Markup, request
from myapp import app,db
from myapp.models.helpers import ImportMixin
# 添加自定义model
from sqlalchemy import Column, Integer, String, ForeignKey ,Date,DateTime
from flask_appbuilder.models.decorators import renders
from flask import Markup
import datetime
metadata = Model.metadata
conf = app.config
# 定义model
class Hyperparameter_Tuning(Model,AuditMixinNullable,MyappModelBase):
__tablename__ = 'hp'
id = Column(Integer, primary_key=True)
job_type = Column(Enum('Job','TFJob','XGBJob','PyTorchJob'),nullable=False,default='Job')
project_id = Column(Integer, ForeignKey('project.id'), nullable=False) # 定义外键
project = relationship(
"Project", foreign_keys=[project_id]
)
name = Column(String(200), unique = True, nullable=False)
namespace = Column(String(200), nullable=False,default='katib')
describe = Column(Text)
parallel_trial_count = Column(Integer,default=3)
max_trial_count = Column(Integer,default=12)
max_failed_trial_count = Column(Integer,default=3)
objective_type = Column(Enum('maximize','minimize'),nullable=False,default='maximize')
objective_goal = Column(Float, nullable=False,default=0.99)
objective_metric_name = Column(String(200), nullable=False,default='Validation-accuracy')
objective_additional_metric_names = Column(String(200),default='') # 逗号分隔
algorithm_name = Column(Enum('grid','random','hyperband','bayesianoptimization'),nullable=False,default='random')
algorithm_setting = Column(Text,default='') # 搜索算法的配置
parameters=Column(Text,default='{}') # 搜索超参的配置
job_json = Column(Text, default='{}') # 根据不同算法和参数写入的task模板
trial_spec=Column(Text,default='') # 根据不同算法和参数写入的task模板
working_dir = Column(String(200), default='') # 挂载
volume_mount = Column(String(100), default='') # 挂载
node_selector = Column(String(100), default='cpu=true,train=true') # 挂载
image_pull_policy = Column(Enum('Always', 'IfNotPresent'), nullable=False, default='Always')
resource_memory = Column(String(100), default='1G')
resource_cpu = Column(String(100), default='1')
experiment=Column(Text,default='') # 构建出来的实验体
alert_status = Column(String(100), default='') # 哪些状态会报警Pending,Running,Succeeded,Failed,Unknown,Waiting,Terminated
def __repr__(self):
return self.name
@renders('parameters')
def parameters_html(self):
return Markup('<pre><code>' + self.parameters + '</code></pre>')
# '''
# "\"单反斜杠 %5C
# "|" %7C
# 回车 %0D%0A
# 空格 %20
# 双引号 %22
# "&" %26
# '''
@property
def name_url(self):
return Markup(f'<a target=_blank href="/experiments_modelview/list/?_flt_2_labels=%22{self.name}%22">{self.name}</a>')
@property
def describe_url(self):
return Markup(f'<a target=_blank href="/experiments_modelview/list/?_flt_2_labels=%22{self.name}%22">{self.describe}</a>')
@property
def run_url(self):
return Markup(f'<a href="/hyperparameter_tuning_modelview/create_experiment/{self.id}">run</a>')
@renders('trial_spec')
def trial_spec_html(self):
return Markup('<pre><code>' + self.trial_spec + '</code></pre>')
@renders('experiment')
def experiment_html(self):
return Markup('<pre><code>' + self.experiment + '</code></pre>')
def get_node_selector(self):
return self.get_default_node_selector(self.project.node_selector,self.resource_gpu,'train')
def clone(self):
return Hyperparameter_Tuning(
name=self.name.replace('_','-'),
job_type = self.job_type,
describe=self.describe,
namespace=self.namespace,
project_id=self.project_id,
parallel_trial_count=self.parallel_trial_count,
max_trial_count=self.max_trial_count,
max_failed_trial_count=self.max_failed_trial_count,
objective_type=self.objective_type,
objective_goal=self.objective_goal,
objective_metric_name=self.objective_metric_name,
objective_additional_metric_names=self.objective_additional_metric_names,
algorithm_name=self.algorithm_name,
algorithm_setting=self.algorithm_setting,
parameters=self.parameters,
job_json = self.job_json,
trial_spec=self.trial_spec,
volume_mount=self.volume_mount,
node_selector=self.node_selector,
image_pull_policy=self.image_pull_policy,
resource_memory=self.resource_memory,
resource_cpu=self.resource_cpu,
experiment=self.experiment,
alert_status=self.alert_status
)
# 定义model
from myapp.models.model_job import Crd
class Experiments(Model,Crd,MyappModelBase):
__tablename__ = 'experiments'
@property
def url(self):
if self.status=='' or self.status=='Created':
katib_url = conf.get('KATIB_URL') + "/katib/hp_monitor/"
return Markup(f'<a target=_blank href="{katib_url}">{self.name}</a>')
else:
katib_url = conf.get('KATIB_URL')+ "/katib/hp_monitor/%s/%s"%(self.namespace,self.name)
return Markup(f'<a target=_blank href="{katib_url}">{self.name}</a>')

View File

@ -26,7 +26,7 @@ from .model_team import Project
from myapp import app,db
from myapp.models.helpers import ImportMixin
# from myapp.models.base import MyappModel
# 添加自定义model
from sqlalchemy import Column, Integer, String, ForeignKey ,Date,DateTime
from flask_appbuilder.models.decorators import renders
from flask import Markup
@ -40,7 +40,7 @@ from myapp.utils.py import py_k8s
import pysnooper
# 定义model
class Metadata_table(Model,ImportMixin,MyappModelBase):
__tablename__ = 'metadata_table'
id = Column(Integer, primary_key=True)

View File

@ -22,7 +22,7 @@ from myapp.models.helpers import AuditMixinNullable, ImportMixin
from flask import escape, g, Markup, request
from myapp import app,db
from myapp.models.helpers import ImportMixin
# 添加自定义model
from sqlalchemy import Column, Integer, String, ForeignKey ,Date,DateTime
from flask_appbuilder.models.decorators import renders
from flask import Markup
@ -31,7 +31,7 @@ metadata = Model.metadata
conf = app.config
# 定义model
class NNI(Model,AuditMixinNullable,MyappModelBase):
__tablename__ = 'nni'
id = Column(Integer, primary_key=True)

View File

@ -21,7 +21,7 @@ from myapp.models.helpers import AuditMixinNullable, ImportMixin
from flask import escape, g, Markup, request
from myapp import app,db
from myapp.models.helpers import ImportMixin
# 添加自定义model
from sqlalchemy import Column, Integer, String, ForeignKey ,Date,DateTime
from flask_appbuilder.models.decorators import renders
from flask import Markup
@ -31,7 +31,7 @@ conf = app.config
from myapp.utils.py import py_k8s
# 定义model
class Notebook(Model,AuditMixinNullable,MyappModelBase):
__tablename__ = 'notebook'
id = Column(Integer, primary_key=True)

View File

@ -38,7 +38,7 @@ class Project(Model,AuditMixinNullable,MyappModelBase):
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
describe = Column(String(500), nullable=False)
type = Column(String(50)) # 项目类型。组织架构项目组,功能项目组
type = Column(String(50)) # org, job_template, model
expand = Column(Text(65536), default='{}')
export_children = ["user"]

View File

@ -41,7 +41,7 @@ else:
print('no kubeconfig in cluster %s' % cluster)
exit(1)
# 推送微信消息
# 推送消息
# @pysnooper.snoop()
def deliver_message(tfjob):
if not tfjob:

View File

@ -1,7 +1,4 @@
import time,datetime,logging,os,sys
dir_common = os.path.split(os.path.realpath(__file__))[0] + '/../'
sys.path.append(dir_common) # 将根目录添加到系统目录,才能正常引用common文件夹
import re
from kubernetes import client,config,watch
from kubernetes.client.models import v1_pod,v1_object_meta,v1_pod_spec,v1_deployment,v1_deployment_spec
@ -19,7 +16,6 @@ from kubernetes import config
from kubernetes.client.rest import ApiException
# K8s操作类型
class K8s():
def __init__(self,file_path=None): # kubeconfig
@ -29,7 +25,7 @@ class K8s():
elif kubeconfig:
config.kube_config.load_kube_config(config_file=kubeconfig)
else:
config.load_incluster_config() # 使用为pod配置的rbac访问集群
config.load_incluster_config()
self.v1 = client.CoreV1Api()
self.v1beta1 = client.ExtensionsV1beta1Api()
self.AppsV1Api = client.AppsV1Api()

View File

@ -22,7 +22,7 @@ import re,os
from sqlalchemy import and_, or_, select
from wtforms.validators import DataRequired, Length, NumberRange, Optional,Regexp
from kfp import compiler
# 将model添加成视图并控制在前端的显示
from myapp import app, appbuilder,db,event_logger
from myapp.utils import core
from wtforms import BooleanField, IntegerField,StringField, SelectField,FloatField,DateField,DateTimeField,SelectMultipleField,FormField,FieldList
@ -209,7 +209,7 @@ class Dimension_table_ModelView_Api(MyappModelRestApi):
"table_html":"表名",
"table_name":"表名"
}
base_filters = [["id", Dimension_table_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Dimension_table_Filter, lambda: []]]
add_fieldsets = [
(

View File

@ -82,7 +82,7 @@ class Docker_ModelView_Base():
crd_name = 'docker'
conv = GeneralModelConverter(datamodel)
base_permissions = ['can_add', 'can_delete','can_edit', 'can_list', 'can_show'] # 默认为这些
base_permissions = ['can_add', 'can_delete','can_edit', 'can_list', 'can_show']
base_order = ('changed_on', 'desc')
base_filters = [["id", Docker_Filter, lambda: []]]
order_columns = ['id']

View File

@ -10,7 +10,7 @@ import re
import urllib.parse
from kfp import compiler
from sqlalchemy.exc import InvalidRequestError
# 将model添加成视图并控制在前端的显示
from myapp.models.model_etl_pipeline import ETL_Pipeline,ETL_Task
from myapp.models.model_team import Project,Project_User
from myapp.views.view_team import Project_Join_Filter
@ -65,7 +65,7 @@ from flask import (
)
from myapp import security_manager
from myapp.views.view_team import filter_join_org_project
import kfp # 使用自定义的就要把pip安装的删除了
from werkzeug.datastructures import FileStorage
from kubernetes import client as k8s_client
from .base import (
@ -180,7 +180,7 @@ class ETL_Pipeline_ModelView_Base():
edit_columns = ['project','name','describe','created_by']
base_filters = [["id", ETL_Pipeline_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", ETL_Pipeline_Filter, lambda: []]]
conv = GeneralModelConverter(datamodel)
# related_views = [ETL_Task_ModelView,]

View File

@ -1,7 +1,7 @@
from flask import render_template,redirect
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask import Blueprint, current_app, jsonify, make_response, request
# 将model添加成视图并控制在前端的显示
from myapp.models.model_serving import InferenceService
from myapp.models.model_team import Project,Project_User
from myapp.utils import core
@ -88,7 +88,7 @@ class InferenceService_ModelView_base():
datamodel = SQLAInterface(InferenceService)
check_redirect_list_url = conf.get('MODEL_URLS',{}).get('inferenceservice','')
# 外层的add_column和edit_columns 还有show_columns 一定要全不然在gunicorn形式下get的不一定能被翻译
# add_columns = ['service_type','project','name', 'label','images','resource_memory','resource_cpu','resource_gpu','min_replicas','max_replicas','ports','host','hpa','metrics','health']
add_columns = ['service_type', 'project', 'label', 'model_name', 'model_version', 'images', 'model_path', 'resource_memory', 'resource_cpu', 'resource_gpu', 'min_replicas', 'max_replicas', 'hpa','priority', 'canary', 'shadow', 'host','inference_config', 'working_dir', 'command','volume_mount', 'env', 'ports', 'metrics', 'health','expand']
show_columns = ['service_type','project', 'name', 'label','model_name', 'model_version', 'images', 'model_path', 'input_html', 'output_html', 'images', 'volume_mount','working_dir', 'command', 'env', 'resource_memory',
@ -121,7 +121,7 @@ class InferenceService_ModelView_base():
base_order = ('id','desc')
order_columns = ['id']
base_filters = [["id",InferenceService_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id",InferenceService_Filter, lambda: []]]
custom_service = 'serving'
service_type_choices= [custom_service,'tfserving','torch-server','onnxruntime','triton-server']
# label_columns = {

View File

@ -12,7 +12,7 @@ from wtforms.validators import DataRequired, Length, NumberRange, Optional,Regex
from kfp import compiler
from sqlalchemy.exc import InvalidRequestError
# 将model添加成视图并控制在前端的显示
from myapp.models.model_job import Repository,Images,Job_Template,Task,Pipeline,Workflow,Tfjob,Xgbjob,RunHistory,Pytorchjob
from myapp.models.model_team import Project,Project_User
from flask_appbuilder.actions import action
@ -82,7 +82,7 @@ class Job_Tempalte_Filter(MyappFilter):
# logging.info(join_projects_id)
return query.filter(self.model.version=='Release')
# 定义数据库视图
class Job_Template_ModelView_Base():
datamodel = SQLAInterface(Job_Template)
label_title='任务模板'
@ -99,7 +99,7 @@ class Job_Template_ModelView_Base():
add_columns = ['project','images','name','version','describe','workdir','entrypoint','volume_mount','job_args_definition','args','env','hostAliases','privileged','accounts','demo','expand']
edit_columns = add_columns
base_filters = [["id", Job_Tempalte_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Job_Tempalte_Filter, lambda: []]]
base_order = ('id', 'desc')
order_columns = ['id']
add_form_query_rel_fields = {

View File

@ -1,372 +0,0 @@
from flask import render_template,redirect
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask import Blueprint, current_app, jsonify, make_response, request
# 将model添加成视图并控制在前端的显示
from myapp.models.model_serving import Service,KfService
from myapp.models.model_team import Project,Project_User
from myapp.utils import core
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
from flask_appbuilder.actions import action
from myapp import app, appbuilder,db,event_logger
import logging
import re
import uuid
import requests
from myapp.exceptions import MyappException
from flask_appbuilder.security.decorators import has_access
from myapp.models.model_job import Repository
from flask_wtf.file import FileAllowed, FileField, FileRequired
from werkzeug.datastructures import FileStorage
from wtforms.ext.sqlalchemy.fields import QuerySelectField
from myapp import security_manager
import os,sys
from wtforms.validators import DataRequired, Length, NumberRange, Optional,Regexp
from wtforms import BooleanField, IntegerField, SelectField, StringField,FloatField,DateField,DateTimeField,SelectMultipleField,FormField,FieldList
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget,BS3PasswordFieldWidget,DatePickerWidget,DateTimePickerWidget,Select2ManyWidget,Select2Widget
from myapp.forms import MyBS3TextAreaFieldWidget,MySelect2Widget,MyCodeArea,MyLineSeparatedListField,MyJSONField,MyBS3TextFieldWidget,MySelectMultipleField
from myapp.utils.py import py_k8s
import os, zipfile
import shutil
from flask import (
current_app,
abort,
flash,
g,
Markup,
make_response,
redirect,
render_template,
request,
send_from_directory,
Response,
url_for,
)
from .base import (
DeleteMixin,
api,
BaseMyappView,
check_ownership,
data_payload_response,
DeleteMixin,
generate_download_headers,
get_error_msg,
get_user_roles,
handle_api_exception,
json_error_response,
json_success,
MyappFilter,
MyappModelView,
)
from sqlalchemy import and_, or_, select
from .baseApi import (
MyappModelRestApi
)
import kubernetes
from kfserving import KFServingClient
from kfserving import V1alpha2EndpointSpec
from kfserving import V1alpha2CustomSpec
from kfserving import V1alpha2PredictorSpec
from kfserving import V1alpha2TensorflowSpec
from kfserving import V1alpha2InferenceServiceSpec
from kfserving import V1alpha2InferenceService
from flask_appbuilder import CompactCRUDMixin, expose
import pysnooper,datetime,time,json
conf = app.config
class KfService_ModelView(MyappModelView):
datamodel = SQLAInterface(KfService)
crd_name = 'inferenceservice'
help_url = conf.get('HELP_URL', {}).get(datamodel.obj.__tablename__, '') if datamodel else ''
show_columns = ['name', 'label','service_type','default_service','canary_service','canary_traffic_percent','k8s_yaml']
add_columns = ['name', 'label', 'service_type','default_service','canary_service','canary_traffic_percent']
list_columns = ['label_url','host','service','deploy','status','roll']
edit_columns = add_columns
base_order = ('id','desc')
order_columns = ['id']
@expose('/deploy1/<kfservice_id>',methods=['POST',"GET"])
def deploy1(self,kfservice_id):
mykfservice = db.session.query(KfService).filter_by(id=kfservice_id).first()
from myapp.utils.py.py_k8s import K8s
k8s = K8s(mykfservice.project.cluster.get('KUBECONFIG',''))
namespace = conf.get('KFSERVING_NAMESPACE')
crd_info = conf.get('CRD_INFO')['inferenceservice']
crd_list = k8s.get_crd(group=crd_info['group'], version=crd_info['version'], plural=crd_info['plural'],
namespace=namespace)
for crd_obj in crd_list:
if crd_obj['name'] == mykfservice.name:
k8s.delete_crd(group=crd_info['group'], version=crd_info['version'], plural=crd_info['plural'],
namespace=namespace, name=mykfservice.name)
def get_env(env_str):
if not env_str:
return []
envs = re.split('\r|\n', env_str)
envs = [env.split('=') for env in envs if env and len(env.split('=')) == 2]
return envs
def get_kfjson(service,mykfservice):
if not service:
return None
image_secrets = conf.get('HUBSECRET', [])
user_hubsecrets = db.session.query(Repository.hubsecret).filter(Repository.created_by_fk == g.user.id).all()
if user_hubsecrets:
for hubsecret in user_hubsecrets:
if hubsecret[0] not in image_secrets:
image_secrets.append(hubsecret[0])
kfjson={
"minReplicas": service.min_replicas,
"maxReplicas": service.max_replicas,
"custom": {
"affinity": {
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{
"matchExpressions": [
{
"key": "gpu" if core.get_gpu(service.resource_gpu)[0] else "cpu",
"operator": "In",
"values": [
"true"
]
},
]
}
]
}
},
},
"imagePullSecrets": [{"name":hubsecret} for hubsecret in image_secrets],
"container": {
"image": service.images,
"imagePullPolicy": conf.get('IMAGE_PULL_POLICY','Always'),
"name": mykfservice.name+"-"+service.name,
"workingDir": service.working_dir if service.working_dir else None,
"command": ["sh", "-c",service.command] if service.command else None,
"resources": {
"requests": {
"cpu": service.resource_cpu,
"memory": service.resource_memory
}
},
"env":[{"name":env[0],"value":env[1]} for env in get_env(service.env)],
# "volumeMounts": [
# {
# "mountPath": "/mnt/%s" % service.created_by.username,
# "name": "workspace",
# "subPath": service.created_by.username
# }
# ],
# "volumeDevices":[
# {
# "devicePath": "/data/home/",
# "name": "workspace"
# }
# ]
}
# "volumes": [
# {
# "name": "workspace",
# "persistentVolumeClaim": {
# "claimName": "kubeflow-user-workspace"
# }
# }
# ]
}
}
return kfjson
crd_json={
"apiVersion": "serving.kubeflow.org/v1alpha2",
"kind": "InferenceService",
"metadata": {
"labels": {
"app": mykfservice.name
},
"name": mykfservice.name,
"namespace": namespace
},
"spec": {
"canaryTrafficPercent": mykfservice.canary_traffic_percent,
"default": {
mykfservice.service_type: get_kfjson(mykfservice.default_service,mykfservice)
},
"canary": {
mykfservice.service_type: get_kfjson(mykfservice.canary_service,mykfservice),
} if mykfservice.canary_service else None,
}
}
import yaml
ya = yaml.load(json.dumps(crd_json))
ya_str = yaml.safe_dump(ya, default_flow_style=False)
logging.info(ya_str)
crd_objects = k8s.create_crd(group=crd_info['group'],version=crd_info['version'],plural=crd_info['plural'],namespace=namespace,body=crd_json)
flash(category='warning',message='部署启动,一分钟后部署完成')
return redirect('/kfservice_modelview/list/')
# 创建kfserving
@expose('/deploy/<kfservice_id>', methods=['POST', "GET"])
def deploy(self, kfservice_id):
mykfservice = db.session.query(KfService).filter_by(id=kfservice_id).first()
namespace = conf.get('KFSERVING_NAMESPACE')
crd_info = conf.get('CRD_INFO')['inferenceservice']
# 根据service生成container
def make_container(service,mykfservice):
from myapp.utils.py.py_k8s import K8s
k8s = K8s() # 不部署,不需要配置集群信息
container = k8s.make_container(name=mykfservice.name + "-" + service.name,
command=["sh", "-c",service.command] if service.command else None,
args=None,
volume_mount=None,
image_pull_policy=conf.get('IMAGE_PULL_POLICY','Always'),
image=service.images,
working_dir=service.working_dir if service.working_dir else None,
env=service.env,
resource_memory=service.resource_memory,
resource_cpu = service.resource_cpu,
resource_gpu= service.resource_gpu,
username = service.created_by.username
)
return container
api_version = crd_info['group'] + '/' + crd_info['version']
default_endpoint_spec = V1alpha2EndpointSpec(
predictor=V1alpha2PredictorSpec(
min_replicas= mykfservice.default_service.min_replicas,
max_replicas=mykfservice.default_service.max_replicas,
custom=V1alpha2CustomSpec(
container=make_container(mykfservice.default_service,mykfservice)
)
)
) if mykfservice.default_service else None
canary_endpoint_spec = V1alpha2EndpointSpec(
predictor= V1alpha2PredictorSpec(
min_replicas=mykfservice.canary_service.min_replicas,
max_replicas=mykfservice.canary_service.max_replicas,
custom=V1alpha2CustomSpec(
container=make_container(mykfservice.canary_service,mykfservice)
)
)
) if mykfservice.canary_service else None
metadata = kubernetes.client.V1ObjectMeta(
name=mykfservice.name,
labels={
"app":mykfservice.name,
"rtx-user":mykfservice.created_by.username
},
namespace=namespace
)
isvc = V1alpha2InferenceService(
api_version=api_version,
kind=crd_info['kind'],
metadata=metadata,
spec=V1alpha2InferenceServiceSpec(
default=default_endpoint_spec,
canary=canary_endpoint_spec,
canary_traffic_percent=mykfservice.canary_traffic_percent
)
)
KFServing = KFServingClient()
try:
KFServing.delete(mykfservice.name, namespace=namespace,version=crd_info['version'])
except Exception as e:
print(e)
KFServing.create(isvc,namespace=namespace,version=crd_info['version'])
flash(category='warning', message='部署启动,一分钟后部署完成')
return redirect('/kfservice_modelview/list/')
# 灰度
@expose('/roll/<kfservice_id>', methods=['POST', "GET"])
def roll(self, kfservice_id):
mykfservice = db.session.query(KfService).filter_by(id=kfservice_id).first()
namespace = conf.get('KFSERVING_NAMESPACE')
crd_info = conf.get('CRD_INFO')['inferenceservice']
# 根据service生成container
def make_container(service, mykfservice):
from myapp.utils.py.py_k8s import K8s
k8s = K8s() # 不部署,不需要配置集群信息
container = k8s.make_container(name=mykfservice.name + "-" + service.name,
command=["sh", "-c", service.command] if service.command else None,
args=None,
volume_mount=None,
image_pull_policy=conf.get('IMAGE_PULL_POLICY','Always'),
image=service.images,
working_dir=service.working_dir if service.working_dir else None,
env=service.env,
resource_memory=service.resource_memory,
resource_cpu=service.resource_cpu,
resource_gpu=service.resource_gpu,
username=service.created_by.username,
ports = service.ports
)
return container
canary_endpoint_spec = V1alpha2EndpointSpec(
predictor=V1alpha2PredictorSpec(
min_replicas=mykfservice.canary_service.min_replicas,
max_replicas=mykfservice.canary_service.max_replicas,
custom=V1alpha2CustomSpec(
container=make_container(mykfservice.canary_service, mykfservice)
)
)
) if mykfservice.canary_service else None
KFServing = KFServingClient()
KFServing.rollout_canary(mykfservice.name, canary=canary_endpoint_spec, percent=mykfservice.canary_traffic_percent,
namespace=namespace, timeout_seconds=120,version=crd_info['version'])
flash(category='warning', message='滚动升级已配置,刷新查看当前流量比例')
return redirect('/kfservice_modelview/list/')
# 基础批量删除
# @pysnooper.snoop()
def base_muldelete(self,items):
if not items:
abort(404)
for item in items:
try:
k8s_client = py_k8s.K8s(item.project.cluster.get('KUBECONFIG',''))
crd_info = conf.get("CRD_INFO", {}).get(self.crd_name, {})
if crd_info:
k8s_client.delete_crd(group=crd_info['group'],version=crd_info['version'],plural=crd_info['plural'],namespace=conf.get('KFSERVING_NAMESPACE'),name=item.name)
except Exception as e:
flash(str(e), "danger")
def pre_delete(self,item):
self.base_muldelete([item])
# @event_logger.log_this
# @expose("/delete/<pk>")
# @has_access
# def delete(self, pk):
# pk = self._deserialize_pk_if_composite(pk)
# self.base_delete(pk)
# url = url_for(f"{self.endpoint}.list")
# return redirect(url)
appbuilder.add_view(KfService_ModelView,"kfserving",icon = 'fa-tasks',category = '服务化')

View File

@ -1,7 +1,7 @@
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
# 将model添加成视图并控制在前端的显示
from myapp import app, appbuilder,db,event_logger
from flask import (

View File

@ -5,7 +5,6 @@ from flask_appbuilder import ModelView,AppBuilder,expose,BaseView,has_access
from importlib import reload
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
# 将model添加成视图并控制在前端的显示
import uuid
from myapp.models.model_nni import NNI
from myapp.models.model_job import Repository
@ -91,8 +90,6 @@ class NNI_Filter(MyappFilter):
).order_by(self.model.id.desc())
# 定义数据库视图
class NNI_ModelView_Base():
datamodel = SQLAInterface(NNI)
conv = GeneralModelConverter(datamodel)
@ -100,9 +97,9 @@ class NNI_ModelView_Base():
check_redirect_list_url = conf.get('MODEL_URLS',{}).get('nni','')
base_permissions = ['can_add', 'can_edit', 'can_delete', 'can_list', 'can_show'] # 默认为这些
base_permissions = ['can_add', 'can_edit', 'can_delete', 'can_list', 'can_show']
base_order = ('id', 'desc')
base_filters = [["id", NNI_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", NNI_Filter, lambda: []]]
order_columns = ['id']
list_columns = ['project','describe_url','job_type','creator','modified','run','log']
show_columns = ['created_by','changed_by','created_on','changed_on','job_type','name','namespace','describe',

View File

@ -6,7 +6,7 @@ from importlib import reload
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
import random
# 将model添加成视图并控制在前端的显示
import uuid
from myapp.models.model_notebook import Notebook
from myapp.models.model_job import Repository
@ -82,7 +82,7 @@ class Notebook_Filter(MyappFilter):
# 定义数据库视图
class Notebook_ModelView_Base():
datamodel = SQLAInterface(Notebook)
label_title='notebook'
@ -91,9 +91,9 @@ class Notebook_ModelView_Base():
datamodel = SQLAInterface(Notebook)
conv = GeneralModelConverter(datamodel)
base_permissions = ['can_add', 'can_delete','can_edit', 'can_list', 'can_show'] # 默认为这些
base_permissions = ['can_add', 'can_delete','can_edit', 'can_list', 'can_show']
base_order = ('changed_on', 'desc')
base_filters = [["id", Notebook_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Notebook_Filter, lambda: []]]
order_columns = ['id']
search_columns = ['created_by']
add_columns = ['project','name','describe','images','working_dir','volume_mount','resource_memory','resource_cpu','resource_gpu']

View File

@ -633,7 +633,7 @@ class Pipeline_ModelView_Base():
edit_columns = add_columns
base_filters = [["id", Pipeline_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Pipeline_Filter, lambda: []]]
conv = GeneralModelConverter(datamodel)

View File

@ -1,7 +1,7 @@
from flask import render_template,redirect
from flask_appbuilder.models.sqla.interface import SQLAInterface
# 将model添加成视图并控制在前端的显示
from myapp.models.model_job import Repository,Images,Job_Template,Task,Pipeline,Workflow,Tfjob,Xgbjob,RunHistory,Pytorchjob
from myapp import app, appbuilder,db,event_logger
@ -68,7 +68,7 @@ class RunHistory_ModelView_Base():
"created_on":{"type": "ellip2", "width": 300}
}
edit_columns = ['status']
base_filters = [["id", RunHistory_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", RunHistory_Filter, lambda: []]]
add_form_extra_fields = {
"status": SelectField(
_(datamodel.obj.lab('status')),

View File

@ -10,7 +10,7 @@ import uuid
import re
from kfp import compiler
from sqlalchemy.exc import InvalidRequestError
# 将model添加成视图并控制在前端的显示
from myapp.models.model_service_pipeline import Service_Pipeline
from myapp.models.model_job import Repository
from myapp.models.model_team import Project,Project_User
@ -132,7 +132,7 @@ class Service_Pipeline_ModelView_Base():
edit_columns = add_columns
base_filters = [["id", Service_Pipeline_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Service_Pipeline_Filter, lambda: []]]
conv = GeneralModelConverter(datamodel)

View File

@ -1,7 +1,7 @@
from flask import render_template,redirect
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask import Blueprint, current_app, jsonify, make_response, request
# 将model添加成视图并控制在前端的显示
from myapp.models.model_serving import Service
from myapp.models.model_team import Project,Project_User
from myapp.utils import core
@ -103,7 +103,7 @@ class Service_ModelView_base():
base_order = ('id','desc')
order_columns = ['id']
label_title = '云原生服务'
base_filters = [["id", Service_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Service_Filter, lambda: []]]
add_form_query_rel_fields = {
"project": [["name", Project_Join_Filter, 'org']]
}

View File

@ -3,7 +3,7 @@ from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import gettext as __
# 将model添加成视图并控制在前端的显示
from myapp.models.model_job import Repository,Images,Job_Template,Task,Pipeline,Workflow,Tfjob,Xgbjob,RunHistory,Pytorchjob
from myapp.models.model_team import Project,Project_User
from flask_appbuilder.actions import action
@ -93,7 +93,7 @@ class Crd_ModelView_Base():
# }
crd_name = ''
base_order = ('create_time', 'desc')
base_filters = [["id", CRD_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", CRD_Filter, lambda: []]]
# list
@ -216,7 +216,7 @@ class Workflow_Filter(MyappFilter):
# list正在运行的workflow
class Workflow_ModelView_Base(Crd_ModelView_Base):
base_filters = [["id", Workflow_Filter, lambda: []]] # 设置权限过滤器
base_filters = [["id", Workflow_Filter, lambda: []]]
# 删除之前的 workflow和相关容器
# @pysnooper.snoop()