saltstack主机管理项目day39:主机管理项目开发

Posted python运维自动化之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了saltstack主机管理项目day39:主机管理项目开发相关的知识,希望对你有一定的参考价值。

项目目标

salt  state.apply   -h "ubuntu,centos"
			     -g "ubuntu,centos"
			     -f "ubuntu,centos"

文件目录规划

配置文件详解

步骤一:创建一个salt 

salt配置文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li


import os,sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Stark.settings")
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    #print(BASE_DIR)
    sys.path.append(BASE_DIR)
    from Arya.action_list import actions
    from Arya.backends.utils import ArgvManagement
    obj = ArgvManagement(sys.argv)

步骤二:utils命令分发器分发器通过action_list.py把不同的命令分给不同的模块

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
import sys

from Arya import action_list
import django
django.setup()

from Stark import settings
from Arya import models
class ArgvManagement(object):
    \'\'\'
    接收用户指令并分配到相应模块
    \'\'\'
    def __init__(self,argvs):
        self.argvs = argvs
        self.argv_parse()

    def help_msg(self):
        print("Available modules:")
        for registered_module in action_list.actions:
            print("  %s" % registered_module)
        exit()
    def argv_parse(self):
        #print(self.argvs)
        if len(self.argvs) <2:
            self.help_msg()
        module_name = self.argvs[1]
        if \'.\' in module_name:
            mod_name,mod_method = module_name.split(\'.\')
            module_instance  = action_list.actions.get(mod_name)
            if module_instance:#matched
                module_obj = module_instance(self.argvs,models,settings)
                module_obj.process() #提取 主机
                if hasattr(module_obj,mod_method):
                    module_method_obj = getattr(module_obj,mod_method)#解析任务,发送到队列,取任务结果
                    module_method_obj() #调用指定的指令
                else:
                    exit("module [%s] doesn\'t have [%s] method" % (mod_name,mod_method))
        else:
            exit("invalid module name argument")

 

actions_list文件内容

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.plugins import cmd,state
actions = {
    \'cmd\': cmd.CMD,
    \'state\':state.State
}

步骤三:state模块

模块功能说明

  1. state模块加载yaml file 文件
  2. 根据字符串把所有的模块加载出来 
  3. 不同的操作系统语法不同,所以就有通用模块和特殊模块
  4. 解析还未做做
  5. 每个参数当做一个函数处理(等待商确)
  6. 通用类的好处 写一个通用的类 类的继承
  7. 体会到用继承类的好处

具体配置文件

state

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule
import os

class State(BaseSaltModule):

    def load_state_files(self,state_filename):   #加载yumfeile
        from yaml import load, dump
        try:
            from yaml import CLoader as Loader, CDumper as Dumper
        except ImportError:
            from yaml import Loader, Dumper
        state_file_path = "%s/%s" %(self.settings.SALT_CONFIG_FILES_DIR,state_filename)
        if os.path.isfile(state_file_path):
            with open(state_file_path) as f:
                data = load(f.read(), Loader=Loader)
                return data
        else:
            exit("%s is not a valid yaml config file" % state_filename)

    def apply(self):
        \'\'\'
        1. load the configurations file
        2. parse it
        3. create a task and sent it to the MQ
        4. collect the result with task-callback id
        :return:
        \'\'\'


        if \'-f\' in self.sys_argvs:
            yaml_file_index = self.sys_argvs.index(\'-f\') + 1
            try:
                yaml_filename = self.sys_argvs[yaml_file_index]
                state_data = self.load_state_files(yaml_filename)
                #print(\'state data:\',state_data)

                for os_type,os_type_data in self.config_data_dic.items(): #按照不同的操作系统单独生成一份配置文件
                    for section_name,section_data in state_data.items():
                        print(\'Section:\',section_name)

                        for mod_name,mod_data in section_data.items():
                            base_mod_name = mod_name.split(".")[0]
                            plugin_file_path = "%s/%s.py" % (self.settings.SALT_PLUGINS_DIR,base_mod_name)
                            if os.path.isfile(plugin_file_path):
                                #导入 模块

                                module_plugin = __import__(\'plugins.%s\' %base_mod_name)
                                special_os_module_name = "%s%s" %(os_type.capitalize(),base_mod_name.capitalize())
                                #print(\'dir module plugin:\',module_plugin,base_mod_name)
                                #getattr(module_plugin,base_mod_name)
                                module_file= getattr(module_plugin, base_mod_name) # 这里才是真正导入模块
                                if hasattr(module_file, special_os_module_name): #判断有没有根据操作系统的类型进行特殊解析 的类,在这个文件里
                                    module_instance = getattr(module_file, special_os_module_name)
                                else:
                                    module_instance = getattr(module_file, base_mod_name.capitalize())

                                #开始调用 此module 进行配置解析
                                module_obj = module_instance(self.sys_argvs,self.db_models,self.settings)
                                module_obj.syntax_parser(section_name,mod_name,mod_data )
                            else:
                                exit("module [%s] is not exist" % base_mod_name)
                            #print("  ",mod_name)
                            #for state_item in mod_data:
                            #    print("\\t",state_item)

            except IndexError as e:
                exit("state file must be provided after -f")

        else:
            exit("statefile must be specified.")

cmd

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li

from Arya.backends.base_module import BaseSaltModule
class CMD(BaseSaltModule):
    print(\'in cmd module \') 

file

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule


class File(BaseSaltModule):

    pass 

group

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule


class Group(BaseSaltModule):

    def gid(self,*args,**kwargs):
        pass 

pkg

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule


class Pkg(BaseSaltModule):

    pass 

service

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule


class Service(BaseSaltModule):

    pass

  

user

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
from Arya.backends.base_module import BaseSaltModule


class User(BaseSaltModule):
    def uid(self,*args,**kwargs):
        pass
    def gid(self,*args,**kwargs):
        pass
    def shell(self,*args,**kwargs):
        pass
    def home(self,*args,**kwargs):
        pass

class UbuntuUser(User):
    def home(self,*args,**kwargs):
        print(\'in ubnutn home \')

models

from django.db import models

# Create your models here.

class Host(models.Model):         #主机管理
    hostname = models.CharField(max_length=128,unique=True)     #saltsack用hostname区别主机
    key = models.TextField()                #客户端主动找服务器,我想被你管理存放key文件
    status_choices = ((0,\'Waiting Approval\'),     #每个主机的三个状态等待、允许、拒绝
                      (1,\'Accepted\'),
                      (2,\'Rejected\'))

# 对操作系统进行判断
    os_type_choices =(
        (\'redhat\',\'Redhat\\CentOS\'),
        (\'ubuntu\',\'Ubuntu\'),
        (\'suse\',\'Suse\'),
        (\'windows\',\'Windows\'),
    )

    os_type = models.CharField(choices=os_type_choices,max_length=64,default=\'redhat\')
    status = models.SmallIntegerField(choices=status_choices,default=0)

    def __str__(self):
        return self.hostname
class HostGroup(models.Model):                #主机组管理
    name =  models.CharField(max_length=64,unique=True)
    hosts = models.ManyToManyField(Host,blank=True)

    def __str__(self):
        return self.name

base_models

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li


class BaseSaltModule(object):
    def __init__(self,sys_argvs,db_models,settings):
        self.db_models = db_models
        self.settings = settings
        self.sys_argvs = sys_argvs

    def get_selected_os_types(self):
        data = {}
        for host in self.host_list:
            data[host.os_type] = []
        print(\'--->data\',data)
        return data
    def process(self):
        self.fetch_hosts()
        self.config_data_dic = self.get_selected_os_types()
    def require(self,*args,**kwargs):
        pass
    def fetch_hosts(self):
        print(\'--fetching hosts---\')

        if \'-h\' in self.sys_argvs or \'-g\' in self.sys_argvs:
            host_list = []
            if \'-h\' in self.sys_argvs:
                host_str_index = self.sys_argvs.index(\'-h\') +1
                if len(self.sys_argvs) <= host_str_index:
                    exit("host argument must be provided after -h")
                else: #get the host str
                    host_str = self.sys_argvs[host_str_index]
                    host_str_list = host_str.split(\',\')
                    host_list += self.db_models.Host.objects.filter(hostname__in=host_str_list)
            if \'-g\' in self.sys_argvs:
                group_str_index = self.sys_argvs.index(\'-g\') +1
                if len(self.sys_argvs) <= group_str_index:
                    exit("group argument must be provided after -g")
                else: #get the group str
                    group_str = self.sys_argvs[group_str_index]
                    group_str_list = group_str.split(\',\')
                    group_list = self.db_models.HostGroup.objects.filter(name__in=group_str_list)
                    for group in group_list:
                        host_list += group.hosts.select_related()
            self.host_list = set(host_list)
            return True
            print(\'----host list:\', host_list)
        else:
            exit("host [-h] or group[-g] argument must be provided")


    def syntax_parser(self,section_name,mod_name,mod_data):
        print("-going to parser state data:",section_name,mod_name)
        for state_item in mod_data:
            print("\\t",state_item)
            for key,val in state_item.items():
                if hasattr(self,key):
                    state_func = getattr(self,key)
                    state_func(val)
                else:
                    exit("Error:module [%s] has no argument [%s]" %( mod_name,key ))

  

 

以上是关于saltstack主机管理项目day39:主机管理项目开发的主要内容,如果未能解决你的问题,请参考以下文章

saltstack主机管理项目:主机管理项目架构设计

saltstack主机管理项目:计主机管理项目命令分发器

saltstack主机管理项目:编写插件基类-获取主机列表-提取yaml配置文件

SaltStack 介绍和安装

用开源自动化运维工具 SaltStack 在云平台中实现各主机统一配置管理

如何用开源自动化运维工具 SaltStack 在云平台中实现各主机统一配置管理