一.服务器管理:

https://github.com/rfjer/autoAdmin/tree/master/apps/servers

一服务器信息收集方式:
1.物理服务器
跑脚本传(bash/ansible/salt)
golang采集(推荐)---不需任何依赖丢上去便可执行(不在乎有无外网),并发高资源占用低。
2.虚拟化服务器vm/kvm--内网
小公司vmware用的多)---vcenter采集,openstack(大公司),kvm
3.云服务器(aws/阿里/青云)--公网
各自sdk接口
4.容器(docker---k8s管理)
用drf作接口展示即可

二.业务线管理:树型结构

怎么进行业务线管理?---树型结构

参考https://github.com/rfjer/autoAdmin/blob/master/apps/products/models.py   业务线模型

https://github.com/rfjer/autoAdmin/blob/master/apps/products/views.py   业务业后端接口实现

https://github.com/rfjer/autoAdmin/blob/master/apps/products/serializers.py  序列化

后端:

如下业务线表模型中只做两层,所以没有用path,pid=0说明就是一级的,不等于0都是二级的
from django.db import models
from django.contrib.auth import get_user_model User = get_user_model() class Product(models.Model):
service_name = models.CharField("业务线名称", max_length=32, help_text="业务线名称")
pid = models.IntegerField("上级业务线id", db_index=True, help_text="上级业务线id")
module_letter = models.CharField("业务线字母简称", max_length=32, help_text="业务线字母简称")
dev_interface = models.ManyToManyField(User, verbose_name="开发接口人", related_name="dev_interface", help_text="开发接口人")
op_interface = models.ManyToManyField(User, verbose_name="运维接口人", related_name="op_interface", help_text="运维接口人") def __str__(self):
return self.service_name class Meta:
db_table = 'resources_product'
permissions = (
("view_product", "can view products"),
)
ordering = ["id"]

views.py:

二业务线管理:

from rest_framework import mixins, viewsets, response, status

from .models import Product
from .serializers import ProductSerializer
from .filters import ProductFilter
from servers.models import Server class ProductViewset(viewsets.ModelViewSet):
"""
retrieve:
返回指定业务线信息
list:
返回业务线列表
update:
更新业务线信息
destroy:
删除业务线记录
create:
创建业务线资源
partial_update:
更新部分字段
"""
queryset = Product.objects.all()
serializer_class = ProductSerializer
extra_perms_map = { //这是给get增加权限
"GET": ["products.view_product"]
}
filter_class = ProductFilter
filter_fields = ("pid",) #销魂/删除
def destroy(self, request, *args, **kwargs):
ret = {"status": 0}
instance = self.get_object()
if instance.pid == 0:
# 顶级业务线
# 查找二级级业务线
if Product.objects.filter(pid__exact=instance.id).count() != 0:
ret["status"] = 1
ret["errmsg"] = "该业务下还有二级业务线"
return response.Response(ret, status=status.HTTP_200_OK)
else:
# 二级业务线
if Server.objects.filter(server_purpose__id__exact=instance.id).count() != 0:
ret["status"] = 1
ret["errmsg"] = "该分组下还有产品线,不能删除"
return response.Response(ret, status=status.HTTP_200_OK) self.perform_destroy(instance)
return response.Response(ret, status=status.HTTP_200_OK) class ProductManageViewSet(mixins.ListModelMixin,
viewsets.GenericViewSet):
"""
list:
业务线管理
"""
queryset = Product.objects.all() def list(self, request, *args, **kwargs):
data = self.get_products()
return response.Response(data) def get_products(self):
ret = []
for obj in self.queryset.filter(pid=0):
node = self.get_node(obj)
node["children"] = self.get_children(obj.id)
ret.append(node)
return ret def get_children(self, pid):
ret = []
for obj in self.queryset.filter(pid=pid):
ret.append(self.get_node(obj))
return ret def get_node(self, product_obj):
node = {}
node["id"] = product_obj.id
node["label"] = product_obj.service_name
node["pid"] = product_obj.pid
return node

serializers.py:

from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Product User = get_user_model() class ProductSerializer(serializers.ModelSerializer): def validate_pid(self, pid): #验证pid
if pid > 0: #则是二级业务线(一级业务线与二级是一对多关系)
try:
product_obj = Product.objects.get(pk=pid) #把关联关系转化成对象
if product_obj.pid != 0:
return serializers.ValidationError("上级业务线错误")
except Product.DoesNotExist:
return serializers.ValidationError("上级业务线不存在")
return pid
else:
return 0 def get_user_response(self, user_queryset):
ret = []
for dev in user_queryset:
ret.append({
"username": dev.username,
"name": dev.name,
"email": dev.email,
"id": dev.id,
})
return ret def to_representation(self, instance):
dev_interface = self.get_user_response(instance.dev_interface.all())
op_interface = self.get_user_response(instance.op_interface.all())
ret = super(ProductSerializer, self).to_representation(instance)
ret["dev_interface"] = dev_interface
ret["op_interface"] = op_interface
return ret def update(self, instance, validated_data):
instance.service_name = validated_data.get("service_name", instance.service_name)
instance.module_letter = validated_data.get("module_letter", instance.module_letter)
instance.dev_interface = validated_data.get("dev_interface", instance.dev_interface)
instance.op_interface = validated_data.get("op_interface", instance.op_interface)
instance.save()
return instance class Meta:
model = Product
fields = '__all__'

效果如图:

前端实现:

https://element.eleme.io/#/zh-CN/component/tree   --树形控件

https://github.com/rfjer/autoAdminWeb/tree/master/src/views/resource

ProductList.vue:

<template>
<div class="user-list-container">
<el-row :gutter="">
<el-col :span="" >
<el-row :gutter="">
<el-col :span="" >
<el-input
placeholder="输入关键字过滤"
v-model="filterText">
</el-input>
</el-col>
<el-col :span="" >
<el-button @click="addClick">添加</el-button>
</el-col>
</el-row>
<div class="filter-tree">
<el-tree
:data="productTreeList"
:props="defaultProps"
:default-expand-all="expandAll"
:highlight-current="true"
:filter-node-method="filterNode"
ref="tree"
@node-click="treeNodeClick">
</el-tree>
</div>
</el-col>
<el-col :span="">
<el-form ref="productForm" size="mini" :model="productForm" label-width="100px" v-show="showForm" :rules="productRules">
<el-form-item label="业务线名称" prop="service_name">
<el-input v-model="productForm.service_name" :disabled="disabled" placeholder="请输入业务线名称"></el-input>
</el-form-item>
<el-form-item label="字母简称" prop="module_letter">
<el-input v-model="productForm.module_letter" :disabled="disabled" placeholder="请输入字母简称"></el-input>
</el-form-item>
<el-form-item label="上级业务线" prop="pid">
<el-select class="select" v-model="productForm.pid" :disabled="disabled" placeholder="上级业务线">
<el-option
v-for="(item, index) in productLevel"
:key="index"
:label="item.service_name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="运维接口人" prop="op_interface">
<el-select multiple class="select" v-model="productForm.op_interface" :disabled="disabled" filterable placeholder="请选择">
<el-option
v-for="(item, index) in userList"
:key="index"
:label="item.name"
:value="item.id">
<span style="float: left">{{ item.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.email }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="业务接口人" prop="dev_interface">
<el-select multiple class="select" v-model="productForm.dev_interface" size="mini" :disabled="disabled" filterable placeholder="请选择">
<el-option
v-for="(item, index) in userList"
:key="index"
:label="item.name"
:value="item.id"
size="mini">
<span style="float: left">{{ item.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.email }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitClick" :disabled="disabled">提交</el-button>
<el-button type="primary" @click="editClick" :disabled="buttonDisabled">修改</el-button>
<el-button type="primary" @click="deleteClick" :disabled="buttonDisabled">删除</el-button>
</el-form-item>
</el-form>
<el-table
class="table"
v-loading="serverListloading"
element-loading-text="拼命加载中"
:data="serverList"
border
v-show="showServerListTable">
<el-table-column
prop="idc.name"
label="机房"
align="center">
</el-table-column>
<el-table-column
prop="hostname"
label="主机名"
align="center">
</el-table-column>
<el-table-column
prop="manage_ip"
label="管理IP"
align="center">
</el-table-column>
<el-table-column
prop="status"
label="状态"
align="center">
</el-table-column>
<el-table-column
prop="last_check"
label="LAST CHECK"
align="center">
</el-table-column>
</el-table>
<div class="text-center" v-show="serverListTotalNum>=10">
<el-pagination
background
@current-change="paginationChange"
layout="total, prev, pager, next, jumper"
:current-page.sync="serverListPage"
:total="serverListTotalNum">
</el-pagination>
</div>
</el-col>
</el-row>
</div>
</template> <script>
import { getUserList } from '@/api/users'
import { getProductTree, getProductLevel, getProductLevelInfo, addProduct, updateProduct, deleteProductLevelInfo, getServerList } from '@/api/resource'
export default {
data() {
return {
productFlag: '',
showForm: false,
disabled: false,
buttonDisabled: false,
name: '',
showServerListTable: false,
server_purpose: 0,
serverList: [],
serverListTotalNum: 0,
serverListPage: 1,
serverListloading: false,
expandAll: false,
productForm: {
service_name: '',
module_letter: '',
dev_interface: [],
op_interface: [],
pid: ''
},
productRules: {
service_name: [
{ required: true, trigger: 'blur', message: '请输入业务线名称' }
],
pid: [
{ required: true, trigger: 'blur', message: '请选择上级业务线' }
],
module_letter: [
{ required: true, trigger: 'change', message: '请输入字母简称' }
]
},
userList: [],
filterText: '',
productTreeList: [],
productLevel: [],
defaultProps: {
children: 'children',
label: 'label'
},
state: 0
}
},
created() {
this.state = 1
},
watch: {
state() {
getUserList({ page_size: 0 }).then(res => {
this.userList = res
})
getProductTree().then(res => {
this.productTreeList = res
})
getProductLevel({ pid: 0, page_size: 0 }).then(res => {
this.productLevel = [{ id: 0, service_name: '顶级' }].concat(res)
})
},
filterText(val) {
this.$refs.tree.filter(val)
}
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
fetchServerListData() {
this.loading = true
getServerList({ page: this.serverListPage, server_purpose: this.server_purpose }).then(res => {
this.serverList = res.results
this.serverListTotalNum = res.count
this.serverListloading = false
})
},
paginationChange(val) {
this.serverListPage = val
this.fetchServerListData()
},
addClick() {
this.productFlag = 'add'
this.$refs['productForm'].resetFields()
this.showForm = true
this.showServerListTable = false
this.disabled = false
this.buttonDisabled = true
},
editClick() {
this.productFlag = 'edit'
this.disabled = false
this.buttonDisabled = true
},
deleteClick() {
this.$confirm('此操作将删除该业务线, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProductLevelInfo(this.productForm.id).then(() => {
this.$message({
message: '删除业务线成功',
type: 'success'
})
this.showForm = false
this.showServerListTable = false
this.getProductTreeInfo()
})
}).catch(() => { })
},
submitClick() {
this.$refs['productForm'].validate((valid) => {
if (!valid) {
return
}
if (this.productFlag === 'add') {
const params = Object.assign({}, this.productForm)
addProduct(params).then(res => {
this.$refs['productForm'].resetFields()
this.$message.success('添加业务线成功')
this.showForm = false
this.showServerListTable = false
this.$message({
message: '操作成功',
type: 'success'
})
this.getProductTreeInfo()
})
} else {
const id = this.productForm.id
delete this.productForm.id
const params = Object.assign({}, this.productForm)
updateProduct(id, params).then(res => {
this.$message.success('修改业务线成功')
this.showForm = false
this.showServerListTable = false
this.disabled = true
this.$message({
message: '操作成功',
type: 'success'
})
this.getProductTreeInfo()
})
}
})
},
getProductTreeInfo() {
getProductTree().then(res => {
this.productTreeList = res
})
},
treeNodeClick(data) {
this.$refs['productForm'].resetFields()
getProductLevelInfo(data.id).then(res => {
const op_interface = []
const dev_interface = []
res.op_interface.forEach(item => {
op_interface.push(item.id)
})
res.dev_interface.forEach(item => {
dev_interface.push(item.id)
})
const { id, pid, module_letter, service_name } = res
this.productForm = { id, pid, module_letter, service_name, op_interface, dev_interface }
this.disabled = true
this.buttonDisabled = false
this.showForm = true
if (pid === 0) {
this.showServerListTable = false
} else {
this.serverListPage = 1
this.server_purpose = data.id
this.serverList = []
this.fetchServerListData()
this.showServerListTable = true
}
})
}
}
}
</script>
<style lang="scss" scoped>
.filter-tree {
margin-top: 20px;
}
.select {
width: 100%;
}
</style>

三.用户管理

  问题1:默认django提供了一套用户管理的.如下中它提供的字段只有id和usermame,password,email,last_login只此有用,所以一般会给加用户手机号,微信,中方名..,那由于此模型不是我们管理的,所以增加字段就直接加不了.

(python36env) [vagrant@CentOS devops]$ python manage.py dbshell
MariaDB [devops]> desc auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| password | varchar(128) | NO | | NULL | |
| last_login | datetime(6) | YES | | NULL | |
| is_superuser | tinyint(1) | NO | | NULL | |
| username | varchar(150) | NO | UNI | NULL | |
| first_name | varchar(30) | NO | | NULL | |
| last_name | varchar(150) | NO | | NULL | |
| email | varchar(254) | NO | | NULL | |
| is_staff | tinyint(1) | NO | | NULL | |
| is_active | tinyint(1) | NO | | NULL | |
| date_joined | datetime(6) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+

问题2:用户来源,公司成千上万人,我不可能一条条添加数据:

  从公司域库(AD)服务器中把用户信息同步过来.

  或LDAP.

1.对接AD/LDAP:
把数据从AD同步过来--(1)同步到系统,
通过AD/LDAP做用户认证--(2)每次用户登录时做请求,
2.SSO(单点登录)
如公司内网一般有wiki,gitlab,运维平台,等各种子系统,而这些系统都对接了AD/LDAP后,用户名密码都是一套通用。
https://pypi.org/project/django-sso/

如何给django用户模型扩展字段:----这一步建议在刚开始做项目时就做好,不要在后期添加,否则会很麻烦

参考https://github.com/rfjer/autoAdmin/blob/master/apps/users/models.py

(1)apps/users/models.py:

from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractUser, Groupclass User(AbstractUser):
name = models.CharField("姓名", max_length=32, null=True, help_text="姓名")
phone = models.CharField("电话", max_length=11, null=True, help_text="手机号")
id_rsa_key = models.TextField(null=True)
id_rsa_pub = models.TextField(null=True) class Meta:
verbose_name = "用户"
ordering = ["id"]
db_table = 'auth_user'
#permissions = (
# ("view_user", "cat view user"), 这里我把这注释了,因为同步不了:老报错与django内置权限冲突
#) def __str__(self):
return self.username

(2)告诉系统用我生成的这张用户表不用系统的用户表settigs.py--即告诉 Django,使用 users 应用下的 User 用户模型。

AUTH_USER_MODEL = "users.User"

INSTALLED_APPS = [
....

(3)生效---因为我devop库中没什么数据,所以可直接删库(生产中不建议)

(python36env) [vagrant@CentOS devops]$ python manage.py dbshell
show create database devops;
drop database devops;
CREATE DATABASE `devops` /*!40100 DEFAULT CHARACTER SET utf8 */;

(4)删除apps下所有migrations文件

(python36env) [vagrant@CentOS devops]$ find apps/ -name migrations |xargs rm -rf

这里我不走token所以settings.py中注释掉:

# 'rest_framework.authtoken',

(python36env) [vagrant@CentOS devops]$ python manage.py makemigrations
(python36env) [vagrant@CentOS devops]$ python manage.py migrate
最后效果如下:即有默认user中的字段又多了我添加的字段
MariaDB [devops]> desc auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| password | varchar(128) | NO | | NULL | |
| last_login | datetime(6) | YES | | NULL | |
| is_superuser | tinyint(1) | NO | | NULL | |
| username | varchar(150) | NO | UNI | NULL | |
| first_name | varchar(30) | NO | | NULL | |
| last_name | varchar(150) | NO | | NULL | |
| email | varchar(254) | NO | | NULL | |
| is_staff | tinyint(1) | NO | | NULL | |
| is_active | tinyint(1) | NO | | NULL | |
| date_joined | datetime(6) | NO | | NULL | |
| name | varchar(32) | YES | | NULL | |
| phone | varchar(11) | YES | | NULL | |
| id_rsa_key | longtext | YES | | NULL | |
| id_rsa_pub | longtext | YES |

四.接口权限控制

如下图中数据库权限表,可看到每个模型有三个权限(增删改)---第四个权限得靠我们自己加,

python36env) [vagrant@CentOS devops]$ python manage.py createsuperuser   创建超级用户
Username: admin
Email address: admin@51reboot.com
curl -X POST -d "username=admin&password=123456" http://localhost:8000/api-token-auth/

我后端的drf中权限全局配置是如下:

    'DEFAULT_PERMISSION_CLASSES': [
# 'rest_framework.permissions.AllowAny',
'devops.permissions.Permissions', 也就是所有接口默认走它
],

我的项目权限文件如下定义:

11

22

三.cmdb的更多相关文章

  1. 魅族CMDB运维自动化实践

    一.简介 原创:梁鹏 本文是根据魅族系统架构师梁鹏10月20日在msup携手魅族.Flyme.百度云主办的第十三期魅族技术开放日< 魅族CMDB运维自动化实践>演讲中的分享内容整理而成. ...

  2. cmdb实现三种方式

    为什么要做CMDB? 1.实现运维自动化,CMDB是实现运维自动化的基石 2.之前做资产统计的时候,使用execl来统计,为了年底资产审计方便 3.运维日常工作繁琐, 4.运行环境不统一 Agent方 ...

  3. Python高手之路【三】python基础之函数

    基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...

  4. python走起之第三话

    一. SET集合 set是一个无序且不重复的元素集 class set(object): """ set() -> new empty set object set ...

  5. CMDB反思4

    CMDB模型设计2 http://blog.vsharing.com/xqscool/A1275233.html 估计大家看到破子的这两篇都有点晕哈,我也有点晕. 两篇对比来看.   第1处,属性部分 ...

  6. CMDB反思3

    CMDB模型设计1 http://blog.vsharing.com/xqscool/A1274634.html 分类的问题上比较有感悟.在之前编写新版的CMDB模型的时候,曾将刀片机.x86服务器. ...

  7. Python CMDB开发

    Python CMDB开发   运维自动化路线: cmdb的开发需要包含三部分功能: 采集硬件数据 API 页面管理 执行流程:服务器的客户端采集硬件数据,然后将硬件信息发送到API,API负责将获取 ...

  8. python基础(三)

    set集合 set集合创建 #方式1: se = {'} #与字典类似dict1 = {'k1','v1','k2','v2'} #方式2: se = set() #创建一个空的集合 list1 = ...

  9. Python学习笔记——基础篇1【第三周】——set集合

    set集合 不允许重复的元素出现(相当于特殊的列表) set 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 练习:寻找差异 # 数据库中原有 old_dic ...

随机推荐

  1. Java实现 蓝桥杯 算法训练 前缀表达式

    算法训练 前缀表达式 时间限制:1.0s 内存限制:512.0MB 问题描述 编写一个程序,以字符串方式输入一个前缀表达式,然后计算它的值.输入格式为:"运算符 对象1 对象2", ...

  2. Java实现 蓝桥杯VIP 算法训练 学做菜

    算法训练 学做菜 时间限制:1.0s 内存限制:256.0MB 问题描述 涛涛立志要做新好青年,他最近在学做菜.由于技术还很生疏,他只会用鸡蛋,西红柿,鸡丁,辣酱这四种原料来做菜,我们给这四种原料标上 ...

  3. Java实现 蓝桥杯VIP 算法训练 P1102

    定义一个学生结构体类型student,包括4个字段,姓名.性别.年龄和成绩.然后在主函数中定义一个结构体数组(长度不超过1000), 并输入每个元素的值,程序使用冒泡排序法将学生按照成绩从小到大的顺序 ...

  4. Java实现第九届蓝桥杯书号验证

    书号验证 2004年起,国际ISBN中心出版了<13位国际标准书号指南>. 原有10位书号前加978作为商品分类标识:校验规则也改变. 校验位的加权算法与10位ISBN的算法不同,具体算法 ...

  5. java实现第六届蓝桥杯隔行变色

    隔行变色 隔行变色 Excel表的格子很多,为了避免把某行的数据和相邻行混淆,可以采用隔行变色的样式. 小明设计的样式为:第1行蓝色,第2行白色,第3行蓝色,第4行白色,- 现在小明想知道,从第21行 ...

  6. Java对象实例化的过程

    1.先为对象分配空间,并按属性类型默认初始化 ps:八种基本数据类型,按照默认方式初始化,其他数据类型默认为null 2.父类属性的初始化(包括代码块,和属性按照代码顺序进行初始化) 3.父类构造函数 ...

  7. python3 源码阅读-虚拟机运行原理

    阅读源码版本python 3.8.3 参考书籍<<Python源码剖析>> 参考书籍<<Python学习手册 第4版>> 官网文档目录介绍 Doc目录主 ...

  8. 附022.Kubernetes_v1.18.3高可用部署架构一

    kubeadm介绍 kubeadm概述 参考附003.Kubeadm部署Kubernetes. kubeadm功能 参考附003.Kubeadm部署Kubernetes. 本方案描述 本方案采用kub ...

  9. Windows下C,C++开发环境搭建指南

    Windows下C,C++开发环境搭建指南 前情提要 基于近一段时间很多网友发邮件反馈,说一些项目编译出现问题,诸如此类的情况. 就觉得很有必要写一篇C,C++开发环境的小指南,统一回复. 1.君欲善 ...

  10. 听说你的资源被盗用了,那你知道 Nginx 怎么防盗链吗?

    上一篇文章讲了 Nginx 中的变量和运行原理,下面就来说一个主要提供变量并修改变量的值的模块,也就是我们要讲的防盗链模块:referer 模块. 简单有效的防盗链手段 场景 如果做过个人站点的同学, ...