You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

723 lines
24 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- coding: utf-8 -*-
import json
import logging
import random
from sqlalchemy import text
from website import consts
from website import db_mysql, errors
from website.db.alg_model.alg_model import ModelRepositry as DB_AlgModel
from website.db.device_classification import device_classification as DB_DeviceClassification
from website.db.enterprise_busi_model import (
enterprise_busi_model as DB_BusiModel,
)
from website.db.enterprise_busi_model import enterprise_busi_model_node_device as DB_BusiModelNodeDevice
from website.db.enterprise_device import enterprise_device as DB_Device
from website.db.enterprise_node import enterprise_node as DB_Node
from website.db.enterprise_node import enterprise_node_base_model_conf as DB_NodeBaseModelConf
from website.handler import APIHandler, authenticated
from website.util import date_util
from website.util import shortuuid
class DeviceClassificationAddHandler(APIHandler):
"""
- 描述:添加设备分类
- 请求方式post
- 请求参数:
>- entity_id, int, 企业id
>- name, string, 设备分类名称
- 返回值:
```
{
"id": 123
}
```
"""
@authenticated
def post(self):
name = self.get_escaped_argument("name", "")
with self.app_mysql.connect() as conn:
cur = conn.execute(
text("SELECT id FROM device_classification WHERE name=:name and del=0"),
{"name": name},
)
row = cur.fetchone()
if row:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备分类已存在")
result = conn.execute(
text(
"INSERT INTO device_classification (name, suid) VALUES (:name, :suid)"
),
{"name": name, "suid": shortuuid.ShortUUID().random(10)},
)
conn.commit()
last_id = result.lastrowid
self.finish({"id": last_id})
class DeviceClassificationHandler(APIHandler):
"""
- 描述:设备分类列表
- 请求方式post
- 请求参数:
>- 无
- 返回值:
```
{
"data": [
{
"id": 123,
"suid": "xxx",
"name": "xxx"
},
...
]
}
```
"""
@authenticated
def post(self):
with self.app_mysql.connect() as conn:
cur = conn.execute(
text(
"SELECT id, suid, name FROM device_classification where del=0 ORDER BY id DESC"
)
)
res = db_mysql.to_json_list(cur)
res = res and res or []
self.finish({"data": res})
class DeviceClassificationDeleteHandler(APIHandler):
"""
- 描述:删除设备分类
- 请求方式post
- 请求参数:
>- id
- 返回值:无
"""
@authenticated
def post(self):
did = self.get_int_argument("id")
with self.app_mysql.connect() as conn:
cur = conn.execute(
text(
"""
select d.id from enterprise_device d, device_classification c
where d.classification=c.suid and c.id=:id and c.del=0
"""
),
{"id": did},
)
rows = cur.fetchall()
if rows:
raise errors.HTTPAPIError(
errors.ERROR_BAD_REQUEST, "该分类使用中,无法删除"
)
conn.execute(
text("update device_classification set del=1 WHERE id=:id"), {"id": did}
)
conn.commit()
self.finish()
class DeviceAddHandler(APIHandler):
"""
- 描述:企业节点,添加设备
- 请求方式post
- 请求参数:
>- entity_id, int, 企业id
>- node_id, int
>- name, string, 设备名称
>- addr, string, 设备位置
>- classification string, 设备分类
>- device_model, string, 设备型号
>- param, string, 设备参数
>- comment, string, 备注
- 返回值:
```
```
"""
@authenticated
def post(self):
entity_id = self.get_int_argument("entity_id")
node_id = self.get_int_argument("node_id")
name = self.get_escaped_argument("name", "")
addr = self.get_escaped_argument("addr", "")
classification = self.get_escaped_argument("classification", "")
device_model = self.get_escaped_argument("device_model", "")
param = self.get_escaped_argument("param", "")
comment = self.get_escaped_argument("comment", "")
if not name:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备名称不能为空")
if not entity_id or not node_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "企业节点不能为空")
# 判断设备分类是否存在
db_classification = DB_DeviceClassification.DeviceClassificationReporitory()
row = db_classification.get_row_by_suid(classification)
if not row:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备分类不存在")
device_data = {
"entity_id": entity_id,
"node_id": node_id,
"name": name,
"addr": addr,
"classification": classification,
"device_model": device_model,
"param": param,
"comment": comment,
}
db_device = DB_Device.EnterpriseDeviceRepository()
db_device.add_device(device_data)
self.finish()
class DeviceEditHandler(APIHandler):
"""
- 描述:企业节点,编辑设备
- 请求方式post
- 请求参数:
>- device_id, int, 设备id
>- name, string, 设备名称
>- addr, string, 设备位置
>- classification string, 设备分类的short uuid
>- device_model, string, 设备型号
>- param, string, 设备参数
>- comment, string, 备注
- 返回值:无
"""
@authenticated
def post(self):
device_id = self.get_int_argument("device_id")
name = self.get_escaped_argument("name", "")
addr = self.get_escaped_argument("addr", "")
classification = self.get_escaped_argument("classification", "")
device_model = self.get_escaped_argument("device_model", "")
param = self.get_escaped_argument("param", "")
comment = self.get_escaped_argument("comment", "")
if not device_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备id不能为空")
if not name:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备名称不能为空")
device_data = {
"id": device_id,
"name": name,
"addr": addr,
"classification": classification,
"device_model": device_model,
"param": param,
"comment": comment,
}
db_device = DB_Device.EnterpriseDeviceRepository()
db_device.edit_device(device_data)
self.finish()
class DeviceDeleteHandler(APIHandler):
"""
- 描述:企业节点,删除设备
- 请求方式post
- 请求参数:
>- node_id, int
>- device_id, int, 设备id
- 返回值:无
"""
@authenticated
def post(self):
# node_id = self.get_int_argument('node_id')
device_id = self.get_int_argument("device_id")
if not device_id:
raise errors.HTTPAPIError(
errors.ERROR_BAD_REQUEST, "企业节点或设备不能为空"
)
db_device = DB_Device.EnterpriseDeviceRepository()
db_device.delete_device(device_id)
self.finish()
class DeviceListHandler(APIHandler):
"""
- 描述:企业节点,设备列表
- 请求方式post
- 请求参数:
> - pageNo
> - pageSize
> - node_id, int, 节点id
- 返回值:
```
{
"count": 123,
"data": [
{
"device_id": 123,
"device_name": "xxx",
"device_class": "xxx", 设备类型
"deployed": 0, # 是否部署, 0/未部署, 1/已部署
},
...
]
}
```
"""
@authenticated
def post(self):
node_id = self.get_int_argument("node_id")
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 20)
if not node_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "企业节点不能为空")
db_device = DB_Device.EnterpriseDeviceRepository()
devices = db_device.list_devices(
node_id=node_id, pageNo=pageNo, pageSize=pageSize
)
logging.info(devices)
self.finish({"count": devices["total_count"], "data": devices["devices"]})
class DeviceListSimpleHandler(APIHandler):
"""获取节点下所有设备的简单信息"""
@authenticated
def post(self):
node_id = self.get_int_argument("node_id")
if not node_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "企业节点不能为空")
db_device = DB_Device.EnterpriseDeviceRepository()
devices = db_device.list_simple_devices(node_id=node_id)
logging.info(devices)
self.finish({"data": devices})
class DeviceInfoHandler(APIHandler):
"""
- 描述:企业节点,设备信息
- 请求方式post
- 请求参数:
> - device_id, int, 设备id
- 返回值:
```
{
"name": "xxx",
"addr": "xxx",
"classification": "xxx",
"device_model": "xxx",
"param": "xxx",
"comment": "xxx",
}
```
"""
def post(self):
device_id = self.get_int_argument("device_id")
if not device_id:
raise errors.HTTPAPIError(
errors.ERROR_BAD_REQUEST, "企业节点或设备不能为空"
)
db_device = DB_Device.EnterpriseDeviceRepository()
device = db_device.get_device(device_id=device_id)
logging.info(device)
self.finish(device)
class DeviceBasemodelListHandler(APIHandler):
"""
- 描述:企业节点,节点信息 -> 设备列表 -> 基础模型配置 -> 模型列表
- 请求方式post
- 请求参数:
> - pageNo
> - pageSize
> - device_id, int, 设备id
- 返回值:
```
{
"count": 123,
"data": [
{
"busi_model": "xxx", # 业务模型的名称
"base_model": [
{
"model_id": 123, # 基础模型id
"model_name": "xxx" # 基础模型name
"model_version": "xxx", # 基础模型的版本
"model_hub_image": "xxx", # 运行库镜像
},
...
]
},
...
]
}
```
"""
@authenticated
def post(self):
device_id = self.get_int_argument("device_id")
if not device_id:
raise errors.HTTPAPIError(
errors.ERROR_BAD_REQUEST, "企业节点或设备不能为空"
)
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 10)
db_busi_model = DB_BusiModelNodeDevice.EnterpriseBusiModelNodeDeviceRepository()
busi_models, count = db_busi_model.get_busi_model_by_device(device_id=device_id, pagination=True,
page_no=pageNo,
page_size=pageSize)
if count == 0:
self.finish({"count": count, "data": []})
return
res = []
for item in busi_models:
busi_model_id = item["busi_model_id"]
busi_model_name = item["name"]
base_model_list = json.loads(item["base_models"])
logging.info("##############################################################")
logging.info(base_model_list)
logging.info("##############################################################")
base_models = []
for base_model in base_model_list:
base_model_id = base_model["id"]
base_model_suid = base_model["suid"]
base_model_name = base_model["name"]
db_alg_model = DB_AlgModel()
base_model = db_alg_model.get_model_dict_by_id(base_model_id)
base_model_version = base_model["default_version"]
db_conf = DB_NodeBaseModelConf.EnterpriseNodeDeviceBMCusConfRepository()
conf = db_conf.get_busi_model_custom_config(
node_id=item["node_id"],
device_id=device_id,
busi_model_id=busi_model_id,
base_model_id=base_model_id
)
base_model_hub_image = ""
if conf:
base_model_hub_image = conf.model_hub_image
base_models.append({
"model_id": base_model_id,
"model_name": base_model_name,
"model_version": base_model_version,
"model_hub_image": base_model_hub_image,
})
res.append({
"busi_model_id": busi_model_id,
"busi_model_name": busi_model_name,
"base_models": base_models
})
self.finish({"count": count, "data": res})
class DeviceBaseModelCustomConfigHandler(APIHandler):
"""
- 描述:企业节点,节点信息 -> 设备列表 -> 基础模型配置 -> 基础模型参数配置
- 请求方式post
- 请求参数:
> - device_id, int, 设备id
> - node_id, int, 节点id
> - base_model_id, int, 基础模型id
> - busi_conf_file, string, 业务参数配置文件md5
> - busi_conf_str, string, 业务参数配置json字符串eg:'{"key1": "value1", "key2": "value2"}'
> - model_hub_image, string, 运行库地址
> - model_conf_file, string, 模型参数配置文件md5
> - model_conf_str, string, 模型参数配置json字符串eg:'{"key1": "value1", "key2": "value2"}'
- 返回值:无
"""
@authenticated
def post(self):
device_id = self.get_int_argument("device_id")
node_id = self.get_int_argument("node_id")
busi_model_id = self.get_int_argument("busi_model_id")
base_model_id = self.get_int_argument("base_model_id")
busi_conf_file = self.get_escaped_argument("busi_conf_file")
busi_conf_str = self.get_escaped_argument("busi_conf_str")
model_hub_image = self.get_escaped_argument("model_hub_image")
model_conf_file = self.get_escaped_argument("model_conf_file")
model_conf_str = self.get_escaped_argument("model_conf_str")
db_device = DB_Device.EnterpriseDeviceRepository()
device = db_device.get_device(device_id=device_id)
if not device:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "device not exist")
if device["node_id"] != node_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "device not belong to this node")
db_alg_model = DB_AlgModel()
base_model = db_alg_model.get_model_dict_by_id(base_model_id)
if not base_model:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "base model not exist")
device_suid = device["suid"]
node_suid = device["node_suid"]
entity_id = device["entity_id"]
entity_suid = device["entity_suid"]
db_busi_model = DB_BusiModel.EnterpriseBusiModelRepository()
busi_model = db_busi_model.get_busi_model_by_id(busi_model_id)
busi_model_suid = busi_model.suid
data = dict()
data.update(
entity_id=entity_id,
entity_suid=entity_suid,
node_id=node_id,
node_suid=node_suid,
device_id=device_id,
device_suid=device_suid,
busi_model_id=busi_model_id,
busi_model_suid=busi_model_suid,
base_model_id=base_model_id,
base_model_suid=base_model["suid"],
busi_conf_file=busi_conf_file,
busi_conf_str=busi_conf_str,
model_hub_image=model_hub_image,
model_conf_file=model_conf_file,
model_conf_str=model_conf_str
)
db_conf = DB_NodeBaseModelConf.EnterpriseNodeDeviceBMCusConfRepository()
db_conf.create_busi_model_custom_config(data=data)
self.finish()
class StatusListHandler(APIHandler):
"""
- 描述:设备状态列表
- 请求方式post
- 请求参数:
> - entity_id, int, 企业id
> - classification_suid, string, 分类id
> - status, int, 状态1000/all/默认, 1001/在线1002/离线1003/运行中1004/故障
> - pageNo
> - pageSize
- 返回值:无
```
{
"count": 123,
"data": [
{
"id": 123,
"name": "xxx",
"status": 1001,
"cpu": 123,
"mem": 123,
"storage": 123,
"gpu": 123,
},
...
]
}
```
"""
@authenticated
def post(self):
entity_id = self.get_int_argument("entity_id")
group = self.get_int_argument("group")
classification = self.get_escaped_argument("classification", "")
status = self.get_int_argument("status", 1000)
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 20)
if not entity_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "企业节点不能为空")
if status not in consts.device_status_map:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "状态参数错误")
db_device = DB_Device.EnterpriseDeviceRepository()
res = db_device.list_entity_devices(
entity_id=entity_id,
pageno=pageNo,
pagesize=pageSize,
classification=classification,
status=status,
group=group
)
count = res["count"]
devices = res["devices"]
data = []
for item, _ in devices:
logging.info(item)
data.append(
{
"id": item.id,
"name": item.name,
"status": item.status,
"cpu": random.randint(20, 30),
"mem": random.randint(20, 30),
"storage": random.randint(20, 30),
"gpu": random.randint(20, 30),
}
)
status_dic = {
consts.device_status_online: 0,
consts.device_status_offline: 0,
consts.device_status_ongoing: 0,
consts.device_status_error: 0,
}
status_count = db_device.status_count(entity_id=entity_id, classification=classification)
for key in status_count:
status_dic.update({key: status_count[key]})
self.finish({"count": count, "data": data, "status_count": status_dic})
class StatusGroupHandler(APIHandler):
@authenticated
def post(self):
entity_id = self.get_int_argument("entity_id")
db_node = DB_Node.EnterpriseNodeRepository()
res = db_node.simple_list(entity_id)
self.finish({"result": res})
class StatusInfoHandler(APIHandler):
""" """
@authenticated
def post(self):
device_id = self.get_int_argument("id")
if not device_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备id不能为空")
# 查询设备信息
db_device = DB_Device.EnterpriseDeviceRepository()
res = db_device.get_devices(device_ids=[device_id])
if not res:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "设备不存在")
res = res[0]
node_id = res["node_id"]
device_suid = res["suid"]
device_name = res["name"]
device_comment = res["comment"]
classification = res["classification"]
db_cls = DB_DeviceClassification.DeviceClassificationReporitory()
row_cls = db_cls.get_row_by_suid(suid=classification)
device_classification_name = row_cls.name
db_node = DB_Node.EnterpriseNodeRepository()
node_info = db_node.get_node_by_id(node_id)
node_name = node_info["name"]
db_busi_model = DB_BusiModelNodeDevice.EnterpriseBusiModelNodeDeviceRepository()
busi_models, _ = db_busi_model.get_busi_model_by_device(device_id=device_id)
models = []
for item in busi_models:
busi_model_id = item["busi_model_id"]
busi_model_name = item["name"]
base_model_list = json.loads(item["base_models"])
base_models = []
for base_model in base_model_list:
base_model_id = base_model["id"]
base_model_name = base_model["name"]
db_alg_model = DB_AlgModel()
base_model = db_alg_model.get_model_dict_by_id(base_model_id)
base_model_version = base_model["default_version"]
db_conf = DB_NodeBaseModelConf.EnterpriseNodeDeviceBMCusConfRepository()
conf = db_conf.get_busi_model_custom_config(busi_model_id=busi_model_id, device_id=device_id,
node_id=item["node_id"])
base_model_hub_image = ""
if conf:
base_model_hub_image = conf.model_hub_image
base_models.append({
"model_id": base_model_id,
"model_name": base_model_name,
"model_version": base_model_version,
"model_hub_image": base_model_hub_image,
})
models.append({
"busi_model": busi_model_name,
"base_models": base_models
})
self.finish({
"classification": device_classification_name,
"name": device_name,
"comment": device_comment,
"ID": device_suid,
"cpu": random.randint(20, 30),
"mem": random.randint(20, 30),
"storage": random.randint(20, 30),
"gpu": random.randint(20, 30),
"models": models,
"group": node_name
})
class StatusLogHandler(APIHandler):
"""
- 描述:设备状态日志
- 请求方式post
- 请求参数:
> - entity_id, int, 企业id
> - pageNo
> - pageSize
- 返回值:
```
{
"count": 123,
"data": [
{
"ID": "xxx",
"name": "xxx",
"classification": "xxx",
"IP": "xxx",
"duration": "xxx",
}
]
}
```
"""
@authenticated
def post(self):
entity_id = self.get_int_argument("entity_id")
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 10)
db_device = DB_Device.EnterpriseDeviceRepository()
res = db_device.list_entity_devices(entity_id=entity_id, pageno=pageNo, pagesize=pageSize)
count = res["count"]
devices = res["devices"]
result = []
for device, classification_name in devices:
device_name = device.name
device_suid = device.suid
device_ip = ""
duration = date_util.time_diff(str(device.create_time))
result.append({
"ID": device_suid,
"name": device_name,
"classification": classification_name,
"IP": device_ip,
"duration": duration,
})
self.finish({"count": count, "data": result})