博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Saltstack Automatic grouping
阅读量:6180 次
发布时间:2019-06-21

本文共 6422 字,大约阅读时间需要 21 分钟。

一、要点:

  1. 知道key验证存放的目录

  2. key在验证是手动还自动

  3. 对不在线的主机的处理 

  4. minion_id的命名规范

二、使用的技术栈

  1. saltstack 相关的库:salt.config,salt.client,salt.runner

  2. 使用redis 存放两个数据库,第一个为存为字典,用于存放minion_id与物理IP的对应,另一个存为集合,用于项目_业务命名的方式包含相应的主机

  3. 使用watchdog对目录变更监控,事件触发机制

三、完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# coding:utf8
# Created by IntelliJ IDEA.
# User: King.gp
# Date: 2016/10/9
# Time: 10:55
# To change this template use File | Settings | File Templates.
import 
time
import 
re
import 
sys
import 
redis
import 
logging
import 
salt.config as saltc
import 
salt.runner as saltr
import 
salt.client as SaltC
from 
watchdog.observers 
import 
Observer
from 
watchdog.events 
import 
FileSystemEventHandler
logging.basicConfig(level
=
logging.DEBUG,
                    
format
=
'%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s'
,
                    
datefmt
=
'%a, %d %b %Y %H:%M:%S'
,
                    
filename
=
'myapp.log'
, )
#################################################################################################
# 定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象#
# console = logging.StreamHandler()
# console.setLevel(logging.INFO)
# formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
# console.setFormatter(formatter)
# logging.getLogger('').addHandler(console)
################################################################################################
class 
MonitorHandler(FileSystemEventHandler):
    
# time
    
localtime 
= 
time.asctime(time.localtime(time.time()))
    
# 文件或目录被移动
    
def 
on_moved(
self
, event):
        
logging.info(MonitorHandler.localtime 
+ 
" - Event :文件/目录: {0} 被移动!"
.
format
(event.src_path))
        
call_func()
    
#  文件或目录被创建
    
def 
on_created(
self
, event):
        
logging.info(MonitorHandler.localtime 
+ 
" - Event: 文件/目录: {0} 被创建"
.
format
(event.src_path))
        
call_func()
    
# 文件或目录被删除
    
def 
on_deleted(
self
, event):
        
logging.info(MonitorHandler.localtime 
+ 
" - Event :文件/目录: {0} 被删除!"
.
format
(event.src_path))
        
call_func()
    
# 文件或目录被修改
    
def 
on_modified(
self
, event):
        
logging.info(MonitorHandler.localtime 
+ 
" - Event :文件/目录: {0} 被修改!"
.
format
(event.src_path))
        
call_func()
def 
client():
    
slc 
= 
SaltC.LocalClient()
    
return 
slc
class 
NodeGroup(
object
):
    
def 
__init__(
self
):
        
self
.member 
= 
redis.StrictRedis(host
=
'127.0.0.1'
,
                                        
port
=
6379
,
                                        
db
=
6
, )  
# 字典数据
        
self
.project 
= 
redis.StrictRedis(host
=
'127.0.0.1'
,
                                         
port
=
6379
,
                                         
db
=
7
, )  
# 集合数据
    
def 
update_info(
self
):
        
self
.member.flushdb()
        
self
.project.flushdb()
        
with 
open
(
'host'
'rb'
) as fd:
            
lines 
= 
fd.readlines()
        
pattern 
= 
re.
compile
(r
'[a-z]+'
)
        
for 
line 
in 
lines:
            
line 
= 
line.strip().split()  
# 1.2.3.4 web01.crms.com
            
self
.member.
set
(line[
1
], line[
0
])  
# web01.crms.com
            
profession_number 
= 
line[
1
].split(
"."
)[
0
]  
# web01
            
= 
re.match(pattern, profession_number)
            
if 
m:
                
profession 
= 
m.group()
                
project_suffix 
= 
line[
1
].split(
'.'
)[
-
2
:]
                
project 
= 
'.'
.join(project_suffix)  
# crms.com
                
self
.project.sadd(
'_'
.join([project, profession]), '
')  # crms.com_web: '
'
        
member_list 
= 
[]
        
match_dict 
= 
{}
        
for 
category 
in 
self
.project.keys():
            
category_pattern 
= 
re.
compile
(category.split(
"_"
)[
1
])  
# vm, logstash, elasticsearch
            
pattern_member_list 
= 
[]
            
for 
key 
in 
self
.member.keys():
                
# ['test.logstash.yinker.com', 'test.elastic.yinker.com', 'test.vm.yinker.com']
                
category_match 
= 
category_pattern.search(key)  
# web we01.crms.com
                
if 
category_match:
                    
pattern_member_list.append(key)
                    
match_dict[category_pattern.pattern] 
= 
pattern_member_list
                    
if 
match_dict 
not 
in 
member_list:
                        
member_list.append(match_dict)
        
# members_dict = {}
        
for 
in 
self
.project.keys():
            
pattern 
= 
re.
compile
(p.split(
"_"
)[
0
])
            
for 
k, values 
in 
member_list[
0
].items():
                
members_list 
= 
[]
                
for 
in 
values:
                    
match 
= 
pattern.search(v)  
# suffix ,
                    
if 
match:
                        
members_list.append(match.string)
                    
else
:
                        
continue
                        
# members_dict['_'.join([pattern.pattern, k])] = members_list
                
# print members_list
                
self
.project.sadd(
'_'
.join([pattern.pattern, k]), members_list)
                
self
.project.srem(
'_'
.join([pattern.pattern, k]), '')
    
def 
append_config(
self
):
        
with 
open
(
"/etc/salt/master.d/nodegroups.conf"
"w"
) as fd:
            
fd.write(
"nodegroups:\n"
)
        
with 
open
(
"/etc/salt/master.d/nodegroups.conf"
"a+"
)as f:
            
for 
mem 
in 
self
.project.keys():
                
# zookeeperg0: 'L@sh-zookeeperg0-10.168.1.32
                
# ["['idp01.crms.com','idp02.crms.com']"]
                
f.write(
"  " 
+ 
mem 
+ 
": " 
+ 
"'" + "L@" + (''.join(
                    
[i.replace("['", '').replace("']", '').replace("'"
, '') 
for 
in
                     
self
.project.smembers(mem)]) 
+ 
"'" 
+ 
'\n
').replace(' 
', '
'))
def 
control_hosts():
    
priv_opts 
= 
saltc.master_config(
'/etc/salt/master'
)
    
priv_runner 
= 
saltr.RunnerClient(priv_opts)
    
# r = priv_runner()
    
host_down 
= 
priv_runner.cmd(
"manage.down"
, [
"removekeys=True"
])  
# 移除DOWN状态的minion
    
if 
len
(host_down) > 
0
:
        
logging.info(MonitorHandler.localtime 
+ 
"minion_id: {0} 己经下线 "
.
format
(
' '
.join(host_down)))
    
local 
= 
client()
    
host_items 
= 
local.cmd(
"*"
"grains.item"
, [
'ip4_interfaces'
'id'
])
    
time.sleep(
3
)
    
if 
host_items:
        
raw 
= 
''
        
for 
in 
host_items.values():
            
raw 
= 
'{0}{1}\n'
.
format
(raw, 
' '
.join([v[
'ip4_interfaces'
][
'eth0'
][
0
], v[
'id'
]]))
        
with 
open
(
"host"
"w+"
) as f:
            
f.write(raw)
        
return 
True
    
else
:
        
logging.error(MonitorHandler.localtime 
+ 
"拉取grains信息失败"
)
        
return 
False
def 
call_func():
    
status 
= 
control_hosts()
    
if 
status:
        
group_agg 
= 
NodeGroup()
        
group_agg.update_info()
        
group_agg.append_config()
    
else
:
        
logging.error(MonitorHandler.localtime 
+ 
"拉取grains信息失败"
)
        
sys.exit(status
=
127
)
if 
__name__ 
=
= 
"__main__"
:
    
Monitor_Dir 
= 
'/etc/salt/pki/master/minions'
    
event_handler 
= 
MonitorHandler()
    
observer 
= 
Observer()
    
NodeGroup_File 
= 
'/etc/salt/master.d/nodegroups.conf'
    
observer.schedule(event_handler, path
=
Monitor_Dir, recursive
=
True
)
    
observer.start()
    
try
:
        
while 
True
:
            
time.sleep(
10
)
    
except 
KeyboardInterrupt:
        
observer.stop()
    
observer.join()

四、关于缺陷

  1. 关于怎么判断minion不在线的界定,是因为网络抖动,还是真的下线;

  2. 如果出来这样的问题是移除,还是不处理,如何取舍,因为这涉及一个问题,利用分组无法准确的执行任务,因为分组依赖于salt的允许的key对应的主机;

  3. 启动时会提示递归溢出,所有移除的主机都会输出到console上;

  4. 请自行添加到supervisor中。

本文转自 jinlinger 51CTO博客,原文链接:http://blog.51cto.com/essun/1959970,如需转载请自行联系原作者
你可能感兴趣的文章
可能是一场很 IN 的技术分享
查看>>
iPad Multitasking:iOS9 iPad 分屏多任务操作教程
查看>>
Kubernetes 调度器实现初探
查看>>
物流机器人也将有国家标准了!
查看>>
C# yield关键字解析
查看>>
构造器、对象数组、对象属性、静态实例块、this关键字 ...
查看>>
Alphabet旗下Verily Study Watch心电图功能获FDA二类许可 ...
查看>>
为Kubernetes中任意应用添加基于oauth2的认证保护 (上) ...
查看>>
Spark in action on Kubernetes - Spark Operator的原理解析
查看>>
Python中浅拷贝和深拷贝的理解与研究
查看>>
「镁客早报」马斯克退出OpenAI;AI医疗公司数坤科技宣布完成2亿元B轮融资 ...
查看>>
中国联通和英特尔打造智慧冬奥 5G仍是英特尔战略重点
查看>>
一周集成行业智能监控应用,阿里云发布智能视频监控平台
查看>>
之前用的一个多进程python爬虫
查看>>
跳槽阿里需要掌握的面试重点和技术——P8架构师为你指路
查看>>
全栈必备 负载均衡
查看>>
30个常用的 Maven 命令
查看>>
阿里云表格存储TableStore全新升级 打造统一在线数据存储平台
查看>>
好程序员分享ApacheSpark常见的三大误解
查看>>
【功能发布】日志服务(SLS)11-12月功能合集
查看>>