区服信息接口基础实现

1. 新增区服信息接口(可按机器minion_id请求查询)
2. 时间字段格式化封装
3. 模型调整,返回的字段有调整,针对字段组合又常用的写入模型property来格式化,接口返回不方便处理
This commit is contained in:
chenzuoqing 2021-12-01 17:40:04 +08:00
parent a2fd364343
commit ce0c1a0cb4
6 changed files with 127 additions and 6 deletions

View File

@ -3,6 +3,7 @@ asset marshal fields
""" """
from flask_restful import fields from flask_restful import fields
from common.fields import DateTime
HostFields = { HostFields = {
@ -16,7 +17,7 @@ HostFields = {
"memory": fields.Integer, "memory": fields.Integer,
"tags": fields.List(fields.String), "tags": fields.List(fields.String),
"labels": fields.Raw, "labels": fields.Raw,
"created": fields.DateTime, "created": DateTime,
} }
HostSimpleFields = { HostSimpleFields = {

20
src/common/fields.py Normal file
View File

@ -0,0 +1,20 @@
from flask_restful import fields
class DateTime(fields.DateTime):
"""时间字段格式化,默认的 `rfc822` 不直观,可以指定 `dt_format` 自定义格式"""
def __init__(self, dt_format='%Y-%m-%d %H:%M:%S', **kwargs):
super(fields.DateTime, self).__init__(**kwargs)
self.dt_format = dt_format
def format(self, value):
try:
if self.dt_format in ('rfc822', 'iso8601'):
return super(fields.DateTime.format(self, value))
else:
if isinstance(value, str):
return value
return value.strftime(self.dt_format)
except AttributeError as ae:
raise fields.MarshallingException(ae)

View File

@ -9,6 +9,7 @@ ProjectFields = {
"id": fields.String, "id": fields.String,
"name": fields.String, "name": fields.String,
"fork": fields.String, "fork": fields.String,
"fullname": fields.String,
"domain": fields.String, "domain": fields.String,
"www_ip": fields.String, "www_ip": fields.String,
"ops_ip": fields.String, "ops_ip": fields.String,
@ -25,6 +26,7 @@ ProjectSimpleField = {
"id": fields.String, "id": fields.String,
"name": fields.String, "name": fields.String,
"fork": fields.String, "fork": fields.String,
"fullname": fields.String,
"domain": fields.String, "domain": fields.String,
} }
@ -58,6 +60,7 @@ ChannelSimpleFields = {
ServerFields = { ServerFields = {
"id": fields.String, "id": fields.String,
"num": fields.Integer, "num": fields.Integer,
"agent": fields.String,
"channel": fields.Nested(ChannelSimpleFields), "channel": fields.Nested(ChannelSimpleFields),
"status": fields.String, "status": fields.String,
"host": fields.Nested(HostSimpleFields), "host": fields.Nested(HostSimpleFields),
@ -66,6 +69,27 @@ ServerFields = {
"version": fields.Nested(VersionFields), "version": fields.Nested(VersionFields),
"weight": fields.Integer, "weight": fields.Integer,
"slot": fields.Integer, "slot": fields.Integer,
"tag": fields.List(fields.String), "tags": fields.List(fields.String),
"labels": fields.Raw, "labels": fields.Raw,
} }
# 主要关联字段平铺了的区服信息
AgentServerFields = {
"id": fields.String,
"num": fields.Integer,
"spid": fields.String,
"agent": fields.String,
# "channel_id": fields.String,
"project": fields.String,
"public_ip": fields.String,
"private_ip": fields.String,
# "host_id": fields.String,
"domain": fields.String,
"port": fields.Integer,
"version": fields.Nested(VersionFields),
"status": fields.String,
"weight": fields.Integer,
"slot": fields.Integer,
# "tags": fields.List(fields.String),
# "labels": fields.Raw,
}

View File

@ -24,6 +24,7 @@ class Project(DocumentBase):
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表 tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
labels = mongo.DictField(default=dict) labels = mongo.DictField(default=dict)
@property
def fullname(self): def fullname(self):
return f"{self.name}/{self.fork}" return f"{self.name}/{self.fork}"
@ -76,7 +77,7 @@ class Server(DocumentBase):
# 机器字段TODO 先允许为空 # 机器字段TODO 先允许为空
host = mongo.ReferenceField(Host, null=True) host = mongo.ReferenceField(Host, null=True)
domain = mongo.StringField(max_length=128, required=False) domain = mongo.StringField(max_length=128, required=False, default="")
port = mongo.IntField() port = mongo.IntField()
version = mongo.EmbeddedDocumentField(Version) version = mongo.EmbeddedDocumentField(Version)
weight = mongo.IntField(default=1) weight = mongo.IntField(default=1)
@ -86,3 +87,44 @@ class Server(DocumentBase):
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表 tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
labels = mongo.DictField(default=dict) labels = mongo.DictField(default=dict)
@property
def agent(self):
if self.channel:
return f"{self.channel.spid}_s{self.num}"
return f"_s{self.num}"
@property
def spid(self):
if self.channel:
return self.channel.spid
return ""
@property
def channel_id(self):
if self.channel:
return self.channel.id
return ""
@property
def project(self):
if self.channel:
return self.channel.project.fullname
return ""
@property
def public_ip(self):
if self.host:
return self.host.public_ip
return ""
@property
def private_ip(self):
if self.host:
return self.host.private_ip
return ""
@property
def host_id(self):
if self.host:
return self.host.id
return ""

View File

@ -22,3 +22,6 @@ api.add_resource(views.ServerViews, '/server/', endpoint="server")
api.add_resource(views.ServerDetailView, '/server/<string:pk>/', endpoint="server-detail") api.add_resource(views.ServerDetailView, '/server/<string:pk>/', endpoint="server-detail")
# 区服信息同步接口,更新区服信息 # 区服信息同步接口,更新区服信息
api.add_resource(operation.ServerSyncView, '/server/sync/', endpoint="server-sync") api.add_resource(operation.ServerSyncView, '/server/sync/', endpoint="server-sync")
# 机器信息
api.add_resource(operation.AgentInfo, '/agent/info/<string:agent_id>/', endpoint="agent-info")

View File

@ -1,12 +1,13 @@
import datetime import datetime
from flask import current_app as app from flask import current_app as app
from flask_restful import reqparse from flask_restful import reqparse, Resource, marshal, fields as F
from asset.models import Host from asset.models import Host
from asset.fields import HostFields
from project import fields from project import fields
from project.models import Project, Channel, Server, Version from project.models import Project, Channel, Server, Version
from common.views import CreateMixin from common.views import CreateMixin, RetrieveMixin
from common.permission import token_header_required from common.permission import token_header_required
from common.utils import make_response from common.utils import make_response
@ -81,7 +82,7 @@ class ServerSyncView(CreateMixin):
try: try:
if not host: if not host:
proj = self.project.fullname() proj = self.project.fullname
hostObj, created = Host.get_or_create( hostObj, created = Host.get_or_create(
public_ip=ip, defaults=dict(public_ip=ip, tags=[proj], created=datetime.datetime.now())) public_ip=ip, defaults=dict(public_ip=ip, tags=[proj], created=datetime.datetime.now()))
# 项目写入机器的tags # 项目写入机器的tags
@ -114,3 +115,33 @@ class ServerSyncView(CreateMixin):
return make_response(200, 1000, "success") return make_response(200, 1000, "success")
class AgentInfo(RetrieveMixin):
"""返回对应机器的所有信息:项目、渠道、区服内容"""
fields = {
"host": F.Nested(HostFields),
"project": F.List(F.Nested(fields.ProjectFields)),
"channel": F.List(F.Nested(fields.ChannelFields)),
"servers": F.List(F.Nested(fields.AgentServerFields))
}
def get(self, agent_id):
"""
:param agent_id: 客户端 id
:return:
"""
# 找到机器不存在就404
host = Host.objects(minion_id=agent_id).first_or_404(message="resource not found")
# 根据机器找区服集合,返回
servers = Server.objects(host=host).all()
channels = servers.values_list("channel").distinct("channel")
projects = [channel.project for channel in channels]
# 填充数据
data = {
"host": host,
"project": projects,
"channel": channels,
"servers": servers,
}
# 返回
return marshal(data, self.fields)