2021-08-17 17:00:34 +08:00
|
|
|
|
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,
|
|
|
|
|
)
|
|
|
|
|
import pysnooper
|
|
|
|
|
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
|
|
|
|
|
from myapp.utils.py import py_k8s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 定义model
|
|
|
|
|
class Notebook(Model,AuditMixinNullable,MyappModelBase):
|
|
|
|
|
__tablename__ = 'notebook'
|
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
|
project_id = Column(Integer, ForeignKey('project.id'), nullable=False) # 定义外键
|
|
|
|
|
project = relationship(
|
|
|
|
|
"Project", foreign_keys=[project_id]
|
|
|
|
|
)
|
|
|
|
|
name = Column(String(200), unique = True, nullable=True)
|
2022-07-26 20:47:49 +08:00
|
|
|
|
describe = Column(String(200), nullable=True)
|
2021-08-17 17:00:34 +08:00
|
|
|
|
namespace = Column(String(200), nullable=True,default='jupyter')
|
|
|
|
|
images=Column(String(200), nullable=True,default='')
|
2022-07-26 20:47:49 +08:00
|
|
|
|
ide_type = Column(String(100), default='jupyter')
|
2021-08-17 17:00:34 +08:00
|
|
|
|
working_dir = Column(String(200), default='') # 挂载
|
|
|
|
|
volume_mount = Column(String(400), default='kubeflow-user-workspace(pvc):/mnt,kubeflow-archives(pvc):/archives') # 挂载
|
|
|
|
|
node_selector = Column(String(200), default='cpu=true,notebook=true') # 挂载
|
|
|
|
|
image_pull_policy = Column(Enum('Always', 'IfNotPresent'), nullable=True, default='Always')
|
2022-08-02 16:02:22 +08:00
|
|
|
|
resource_memory = Column(String(100), default='10G')
|
|
|
|
|
resource_cpu = Column(String(100), default='10')
|
2021-08-17 17:00:34 +08:00
|
|
|
|
resource_gpu = Column(String(100), default='0')
|
2021-11-25 18:05:19 +08:00
|
|
|
|
expand = Column(Text(65536), default='')
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def name_url(self):
|
|
|
|
|
if self.ide_type=='theia':
|
2022-02-26 22:36:57 +08:00
|
|
|
|
url = "/notebook/"+self.namespace + "/" + self.name+"/" + "#"+self.mount
|
2021-08-17 17:00:34 +08:00
|
|
|
|
else:
|
2022-07-26 20:47:49 +08:00
|
|
|
|
url = "/notebook/"+self.namespace + "/" + self.name+"/lab?#"+self.mount
|
2022-02-26 22:36:57 +08:00
|
|
|
|
|
|
|
|
|
# url= url + "#"+self.mount
|
|
|
|
|
JUPYTER_DOMAIN = self.project.cluster.get('JUPYTER_DOMAIN',request.host)
|
|
|
|
|
if JUPYTER_DOMAIN:
|
|
|
|
|
host = "http://"+JUPYTER_DOMAIN
|
|
|
|
|
else:
|
2022-08-08 15:39:44 +08:00
|
|
|
|
host = request.host_url.strip('/') # 使用当前域名打开
|
2022-05-25 11:28:30 +08:00
|
|
|
|
|
|
|
|
|
# 对于有边缘节点,直接使用边缘集群的代理ip
|
|
|
|
|
SERVICE_EXTERNAL_IP = json.loads(self.project.expand).get('SERVICE_EXTERNAL_IP',None) if self.project.expand else None
|
|
|
|
|
if SERVICE_EXTERNAL_IP:
|
|
|
|
|
service_ports = 10000 + 10 * self.id
|
|
|
|
|
host = "http://%s:%s"%(SERVICE_EXTERNAL_IP,str(service_ports))
|
2022-06-08 19:40:34 +08:00
|
|
|
|
if self.ide_type=='theia':
|
|
|
|
|
url = "/" + "#/mnt/" + self.created_by.username
|
|
|
|
|
else:
|
|
|
|
|
url = '/notebook/jupyter/%s/lab/tree/mnt/%s'%(self.name,self.created_by.username)
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return Markup(f'<a target=_blank href="{host}{url}">{self.name}</a>')
|
|
|
|
|
|
2021-10-14 17:33:57 +08:00
|
|
|
|
@property
|
|
|
|
|
def mount(self):
|
2022-07-26 20:47:49 +08:00
|
|
|
|
# if "(hostpath)" in self.volume_mount:
|
|
|
|
|
# mount = self.volume_mount[self.volume_mount.index('(hostpath)'):]
|
|
|
|
|
# mount=mount.replace('(hostpath):','')
|
|
|
|
|
# if ',' in mount:
|
|
|
|
|
# mount = mount[:mount.index(',')]
|
|
|
|
|
# return mount
|
|
|
|
|
# else:
|
|
|
|
|
# return mount
|
|
|
|
|
# else:
|
|
|
|
|
if self.created_by:
|
|
|
|
|
return "/mnt/%s"% self.created_by.username
|
2021-10-14 17:33:57 +08:00
|
|
|
|
else:
|
2022-07-26 20:47:49 +08:00
|
|
|
|
return "/mnt/%s"%g.user.username
|
2021-10-14 17:33:57 +08:00
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def resource(self):
|
|
|
|
|
return self.resource_cpu+"(cpu)"+self.resource_memory+"(memory)"+self.resource_gpu+"(gpu)"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def status(self):
|
|
|
|
|
try:
|
2022-05-31 14:16:55 +08:00
|
|
|
|
k8s_client = py_k8s.K8s(self.cluster.get('KUBECONFIG',''))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
namespace = conf.get('NOTEBOOK_NAMESPACE')
|
|
|
|
|
pods = k8s_client.get_pods(namespace=namespace,pod_name=self.name)
|
|
|
|
|
status = pods[0]['status']
|
2021-09-07 18:09:47 +08:00
|
|
|
|
if g.user.is_admin():
|
|
|
|
|
k8s_dash_url = self.cluster.get('K8S_DASHBOARD_CLUSTER') + "#/search?namespace=jupyter&q=" + self.name
|
|
|
|
|
url = Markup(f'<a target=_blank href="{k8s_dash_url}">{status}</a>')
|
|
|
|
|
return url
|
|
|
|
|
return status
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# print(e)
|
|
|
|
|
return "unknown"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def cluster(self):
|
|
|
|
|
if self.project:
|
|
|
|
|
return self.project.cluster
|
|
|
|
|
else:
|
2021-09-07 18:09:47 +08:00
|
|
|
|
return conf.get('CLUSTERS')[conf.get('ENVIRONMENT')]
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
# 清空激活
|
|
|
|
|
@property
|
|
|
|
|
def renew(self):
|
|
|
|
|
object_info = conf.get("CRD_INFO", {}).get('notebook', {})
|
|
|
|
|
timeout = int(object_info.get('timeout', 60 * 60 * 24 * 3))
|
|
|
|
|
|
|
|
|
|
end = self.changed_on+datetime.timedelta(seconds=timeout)
|
|
|
|
|
end = end.strftime('%Y-%m-%d')
|
|
|
|
|
return Markup(f'<a href="/notebook_modelview/renew/{self.id}">截至 {end}</a>')
|
|
|
|
|
|
|
|
|
|
|
2021-09-07 18:09:47 +08:00
|
|
|
|
def get_node_selector(self):
|
|
|
|
|
return self.get_default_node_selector(self.project.node_selector,self.resource_gpu,'notebook')
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
# 清空激活
|
|
|
|
|
@property
|
|
|
|
|
def reset(self):
|
|
|
|
|
return Markup(f'<a href="/notebook_modelview/reset/{self.id}">reset</a>')
|
|
|
|
|
|
|
|
|
|
|