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 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 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) describe = Column(String(200), nullable=True) namespace = Column(String(200), nullable=True,default='jupyter') images=Column(String(200), nullable=True,default='') ide_type = Column(String(100), default='jupyter') 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') resource_memory = Column(String(100), default='10G') resource_cpu = Column(String(100), default='10') resource_gpu = Column(String(100), default='0') expand = Column(Text(65536), default='') def __repr__(self): return self.name @property def name_url(self): if self.ide_type=='theia': url = "/notebook/"+self.namespace + "/" + self.name+"/" + "#"+self.mount else: url = "/notebook/"+self.namespace + "/" + self.name+"/lab?#"+self.mount # url= url + "#"+self.mount JUPYTER_DOMAIN = self.project.cluster.get('JUPYTER_DOMAIN',request.host) if JUPYTER_DOMAIN: host = "http://"+JUPYTER_DOMAIN else: host = request.host_url.strip('/') # 使用当前域名打开 # 对于有边缘节点,直接使用边缘集群的代理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)) 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) return Markup(f'{self.name}') @property def mount(self): # 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 else: return "/mnt/%s"%g.user.username @property def resource(self): return self.resource_cpu+"(cpu)"+self.resource_memory+"(memory)"+self.resource_gpu+"(gpu)" @property def status(self): try: k8s_client = py_k8s.K8s(self.cluster.get('KUBECONFIG','')) namespace = conf.get('NOTEBOOK_NAMESPACE') pods = k8s_client.get_pods(namespace=namespace,pod_name=self.name) status = pods[0]['status'] if g.user.is_admin(): k8s_dash_url = self.cluster.get('K8S_DASHBOARD_CLUSTER') + "#/search?namespace=jupyter&q=" + self.name url = Markup(f'{status}') return url return status except Exception as e: # print(e) return "unknown" @property def cluster(self): if self.project: return self.project.cluster else: return conf.get('CLUSTERS')[conf.get('ENVIRONMENT')] # 清空激活 @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'截至 {end}') def get_node_selector(self): return self.get_default_node_selector(self.project.node_selector,self.resource_gpu,'notebook') # 清空激活 @property def reset(self): return Markup(f'reset')