saltstack的api安装以及使用解释

首先,贴上官方地址:https://docs.saltstack.cn/

salt,一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯。
salt底层采用动态的连接总线, 使其可以用于编配, 远程执行, 配置管理等等.

一、什么是saltstack
什么是saltstack

• Saltstack是基于python开发的一套C/S架构配置管理工具

• 使用SSL证书签方的方式进行认证管理

• 底层使用ZeroMQ消息队列pub/sub方式通信

    – 号称世界上最快的消息队列ZeroMQ能快速在成千上万台主机上进行各种操作

    – 采用RSA Key方式确认身

Salt 是:

一个配置管理系统,能够维护预定义状态的远程节点(比如,确保指定的报被安装,指定的服务在运行)

一个分布式远程执行系统,用来在远程节点(可以是单个节点,也可以是任意规则挑选出来的节点)

上执行命令和查询数据

开发其的目的是为远程执行提供最好的解决方案,并使远程执行变得更好,更快,更简单

既要考虑大规模部署,又要考虑小规模系统,提供适应多种场合的应用让人沮丧,但Salt非常容易设置和维护,

而不用考虑项目的大小。从数量可观的本地网络系统,到跨数据中心的互联网部署,

Salt设计为在任意数量的server下都可工作。

salt的拓扑使用简单的server/client模式,需求的功能内建在一组daemon中。

salt在几乎不改动配置的情况下就可以工作,也可以调整从而满足特定的需求。
二、官网的介绍:

Salt的核心功能:

  • 使命令发送到远程系统是并行的而不是串行的

  • 使用安全加密的协议

  • 使用最小最快的网络载荷

  • 提供简单的编程接口

  • Salt同样引入了更加细致化的领域控制系统来远程执行,使得系统成为目标不止可以通过主机名,还可以通过系统属性。

saltstack的api安装以及使用解释_第1张图片

三、主要功能
主要功能

• Saltstack最主要的两个功能是:配置管理与远程执行

• Saltstack不只是一个配置管理工具,还是一个云计算与数据中心架构编排的利器

• Saltstack已经支持Docker相关模块

• 在友好地支持各大云平台之后,配合Saltstack的Mine实时发现功能可以实现各种云平台业务的自动扩展
四、Saltstack架构
• Saltstack基于C/S架构

    – 服务器端称作Master

    – 客户端称作Minion

• 可以实现传统处理方式,即:客户端发送请求给服务器,服务器收到请求后处理请求,再将结果返回

• 也可以使用消息队列中的发布与订阅(pub/sub)服务模式

saltstack的api安装以及使用解释_第2张图片

五、Saltstack工作机制
  • Master和Minion都以守护进程的方式运行

  • Master监听配置文件里定义的ret_port(接收minion请求),和publish_port(发布消息)的端口

  • 当Minion运行时,它会自动连接到配置文件里定义的Master地址ret_port端口进行连接认证

  • 当Master和Minion可以正常通信后,就可以进行各种各样的配置管理工作了

六、安装salt api

saltstack的api安装以及使用解释_第3张图片

[root@master ~]#  yum -y install salt-api pyOpenSSL  
[root@master ~]#  systemctl restart salt-api

1) 创建用户,saltapi认证使用
[root@master ~]#  useradd -M -s /sbin/nologin wmm  
[root@master ~]#  echo 'wmm' | passwd wmm --stdin  

2) 添加salt api配置
Last login: Sat Sep  7 19:08:35 2019 from 192.168.10.1
[root@master ~]# cat /etc/salt/master.d/api.conf 
rest_cherrypy:
  port: 8888
  #ssl_crt: /etc/pki/tls/certs/localhost.crt
  #ssl_key: /etc/pki/tls/certs/localhost.key
  disable_ssl: True
external_auth:
  pam:
    wmm:
      - .*
      - '@wheel'
      - '@runner'
[root@master ~]# 

3) 不使用ssl
rest_cherrypy:
  port: 8000
  #ssl_crt: /etc/pki/tls/certs/localhost.crt
  #ssl_key: /etc/pki/tls/private/localhost.key
  disable_ssl: True
external_auth:
  pam:
    wmm:
      - .*
      - '@wheel'
      - '@runner'

4) 生成自签名证书
[root@master ~]# salt-call tls.create_self_signed_cert
local:
    Certificate "localhost" already exists

提示已经存在时,可以删除/etc/pki/tls/certs/localhost.crt /etc/pki/tls/certs/localhost.key重新生成

如果这里报异常,请先确认下有没有未认证的主机:

[root@master ~]# salt-key -L
Accepted Keys:
minion-01
minion-02
Denied Keys:
Unaccepted Keys:
Rejected Keys:
[root@master ~]# 
5)获取token
[oot@master ~]# curl -k https://192.168.10.12:8000/login  -H "Accept: application/x-yaml" -d username='wmm' -d password='wmm' -d eauth='pam'
return:
- eauth: pam
  expire: 1480714218.787106
  perms:
  - .*
  - '@wheel'
  - '@runner'
  start: 1480671018.787106
  token: ab3749a9a0fe83386b8a5d558d10e346c252e336
  user: wmm

重启salt-api后token会改变

6)执行models,test.ping测试minion连通性
[root@master ~]# curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: ab3749a9a0fe83386b8a5d558d10e346c252e336" -d client='local' -d tgt='*' -d fun='test.ping'  
return:
- minion-02: true

7)远程执行命令
[root@master ~]# curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: ab3749a9a0fe83386b8a5d558d10e346c252e336" -d client='local' -d tgt='*' -d fun='cmd.run'   -d arg='free -m'
return:
- minion-02: '             total       used       free     shared    buffers     cached
    Mem:           988        932         56          1         19        107
    -/+ buffers/cache:        805        182
    Swap:         1983        382       1601'

8)远程执行多个minion命令
[root@master ~]# curl -k https://192.168.62.200:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: ab3749a9a0fe83386b8a5d558d10e346c252e336"  -d client='local' -d tgt='operation,slave01'  -d expr_form='list'  -d fun='cmd.run' -d arg='free -m'
return:
- minion-02: '             total       used       free     shared    buffers     cached
    Mem:           988        925         63          1         21         81
    -/+ buffers/cache:        821        166
    Swap:         1983        393       1590'
  minion-01: '             total       used       free     shared    buffers     cached
    Mem:          1870        622       1248          6         79        300
    -/+ buffers/cache:        242       1628
    Swap:         2047          0       2047'
[root@master ~]#

9)执行wheel

查看minion key状态

[root@master ~]#curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: ab3749a9a0fe83386b8a5d558d10e346c252e336" -d client='wheel'  -d fun='key.list_all'
return:
- data:
    _stamp: '2019-09-14S09:30:35.235660'
    fun: wheel.key.list_all
    jid: '20190914173034905379'
    return:
      local:
      - master.pem
      - master.pub
      minions:
      - minion-01
      - minion-02
      minions_denied: []
      minions_pre: []
      minions_rejected: []
    success: true
    tag: salt/wheel/20161202173034905379
    user: wmm
  tag: salt/wheel/20161202173034905379

10)查看sls模块信息 wheel.file_roots.list_roots
[root@master ~]# curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: 2ea1a20373900c311cf4ab1a707da5de4c9c44fc" -d client='wheel'  -d fun='file_roots.list_roots'
return:
- data:
    _stamp: '2019-09-14S09:30:35.235951'
    fun: wheel.file_roots.list_roots
    jid: '20190914173034906684'
    return:
      app:
      - /data/salt/app:
          memcached:
            file:
              install_memcached-1.4.15.tar.gz: f
            init.sls: f
            install.sls: f
          nginx:
            conf.sls: f
            file:
              nginx: f
              nginx-1.2.5.tar.gz: f
              nginx.conf: f
              nginx_log_cut.sh: f
              vhost.conf: f
            init.sls: f
            install.sls: f
            vhost.sls: f

11)执行runner

查看saltenv环境配置

[root@master ~] # curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: 2ea1a20373900c311cf4ab1a707da5de4c9c44fc" -d client='runner'  -d fun='fileserver.envs'
return:
- - app
  - base
  - online

查看minion运行状态

[root@master ~]# curl -k https://192.168.62.200:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: ab3749a9a0fe83386b8a5d558d10e346c252e336" -d client='runner'  -d fun='manage.status'
return:
- down:
  - minion-01
  up:
  - minion-02

异步执行命令job:

# curl -k https://192.168.10.12:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: 14e719b94839b680e7860bfa34db7a385070dd53" -d client="local_async" -d expr_form="glob" -d tgt="minion-01"   -d fun="cmd.run" -d  arg="free -m"
return:
- jid: '20190914111629216443'
  minions:
  - operation
 
 
# curl -k https://192.168.10.12:8000/jobs/20161205111629216443 -H "Accept: application/x-yaml" -H "X-Auth-Token: 14e719b94839b680e7860bfa34db7a385070dd53"
info:
- Arguments:
  - free -m
  Function: cmd.run
  Minions:
  - minion-01
  Result:
    minion-01:
      return: '             total       used       free     shared    buffers     cached
 
        Mem:           988        928         59          1         17         75
 
        -/+ buffers/cache:        836        152
 
        Swap:         1983        330       1653'
  StartTime: 2019, Dec 14 11:16:29.216443
  Target: minion-01
  Target-type: glob
  User: wmm
  jid: '20190914111629216443'
return:
- minion-01: '             total       used       free     shared    buffers     cached
 
    Mem:           988        928         59          1         17         75
 
    -/+ buffers/cache:        836        152
 
    Swap:         1983        330       1653'

这里之前查阅资料过前辈们概括的整个大致过程:

 首先是服务端认证,通过每个请求传递会话令牌来执行身份验证,token通过Login URL生成。

token认证采用两种方法发送:一种是hearder头添加认证token,另一种作为会话cookie。

用法:

  请求主体必须是一组命令。使用此工作流程来构建命令:

    1. 选择一个客户端界面。

    2. 选择一个功能。

    3.填写所选客户端所需的其余参数。

client字段是对Salt的python api中使用的主要python类的引用。

  local:向本地发送命令的“本地”使用。等同于salt 命令。

  runner:调用master的runner 模块。等同于salt-run命令。

  wheel:调用master的wheel模块。wheel没有知己额的CLI命令,它通常广利Master-side资源,例如状态文件,支柱文件,salt配置文件,以及salt-key类似的功能。

 

在执行LocalClient,它需要将命令转发给Minions,所以需要tgt参数来指定minionid.

           也需要arg(数组)和kwarg(之前)参数,这些值被发送到minions并用作请求函数的参数。

RunnerClient和WheelClient直接在Master上执行,因此不需要接受这些参数。

header头设置:

  REST接口在接受什么样的数据格式以及它将返回什么格式(例如,JSON,YAML,urlencoded)方面是灵活的

    通过包含Content-type头来指定请求正文中的数据格式。

    使用Accept头指定相应主体所需的数据格式。

关于CherryPy的并发:

  CherryPy服务器是一个生成就绪的线程HTTP服务器,用Python编写。它使用线程池来处理HTTP请求,所以不适合维护大量的并发同步连接,在配置默认设置的中等硬件上,他最高大约3050个并发连接。

  注意:每个salt的命令运行都会启动一个实例化的进程(LocalClient),它将自己的监听器实例化为salt事件总线,并发出自己的周期性salturil.find_job查询来确定Minion是否仍在运行该命令,不完全是一个轻量级操作。

超时:

  CherryPy还可以设置HTTP超时时间。LocalClient和RunnerClient都可以在顶级关键字(timeout)中设置自己的超时参数。

异步操作:

  由于性能开销和HTTP超时,长时间运行上述操作,可以使用local_asyn,runner_asyn,wheel_asyn进行异步方式运行更能节省开销。执行结果可以通过 /jobs/<jid> URL 从缓存中获取,也可以使用salt的Rerutner 系统收集到数据存储中。

  /events URL专门用户处理长时间运行的HTTP请求,并包含了作业返回的salt事件总线,但该操作具有不同步性。

性能调整:

  设置thread_pool和socket_queue_size 可以用来增加处理传入请求的rest_cherrypy的能力。设置这些配置时需要留意RAM的使用情况以及可用文件句柄。由于salt-api是基于salt使用,同时还需要考虑salt的性能。

下面是一些运维平台中,有关资产管理的一些常用API:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = '40kuai'
__version__ = 'v0.0.1'
"""
1. 整合 salt-api 功能
2. 获取token多次使用,发现token过期后重新获取token从当前失败任务重新继续执行
3. 可选:出现接口或服务异常(501),本次操作尝试几次重新执行
arg 为模块需要传入的参数,kwargs为pillar或grains参数。

分为以下几个类:
    1. salt-api 方法类
    2. 发送请求的类
"""

from urlparse import urljoin
import requests


class Salt_Api():
    def __init__(self, url, username, password):
        self.url = url
        self._username = username
        self._password = password
        self.get_token()

    def get_token(self, eauth='pam', ):
        """获取salt-api使用的token"""
        get_token_url = urljoin(self.url, 'login')
        json_data = {'username': self._username, 'password': self._password, 'eauth': eauth}
        token_obj = requests.post(get_token_url, json=json_data, verify=False)
        if token_obj.status_code != 200:
            raise Exception(token_obj.status_code)
        self.token = token_obj.json()['return'][0]['token']

    def post(self, prefix='/', json_data=None, headers=None):
        post_url = urljoin(self.url, prefix)
        if headers is None:
            headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'}
        else:
            headers = {'X-Auth-Token': self.token, }.update(headers)
        post_requests = requests.post(post_url, json=json_data, headers=headers, verify=False)
        return post_requests.json()

    def get(self, prefix='/', json_data=None, headers=None):
        post_url = urljoin(self.url, prefix)
        if headers is None:
            headers = {'X-Auth-Token': self.token, 'Accept': 'application/json'}
        else:
            headers = {'X-Auth-Token': self.token, }.update(headers)
        get_requests = requests.get(post_url, json=json_data, headers=headers, verify=False)
        return get_requests.json()

    def get_all_key(self):
        """获取所有minion的key"""
        json_data = {'client': 'wheel', 'fun': 'key.list_all'}
        content = self.post(json_data=json_data)
        minions = content['return'][0]['data']['return']['minions']
        minions_pre = content['return'][0]['data']['return']['minions_pre']
        return minions, minions_pre

    def accept_key(self, minion_id):
        """认证minion_id,返回Ture or False"""
        json_data = {'client': 'wheel', 'fun': 'key.accept', 'match': minion_id}
        content = self.post(json_data=json_data)
        return content['return'][0]['data']['success']

    def delete_key(self, node_name):
        """删除minion_id,返回Ture or False"""
        json_data = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
        content = self.post(json_data=json_data)
        return content['return'][0]['data']['success']

    def host_remote_module(self, tgt, fun, arg=None):
        """根据主机执行函数或模块,模块的参数为arg"""
        json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, }
        if arg:
            json_data.update({'arg': arg})
        content = self.post(json_data=json_data)
        return content['return']

    def group_remote_module(self, tgt, fun, arg=None):
        """根据分组执行函数或模块,模块的参数为arg"""
        json_data = {'client': 'local', 'tgt': tgt, 'fun': fun, 'expr_form': 'nodegroup'}
        if arg:
            json_data.update({'arg': arg})
        content = self.post(json_data=json_data)
        return content['return']

    def host_sls_async(self, tgt, arg):
        '''主机异步sls '''
        json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
        content = self.post(json_data=json_data)
        return content['return']

    def group_sls_async(self, tgt, arg):
        '''分组异步sls '''
        json_data = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup'}
        content = self.post(json_data=json_data)
        return content['return']

    def server_hosts_pillar(self, tgt, arg, **kwargs):
        '''针对主机执行sls and pillar '''
        print kwargs
        kwargs = {'pillar': kwargs['kwargs']}
        json_data = {"client": "local", "tgt": tgt, "fun": "state.sls", "arg": arg, "kwarg": kwargs}
        content = self.post(json_data=json_data)
        return content['return']

    def server_group_pillar(self, tgt, arg, **kwargs):
        '''分组进行sls and pillar'''
        kwargs = {'pillar': kwargs['kwargs']}
        json_data = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup',
                     'kwarg': kwargs}
        content = self.post(json_data=json_data)
        return content['return']

    def jobs_all_list(self):
        '''打印所有jid缓存'''
        json_data = {"client": "runner", "fun": "jobs.list_jobs"}
        content = self.post(json_data=json_data)
        return content['return']

    def jobs_jid_status(self, jid):
        '''查看jid运行状态'''
        json_data = {"client": "runner", "fun": "jobs.lookup_jid", "jid": jid}
        content = self.post(json_data=json_data)
        return content['return']

    def keys_minion(self, hostname):
        """Show the list of minion keys or detail on a specific key"""
        content = self.get('keys/%s' % hostname)
        return content


if __name__ == '__main__':
    url = 'https://local:8000/'
    obj = Salt_Api(url, 'username', 'password')
    print obj.keys_minion('minionid')

salt-api

我在运维平台中针对于IP地址的获取,使用的是这样的思路,因为大家可以看到:

[root@master ~]# ip a
1: lo: ,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp0s3: ,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:10:97:0f brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.12/24 brd 192.168.10.255 scope global dynamic enp0s3
       valid_lft 1097sec preferred_lft 1097sec
[root@master ~]# 

这里会出现两个IP 地址,而且运维平台中的资产管理,是根据IP和主机名进行区分的,所以要首先过滤掉127.0.0.1,这个IP地址:
项目中的核心代码如下


def getHostInfo():
    ### salt调用 ###
    local = salt.client.LocalClient() # api
    ### 目标主机指定 ###
    tgt = "*"
    ### 获取grains,disk信息 ###
    grains = local.cmd(tgt,"grains.items") # api
    (status, grains_return) = subprocess.getstatusoutput(" ssh 127.0.0.1 'salt \"*\" --out raw grains.items' ")
    grains = eval(grains_return.replace('}}\n{', '},'))
    diskusage = local.cmd(tgt,"disk.usage") # api
    (status, diskusage) = subprocess.getstatusoutput(" ssh 127.0.0.1 'salt \"*\" --out raw disk.usage' ")
    diskusage = eval(diskusage.replace('}}\n{', '},'))
    for i in grains.keys():
        try:
            ###去掉127.0.0.1这个地址
            hostname = grains[i]["nodename"]
            ip = str(grains[i]["ipv4"]).strip('[]')
            ip = ip.replace("\'", "")
            ip = ip.replace("127.0.0.1,", "")
            ip = ip.replace(", 127.0.0.1", "")
            ip = ''.join(ip.split())
            ip = ip.replace(",", " | ")
            mem = grains[i]["mem_total"] / 1024 + 1
            num_cpu = grains[i]["num_cpus"]
            OS = grains[i]["os"] + ' ' + grains[i]["osrelease"]
            cpu = grains[i]["cpu_model"]
            virtual1 = grains[i]["virtual"]
            status = '连接'
            # 磁盘容量
            if "/" not in diskusage[i]:
                disk_used = " "
                disk_capacity = " "
            else:
                disk_used = float(diskusage[i]["/"]["1K-blocks"]) / 1048576
                disk_capacity = diskusage[i]["/"]["capacity"]
            if "/data" not in diskusage[i]:
                disk_data_used = " "
                disk_data_capacity = " "
            else:
                disk_data_used = float(diskusage[i]["/data"]["1K-blocks"]) / 1048576
                disk_data_capacity = diskusage[i]["/data"]["capacity"]

            if "/data1" not in diskusage[i]:
                disk_data1_used = " "
                disk_data1_capacity = " "
            else:
                disk_data1_used = float(diskusage[i]["/data"]["1K-blocks"]) / 1048576
                disk_data1_capacity = diskusage[i]["/data"]["capacity"]

                ####获取网卡mac信息####
            # if "eth0" not in grains[i]["hwaddr_interfaces"]:
            #     eth0=" "
            # else:
            #     eth0=grains[i]["hwaddr_interfaces"]["eth0"]
            #
            # if "eth1" not in grains[i]["hwaddr_interfaces"]:
            #     eth1=" "
            # else:
            #     eth1=grains[i]["hwaddr_interfaces"]["eth1"]

            grains[i]["hwaddr_interfaces"].pop("lo")
            hostnames = hostinfo.objects.values_list('hostname', flat=True)  # 获取资产列表中的主机名
            if hostnames:
                if hostname in hostnames:  ##判断主机是否已经入库,如果存在输出提示,不存在则入库
                    hostinfoupdate = hostinfo.objects.get(hostname=hostname)
                    hostinfoupdate.hostname = hostname
                    hostinfoupdate.IP = ip
                    hostinfoupdate.Mem = mem
                    hostinfoupdate.CPU = cpu
                    hostinfoupdate.CPUS = num_cpu
                    hostinfoupdate.OS = OS
                    hostinfoupdate.virtual1 = virtual1
                    hostinfoupdate.status = status
                    hostinfoupdate.save()
                else:
                    hostinfoadd = hostinfo()
                    hostinfoadd.hostname = hostname
                    hostinfoadd.IP = ip
                    hostinfoadd.Mem = mem
                    hostinfoadd.CPU = cpu
                    hostinfoadd.CPUS = num_cpu
                    hostinfoadd.OS = OS
                    hostinfoadd.virtual1 = virtual1
                    hostinfoadd.status = status
                    hostinfoadd.save()
            else:
                hostinfoadd = hostinfo()
                hostinfoadd.hostname = hostname
                hostinfoadd.IP = ip
                hostinfoadd.Mem = mem
                hostinfoadd.CPU = cpu
                hostinfoadd.CPUS = num_cpu
                hostinfoadd.OS = OS
                hostinfoadd.virtual1 = virtual1
                hostinfoadd.status = status
                hostinfoadd.save()
        except:
            hostnames = hostinfo.objects.values_list('hostname', flat=True)  # 获取资产列表中的主机名
            if i in hostnames:
                hostinfoupstatus = hostinfo.objects.get(hostname=i)
                hostinfoupstatus.status = '未连接'
                hostinfoupstatus.save()
            continue


后面也使用了salt api进行自动部署minion,并且添加主机:
项目中涉及代码如下:


@login_required
def serverAdd(request):
    result = ''
    check_ip_inro = 0  # 检查主机是否存在,0不存在,1存在
    if request.method == "POST":
        form = autoArrMinionForm(request.POST)
        if form.is_valid():
            ip = request.POST.get('add_ip')  # 需要安装minion端的ip
            username = request.POST.get('add_username')  # 需要安装minion端的用户名
            password = request.POST.get('add_password')  # 需要安装minion端的密码
            check_ip_list = hostinfo.objects.values_list('IP', flat=True)  # 获取已经安装minion的ip列表
            for i in check_ip_list:  # 将有多个ip的主机ip分开,自成一个列表供匹配检查主机是否已经存在
                if " | " in i:
                    check_ip_list_two = i.split(" | ")
                    if ip in check_ip_list_two:  # 判断输入的ip是否在主机列表中
                        check_ip_inro = 1
                        break
            if ip not in check_ip_list and check_ip_inro == 0:
                try:
                    os.system("echo '" + ip + ":'>> /etc/salt/roster && \
                                echo '  host: " + ip + "'>> /etc/salt/roster && \
                                echo '  user: " + username + "'>> /etc/salt/roster && \
                                echo '  passwd: " + password + "'>> /etc/salt/roster && \
                                echo '  sudo: True'>> /etc/salt/roster && \
                                echo '  tty: True'>> /etc/salt/roster && \
                                echo '  timeout: 10'>> /etc/salt/roster")
                    os.system("salt-ssh '" + ip + "' -ir 'easy_install certifi'")  # 安装cretifi模块
                    (status_gethostname, resultgethostname) = subprocess.getstatusoutput(
                        "salt-ssh -ir '" + ip + "' 'hostname'")  # 获取hostname
                    os.system(
                        "salt-ssh '" + ip + "' -ir 'echo ''" + ip + "' '" + resultgethostname + "''>> /etc/hosts'")  # 添加hosts
                    (status, result) = subprocess.getstatusoutput(
                        "salt-ssh -i '" + ip + "' state.sls minions.install")  # 执行安装命令,并返回结果
                except:
                    result = "注意:无法连接该主机,请检查ip和用户密码是否正确!"
            else:
                result = "提示:这台主机已加入主机列表!"
        else:
            result = "注意:请填写正确的ip、用户名或密码!"
    else:
        form = autoArrMinionForm()
    re = {
        "form": form,
        "result": result
    }
    return render(request, "serveradd.html", re)

将获取到的信息内容,进行操作,整个资产管理的列表如下:
saltstack的api安装以及使用解释_第4张图片


@login_required
def serverList(request, id=0):
    '''
    服务器列表
    '''
    if id != 0:
        hostinfo.objects.filter(id=id).delete()
    if request.method == "POST":
        getHostInfo()
        print(request.POST)
        pageSize = request.POST.get('pageSize')  # how manufactoryy items per page
        pageNumber = request.POST.get('pageNumber')
        offset = request.POST.get('offset')  # how many items in total in the DB
        search = request.POST.get('search')
        sort_column = request.POST.get('sort')  # which column need to sort
        order = request.POST.get('order')  # ascending or descending
        if search:  # 判断是否有搜索字
            all_records = hostinfo.objects.filter(id=search, asset_type=search, business_unit=search, idc=search)
        else:
            all_records = hostinfo.objects.all()  # must be wirte the line code here

        if sort_column:  # 判断是否有排序需求
            sort_column = sort_column.replace('asset_', '')
            if sort_column in ['id', 'asset_type', 'sn', 'name', 'management_ip', 'manufactory',
                               'type']:  # 如果排序的列表在这些内容里面
                if order == 'desc':  # 如果排序是反向
                    sort_column = '-%s' % (sort_column)
                all_records = hostinfo.objects.all().order_by(sort_column)
            elif sort_column in ['salt_minion_id', 'os_release', ]:
                # server__ 表示asset下的外键关联的表server下面的os_release或者其他的字段进行排序
                sort_column = "server__%s" % (sort_column)
                if order == 'desc':
                    sort_column = '-%s' % (sort_column)
                all_records = hostinfo.objects.all().order_by(sort_column)
            elif sort_column in ['cpu_model', 'cpu_count', 'cpu_core_count']:
                sort_column = "cpu__%s" % (sort_column)
                if order == 'desc':
                    sort_column = '-%s' % (sort_column)
                all_records = hostinfo.objects.all().order_by(sort_column)
            elif sort_column in ['rams_size', ]:
                if order == 'desc':
                    sort_column = '-rams_size'
                else:
                    sort_column = 'rams_size'
                all_records = hostinfo.objects.all().annotate(rams_size=Sum('ram__capacity')).order_by(sort_column)
            elif sort_column in [
                'localdisks_size', ]:  # using variable of localdisks_size because there have a annotation below of this line
                if order == "desc":
                    sort_column = '-localdisks_size'
                else:
                    sort_column = 'localdisks_size'
                #     annotate 是注释的功能,localdisks_size前端传过来的是这个值,后端也必须这样写,Sum方法是django里面的,不是小写的sum方法,
                # 两者的区别需要注意,Sum('disk__capacity‘)表示对disk表下面的capacity进行加法计算,返回一个总值.
                all_records = hostinfo.objects.all().annotate(localdisks_size=Sum('disk__capacity')).order_by(
                    sort_column)

            elif sort_column in ['idc', ]:
                sort_column = "idc__%s" % (sort_column)
                if order == 'desc':
                    sort_column = '-%s' % (sort_column)
                all_records = hostinfo.objects.all().order_by(sort_column)

            elif sort_column in ['trade_date', 'create_date']:
                if order == 'desc':
                    sort_column = '-%s' % sort_column
                all_records = User.objects.all().order_by(sort_column)

        all_records_count = all_records.count()

        if not offset:
            offset = 0
        if not pageSize:
            pageSize = 10  # 默认是每页20行的内容,与前端默认行数一致
        pageinator = Paginator(all_records, pageSize)  # 开始做分页
        page = int(int(offset) / int(pageSize) + 1)
        response_data = {'total': all_records_count, 'rows': []}
        for server_li in pageinator.page(page):
            response_data['rows'].append({
                "id": server_li.id if server_li.id else "",
                "hostname": server_li.hostname if server_li.hostname else "",
                "IP": server_li.IP if server_li.IP else "",
                "Mem": server_li.Mem if server_li.Mem else "",
                "CPU": server_li.CPU if server_li.CPU else "",
                "CPUS": server_li.CPUS if server_li.CPUS else "",
                "OS": server_li.OS if server_li.OS else "",
                "virtual1": server_li.virtual1 if server_li.virtual1 else "",
                "status": server_li.status if server_li.status else "",
            })
        return HttpResponse(json.dumps(response_data))
    return render(request, 'serverlist.html')

下篇博客将单独进行salt-api与运维相关的管理命令的使用就想hostinfo的获取:
快速进入:saltstack 自动化运维工具管理命令的详细使用,获取指定数据集

你可能感兴趣的:(saltstack)