取消 ReferenceField 字段,改用字符串字段存储对象id,手动关联,接口同步修改

This commit is contained in:
chenzuoqing 2021-12-06 14:20:12 +08:00
parent 7cb3848751
commit 8d54f9e8fd
4 changed files with 89 additions and 24 deletions

View File

@ -13,3 +13,11 @@ def is_ipaddr(ip):
ipaddress.ip_address(ip) ipaddress.ip_address(ip)
except: except:
raise mongo.ValidationError('The value must be a ip address') raise mongo.ValidationError('The value must be a ip address')
def is_hex_string(string: str):
"""校验 hex 字符串(十六进制)"""
try:
int(string, 16)
except:
raise mongo.ValidationError('The value must be a hex string')

View File

@ -83,6 +83,8 @@ AgentServerFields = {
"is_cross": fields.Boolean, "is_cross": fields.Boolean,
# "channel_id": fields.String, # "channel_id": fields.String,
"project": fields.String, "project": fields.String,
"project_name": fields.String,
"project_fork": fields.String,
"public_ip": fields.String, "public_ip": fields.String,
"private_ip": fields.String, "private_ip": fields.String,
# "host_id": fields.String, # "host_id": fields.String,

View File

@ -2,7 +2,7 @@ import mongoengine as mongo
from settings import common from settings import common
from common.document import DocumentBase from common.document import DocumentBase
from common.validator import isalnum from common.validator import isalnum, is_hex_string
from asset.models import Host from asset.models import Host
@ -44,9 +44,9 @@ class Version(mongo.EmbeddedDocument):
class Channel(DocumentBase): class Channel(DocumentBase):
"""渠道""" """渠道"""
# spid项目内唯一 # spid项目内唯一
project = mongo.ReferenceField(Project, reverse_delete_rule=mongo.NULLIFY) project_id = mongo.StringField(max_length=128, required=True, validation=is_hex_string)
name = mongo.StringField(max_length=32, default="") name = mongo.StringField(max_length=32, default="")
spid = mongo.StringField(max_length=3, min_length=3, required=True, unique_with="project", validation=isalnum) spid = mongo.StringField(max_length=3, min_length=3, required=True, unique_with="project_id", validation=isalnum)
version = mongo.EmbeddedDocumentField(Version) # 缺失时获取对象的此字段为 None version = mongo.EmbeddedDocumentField(Version) # 缺失时获取对象的此字段为 None
# 项目的代码仓库地址 # 项目的代码仓库地址
@ -64,6 +64,20 @@ class Channel(DocumentBase):
"""渠道 spid 在 CROSS_SPID_SET表示跨服""" """渠道 spid 在 CROSS_SPID_SET表示跨服"""
return self.spid in common.CROSS_SPID_SET return self.spid in common.CROSS_SPID_SET
@property
def project(self):
if self.project_id:
return Project.objects(id=self.project_id).first()
return None
@project.setter
def project(self, val):
if isinstance(val, str):
assert Project.objects(id=val).first(), f"对象不存在,id={val}"
self.project_id = val
if isinstance(val, Project):
self.project_id = str(val.id)
class Server(DocumentBase): class Server(DocumentBase):
"""服务""" """服务"""
@ -77,12 +91,13 @@ class Server(DocumentBase):
"error": "异常" "error": "异常"
} }
num = mongo.IntField(required=True, unique_with="channel") num = mongo.IntField(required=True, unique_with="channel_id")
channel = mongo.ReferenceField(Channel) # 关联channel表保存是一个channel._id的hex字符串
channel_id = mongo.StringField(max_length=128, required=True, validation=is_hex_string)
status = mongo.StringField(max_length=12, choices=STATUS.keys(), required=True, default="running") status = mongo.StringField(max_length=12, choices=STATUS.keys(), required=True, default="running")
# 机器字段TODO 先允许为空 # 机器字段TODO 先允许为空
host = mongo.ReferenceField(Host, null=True) host_id = mongo.StringField(max_length=128, null=True, validation=is_hex_string)
domain = mongo.StringField(max_length=128, required=False, default="") domain = mongo.StringField(max_length=128, required=False, default="")
port = mongo.IntField() port = mongo.IntField()
version = mongo.EmbeddedDocumentField(Version) version = mongo.EmbeddedDocumentField(Version)
@ -106,17 +121,38 @@ class Server(DocumentBase):
return "" return ""
@property @property
def channel_id(self): def channel(self):
if self.channel: """非强关联方便取出channel对象"""
return self.channel.id if self.channel_id:
return Channel.objects(id=self.channel_id).first()
return "" return ""
@channel.setter
def channel(self, val):
if isinstance(val, str):
assert Channel.objects(id=val).first(), f"对象不存在,id={val}"
self.channel_id = val
if isinstance(val, Channel):
self.channel_id = str(val.id)
@property @property
def project(self): def project(self):
if self.channel: if self.channel and self.channel.project:
return self.channel.project.fullname return self.channel.project.fullname
return "" return ""
@property
def project_name(self):
if self.channel and self.channel.project:
return self.channel.project.name
return ""
@property
def project_fork(self):
if self.channel and self.channel.project:
return self.channel.project.fork
return ""
@property @property
def public_ip(self): def public_ip(self):
if self.host: if self.host:
@ -130,11 +166,20 @@ class Server(DocumentBase):
return "" return ""
@property @property
def host_id(self): def host(self):
if self.host: """非强关联为了取出host对象"""
return self.host.id if self.host_id:
return Host.objects(id=self.host_id).first()
return "" return ""
@host.setter
def host(self, val):
if isinstance(val, str):
assert Host.objects(id=val).first(), f"对象不存在,id={val}"
self.host_id = val
if isinstance(val, Host):
self.host_id = str(val.id)
@property @property
def is_cross(self): def is_cross(self):
if self.channel: if self.channel:

View File

@ -65,7 +65,7 @@ class ServerSyncView(CreateMixin):
if count != len(data): if count != len(data):
return make_response(400, 1001, "quantity mismatch") return make_response(400, 1001, "quantity mismatch")
project_id = str(self.project.id)
hosts = {} hosts = {}
channels = {} channels = {}
errors = [] errors = []
@ -89,17 +89,17 @@ class ServerSyncView(CreateMixin):
if not created and proj not in hostObj.tags: if not created and proj not in hostObj.tags:
hostObj.tags.append(proj) hostObj.tags.append(proj)
hostObj.save() hostObj.save()
host = hostObj.id host = str(hostObj.id)
hosts[ip] = hostObj.id hosts[ip] = host
if not channel: if not channel:
channelObj, _ = Channel.get_or_create( channelObj, _ = Channel.get_or_create(
project=self.project, spid=spid, defaults=dict(project=self.project, spid=spid)) project_id=project_id, spid=spid, defaults=dict(project_id=project_id, spid=spid))
channel = channelObj.id channel = str(channelObj.id)
channels[spid] = channelObj.id channels[spid] = channel
# 更新、创建的参数 # 更新、创建的参数
defaults = dict(num=num, channel=channel, host=host, version=version, port=port, status=status) defaults = dict(num=num, channel_id=channel, host_id=host, version=version, port=port, status=status)
obj, created = Server.update_or_create(defaults=defaults, num=num, channel=channel) obj, created = Server.update_or_create(defaults=defaults, num=num, channel_id=channel)
if created: # 创建 if created: # 创建
app.logger.debug(f"创建 {spid}_{num} 区服信息成功") app.logger.debug(f"创建 {spid}_{num} 区服信息成功")
continue continue
@ -119,6 +119,8 @@ class ServerSyncView(CreateMixin):
class AgentInfo(RetrieveMixin): class AgentInfo(RetrieveMixin):
"""返回对应机器的所有信息:项目、渠道、区服内容""" """返回对应机器的所有信息:项目、渠道、区服内容"""
fields = { fields = {
# marshal schedule dict
"schedule": F.Raw,
"host": F.Nested(HostFields), "host": F.Nested(HostFields),
"project": F.List(F.Nested(fields.ProjectFields)), "project": F.List(F.Nested(fields.ProjectFields)),
"channel": F.List(F.Nested(fields.ChannelFields)), "channel": F.List(F.Nested(fields.ChannelFields)),
@ -133,11 +135,19 @@ class AgentInfo(RetrieveMixin):
# 找到机器不存在就404 # 找到机器不存在就404
host = Host.objects(minion_id=agent_id).first_or_404(message="resource not found") host = Host.objects(minion_id=agent_id).first_or_404(message="resource not found")
# 根据机器找区服集合,返回 # 根据机器找区服集合,返回
servers = Server.objects(host=host).all() servers = Server.objects(host_id=str(host.id)).all()
channels = servers.values_list("channel").distinct("channel") channels = Channel.objects(id__in=servers.values_list("channel_id").distinct("channel_id"))
projects = [channel.project for channel in channels] projects = {channel.project for channel in channels}
# 填充数据 # 填充数据
data = { data = {
# TODO schedule 这里的内容可以动态配置,为 minion 增加计划任务
# "schedule": {
# # 如下为刷新pillar自动请求本接口先测试用20s
# "job_refresh": {
# "function": "saltutil.refresh_pillar",
# "seconds": 20,
# }
# },
"host": host, "host": host,
"project": projects, "project": projects,
"channel": channels, "channel": channels,