zoukankan      html  css  js  c++  java
  • 配置管理系统

    一、 前言

    1.1 简介

    CMDB(Configuration Management Database)配置管理数据库,是所有运维工具的数据基础。70%~80%的IT相关问题与环境的变更有着直接的关系。实施变更管理的难点和重点并不是工具,而是流程。即通过一个自动化的、可重复的流程管理变更,使得当变更发生的时候,有一个标准化的流程去执行,能够预测到这个变更对整个系统管理产生的影响,并对这些影响进行评估和控制。而变更管理流程自动化的实现关键就是CMDB

    1.2 功能

    应该知道包含这几种功能:整合、调和、同步、映射和可视化

    • 用户管理,记录测试,开发,运维人员的用户表
    • 业务线管理,需要记录业务的详情
    • 项目管理,指定此项目用属于哪条业务线,以及项目详情
    • 应用管理,指定此应用的开发人员,属于哪个项目,和代码地址,部署目录,部署集群,依赖的应用,软件等信息
    • 主机管理,包括云主机,物理机,主机属于哪个集群,运行着哪些软件,主机管理员,连接哪些网络设备,云主机的资源池,存储等相关信息
    • 主机变更管理,主机的一些信息变更,例如管理员,所属集群等信息更改,连接的网络变更等
    • 网络设备管理,主要记录网络设备的详细信息,及网络设备连接的上级设备
    • IP管理,IP属于哪个主机,哪个网段, 是否被占用等

    二、 四种实现方式

    2.1 Agent方式

    • 流程分析
      • 在每台服务器上部署一个agent脚本(python代码实现的,用的是它的subprocess模块,定时触发执行subprocess.getoutput(cmd)方法) ,将agent执行的结果通过requests模块返回给API程序,处理之后储存到数据库,然后通过前端界面展示出来

    优缺点分析:

      优点: 速度快,使用于服务器多的大型公司

      缺点: 需要为每一台服务器都部署一个Agent程序,机器过多时耗费的人力成本大

    2.2 ssh方式(基于paramiko模块

    • 流程分析
      • agent方式不同的是,不用再每台服务器上部署agent脚本,而是通过ssh服务实现的。方法就是将python代码放置于一台单独的服务器上,即中控机。中控机通过paramiko模块以ssh方式远程链接登录到每台服务器上执行linux命令来获取所需要的信息并将数据返回到中控机并转交给API,然后由API程序将数据处理之后储存到数据库,再通过前端界面展示

     

    优缺点分析:

      优点: 不需要为每一台服务器都部署一个Agent程序,适用于服务器较少的情况

      缺点: 需要登录,执行速度慢,需要部署一台中控机

    import paramiko
    
    #创建ssh对象
    ssh = paramiko.SSHClient()
    
    # 连接服务器
    ssh.connect(hostname='localhost', port=22, username='root', password='123')
    
    # 执行命令
    stdin, stdout, stderr= ssh.exec_command('ifconfig')
    
    # 拿到命令的执行结果
    res = stdout.read()
    
    # 关闭连接
    ssh.close()
    机器较少时可以使用此方法

    2.3 saltstack方式

    • 流程分析
      • 与第二种类似,同样需要一个中控机,同时它还依赖于第三方软件saltstacksaltstack有两个身份,即masterminion,我们可以在中控机上安装salt-master来控制所有的salt-minion服务器,中控机salt-master通过(salt 'minion主机名' cmd.run '命令')向服务器minion发送命令,minion会将执行的结果放入队列中,再由master从队列中取出数据,转交给API处理后储存到数据库中,通过前端界面展示

     

    优缺点分析:

      优点: 速度快,开发成本低

      缺点: 需要依赖于第三方工具,需要部署中控机

    • saltstack安装与配置
    1. 安装
        master端
            # 安装salt-master
                yum install salt-master
            # 修改配置文件:/etc/salt/master
                interface: 0.0.0.0    # 表示Master的IP
            # 启动
                service salt-master start
    
        slave端:
            # 安装salt-minion
                yum install salt-minion
            # 修改配置文件 /etc/salt/minion
                master: 10.211.55.4   # master的地址
                或
                master:
                    - 10.211.55.4
                    - 10.211.55.5
                random_master: True
                id: c2.salt.com     # 客户端在salt-master中显示的唯一ID
            # 启动
                service salt-minion start
    2. 授权
        """
        salt-key -L                    # 查看已授权和未授权的slave
        salt-key -a  salve_id      # 接受指定id的salve
        salt-key -r  salve_id      # 拒绝指定id的salve
        salt-key -d  salve_id      # 删除指定id的salve
        """
    
    3. 执行
        # 在master服务器上对salve进行远程操作
        salt 'c2.salt.com' cmd.run  'ifconfig'
        
        
        # 基于API的方式
        import salt.client
        local = salt.client.LocalClient()
        result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
    

    2.4 Puppet方式(了解)

    • 通过RPC消息队列将执行的结果返回给用户!年代久远,作为了解,不做叙述

    三、 表结构设计

    首先,创建一个Django项目,由于我们的数据表既与后台管理有关又与API有关,所以我们在设计表结构时又新创建了两个APP(backend,warehouse),这样设计的好处就是相互独立又方便三者间的关联。

    然后我们在warehouse的models中创建数据库模型

    from django.db import models
    
    
    # Create your models here.
    class UserInfo(models.Model):
        '''
        用户信息
        '''
        name = models.CharField(verbose_name='姓名', max_length=32)
        age = models.CharField(max_length=11, verbose_name='年龄')
        gender = models.CharField(max_length=11, verbose_name='性别')
        email = models.EmailField(verbose_name='邮箱')
        phone = models.CharField(verbose_name='手机', max_length=32)
    
        class Meta:
            verbose_name_plural = '用户表'
    
        def __str__(self):
            return self.name
    
    
    class UserGroup(models.Model):
        '''
        用户组
        '''
        name = models.CharField(max_length=32, verbose_name='组名')
        users = models.ManyToManyField('UserInfo', verbose_name='组成员')
    
        class Meta:
            verbose_name_plural = '用户组表'
    
        def __str__(self):
            return self.name
    
    
    class BusinessUnit(models.Model):
        '''
        业务线
        '''
        name = models.CharField(max_length=32)
        contact = models.ForeignKey('UserGroup', verbose_name='业务联系人')
        manager = models.ForeignKey('UserGroup', verbose_name='管理人员', related_name='aaa')
    
        class Meta:
            verbose_name_plural = '业务线表'
    
        def __str__(self):
            return self.name
    
    
    class Idc(models.Model):
        '''
        机房信息
        '''
        name = models.CharField(max_length=32, verbose_name='机房名')
        floor = models.IntegerField(default=10, verbose_name='楼层')
    
        class Meta:
            verbose_name_plural = '机房信息表'
    
        def __str__(self):
            return self.name
    
    
    class Tag(models.Model):
        '''
        资产标签
        '''
        name = models.CharField('标签', max_length=32, unique=True)
    
        class Meta:
            verbose_name_plural = "标签表"
    
        def __str__(self):
            return self.name
    
    
    class Asset(models.Model):
        '''
        资产信息表
        '''
        type_choices = (
            (1, '服务器'),
            (2, '交换机'),
            (3, '防火墙')
        )
    
        status_choices = (
            (1, '上架'),
            (2, '在线'),
            (3, '离线'),
            (4, '下架')
        )
    
        device_type_id = models.IntegerField(choices=type_choices, default=1)
        device_status_id = models.IntegerField(choices=status_choices, default=1)
    
        cabinet_num = models.CharField(max_length=32, verbose_name='机柜号', null=True, blank=True)
        cabinet_order = models.CharField(max_length=32, verbose_name='机柜序号', null=True, blank=True)
    
        idc = models.ForeignKey('Idc', verbose_name='IDC机房', null=True, blank=True)
        business_unit = models.ForeignKey('BusinessUnit', verbose_name='属于的业务线', null=True, blank=True)
    
        tag = models.ManyToManyField('Tag')
    
        latest_date = models.DateField(null=True)
        create_at = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = "资产表"
    
        def __str__(self):
            return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order)
    
    
    class NetworkDevice(models.Model):
        '''
        网络设备
        '''
        asset = models.OneToOneField('Asset')
        management_ip = models.CharField(max_length=64, verbose_name='管理ip', null=True, blank=True)
        vlan_ip = models.CharField(max_length=64, verbose_name='VLANIP', null=True, blank=True)
        intranet_ip = models.CharField(max_length=128, verbose_name='内网IP', null=True, blank=True)
        sn = models.CharField(max_length=64, verbose_name='sn号', null=True, blank=True)
        manufacture = models.CharField(max_length=128, verbose_name='制造商', null=True, blank=True)
        model = models.CharField(max_length=128, verbose_name='型号', null=True, blank=True)
        port_num = models.SmallIntegerField(verbose_name='端口数量', null=True, blank=True)
        device_detail = models.CharField(max_length=255, verbose_name='设置详细配置', null=True, blank=True)
    
        class Meta:
            verbose_name_plural = "网络设备表"
    
    
    class Server(models.Model):
        '''
        服务器
        '''
        asset = models.OneToOneField('Asset')
        hostname = models.CharField(max_length=32, unique=True)
        sn = models.CharField(max_length=64, db_index=True)
        manufacturer = models.CharField(max_length=64, verbose_name='制造商', null=True, blank=True)
        model = models.CharField(max_length=64, verbose_name='型号', blank=True, null=True)
        manage_ip = models.GenericIPAddressField(verbose_name='管理IP', null=True, blank=True)
    
        os_platform = models.CharField(max_length=32, verbose_name='系统', null=True, blank=True)
        os_version = models.CharField(max_length=32, verbose_name='系统版本', null=True, blank=True)
    
        cpu_count = models.IntegerField(verbose_name='CPU数量', null=True, blank=True)
        cpu_physical = models.IntegerField(verbose_name='CPU物理数量', null=True, blank=True)
        cpu_model = models.CharField(max_length=128, verbose_name='CPU型号', null=True, blank=True)
    
        create_time = models.DateTimeField(auto_now_add=True, blank=True)
    
        class Meta:
            verbose_name_plural = "服务器表"
    
        def __str__(self):
            return self.hostname
    
    
    class Disk(models.Model):
        '''
        硬盘信息
        '''
        slot = models.CharField(max_length=12, verbose_name='插槽位')
        model = models.CharField(max_length=32, verbose_name='磁盘型号')
        capacity = models.CharField(max_length=32, verbose_name='磁盘容量GB')
        pd_type = models.CharField(max_length=32, verbose_name='磁盘类型')
        server = models.ForeignKey('Server', related_name='disk')
    
        class Meta:
            verbose_name_plural = "硬盘表"
    
        def __str__(self):
            return self.slot
    
    
    class Nic(models.Model):
        '''
        网卡信息
        '''
        name = models.CharField(max_length=32, verbose_name='网卡名称')
        hwaddr = models.CharField(max_length=64, verbose_name='网卡MAC地址')
        netmask = models.CharField(max_length=64)
        ipaddrs = models.CharField(max_length=256, verbose_name='IP地址')
        up = models.BooleanField(default=False)
    
        server = models.ForeignKey('Server', related_name='nic')
    
        class Meta:
            verbose_name_plural = "网卡表"
    
        def __str__(self):
            return self.name
    
    
    class Memory(models.Model):
        '''
        内存信息
        '''
        slot = models.CharField(max_length=12, verbose_name='插槽位')
        model = models.CharField(max_length=64, verbose_name='内存型号')
        manufacturer = models.CharField(max_length=32, verbose_name='制造商', null=True, blank=True)
        capacity = models.FloatField(verbose_name='容量', null=True, blank=True)
        sn = models.CharField(max_length=64, verbose_name='sn号', null=True, blank=True)
        speed = models.CharField(max_length=16, verbose_name='速度', null=True, blank=True)
    
        class Meta:
            verbose_name_plural = "内存表"
    
        def __str__(self):
            return self.slot
    
    
    class AssetRecord(models.Model):
        '''
        资产变更记录表
        '''
        asset = models.ForeignKey('Asset')
        content = models.TextField(null=True)
        creator = models.ForeignKey('UserInfo', null=True, blank=True)
        create_time = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = "资产记录表"
    
        def __str__(self):
            return '<{}> <{}> <{}>'.format(self.asset.idc.name, self.asset.cabinet_num, self.asset.cabinet_order)
    
    
    class ErrorLog(models.Model):
        '''
        错误日志记录
        '''
        asset = models.ForeignKey('Asset', null=True, blank=True)
        title = models.CharField(max_length=64)
        content = models.TextField()
        create_time = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = "错误日志表"
    
        def __str__(self):
            return self.title
    models.py
  • 相关阅读:
    loj#2540. 「PKUWC2018」随机算法
    loj#2538. 「PKUWC2018」Slay the Spire
    loj#2537. 「PKUWC2018」Minimax
    CF662C Binary Table
    bzoj4589: Hard Nim
    【HDU5909】Tree Cutting(FWT)
    P3175 [HAOI2015]按位或
    P4389 付公主的背包
    P4233 射命丸文的笔记
    GFS分布式文件系统环境部署与管理
  • 原文地址:https://www.cnblogs.com/rongge95500/p/10241117.html
Copyright © 2011-2022 走看看