bifangback-model初设计及mock数据
2021-01-03 本文已影响0人
万州客
作一个记录,这版bifang后端数据库设计,以极简和高度规范为原则。配置即代码,devops潮流大势。
一,base_models
from django.db import models
from simple_history.models import HistoricalRecords
from django.contrib.auth.models import User
# 基础虚类,所有Model的共同字段,其它model由此继承,包括记录orm操作历史的history字段。
class BaseModel(models.Model):
# unique=True用于保证名称不重复
name = models.CharField(max_length=100,
unique=True,
verbose_name="名称")
description = models.CharField(max_length=100,
null=True,
blank=True,
verbose_name="描述")
# 为了避免删除关联记录,bigang里所有外键都是on_delete=models.SET_NULL
create_user = models.ForeignKey(User,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="用户")
# auto_now用于orm更新记录时,每次自动更新此字段时间
update_date = models.DateTimeField(auto_now=True)
# auto_now_add只用于第一次新增时,自动更新此字段时间
create_date = models.DateTimeField(auto_now_add=True)
# 用于扩展
base_status = models.BooleanField(default=True)
# django的simple_history库,加此字段,用于自动保存每个表的操作历史
history = HistoricalRecords(inherit=True)
# property用于为orm查询增加一个计算型字段
@property
def username(self):
return self.create_user.username
# 记录的默认显示值
def __str__(self):
return self.name
class Meta:
# abstract关键字,表示此class不会生成数据表,只能被继承使用
abstract = True
# 默认排序规则,按更新时间降序
ordering = ('-update_date',)
- django-simple-history的用法,以后再单文说明。
- 所有的model都继承自这个Model,所以这个model的abstract = True。
- name要求unique,在设计时要注意条件满足。
- property装饰符,用于每个rest的返回值加用户名。
- update_date和create_date也为必有字段,保持每次更新时间和记录新增时间。
二,git_models
from django.db import models
from .base_models import BaseModel
# GitLab代码仓库地址,有的公司可能有多个Git仓库,所以独立出一个数据表
# 如果只有一个代码仓库,当然也可以直接在django的settings文件里定义
class GitTb(BaseModel):
# gitlab的URL
git_url = models.URLField(verbose_name="Git API地址")
# 用于python的gitlab库去进行API 认证时需要
git_token = models.CharField(max_length=64, default='no_token', verbose_name="Git API认证token")
# gitlab的版本,仅于展示记录,无实在用途
git_ver = models.CharField(max_length=16, default='12.10', verbose_name="Git版本")
class Meta:
# 用于定义数据表名称,而不使用系统自动生成的,统一命名为与类名相同
db_table = 'GitTb'
# 用一起定义admin后台显示名称(规则为数据表名及简短中文)
verbose_name = 'GitTb代码仓库'
verbose_name_plural = 'GitTb代码仓库'
- db_table均统一命名为与类名相同。
- Git,Salt,Jenkins这种表,为了避免与可能的第三方库命令相同,无论是app名称还是数据表名称,都要注意加一点后缀。
- verbose_name_plural 和verbose_name相同,命名为表名+中文说明。
- git_token第三方库去gitlab拉代码时的认证。
三,salt_models
from django.db import models
from .base_models import BaseModel
# Sat Api地址,不同环境,可能需要不同的Salt Master隔离
# 同样,如果只有一个salt master,只需要在django settings文件里定义
class SaltTb(BaseModel):
# bifang项目主要使用了saltypie这个第三方库操作salt-api,之前的字段,主要是满足saltypie的认证salt-api的参数
salt_url = models.URLField(verbose_name="Salt API地址")
salt_user = models.CharField(max_length=64, verbose_name="Salt API用户")
salt_pwd = models.CharField(max_length=64, verbose_name="Salt API密码")
eauth = models.CharField(max_length=64, default='pam', verbose_name="Salt API用户认证")
trust_host = models.BooleanField(default=True, verbose_name="Salt API安全认证")
# 同样,这个版本只用于可能的展示,现在没有使用
salt_ver = models.CharField(max_length=12, default='2019.3010', verbose_name="Salt版本")
class Meta:
db_table = 'SaltTb'
verbose_name = 'SaltTb远程执行工具'
verbose_name_plural = 'SaltTb远程执行工具'
- salt和git表类似,一般公司可能是只有一个,但为了能灵活,放在数据库里配置。
- saltypie库的初始化如下:
salt = Salt( url=salt_url, username=salt_user, passwd=salt_pwd, trust_host=True, eauth=eauth )
四, env_models
from django.db import models
from .base_models import BaseModel
from .salt_models import SaltTb
# 开发环境 ,线上环境,等等
class Env(BaseModel):
# 因为继续自BaseModel,所以name,description,user,date那些字段都有了,不用重复
# 使用id,可以在必要时,减少一些对数据表自增id的依赖,在作数据库迁移方面,还是有好处的
env_id = models.IntegerField(default=0, verbose_name="环境Id")
# 一般salt master都是分环境建的,这样能达到批量管理的目的,多套saltmaster又可以隔离安全网络
salt = models.ForeignKey(SaltTb,
related_name="ra_env",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="Salt地址")
class Meta:
db_table = 'Env'
verbose_name = 'Env环境'
verbose_name_plural = 'Env环境'
- 环境表,可能只需要name就可以满足需求,但为了更有扩展性,加一个env_id,没害处。
- 假定我们可以按环境可接入salt,所以这里加入一个salt的外键字段。
- django 默认每个主表的对象都有一个是外键的属性,可以通过它来查询到所有属于主表的子表的信息。这个属性的名称默认是以子表的名称小写加上_set()来表示,默认返回的是一个querydict对象。related_name 可以给这个外键定义好一个别的名称。
- related_name我的命名规则,是ra_开头,然后加上表名env。这样的约定,更易理解代码中的引用。如果有两个字段关联到同一个外键表,才需要再定义一个不同的related_name(如server里关联两个release,一个运行发布单 ,一个可能的回滚单)。
- blank=True,null=True,on_delete=models.SET_NULL,这三者定义是关联的。如果我们定义了on_delete策略为models.SET_NULL,则必须定义null=True,即允许此字段为空。不然,在作数据库的mock数据时,删除一个表的所有记录时,会有些细节和顺序要调整。而如果使用这三个值,则基本无所谓顺序。
- null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空。blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填。
五,project_models
from django.db import models
from .base_models import BaseModel
# 项目,可表示由多个相关微服务组成的项目
# 比如,istio里的bookin就算是bifang中的一个project
# 而其中的productpage,reviews,details,ratings这些应用,就相当于bifang中的app应用
class Project(BaseModel):
# 只是为了一个中文显示,及统一的项目id加的。不解释
cn_name = models.CharField(max_length=255, verbose_name="中文名")
project_id = models.IntegerField(default=0, verbose_name="项目编号")
class Meta:
db_table = 'Project'
verbose_name = 'Project项目'
verbose_name_plural = 'Project项目'
- 无须解释,可以用来表示多含多个组件的项目,也可以用来表达一个含有很多微服务的项目总和,方便分类和管理。
- 一般项目命令为英文字母,加一个中文别名和项目id,更易沟通和语义定义。
- istio的bookinfo项目详情:https://www.jianshu.com/c/8572c5dbba97
六,app_models
from django.db import models
from .base_models import BaseModel
from .git_models import GitTb
from .project_models import Project
# 应用服务,相当于一个可独立部署的微服务
# 如istio bookinfo中,可独立部署,且使用不同语言开发的4个应用(productpage, details, reviews, ratings)
class App(BaseModel):
# cn_name和app_id意义和project中的一样。但要注意,这个app_id,会和一些外键表中的app_id有雷同,这是高级技巧了,
# 这是一个坑,但本来这样命名,也是最自然的,无所畏惧。
cn_name = models.CharField(max_length=255, verbose_name="中文名")
app_id = models.IntegerField(default=0, verbose_name="应用编号")
# 每个app应用,与一个代码关联
git = models.ForeignKey(GitTb,
related_name="ra_app",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="Git实例")
# 这里单独定义一个git中这个app的id,可能有优化的空间,也可能没有。git库在定义具体的代码仓库时,就是要这个参数
git_app_id = models.IntegerField(default=0, verbose_name="Git应用ID")
# 为了加强控制,git中每一个ci/cd功能,当代码提交之后,都不会自动运行,而要通过一个trigger token去人工触发
# 这个trigger token的生成,在gitlab的ci/cd里,很容易生成。
git_trigger_token = models.CharField(max_length=64,
blank=True,
null=True,
verbose_name="git trigger token")
# 将app与project进行关联,方便数据统计,关联显示
project = models.ForeignKey(Project,
related_name='ra_project',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='项目')
# 按devops及gitops的理念,开发维护自己的编译脚本和部署脚本,并进行版本管理
# build_script用于定义通过构建,生成软件包的脚本
build_script = models.CharField(max_length=255, default='build.sh', verbose_name="编译脚本名")
# deploy_script用于定义服务部署,启停,备份,回滚,健康状态检测等功能,
# 如果为开发提供了模板,是很容易作为代码一部份管理起来的,配置即代码!
# 如果bifang本身来存储这些脚本,反而增加管理难度,不透明度及中心化
deploy_script = models.CharField(max_length=255, default='bifang.sh', verbose_name="部署脚本名")
# 定义软件包的名称,这里也有纠结,是自定义,还是强约定
# 如果规定了软件包名必须与app名称相同,会少很多事,但又显得过于霸道
# 这里留个小口吧,另外,在部署脚本时,还会有几个类似的软件包,软件压缩包名,软件部署目录,都类似
zip_package_name = models.CharField(max_length=255, default='demo.zio', verbose_name="应用压缩包")
# 如果app有脚本端口,则可能用于状态检测,增加部署的成功判断率
service_port = models.IntegerField(default=0, verbose_name="服务端口")
# 使用哪个用户名和哪个用户组启动,
service_username = models.CharField(max_length=24,
blank=True,
null=True,
verbose_name="执行用户名")
service_group = models.CharField(max_length=24,
blank=True,
null=True,
verbose_name="执行用户组")
# 如果bifang增加独立的服务器启停功能,日志单独数据表保存,但这里可以保存最近启停次数,用于定义日志
op_log_no = models.IntegerField(default=0, verbose_name="启停日志次数")
class Meta:
db_table = 'App'
verbose_name = 'App应用'
verbose_name_plural = 'App应用'
- cn_name和app_id,和Project字段同义。
- 每个app属于一个project。所以它们之间有一对多的关系。
- 使用django model orm的外键定义,主要是在查询方便,有很强大的语法支持。在更新时,orm更易和python的数据结构交互。
- git和git_repo用于定义此app的git地址,方便bifang对此代码库进行ci/cd操作。
- service_username和service_group,用于调用salt进行远程部署时,指定用户名和用户组。一般来说,用户名足够了。但,万一有用户的要求呢?留有扩展。
- op_log_no 字段,用于定位此app组件的启停批次,方便查看日志时的定义。当然,也可以在此app组件下的每个server中,使用此字段。但那样ms管理有点不集中了。待优化~
七,server_models
from django.db import models
from .base_models import BaseModel
from .app_models import App
from .release_models import Release
SYSTEM_CHOICES = (
('WINDOWS', 'WINDOWS'),
('LINUX', 'LINUX'),
)
# 部署服务器,保证ip和port结合起来的唯一性,可以一个服务器上部署多个应用
# 当然,能在同一个服务器上,部署多个相同的应用,这得益于将部署脚本让开发自己维护。
# 真正的devops团队,是需要都有开发和运维的跨界实力的啦~
class Server(BaseModel):
# GenericIPAddressField的字段,让这里只存储ip地址
ip = models.GenericIPAddressField(max_length=64, verbose_name="服务器Ip")
# 服务端口,其实,这里是需要优化的,
# 如果有的服务启动,不提供端口服务呢?乱写么?如何保证多个无端口服务不冲突?
port = models.IntegerField(verbose_name="服务器端口")
system_type = models.CharField(max_length=16,
choices=SYSTEM_CHOICES,
default='LINUX',
verbose_name="操作系统")
# 此服务器与哪一个app关联
app = models.ForeignKey(App,
related_name='ra_server',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='应用服务')
# 保存在此服务器正在运行的app的最近发布单
main_release = models.ForeignKey(Release,
related_name='ra_server_main',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='主发布单')
# 保存在此服务器正在运行的app的次新发布单,主要用于回滚,bifang只支持最近一次回滚,不支持无限回滚
back_release = models.ForeignKey(Release,
related_name='ra_server_back',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='备份发布单')
class Meta:
db_table = 'Server'
# 一个服务器上,部署多个应用,保证Ip加port的唯一性。
unique_together = ('ip', 'port')
verbose_name = 'Server服务器'
verbose_name_plural = 'Server服务器'
- unique_together,联合约束,这样,在同一个服务器上,就可以部署多个app应用。
- main_release 和back_release ,主要用来显示服务器最新应用,以及回滚发布单。在每次部署时,都会影响这两个字段。但只是停启服务时,则不会更新这两个字段。
八,release_models
from django.db import models
from .base_models import BaseModel
from .app_models import App
from .env_models import Env
# 发布单状态,为了能动态管理,我觉得加个单独的表,有必要。
class ReleaseStatus(BaseModel):
# ['Create', 'Building', 'BuildFailed', 'Build', 'Ready', 'Ongoing', 'Success', 'Failed']
# ['创建', '编译中', '编译失败', '编译成功', '准备部署', '部署中', '部署成功', '部署失败']
status_value = models.CharField(max_length=1024, blank=True, verbose_name="状态值")
class Meta:
db_table = 'ReleaseStatus'
verbose_name = 'ReleaseStatus发布单状态'
verbose_name_plural = 'ReleaseStatus发布单状态'
# 发布单, bifang部署平台中的灵魂和纽带
# 各种配置经由它作融合,各种动态数据经由它启动发散
class Release(BaseModel):
# app关联
app = models.ForeignKey(App,
related_name='ra_release',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="应用")
# 环境关联,这个在新建和编译发布单过程中,是没有数据的,在环境流转之后才有
env = models.ForeignKey(Env,
related_name="ra_release",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="环境")
# 如果一个发布单部署了多次,或是分批在服务器部署,就有这个记录的必要性了。
deploy_no = models.IntegerField(blank=True,
null=True,
default=0,
verbose_name="部署次数")
# 自定义需要部署的git分支
git_branch = models.CharField(max_length=255,
blank=True,
null=True)
# pipeline_id和pipeline_url在编译软件包的过程中生成,用于获取编译状态及定位编译输出
pipeline_id = models.IntegerField(default=0)
pipeline_url = models.URLField(default='http://www.demo.com')
# 这个部署脚本,在git代码中的一般会有自己独立的目录,而在制品仓库时,可能就有软件包并列在同一个目录了,清晰。
deploy_script_url = models.URLField(default=None,
blank=True,
null=True,
verbose_name="部署脚本路径")
# 这里生成软件包之后,直接记录url软件包路径,这样在部署脚本中,就可以直接使用wget下载了。
# 为什么不使用salt?其实也行,但wget不是更稳定和简单么?
zip_package_url = models.URLField(default=None,
blank=True,
null=True,
verbose_name="压缩制品库路径")
# 记录各种状态用于前端显示
deploy_status = models.ForeignKey(ReleaseStatus,
related_name='ra_release',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="发布单状态")
class Meta:
db_table = 'Release'
verbose_name = 'Release发布单'
verbose_name_plural = 'Release发布单'
- ReleaseStatus表,用于定义发布单的状态。用外表定义,比普通的字段,更有统一性。
- Release发布单数据表,需和app,env关联。但其状态随时间的变化,则放到后面的ReleaseHistory表中。这样就可以在时间上串联起操作历史,而在空间上唯一定位当前发布单。这对于我之前的设计来说,是个改进(唯一尴尬的是,这种ReleaseHistory数据表,本身要不是记录操作历史?:))---更新,服务器的操作历史,记录在ServerHistory数据表中,完美解决。
- git_branch 和git_commit,用于追踪此个发布单 的代码分支。
- deploy_no 用于跟踪此发布单在不同环境的部署日志。
- salt_path和nginx_url 用于定位此app组件的制品库路径。此路径下,一般会有两个文件,一个制品包(war, zip...),另一个部署脚本。salt会调用这个部署脚本,操作制品包的部署全过程。这种集成的东东,对于之前的部署来说,也是一个新思路。
九,history_models
from django.db import models
from .base_models import BaseModel
from .env_models import Env
from .release_models import Release, ReleaseStatus
from .server_models import Server
# 用于在发布单的部署代码层次内的记录,是部署新代码,还是回滚老代码?
# 用于发布单历史
DEPLOY_CHOICES = (
('deploy', '部署'),
('rollback', '回滚'),
)
# 用于大的方向,是在部署代码,还是单纯在维护服务器启停?
# 用于服务器操作历史,区分发布单和服务器操作历史是有意义的,维护不一样,但也可以一追到底
OP_CHOICES = (
('deploy', '部署'),
('maintenance', '启停维护'),
)
# 在服务器上操作的第一步作记录,后期根据需要,有可能作维护改动
# 它主要要能包括所有deploy过程中的action_list列表项目
ACTION_CHOICES = (
('fetch', '获取软件'),
('stop', '停止'),
('stop_status', '停止状态检测'),
('deploy', '部署'),
('rollback', '回滚'),
('start', '启动'),
('start_status', '启动状态检测'),
('health_check', '服务健康检测'),
)
# 发布单历史,记录发布单的生命周期,新建,编译,流转,部署,回滚部署
class ReleaseHistory(BaseModel):
release = models.ForeignKey(Release,
related_name='ra_release_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='发布单')
env = models.ForeignKey(Env,
related_name="ra_release_history",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="环境")
deploy_status = models.ForeignKey(ReleaseStatus,
related_name='ra_release_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="发布单状态")
deploy_type = models.CharField(max_length=255,
choices=DEPLOY_CHOICES,
blank=True,
null=True,
verbose_name="部署类型")
log = models.TextField(verbose_name="日志内容")
class Meta:
db_table = 'ReleaseHistory'
verbose_name = 'ReleaseHistory发布单历史'
verbose_name_plural = 'ReleaseHistory发布单历史'
# 服务器变更历史,记录服务器上的部署,停止,回滚
class ServerHistory(BaseModel):
server = models.ForeignKey(Server,
related_name='ra_server_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='服务器')
release = models.ForeignKey(Release,
related_name='ra_server_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='发布单')
env = models.ForeignKey(Env,
related_name="ra_server_history",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="环境")
op_type = models.CharField(max_length=255,
choices=OP_CHOICES,
blank=True,
null=True,
verbose_name="操作类型")
action_type = models.CharField(max_length=255,
choices=ACTION_CHOICES,
blank=True,
null=True,
verbose_name="服务器操作类型")
log = models.TextField(verbose_name="日志内容")
class Meta:
db_table = 'ServerHistory'
verbose_name = 'ServerHistory服务器历史'
verbose_name_plural = 'ServerHistory服务器历史'
- 维护两个历史表,一个记录发布单历史,一个记录服务器历史。待完善。
十,permission_models
from django.db import models
from .base_models import BaseModel
from django.contrib.auth.models import User
from .app_models import App
# 创建编译发布单, 环境流转,部署发布单三个大的权限,
# bifang暂不支持基于各个具体环境的细致权限
# 大家可以自己基于书上教授的技能,自行实现
class Action(BaseModel):
action_id = models.IntegerField(unique=True, verbose_name="权限序号")
class Meta:
db_table = 'Action'
verbose_name = 'Action权限'
verbose_name_plural = 'Action权限'
# 具体的权限数据表
# 如果要获取某个服务的所有权限,或是某一应用的指定权限的用户列表,都是OK的。
class Permission(BaseModel):
# 权限与app应用级别关联
app = models.ForeignKey(App,
related_name="ra_permission",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="App应用")
# 权限与具体的权限动作(创建编译,环境流转,部署发布)关联
action = models.ForeignKey(Action,
related_name="ra_permission",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="操作权限")
# 权限关联到用户
pm_user = models.ForeignKey(User,
related_name="ra_permission",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="权限用户")
class Meta:
db_table = 'Permission'
verbose_name = 'Permission应用权限'
verbose_name_plural = 'Permission应用权限'
- casbin感觉一般般,可能不太适用于我这种情况,或是动静开大,直接手撸。
- 将权限分为三个,一个是新建编译权限,一个为环境流转权限,一个为部署各个环境的权限(不再区分),自己的东东自己负责。
- 能编辑权限的,只有三种用户,一个是系统admin,一种是project的创建用户,一个是app的创建用户。
- 小而美的权限,也不过如彼。
十一,mock数据
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import Group
from cmdb.models import *
import string
import random
import time
import datetime
from django.contrib.auth import get_user_model
User = get_user_model()
username = 'admin'
group_name = 'admin'
# 自定义命令,用于建立测试数据,很多ORM语句会使用
class Command(BaseCommand):
help = 'create test data for BiFang back server.'
def add_arguments(self, parser):
self.stdout.write(self.style.SUCCESS('没有额外参数,新建全部模拟测试数据,删除所有旧记录'))
def handle(self, *args, **options):
self.add_user()
self.add_git()
self.add_salt()
self.add_env()
self.add_project()
self.add_app()
self.add_server()
self.add_release_status()
self.add_release()
self.add_action()
self.add_permission()
self.stdout.write(self.style.SUCCESS('数据重建完成,一把梭哈~~~'))
# raise CommandError('Ok!')
# 新建一个用户
def add_user(self):
User.objects.all().delete()
Group.objects.all().delete()
print('delete all user and group data')
User.objects.create_user(username='Dylan', email='user@demo.com', password="password")
User.objects.create_user(username='Tyler', email='user@demo.com', password="password")
User.objects.create_user(username='Kyle', email='user@demo.com', password="password")
User.objects.create_user(username='Dakota', email='user@demo.com', password="password")
User.objects.create_user(username='Marcus', email='user@demo.com', password="password")
User.objects.create_user(username='Samantha', email='user@demo.com', password="password")
User.objects.create_user(username='Kayla', email='user@demo.com', password="password")
User.objects.create_user(username='Sydney', email='user@demo.com', password="password")
User.objects.create_user(username='Courtney', email='user@demo.com', password="password")
User.objects.create_user(username='Mariah', email='user@demo.com', password="password")
User.objects.create_user(username='tom', email='user@demo.com', password="password")
User.objects.create_user(username='mary', email='user@demo.com', password="password")
admin = User.objects.create_superuser(username, 'admin@demon.com', 'password')
root = User.objects.create_superuser('root', 'root@demon.com', 'password')
admin_group = Group.objects.create(name=group_name)
Group.objects.create(name='test')
Group.objects.create(name='dev')
Group.objects.create(name='operate')
admin_users = [admin, root]
admin_group.user_set.set(admin_users)
self.stdout.write('用户和用户组重建完成。')
# 新建一个Git仓库
def add_git(self):
GitTb.objects.all().delete()
print('delete all GitTb data')
create_user = User.objects.get(username=username)
GitTb.objects.create(name='MainGit',
description='主要git库',
create_user=create_user,
git_url='http://192.168.1.211:8180',
git_token='RbCcuLssPekyVgy24Nui')
self.stdout.write('GitTb重建完成。')
# 新建一个SaltApi
def add_salt(self):
SaltTb.objects.all().delete()
print('delete all SaltTb data')
create_user = User.objects.get(username=username)
SaltTb.objects.create(name='MainSalt',
description='主要SaltApi',
create_user=create_user,
salt_url='https://192.168.1.211:8000',
salt_user='saltapi',
salt_pwd='saltapipwd',
eauth='pam',
trust_host=True)
self.stdout.write('SaltTb重建完成。')
# 新建一个环境
def add_env(self):
Env.objects.all().delete()
print('delete all Env data')
create_user = User.objects.get(username=username)
salt = SaltTb.objects.order_by('?').first()
env_list = ['dev', 'prd']
for index, env in enumerate(env_list):
Env.objects.create(name=env,
description=env,
create_user=create_user,
env_id=index,
salt=salt)
self.stdout.write('Env重建完成。')
# 新建demo项目
def add_project(self):
Project.objects.all().delete()
print('delete all Project data')
create_user = User.objects.get(username=username)
project_name_list = ['User', 'Service', 'Store', 'Card', 'Support']
project_cn_name_list = ['用户管理', '服务', '库存', '购物车', '客服']
for project_name, project_cn_name in zip(project_name_list, project_cn_name_list):
Project.objects.create(name=project_name,
description=project_name,
cn_name=project_cn_name,
create_user=create_user,
project_id=random.randint(1000, 10000))
self.stdout.write('Project重建完成。')
# 新建demo应用
def add_app(self):
App.objects.all().delete()
print('delete all App data')
create_user = User.objects.get(username=username)
app_name_list = ['User-Login', 'Service-724', 'Store-Address', 'Card-Adjust', 'Support-Admin', 'go-demo']
app_cn_name_list = ['用户登陆', '全天服务', '库存地址', '购物车调配', '客服后管', '毕方演示go示例']
for app_name, app_cn_name in zip(app_name_list, app_cn_name_list):
git = GitTb.objects.order_by('?').first()
project = Project.objects.order_by('?').first()
App.objects.create(name=app_name,
description=app_name,
cn_name=app_cn_name,
create_user=create_user,
app_id=random.randint(10000, 100000),
git=git,
git_app_id=1,
git_trigger_token='559fbd3381bc39100811bd00e499a7',
project=project,
build_script='script/build.sh',
deploy_script='script/deploy.sh',
zip_package_name='go-demo.tar.gz',
service_port=9090,
service_username='sky',
service_group='operate')
self.stdout.write('App重建完成。')
# 新建server服务器
def add_server(self):
Server.objects.all().delete()
print('delete all Server data')
create_user = User.objects.get(username=username)
for number in range(100):
ip = '192.168.1.{}'.format(number)
app = App.objects.order_by('?').first()
Server.objects.create(name=ip,
description=ip,
create_user=create_user,
ip=ip,
port=random.randint(10000, 100000),
app=app,
system_type=random.choice(['WINDOWS', 'LINUX']))
self.stdout.write('Server重建完成。')
# 新建发布单状态
def add_release_status(self):
ReleaseStatus.objects.all().delete()
print('delete all ReleaseStatus data')
create_user = User.objects.get(username=username)
status_list = ['Create', 'Building', 'BuildFailed', 'Build', 'Ready', 'Ongoing', 'Success', 'Failed']
status_value_list = ['创建', '编译中', '编译失败', '编译成功', '准备部署', '部署中', '部署成功', '部署失败']
for status_name, status_value_name in zip(status_list, status_value_list):
ReleaseStatus.objects.create(name=status_name,
description=status_name,
create_user=create_user,
status_value=status_value_name)
self.stdout.write('ReleaseStatus重建完成。')
# 新建demo发布单
def add_release(self):
Release.objects.all().delete()
print('delete all Release data')
create_user = User.objects.get(username=username)
for number in range(100):
app = App.objects.order_by('?').first()
env = Env.objects.order_by('?').first()
deploy_status = ReleaseStatus.objects.order_by('?').first()
random_letter = ''.join(random.sample(string.ascii_letters, 2))
name = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f") + random_letter.upper()
Release.objects.create(name=name,
description=name,
create_user=create_user,
app=app,
env=env,
git_branch='master',
pipeline_id=0,
pipeline_url='http://www.demo.com',
deploy_script_url='http://192.168.1.213:8080/a/b/bifang.sh',
zip_package_url='http://192.168.1.213:8080/a/b/go-demo.zip',
deploy_status=deploy_status)
self.stdout.write('Release重建完成。')
# 新建权限
def add_action(self):
Action.objects.all().delete()
print('delete all Action data')
create_user = User.objects.get(username=username)
Action.objects.create(name='Create',
description='创建编译权限',
create_user=create_user,
action_id=100)
Action.objects.create(name='Env',
description='环境权限',
create_user=create_user,
action_id=1000)
Action.objects.create(name='Deploy',
description='部署权限',
create_user=create_user,
action_id=10000)
self.stdout.write('Action重建完成。')
# 新建demo应用权限用户表
def add_permission(self):
Permission.objects.all().delete()
print('delete all Permission data')
create_user = User.objects.get(username=username)
for number in range(5):
app = App.objects.order_by('?').first()
action = Action.objects.order_by('?').first()
pm_user = User.objects.order_by('?').first()
name = '{}-{}-{}'.format(app.name, action.name, pm_user.username)
Permission.objects.create(name=name,
description=name,
create_user=create_user,
app=app,
action=action,
pm_user=pm_user)
self.stdout.write('Permission重建完成。')
- 使用
(venv) D:\Code\bifang\bifangback>python manage.py mockdb
自定义命令,可把这些mock数据导入数据库。 - 这里也使用了不同django orm和Python随机选择的技巧。