三.cmdb
一.服务器管理:
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的更多相关文章
- 魅族CMDB运维自动化实践
一.简介 原创:梁鹏 本文是根据魅族系统架构师梁鹏10月20日在msup携手魅族.Flyme.百度云主办的第十三期魅族技术开放日< 魅族CMDB运维自动化实践>演讲中的分享内容整理而成. ...
- cmdb实现三种方式
为什么要做CMDB? 1.实现运维自动化,CMDB是实现运维自动化的基石 2.之前做资产统计的时候,使用execl来统计,为了年底资产审计方便 3.运维日常工作繁琐, 4.运行环境不统一 Agent方 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
- python走起之第三话
一. SET集合 set是一个无序且不重复的元素集 class set(object): """ set() -> new empty set object set ...
- CMDB反思4
CMDB模型设计2 http://blog.vsharing.com/xqscool/A1275233.html 估计大家看到破子的这两篇都有点晕哈,我也有点晕. 两篇对比来看. 第1处,属性部分 ...
- CMDB反思3
CMDB模型设计1 http://blog.vsharing.com/xqscool/A1274634.html 分类的问题上比较有感悟.在之前编写新版的CMDB模型的时候,曾将刀片机.x86服务器. ...
- Python CMDB开发
Python CMDB开发 运维自动化路线: cmdb的开发需要包含三部分功能: 采集硬件数据 API 页面管理 执行流程:服务器的客户端采集硬件数据,然后将硬件信息发送到API,API负责将获取 ...
- python基础(三)
set集合 set集合创建 #方式1: se = {'} #与字典类似dict1 = {'k1','v1','k2','v2'} #方式2: se = set() #创建一个空的集合 list1 = ...
- 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 ...
随机推荐
- Java实现 LeetCode 767 重构字符串(ASCII的转换)
767. 重构字符串 给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同. 若可行,输出任意可行的结果.若不可行,返回空字符串. 示例 1: 输入: S = "aab&qu ...
- Java实现 LeetCode 525 连续数组
525. 连续数组 给定一个二进制数组, 找到含有相同数量的 0 和 1 的最长连续子数组(的长度). 示例 1: 输入: [0,1] 输出: 2 说明: [0, 1] 是具有相同数量0和1的最长连续 ...
- Java实现 蓝桥杯VIP 算法训练 数列
问题描述 给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,- (该序列实际上就是 ...
- 获取ip地址,并根据ip获取当前省份
<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> //methods里面 // 获取 ...
- 连接mongoodb并且向数据库添加信息
连接mongoodb 首先安装mongoose 配置URL 连接Mongoodb数据库 控制台输入指令运行该js文件 像这样就连接成功了 向Mongodb数据库增加信息,首先需要写入表格信息 接着解构 ...
- zabbix 大流量断图
一. 环境介绍 系统版本:Centos7.4 zabbix-agent 版本:zabbix-agent 3.4.7 二. 问题现象 在使用zabbix的snmp方式的监控端口流量时,某一个图总是断 ...
- KVM虚拟机使用NAT+iptables做端口映射
环境介绍 有一个KVM宿主机,一个外网IP绑定在了宿主服务器上,但是希望直接用ssh访问上面的所有虚拟机,还想虚拟机提供外网服务, 解决方法如下: 环境为RHEL6.3,外网IP为 61.155.xx ...
- 实验四 Linux系统搭建C语言编程环境
项目 内容 这个作业属于那个课程 <班级课程的主页链接> 这个作业的要求在哪里 <作业要求链接地址> 学号-姓名 17043220-万文文 作业学习目标 1).Linux系统下 ...
- Centos 7 k8s Deployment新副本控制器
一.概念 Kubernetes提供了一种更加简单的更新RC和Pod的机制,叫做Deployment.通过在Deployment中描述你所期望的集群状态,Deployment Controller会将在 ...
- 1.4 Spring 依赖注入(DI)和控制反转(IOC)详解
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1 Spring 依赖注 ...