-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConfigManager.py
More file actions
201 lines (172 loc) · 7.79 KB
/
Copy pathConfigManager.py
File metadata and controls
201 lines (172 loc) · 7.79 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/python
#coding:utf-8
#kazoo 2.1+
#python 2.7 2.6
from AbstractZookeeperClient import *
from kazoo.client import KazooClient,DataWatch,ChildrenWatch
from kazoo.exceptions import NoNodeException,NodeExistsException,KazooException
import logging
import os
import socket
import fcntl
class Constants(object):
ZOOKEEPER_ROOT_PATH = '/config'
DEFAULT_PRODUCTION_ZKADDRESS = "127.0.0.1:2181"
ZOOKEEPER_TIMEOUT = 3
ZOOKEEPER_DOMAIN = 'zookeeper.domain'
CONFIG_FILE_SNAPSHOT_PATH = os.environ['HOME'] + '/.config/config_snapshot'
class ConfigManager(object):
'''manage configuration of services by zookeeper'''
def __init__(self,logger,serverlist=None,appkey=None):
self._logger = logger
self.localCacheDict = {}
self.WatchDict = {}
self.initAppKeyDict = {}
self.appkey = appkey
self.serverlist = serverlist or self.getConfigZkAddress()
self.snapshotPath = Constants.CONFIG_FILE_SNAPSHOT_PATH
try:
self.zk = AbstractZookeeperClient(self.serverlist,self._logger,Constants.ZOOKEEPER_TIMEOUT)
self._iszktimeout = False
except Exception as why:
self._logger.error('connect to zookeeper %s, will load local_snapshot',why)
self._read_snapshot()
self._iszktimeout = True
@staticmethod
def writefile(fileSnapshot,kvlist):
with open(fileSnapshot,'w') as fp:
for kv in kvlist:
fp.write(kv)
fp.write('\n')
def getConfigZkAddress(self):
'''get zookeeper address by dns'''
serverList = ""
try:
serverList = socket.gethostbyname_ex(Constants.ZOOKEEPER_DOMAIN)[2]
serverList= ','.join(map(lambda x:x+':2181',serverList))
except (socket.gaierror,socket.herror) as why:
self._logger.error('Parse %s error,will loading default zookeeper address of prod %s',Constants.ZOOKEEPER_DOMAIN,why)
serverList = Constants.DEFAULT_PRODUCTION_ZKADDRESS
return serverList
def iszktimeout(self):
if self._iszktimeout: return True
if self.zk.iszktimeout : return True
def _read_snapshot(self):
'''load loacl snapshaot of configurations'''
self._logger.info('loading file snapshot to local cache!')
if os.path.isdir(self.snapshotPath) and os.path.exists(self.snapshotPath):
filelist = [ filename for filename in os.listdir(self.snapshotPath) if os.path.isfile(os.path.join(self.snapshotPath,filename)) ]
for snapshotfile in filelist :
if snapshotfile.endswith('.properties'):
cacheKeyPrefix = os.path.join(Constants.ZOOKEEPER_ROOT_PATH,snapshotfile.replace('.properties',''))
with open(self.snapshotPath+'/'+snapshotfile,'r') as f:
for line in f.readlines():
(key,value) = line.split('=')
self._update_localcache(cacheKeyPrefix+'/'+key,value)
def _update_localcache(self,cachekey,cachevalue):
'''update localcache of configurations'''
self.localCacheDict[cachekey] = cachevalue
def _datawatch_handle(self,data,stat,event):
'''callback func for datawatch
what about del event ?'''
if event:
watchKey = event[2]
self.localCacheDict[watchKey] = data
def _childwatch_handle(self,children,event):
'''callback func for childwatch'''
if event:
watchChild = event[2]
appkey = watchChild.split('/')[-1]
self.loadconfig_byappKey_fromzk(appkey)
def get_appconfigvalue(self,appkey,is_watch=False):
'''hight-level ChildrenWatch ,return kvs of parent's node'''
if not self.iszktimeout():
configValue = {}
appPath = os.path.join(Constants.ZOOKEEPER_ROOT_PATH,appkey)
if appPath not in self.WatchDict:
if is_watch:
ChildrenWatch(self.zk.client,appPath,self._childwatch_handle,send_event=True)
self.WatchDict[appPath] = True
if appkey not in self.initAppKeyDict:
self.loadconfig_byappKey_fromzk(appkey)
self.initAppKeyDict[appkey] = True
for key,value in self.localCacheDict.iteritems():
if appkey == key.split('/')[2]:
configKey = key.split('/')[-1]
configValue[configKey] = value
return configValue
@property
def get_appconf(self):
'''use easily '''
if not self.appkey: return
appkey = self.appkey
if not self.iszktimeout():
configValue = {}
appPath = os.path.join(Constants.ZOOKEEPER_ROOT_PATH,appkey)
if appPath not in self.WatchDict:
if is_watch:
ChildrenWatch(self.zk.client,appPath,self._childwatch_handle,send_event=True)
self.WatchDict[appPath] = True
if appkey not in self.initAppKeyDict:
self.loadconfig_byappKey_fromzk(appkey)
self.initAppKeyDict[appkey] = True
for key,value in self.localCacheDict.iteritems():
if appkey == key.split('/')[2]:
configKey = key.split('/')[-1]
configValue[configKey] = value
return configValue
def get_configvalue(self,appkey,configkey,defaultvalue=None,is_watch=False):
'''hight-level DataWatch, return the configvalue of the key'''
configPath = os.path.join(Constants.ZOOKEEPER_ROOT_PATH,appkey,configkey)
if not self.iszktimeout():
if configPath not in self.WatchDict:
# first watch and add it ;will not fire event
if is_watch:
DataWatch(self.zk.client,configPath,self._datawatch_handle)
self.WatchDict[configPath] = True
# if not load conf then init it
if appkey not in self.initAppKeyDict:
self.loadconfig_byappKey_fromzk(appkey)
self.initAppKeyDict[appkey] = True
configvalue = self.localCacheDict[configPath]
return configvalue if configvalue else defaultvalue
def loadconfig_byappKey_fromzk(self,appkey):
# init local snapshot file
self._create_snapshot(appkey)
#init local cache
appPath = Constants.ZOOKEEPER_ROOT_PATH + '/' +appkey
configDict = self.zk.get_kvmap_byparent(appPath)
if configDict :
for key in configDict:
dataPath = appPath + '/' + key
self.localCacheDict[dataPath] = configDict[key]
def _create_snapshot(self,appkey):
'''create local snapshot '''
#fcntl.flock
fileSnapshot = os.path.join(Constants.CONFIG_FILE_SNAPSHOT_PATH,appkey+'.properties')
fileLock = fileSnapshot + '.lock'
appPath = os.path.join(Constants.ZOOKEEPER_ROOT_PATH,appkey)
try:
os.makedirs(Constants.CONFIG_FILE_SNAPSHOT_PATH)
except OSError as why:
self._logger.warn('%s',why)
configMap = self.zk.get_kvlist_byparent(appPath)
if configMap:
fp = open(fileLock,'w+')
try:
fcntl.lockf(fp,fcntl.LOCK_EX|fcntl.LOCK_NB)
self.writefile(fileSnapshot,configMap)
self._logger.info('file sbapshot %s create',fileSnapshot)
except Exception as why:
self._logger.info('%s locking conflict %s' % (fileLock,why))
finally:
fp.close()
@property
def get_localcache(self):
return self.localCacheDict
@property
def get_localinitinfo(self):
info = {}
info['initapp'] = self.initAppKeyDict.keys()
info['watchkey'] = self.WatchDict.keys()
return info