123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- """
- dever-docker tools
- name:dever.py
- author:rabin
- """
- import time
- import datetime
- import os
- import sys
- import getopt
- import ConfigParser
- import commands
- import re
- import subprocess
- import urlparse
- PATH = ''
- class Dever(object):
- config = {}
- server = []
- core = {}
- base = {}
- path = ''
- method = ''
- conf = ''
- name = ''
- param = ''
- def __init__(self):
- self.initObject()
- self.initCore()
- self.initArgv()
- state = self.initConfig()
- if state == 1:
- self.run()
- def initObject(self):
- self.File = File()
- self.Container = Container()
- self.Image = Image()
- self.Alias = Alias()
- global PATH
- if PATH == '':
- PATH = self.File.path()
- self.path = PATH
- def initCore(self):
- core = self.path + 'conf/core.conf'
- if self.File.exists(core):
- config = ConfigParser.ConfigParser()
- config.read(core)
- for item in config.sections():
- self.core[item] = self.readConfig(config, item)
- else:
- print core + ' is not exists'
- sys.exit()
- def initConfig(self):
- filename = self.path + 'conf/dever/' + self.conf + '.conf'
- if self.File.exists(filename):
- config = ConfigParser.ConfigParser()
- config.read(filename)
- for item in config.sections():
- if item == 'base':
- self.base = self.readConfig(config, item)
- else:
- self.server.append(item)
- self.config[item] = self.readConfig(config, item)
- self.base['path'] = replace('{base}', self.path, self.base['path'])
- return 1
- else:
- print filename + ' is not exists'
- return 0
- def readConfig(self, config, type):
- value = config.options(type)
- result = {}
- for item in value:
- result[item] = config.get(type, item)
- return result
- def initArgv(self):
- slen = len(sys.argv)
- if slen >= 2:
- self.method = sys.argv[1]
- if slen >= 3:
- self.conf = sys.argv[2]
- if slen >= 4:
- self.name = sys.argv[3]
- if slen >= 5:
- self.param = sys.argv[4]
- self.options()
- self.handle()
- if self.method == '':
- print 'method error'
- sys.exit()
- def options(self):
- try:
- options, args = getopt.getopt(sys.argv[1:], "hm:n:a:p:", ['help', "method=", "name=", "action=", "param="])
- for name, value in options:
- if name in ('-h', '--help'):
- self.usage()
- elif name in ('-m', '--method'):
- self.method = value
- elif name in ('-c', '--conf'):
- self.conf = value
- elif name in ('-n', '--name'):
- self.name = value
- elif name in ('-p', '--param'):
- self.param = value
- except getopt.GetoptError:
- self.usage()
- def usage(self):
- print ' Usage: \n' + \
- ' dever [-m] <method> [-n] <name> [-a] <action> [-p] <param>\n' + \
- ' dever <method> <name> <action> <param>\n\n' + \
- ' -h or --help Help\n' + \
- ' -m or --method Method name\n' + \
- ' -c or --conf Configuration file name\n' + \
- ' -n or --name The index name in the configuration file\n' + \
- ' -p or --param Execution parameters are generally judged by actions\n\n' + \
- ' <method>list:\n' + \
- ' init Initializes and updates the Dever code\n' + \
- ' up Update the Dever code\n' + \
- ' show Displays the docker container that is currently started\n' + \
- ' showi Displays the current docker mirror\n' + \
- ' rm Remove an exception or docker container that has not been started\n' + \
- ' rmi Delete expired docker images\n\n' + \
- ' <method>+<conf>list:\n' + \
- ' run Run the container\n' + \
- ' stop Stop the container\n' + \
- ' create Create the container\n' + \
- ' call Run the container, run only once\n' + \
- ' up Run the container and update the docker mirror\n' + \
- ' rm Remove the running docker container\n' + \
- ' save Save or backup the running docker container\n' + \
- ' load Restores and re run the docker container that is saved or backed up\n\n' + \
- ' Example:\n' + \
- ' dever -m run -c web -n php\n' + \
- ' dever run web php\n' + \
- ' dever -m call -c tool -n apidoc -p input=demo^out=output\n' + \
- ' dever call tool apidoc input=demo^out=output\n\n' + \
- '[Dever is a small docker choreography tool]\n'
- sys.exit()
- def handle(self):
- method = ['build', 'push', 'shell']
- if self.method not in method and self.conf != '':
- return
- if self.method == 'init':
- self.update()
- popen('chmod -R +x ' + self.path + 'shell/')
- check('curl')
- check('docker')
- print 'dever init success'
- elif self.method == 'up':
- self.update()
- print 'dever update success'
- elif self.method == 'commit':
- print shell('git.push ' + self.path)
- elif self.method == 'push':
- self.push(self.conf)
- elif self.method == 'package':
- self.package()
- elif self.method == 'path':
- print self.path
- elif self.method == 'show':
- self.Container.show()
- elif self.method == 'showi':
- self.Image.show()
- elif self.method == 'rmi':
- self.Image.delete()
- print 'docker rm none container:yes'
- elif self.method == 'rm':
- self.Container.delete()
- print 'docker rm image:yes'
- elif self.method == 'drop':
- self.Container.drop()
- self.Image.drop()
- print 'docker drop image:yes'
- elif self.method == 'build':
- self.Image.build(self.core['base'], self.path, self.conf)
- self.Container.delete()
- self.Image.delete()
- print 'docker build '+self.conf+':yes'
- elif self.method == 'shell':
- print shell(self.conf)
- else:
- return
- sys.exit()
- def package(self):
- dockerHub = self.core['base']['dockerhub'] + '/'
- dockerMe = self.core['base']['dockerme'] + '/'
- result = {}
- for key in self.core['package']:
- print 'package : [' + dockerHub + key + '] or [' + dockerMe + self.core['package'][key] + ']'
- result[dockerHub + key] = dockerMe + self.core['package'][key]
- return result
- def push(self, name=''):
- package = self.package()
- if name != '':
- if name in package:
- self.Image.push(package[name], name)
- else:
- print 'error ' + name
- sys.exit()
- for key in package:
- self.Image.push(package[key], key)
- def update(self):
- print 'loading...'
- if '/usr/bin/' not in self.path:
- shell('git.pull ' + self.path)
- self.code()
- def code(self):
- content = self.File.read(self.path, 'dever.py')
- content = content.replace('PATH = \'\'', 'PATH="'+self.path+'"')
- self.File.write('/usr/bin/dever', content)
- content = '#!/usr/bin/env sh \nset -e\ncd ' + self.path
- self.File.write('/usr/bin/godever', content)
- def run(self):
- self.Container.network(self.base)
- self.rely(self.base, self.method)
- one = False
- if self.name in self.config:
- one = True
- if one:
- self.runServer(self.config[self.name], self.name, self.method)
- else:
- for item in self.server:
- if self.checkServer(self.name, item) == True:
- self.runServer(self.config[item], item, self.method)
- def checkServer(self, name, item):
- if '#' in item:
- return False
- elif name == '':
- return True
- elif name+'-' in item:
- return True
- else:
- return False
- def runServer(self, config, item, action='run'):
- self.rely(config, action)
- if 'num' not in config:
- config['num'] = 1
- num = int(config['num'])
- i = 1;
- while (i <= num):
- self.runServerOne(config, item, i, action)
- i = i + 1
- def runServerOne(self, config, item, i, action=''):
- name = self.getServerName(item, i)
- command = ''
- daemon = '-d'
- restart = '--restart=always'
- method = 'run'
- if 'daemon' in config:
- daemon = config['daemon']
- if daemon == 'false':
- daemon = ''
- restart = ''
- if 'image' not in config:
- config['image'] = ''
- if 'restart' in config:
- restart = ''
- run = True;
- if action == 'create':
- method = action
- elif action == 'call':
- runCommand = self.getServerParam(config, 'call', '', name)
- command = self.getServerParam(config, 'param', '', name)
- restart = '--entrypoint' + runCommand
- daemon = '--rm'
- elif action == 'stop':
- self.Container.stop(name)
- self.slave(config, item, action)
- run = False
- elif action == 'restart':
- self.Container.restart(name)
- self.slave(config, item, action)
- run = False
- elif action == 'logs':
- self.Container.logs(name)
- run = False
- elif action == 'show':
- self.Container.show(name)
- run = False
- elif action == 'inspect':
- self.Container.inspect(name)
- run = False
- elif action in ['rm', 'reset']:
- self.Container.delete(name)
- self.Alias.delete(self.path, config, name)
- self.slave(config, item, action)
- run = False
- elif action in ['up', 'reset']:
- self.update()
- self.Image.install(self.config, self.base['library'], config['image'])
- elif action in ['save', 'load']:
- path = self.path + 'data/backup/' + name + '/'
- self.File.mkdir(path)
- backup = 'backup/' + name
- tar = path + name + '.tar'
- if action == 'save':
- self.Container.save(self.File, tar, name, backup)
-
- elif action == 'load':
- self.Container.load(tar, name)
- self.base['library'] = ''
- config['image'] = backup
- self.runServerOne(config, item, i)
- run = False;
- if run == False:
- return
- state = self.Container.check(name)
- if state == 0:
- self.hook('start', config, name, self.path)
- docker = ['-it', '--name='+name, '--hostname='+name, restart, daemon, '-v '+self.path+'data/share:/share -v /etc/hosts:/etc/hosts.main']
- param = self.Container.config()
- for key in param:
- if param[key] != '':
- value = self.getServerParam(config, key, param[key], name)
- if value != '':
- docker.append(value)
- docker.append(self.base['library'] + config['image'])
- if command == '' and 'command' in param:
- value = self.getServerParam(config, 'command', param['command'], name)
- command = value
- if command != '':
- docker.append(command)
- command = ' '.join(docker)
- bg = False
- print 'setuping ' + name + ', please wait...'
- else:
- #if daemon == '':
- #self.runServerOne(config, item, i, 'rm')
- #self.runServerOne(config, item, i)
- #return
- method = 'restart';
- command = name
- bg = True
- print 'reloading ' + name + ', please wait...'
-
- if action == 'test':
- print command
- else:
- self.Container.run(method, method + ' ' + command, bg)
- if state == 0:
- self.Alias.add(self.path, config, name, 'docker ' + method + ' ' + command, self.File, action)
- self.hook('end', config, name, self.path)
- self.slave(config, item, action)
- def rely(self, config, action):
- if 'rely' in config:
- if ',' in config['rely']:
- rely = config['rely'].split(',');
- for i in rely:
- popen('dever ' + action + ' ' + i, True)
- else:
- popen('dever ' + action + ' ' + config['rely'], True)
- def hook(self, type, config, name, path):
- key = 'hook.'+type
- if key in config:
- shell('hook.' + config[key] + ' ' + name + ' ' + path, bg=True)
- def slave(self, config, name, action):
- if 'slave' in config:
- i = 1
- num = int(config['slave'])
- key = ['slave', 'command', 'alias', 'port', 'hook.start', 'hook.end']
- for k in key:
- if k in config:
- del config[k]
- while (i <= num):
- self.runServerOne(config, name + '-slave', i, action)
- i = i + 1
- def getServerName(self, name, i):
- name = self.conf + '-' + name
- if i > 1:
- self.base['i'] = '' + str(i)
- i = i - 1;
- self.base['num'] = '' + str(i)
- return name + self.base['num'];
- self.base['num'] = ''
- self.base['i'] = '1'
- return name;
- def getServerParam(self, config, item, prefix, name):
- result = ''
- concat = ' '
- if item in config:
- if '#' not in item:
- result = config[item]
- if '[' in config[item]:
- search = re.search(r'\[(.*?)\]', result, re.M|re.I)
- temp = search.group(1)
- if temp:
- result = replace('['+str(temp)+']', self.getServerName(temp, 1), result)
- result = replace('{num}', self.base['num'], result)
- result = replace('{i}', self.base['i'], result)
- result = replace('{path}', self.base['path'], result)
- result = replace('{name}', name, result)
- result = self.getServerParse(result)
- result = replace(',', ' ' + prefix + ' ', result)
- if item == 'hostname':
- name = result
- elif item == 'network' and 'network' in self.base:
- result = self.base['network']
- if result != '':
- if '=' in prefix:
- concat = ''
- result = prefix + concat + result
- return result
- def getServerParse(self, result):
- if '{$' in result:
- param = {}
- if self.param != '':
- if 'http://' not in self.param:
- self.param = 'http://shemic.com/?' + self.param;
- if '^' in self.param:
- self.param = replace('^', '&', self.param)
- parse = urlparse.urlparse(self.param)
- param = urlparse.parse_qs(parse.query,True)
- search = re.compile(r'\{\$(.*?)\}')
- search = search.findall(result)
- for key in search:
- value = ''
- index = key
- if ':' in key:
- arr = key.split(':');
- index = arr[0]
- value = arr[1]
- if index in param:
- value = param[index][0]
- if value == '':
- print 'please set param value:' + index
- sys.exit()
- else:
- result = replace('{$'+key+'}', value, result)
- return result
- class Container(object):
- def run(self, method, command, bg):
- command = 'container.exec ' + command
- shell(command, True, bg)
- return command
- def show(self, name=''):
- print shell('container.show ' + name)
- def config(self):
- config = {
- 'port' : '-p'
- ,'volumes' : '-v'
- ,'environment' : '-e'
- ,'link' : '--link'
- ,'volumes_from' : '--volumes-from'
- ,'command' : ''
- ,'entrypoint' : '--entrypoint'
- ,'network' : '--net='
- ,'host' : '--add-host'
- ,'root' : '--privileged='
- ,'memory' : '--memory='
- ,'expose' : '--expose',
- }
- return config
- def drop(self):
- shell('container.drop', bg=True)
- def stop(self, name):
- shell('container.stop ' + name, bg=True)
- def logs(self, name):
- shell('container.logs ' + name, True)
- def inspect(self, name):
- shell('container.inspect ' + name, True)
- def restart(self, name):
- shell('container.restart ' + name, bg=True)
- def delete(self, name=''):
- if name != '':
- print 'rm ' + name + ', please wait...'
- if self.check(name) == 1:
- shell('container.rm ' + name, bg=True)
- else:
- shell('container.rm', bg=True)
-
- def check(self, name):
- result = int(popen('docker ps -a | grep '+name+' | wc -l'))
- if result != 0:
- return 1
- else:
- return 0
- def network(self, config):
- if 'network' in config:
- result = int(popen('docker network ls | grep ' + config['network'] + ' | wc -l'))
- if result == 0:
- shell('container.network ' + config['network'], True)
- def save(self, File, tar, name, backup):
- if File.exists(tar) == True:
- now = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
- old = replace('.tar', '.' + now + '.tar', tar)
- File.rename(tar, old)
- popen('docker commit -p ' + name + ' ' + backup)
- popen('docker save ' + backup + ' > ' + tar, True)
- def load(self, tar, name):
- popen('docker load < ' + tar, True)
- self.delete(name)
- class Image(object):
- def push(self, me, hub):
- if self.check(me) == 1:
- command = 'image.push ' + me + ' ' + hub
- print command
- shell(command, bg=True)
- def show(self):
- print shell('image.show')
- def drop(self):
- shell('image.drop', bg=True)
- def delete(self):
- shell('image.rm', bg=True)
- def build(self, core, path, name):
- file = path + 'conf/docker/' + name + '/'
- name = core['dockerme'] + '/' + name
- shell('image.build ' + name + ' ' + file, True)
- def check(self, name):
- result = int(popen('docker images | grep '+name+' | wc -l'))
- if result != 0:
- return 1
- else:
- return 0
- def install(self, config, library, key):
- pull = 'docker pull';
- for item in config:
- if config[item]['image'] == key:
- command = pull + ' ' + library + config[item]['image']
- popen(command, True)
- print 'finished'
- class Alias(object):
- def delete(self, path, config, name):
- return
- result = self.get(path, config, name)
- for key in result:
- action = self.action(name, key)
- popen('rm -rf ' + action[1], bg=True)
- popen('rm -rf ' + action[2], bg=True)
- def add(self, path, config, name, content, File, type):
- result = self.get(path, config, name)
- for key in result:
- action = self.action(name, key)
- content = '#!/usr/bin/env sh \nset -e\n'
- if type != 'call':
- content = content + self.define(name) + \
- 'else\n' + \
- 'docker exec -it ' + name + ' ' + action[0] + ' $@\n' + \
- 'fi'
- else:
- content = content + ' $@'
- File.write(action[1], content)
- popen('ln -sf ' + action[1] + ' ' + action[2])
- def define(self, name):
- conf = ['logs', 'inspect', 'restart', 'stop', 'rm', 'run', 'show']
- result = ''
- container = name
- arr = name.split('-');
- prefix = arr[0]
- del arr[0]
- name = '-'.join(arr)
- name = prefix + ' ' + name
- for key in conf:
- control = 'elif'
- shell = 'dever ' + key + ' ' + name + '\n'
- if key == 'logs':
- control = 'if'
- result = result + control + ' [ "$1" = "'+key+'" ];then\n' + shell
- return result
- def get(self, path, config, name):
- self.path = path + 'data/alias/'
- result = []
- default = 'sh->' + name
- if 'alias' in config:
- config['alias'] = config['alias'] + ',' + default
- if ',' in config['alias']:
- result = config['alias'].split(',');
- else:
- result = [config['alias']]
- else:
- result = [default]
- return result
- def action(self, name, key):
- file = key
- if '->' in key:
- temp = key.split('->')
- key = temp[0]
- file = temp[1]
- link = '/usr/bin/' + file
- file = self.path + file
- return [key, file, link]
- class File(object):
- def write(self, file, content):
- handle = open(file, 'w')
- handle.write(content)
- handle.close()
- popen('chmod +x ' + file)
- def read(self, path, name):
- handle = open(path + name, 'r')
- content = handle.read()
- handle.close()
- return content
- def path(self):
- return os.path.split(os.path.realpath(__file__))[0] + '/'
- def exists(self, name):
- return os.path.exists(name)
- def rename(self, old, new):
- return os.rename(old, new)
- def remove(self, file):
- return os.remove(file)
- def mkdir(self, path):
- if self.exists(path) == False:
- os.mkdir(path)
- def shell(command, sub=False, bg=False):
- global PATH
- shell = PATH + 'shell/' + command.replace('.', '/', 1)
- return popen(shell, sub, bg)
- def popen(command, sub=False, bg=False):
- string = command
- if bg == True:
- command = command + ' 1>/dev/null 2>&1 &'
- if sub == False:
- process = os.popen(command)
- output = process.read()
- process.close()
- return output
- else:
- popen = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
- output = ''
- print string
- while True:
- output = popen.stdout.readline()
- print output
- if popen.poll() is not None:
- break
- return output
- def install(soft):
- print 'install ' + soft + '...'
- if soft == 'docker':
- shell('install.docker', True)
- else:
- shell('install.package ' + soft, True)
- def isset(v):
- try :
- type(eval(v))
- except :
- return 0
- else :
- return 1
- def check(soft):
- result = int(popen('which '+soft+' | wc -l'))
- if result != 0:
- return 1
- else:
- install(soft)
- return 0
- def replace(old, new, string):
- if old in string:
- string = string.replace(old, new)
- return string
- Dever()
|