docker.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. dever-manage tools
  5. name:docker.py
  6. author:rabin
  7. """
  8. from core import *
  9. class Docker(object):
  10. path = 'src/docker/'
  11. default = 'shemic'
  12. @classmethod
  13. def init(self):
  14. self.conf = {}
  15. self.core = Config.core(self.path)
  16. self.store = Env.store()
  17. self.storeHost = self.core['store'][self.store] + '/'
  18. action = ('uprun', 'run', 'rm', 'rmb', 'stop', 'create', 'call', 'save', 'load', 'show', 'reset', 'logs', 'restart', 'inspect', 'test')
  19. method = Core.getMethod(Docker_Action, Args.action)
  20. if Args.name and Args.action in action:
  21. self.load(method)
  22. else:
  23. method()
  24. @classmethod
  25. def load(self, method):
  26. self.config()
  27. Container.network(self.conf['base'])
  28. self.rely(self.conf['base'], Args.action)
  29. one = False
  30. if Args.index in self.conf['config']:
  31. self.handle(method, self.conf['config'][Args.index], Args.index, Args.action)
  32. else:
  33. for item in self.conf['server']:
  34. if self.check(Args.index, item) == True:
  35. self.handle(method, self.conf['config'][item], item, Args.action)
  36. @classmethod
  37. def config(self):
  38. if not self.conf:
  39. self.conf = Config.read(self.path)
  40. @classmethod
  41. def check(self, name, item):
  42. if '#' in item:
  43. return False
  44. elif name == '':
  45. return True
  46. elif name + '-' in item:
  47. return True
  48. else:
  49. return False
  50. @classmethod
  51. def handle(self, method, config, item, action='run'):
  52. self.rely(config, action)
  53. if 'num' not in config:
  54. config['num'] = 1
  55. num = int(config['num'])
  56. i = 1;
  57. while (i <= num):
  58. name = self.name(item, i)
  59. if 'image' not in config:
  60. config['image'] = item
  61. if self.store == 'private' and config['image'] in self.core['images']:
  62. config['image'] = self.core['images'][config['image']]
  63. method(config=config, name=name, item=item, index=i, action=action)
  64. if action in ('stop', 'restart', 'rm', 'rmb', 'reset', 'run', 'create'):
  65. self.slave(method, config, item, action)
  66. i = i + 1
  67. @classmethod
  68. def name(self, name, i):
  69. name = Args.name + '-' + name
  70. if i > 1:
  71. self.conf['base']['i'] = '' + str(i)
  72. i = i - 1;
  73. self.conf['base']['num'] = '' + str(i)
  74. return name + self.conf['base']['num'];
  75. self.conf['base']['num'] = ''
  76. self.conf['base']['i'] = '1'
  77. return name;
  78. @classmethod
  79. def param(self, config, item, prefix, name):
  80. result = ''
  81. concat = ' '
  82. if item in config:
  83. if '#' not in item:
  84. result = config[item]
  85. if '[' in config[item]:
  86. search = re.search(r'\[(.*?)\]', result, re.M|re.I)
  87. temp = search.group(1)
  88. if temp:
  89. result = Core.replace('['+str(temp)+']', self.name(temp, 1), result)
  90. result = Core.replace('{num}', self.conf['base']['num'], result)
  91. result = Core.replace('{i}', self.conf['base']['i'], result)
  92. result = Core.replace('{path}', self.conf['base']['path'], result)
  93. result = Core.replace('{container}', self.conf['base']['path'] + 'container/', result)
  94. result = Core.replace('{name}', name, result)
  95. result = self.parse(result)
  96. result = Core.replace(',', ' ' + prefix + ' ', result)
  97. if item == 'hostname':
  98. name = result
  99. elif item == 'network' and 'network' in self.conf['base']:
  100. result = self.conf['base']['network']
  101. if result != '':
  102. if '=' in prefix:
  103. concat = ''
  104. result = prefix + concat + result
  105. return result
  106. @classmethod
  107. def parse(self, result):
  108. if '{$' in result:
  109. param = {}
  110. if Args.param != '':
  111. if 'http://' not in Args.param:
  112. Args.param = 'http://shemic.com/?' + Args.param;
  113. if '^' in Args.param:
  114. Args.param = Core.replace('^', '&', Args.param)
  115. parse = urlparse.urlparse(Args.param)
  116. param = urlparse.parse_qs(parse.query,True)
  117. search = re.compile(r'\{\$(.*?)\}')
  118. search = search.findall(result)
  119. for key in search:
  120. value = ''
  121. index = key
  122. if ':' in key:
  123. arr = key.split(':');
  124. index = arr[0]
  125. value = arr[1]
  126. if index in param:
  127. value = param[index][0]
  128. if value == '':
  129. print 'please set param value:' + index
  130. sys.exit()
  131. else:
  132. result = Core.replace('{$'+key+'}', value, result)
  133. return result
  134. @classmethod
  135. def rely(self, config, action):
  136. if 'rely' in config:
  137. if ',' in config['rely']:
  138. rely = config['rely'].split(',');
  139. for i in rely:
  140. Core.popen('Core ' + action + ' ' + i, True)
  141. else:
  142. Core.popen('Core ' + action + ' ' + config['rely'], True)
  143. @classmethod
  144. def hook(self, type, config, name):
  145. key = 'hook.'+type
  146. if key in config:
  147. Core.shell('hook.' + config[key] + ' ' + name + ' ' + Core.path, bg=True)
  148. @classmethod
  149. def slave(self, method, config, name, action):
  150. if 'slave' in config:
  151. num = int(config['slave'])
  152. key = ['slave', 'command', 'alias', 'port', 'hook.start', 'hook.end']
  153. for k in key:
  154. if k in config:
  155. del config[k]
  156. config['num'] = num
  157. self.handle(method, config, name + '-slave', action)
  158. @classmethod
  159. def tar(self, name):
  160. path = Core.path + 'data/backup/' + name + '/'
  161. File.mkdir(path)
  162. backup = 'backup/' + name
  163. tar = path + name + '.tar'
  164. return tar,backup
  165. class Docker_Action(object):
  166. @staticmethod
  167. def build():
  168. if Args.name and Args.name in Docker.core['images']:
  169. Args.name = Docker.core['images'][Args.name]
  170. Image.build(Docker.storeHost, Args.name)
  171. Container.delete()
  172. Image.delete()
  173. print 'docker build '+Args.name+':yes'
  174. @classmethod
  175. def push(self):
  176. package = self.package()
  177. if Args.name != '':
  178. if Args.name in package:
  179. Image.push(package[Args.name])
  180. else:
  181. print 'error ' + Args.name
  182. sys.exit()
  183. for key in package:
  184. Image.push(package[key])
  185. @classmethod
  186. def login(self):
  187. if Args.name and Args.name in Docker.core['store']:
  188. Core.shell('docker.login ' + Docker.core['store'][Args.name], True)
  189. else:
  190. for key,value in Docker.core['store'].items():
  191. Core.shell('docker.login ' + value, True)
  192. @staticmethod
  193. def package():
  194. stores = Docker.core['store']
  195. result = {}
  196. del stores[Docker.store]
  197. for key,value in Docker.core['images'].items():
  198. if Docker.store == 'private':
  199. index = Docker.storeHost + value
  200. else:
  201. index = Docker.storeHost + key
  202. result[key] = []
  203. result[key].append(index)
  204. for k,v in stores.items():
  205. if k == 'private':
  206. host = v + '/' + value
  207. else:
  208. host = v + '/' + key
  209. if host != index:
  210. result[key].append(host)
  211. if Args.name and Args.name in result:
  212. value = Args.name + ' [' + ",".join(result[Args.name ]) + ']'
  213. print value
  214. else:
  215. i = 1
  216. for key in result:
  217. value = key + ' [' + ",".join(result[key]) + ']'
  218. print str(i) + ':' + value
  219. i = i + 1
  220. return result
  221. @staticmethod
  222. def showi():
  223. Image.show()
  224. @staticmethod
  225. def rmi():
  226. Image.delete()
  227. print 'rm image:yes'
  228. @staticmethod
  229. def drop():
  230. Container.drop()
  231. print 'drop container:yes'
  232. @staticmethod
  233. def dropi():
  234. Image.drop(Args.name)
  235. print 'drop image:yes'
  236. @staticmethod
  237. def show(**param):
  238. name = ''
  239. if param:
  240. name = param['name']
  241. Container.show(name)
  242. @staticmethod
  243. def logs(**param):
  244. Container.logs(param['name'])
  245. @staticmethod
  246. def restart(**param):
  247. print 'reloading ' + param['name'] + ', please wait...'
  248. Container.restart(param['name'])
  249. @staticmethod
  250. def inspect(**param):
  251. Container.inspect(param['name'])
  252. @staticmethod
  253. def stop(**param):
  254. Container.stop(param['name'])
  255. @staticmethod
  256. def save(**param):
  257. tar,backup = Docker.tar(param['name'])
  258. Container.save(tar, param['name'], backup)
  259. @classmethod
  260. def load(self, **param):
  261. tar,backup = Docker.tar(param['name'])
  262. Container.load(tar, param['name'])
  263. Docker.storeHost = ''
  264. param['config']['image'] = backup
  265. self.run(**param)
  266. @classmethod
  267. def uprun(self, **param):
  268. Image.install(Docker.storeHost, param['config']['image'])
  269. param['action'] = 'run'
  270. self.run(**param)
  271. @staticmethod
  272. def rm(**param):
  273. if param and 'name' in param:
  274. Container.delete(param['name'])
  275. Alias.delete(param['config'], param['name'])
  276. else:
  277. Container.delete()
  278. print 'rm container:yes'
  279. @staticmethod
  280. def rmb(**param):
  281. if param and 'name' in param:
  282. Container.delete(param['name'], bg=True)
  283. Alias.delete(param['config'], param['name'])
  284. else:
  285. Container.delete()
  286. print 'rm container:yes'
  287. @classmethod
  288. def reset(self, **param):
  289. self.rm(**param)
  290. self.up(**param)
  291. @classmethod
  292. def test(self, **param):
  293. param['test'] = True
  294. print self.run(**param)
  295. @classmethod
  296. def create(self, **param):
  297. self.run(**param)
  298. @classmethod
  299. def call(self, **param):
  300. self.run(**param)
  301. @classmethod
  302. def run(self, **param):
  303. command = ''
  304. daemon = '-d'
  305. restart = '--restart=always'
  306. if 'daemon' in param['config']:
  307. daemon = param['config']['daemon']
  308. if daemon == 'false':
  309. daemon = ''
  310. restart = ''
  311. if 'image' not in param['config']:
  312. param['config']['image'] = ''
  313. if 'restart' in param['config']:
  314. restart = ''
  315. if param['action'] == 'call':
  316. runCommand = Docker.param(param['config'], 'call', '', param['name'])
  317. command = Docker.param(param['config'], 'param', '', param['name'])
  318. restart = '--entrypoint' + runCommand
  319. daemon = '--rm'
  320. param['action'] = 'run'
  321. state = Container.check(param['name'])
  322. if state == 0:
  323. Docker.hook('start', param['config'], param['name'])
  324. run = ['-it', '--name='+param['name'], '--hostname='+param['name'], restart, daemon, '-v '+Core.path+'container/share:/share -v /etc/hosts:/etc/hosts.main']
  325. args = Container.args()
  326. for key in args:
  327. if args[key] != '':
  328. value = Docker.param(param['config'], key, args[key], param['name'])
  329. if value != '':
  330. run.append(value)
  331. run.append(Docker.storeHost + param['config']['image'])
  332. if command == '' and 'command' in args:
  333. value = Docker.param(param['config'], 'command', args['command'], param['name'])
  334. command = value
  335. if command != '':
  336. run.append(command)
  337. command = ' '.join(run)
  338. if 'test' in param:
  339. return 'docker run ' + command
  340. print 'setuping ' + param['name'] + ', please wait...'
  341. method = Core.getMethod(Container, param['action'])
  342. method(command)
  343. Alias.add(param['config'], param['name'], 'docker run ' + command, param['action'])
  344. Docker.hook('end', param['config'], param['name'])
  345. else:
  346. self.restart(**param)
  347. class Container(object):
  348. @staticmethod
  349. def run(command):
  350. #command = 'container.run ' + command
  351. #Core.shell(command, True, bg=False)
  352. command = 'docker run ' + command
  353. Core.popen(command, True, bg=False)
  354. return command
  355. @staticmethod
  356. def show(name=''):
  357. print Core.shell('container.show ' + name)
  358. @staticmethod
  359. def args():
  360. return {
  361. 'port' : '-p'
  362. ,'volumes' : '-v'
  363. ,'environment' : '-e'
  364. ,'link' : '--link'
  365. ,'volumes_from' : '--volumes-from'
  366. ,'command' : ''
  367. ,'entrypoint' : '--entrypoint'
  368. ,'network' : '--net='
  369. ,'host' : '--add-host'
  370. ,'root' : '--privileged='
  371. ,'memory' : '--memory='
  372. ,'expose' : '--expose',
  373. }
  374. @staticmethod
  375. def drop():
  376. Core.shell('container.drop', bg=True)
  377. @staticmethod
  378. def stop(name):
  379. Core.shell('container.stop ' + name)
  380. @staticmethod
  381. def logs(name):
  382. Core.shell('container.logs ' + name, True)
  383. @staticmethod
  384. def inspect(name):
  385. Core.shell('container.inspect ' + name, True)
  386. @staticmethod
  387. def restart(name):
  388. Core.shell('container.restart ' + name)
  389. @classmethod
  390. def delete(self, name='', bg=False):
  391. if name != '':
  392. print 'rm ' + name + ', please wait...'
  393. if self.check(name) == 1:
  394. Core.shell('container.rm ' + name, False, bg=bg)
  395. else:
  396. Core.shell('container.rm', False)
  397. @staticmethod
  398. def check(name):
  399. result = int(Core.popen('docker ps -a | grep '+name+' | wc -l'))
  400. if result != 0:
  401. return 1
  402. else:
  403. return 0
  404. @staticmethod
  405. def network(config):
  406. if 'network' in config:
  407. result = int(Core.popen('docker network ls | grep ' + config['network'] + ' | wc -l'))
  408. if result == 0:
  409. Core.shell('container.network ' + config['network'], True)
  410. @staticmethod
  411. def save(tar, name, backup):
  412. if File.exists(tar) == True:
  413. now = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
  414. old = replace('.tar', '.' + now + '.tar', tar)
  415. File.rename(tar, old)
  416. Core.popen('docker commit -p ' + name + ' ' + backup)
  417. Core.popen('docker save ' + backup + ' > ' + tar, True)
  418. @classmethod
  419. def load(self, tar, name):
  420. Core.popen('docker load < ' + tar, True)
  421. self.delete(name)
  422. class Image(object):
  423. @classmethod
  424. def push(self, stores):
  425. store = stores[0]
  426. if self.check(store) == 1:
  427. del stores[0]
  428. Core.shell('image.push ' + store, bg=True)
  429. for value in stores:
  430. #print store + ' ' + value
  431. Core.shell('image.push ' + store + ' ' + value, bg=True)
  432. @staticmethod
  433. def show():
  434. print Core.shell('image.show')
  435. @staticmethod
  436. def drop(name=''):
  437. Core.shell('image.drop ' + name, bg=True)
  438. @staticmethod
  439. def delete():
  440. Core.shell('image.rm', bg=True)
  441. @staticmethod
  442. def build(path, name):
  443. file = Core.path + Docker.path + 'build/' + name + '/'
  444. name = path + name
  445. Core.shell('image.build ' + name + ' ' + file, True)
  446. @staticmethod
  447. def check(name):
  448. result = int(Core.popen('docker images | grep '+name+' | wc -l'))
  449. if result != 0:
  450. return 1
  451. else:
  452. return 0
  453. @staticmethod
  454. def install(library, key):
  455. pull = 'docker pull';
  456. command = pull + ' ' + library + key
  457. Core.popen(command, True)
  458. print 'finished'