def kill(config, container, *args, **kwargs): ''' Kill a running container :type container: string :param container: The container id to kill :rtype: dict :returns: boolean ''' err = "Unknown" client = _get_client(config) try: dcontainer = _get_container_infos(config, container)['Id'] if is_running(config, dcontainer): client.kill(dcontainer) if not is_running(config, dcontainer): print "Container killed." return True else: print "Container not running." return True except Exception as e: err = e utils.error("Unable to kill the container: %s"%err) return False
def restart_app(self, config, appname, app_dict): if boot2docker.has(): boot2docker.run(config, appname) config["docker_sock"] = "tcp://%s:2375"%(boot2docker.ip(config,appname)) config["chroot"] = os.path.join("/mnt/host",config.get("chroot","")) config["hosts_table"] = app_dict.get("hosts_table",{}) app = {} for hostname in app_dict.get("hosts",{}): for state in app_dict["hosts"][hostname]: if state == "linux.docker.deploy": for container in app_dict["hosts"][hostname][state]: container_name = "%s-%s-%s"%(appname,hostname,container) containers = ([container_name] if not app_dict["hosts"][hostname][state][container].get("count") else ["%s_%s"%(container_name,i) for i in range(1,int(app_dict["hosts"][hostname][state][container]["count"])+1)]) for cname in containers: if dockervisops.restart(config, cname) is True: app[cname] = dockervisops.get_container_infos(config,cname) print "Container %s restarted"%cname else: utils.error("Unable to restart container %s"%container_name) dockervisops.generate_hosts(config, app) print "App %s restarted."%appname
def restart(config, container, timeout=10, *args, **kwargs): ''' Restart a running container :type container: string :param container: The container id to restart :type timout: int :param timeout: Wait for a timeout to let the container exit gracefully before killing it :rtype: dict :returns: boolean ''' err = "Unknown" client = _get_client(config) try: dcontainer = _get_container_infos(config, container)['Id'] client.restart(dcontainer, timeout=timeout) if is_running(config, dcontainer): print "Container restarted." return True except Exception as e: err = e if stop(config, container, timeout): ret = start(config, container) if ret: return True utils.error("Unable to restart the container: %s"%err) return False
def get_containers(config, all=True, trunc=False, since=None, before=None, limit=-1, *args, **kwargs): ''' Get a list of mappings representing all containers all Return all containers trunc Set it to True to have the short ID Returns a mapping of containers ''' err = "Unknown" client = _get_client(config) try: ret = client.containers(all=all, trunc=trunc, since=since, before=before, limit=limit) return ret except Exception as e: err = e utils.error("Unable to list Docker containers: %s"%err) return None
def run_stack(config, app_dict, force=True): config["appname"] = utils.user_param(config, "Enter app name",config["appname"]) config["dirs"] = { "containers": os.path.join(config["config_path"],"docker","containers"), "boot2docker": os.path.join(config["config_path"],"docker","boot2docker"), } for d in config["dirs"]: if not os.path.exists(config["dirs"][d]): os.makedirs(config["dirs"][d]) if boot2docker.has(): print "Starting Boot2docker ... (this may take a while)" if not os.path.isfile(os.path.join(config["dirs"]["boot2docker"],"boot2docker.iso")): utils.download(config["boot2docker_iso"],os.path.join(config["dirs"]["boot2docker"],"boot2docker.iso")) if not boot2docker.gen_config(config, config["appname"]): utils.error("Unable to generate boot2docker configuration") return False boot2docker.delete(config, config["appname"]) boot2docker.init(config, config["appname"]) boot2docker.mount(config["appname"], [{ "volume": "visops_root", "hostpath": "/", },{ "volume": "visops_containers", "hostpath": config["dirs"]["containers"], }]) if boot2docker.run(config, config["appname"]): print "Boot2docker successfully running!" else: utils.error("Unable to run Boot2docker.") config["chroot"] = os.path.join("/mnt/host",config.get("chroot","")) config["docker_sock"] = "tcp://%s:2375"%(boot2docker.ip(config,config["appname"])) config["hosts_table"] = app_dict.get("hosts_table",{}) actions = {} for hostname in app_dict.get("hosts",{}): actions[hostname] = {} for state in app_dict["hosts"][hostname]: if state == "linux.docker.deploy": for container in app_dict["hosts"][hostname][state]: app_dict["hosts"][hostname][state][container]["hostname"] = app_dict["hosts"][hostname][state][container].get("container") app_dict["hosts"][hostname][state][container]["container"] = "%s-%s-%s"%(config["appname"], hostname, app_dict["hosts"][hostname][state][container].get("container","")) actions[hostname][container] = (dockervisops.preproc_deploy(config, config["appname"], hostname, app_dict["hosts"][hostname][state][container], "deploy")) config["actions"] = actions actions = dockervisops.render_all(config, actions) config["actions"] = actions app = {} for hostname in actions: for container in actions[hostname]: app.update(dockervisops.deploy(config, actions[hostname][container])) dockervisops.generate_hosts(config, app) #save user input parameter to app_dict utils.persist_app(actions,app_dict)
def login(config, username=None, password=None, email=None, url=None, client=None, *args, **kwargs): ''' Wrapper to the docker.py login method ''' try: c = (_get_client(config) if not client else client) lg = c.login(username, password, email, url) print "%s logged to %s"%(username,(url if url else "default hub")) except Exception as e: utils.error("%s can't login to repo %s: %s"%(username,(url if url else "default repo"),e)) return False return True
def _create_files_volumes(config, state_params, exec_params): volumes = [] for f in state_params.get("files",[]): path = f.get("key") if not path: utils.error("Unable to read config file path.") continue print "Configuration file found: %s."%path dir_path = os.path.join(config["config_path"],"docker","files",state_params["container"]) host_path = os.path.join(dir_path,("%s"%path).replace('/','-')) volumes.append({"key":host_path,"value":path}) exec_params["volumes"] = exec_params.get("volumes",[])+volumes return exec_params
def init(config, appid): delete(config,appid) try: env = os.environ.copy() env.update({"BOOT2DOCKER_PROFILE":os.path.join(config["dirs"]["boot2docker"],"%s.cfg"%appid)}) out, err = subprocess.Popen(["boot2docker","init"], env=env, stdout=PIPE,stderr=PIPE).communicate() except Exception as e: return False if err: utils.error(err) return False return True
def mount(name,volumes): ''' volumes: [{ "volume": "root", "hostpath": "/" }, ... ] ''' for vol in volumes: try: out, err = subprocess.Popen(["VBoxManage","sharedfolder","add",name,"--name",vol["volume"],"--hostpath",vol["hostpath"]], stdout=PIPE,stderr=PIPE).communicate() except Exception as e: utils.error(e) return False return True
def start_all(config, containers=None, binds=None, ports=None, port_bindings=None, lxc_conf=None, publish_all_ports=None, links=None, privileged=False, *args, **kwargs): failure = False containers_out = [] for container in containers: started = start(config, container=container, binds=binds, ports=ports, port_bindings=port_bindings, lxc_conf=lxc_conf, publish_all_ports=publish_all_ports, links=links, privileged=privileged, *args, **kwargs) if is_running(config, container) and started: print "Container started, id: %s"%started.get("Id") containers_out.append(started) else: failure = True utils.error("Unable to run container: %s - can't start"%container) return containers_out, failure
def pull(config, repo, tag=None, username=None, password=None, email=None, *args, **kwargs): ''' Pulls an repo from any registry. See above documentation for how to configure authenticated access. :type repo: string :param repo: The repository to pull. \ [registryurl://]REPOSITORY_NAME eg:: index.docker.io:MyRepo superaddress.cdn:MyRepo MyRepo :type tag: string :param tag: The specific tag to pull :rtype: dict :returns: the repo details ''' err = "Unknown" client = _get_client(config) try: if username: url = repo.split(":") url = (url[0] if len(url) > 1 else None) if not login(config,username,password,email,url): raise Exception("Can't login") print "Pulling repository %s ... (This may take a while)"%repo ret = client.pull(repo, tag=tag) if ret: logs, infos = _parse_image_multilogs_string(config, ret, repo) if infos and infos.get('Id', None): repotag = repo if tag: repotag = '{0}:{1}'.format(repo, tag) print 'Repo {0} was pulled ({1})'.format(repotag, infos['Id']) return infos, False else: err = _pull_assemble_error_status(logs) except Exception as e: err = e utils.error("An error has occured pulling repo %s: %s"%(repo,err)) return None, True
def remove_container(config, container=None, force=True, v=False, *args, **kwargs): ''' Removes a container from a docker installation container Container id to remove force By default, remove a running container, set this to notremove it unconditionally v verbose mode Return boolean ''' err = "Unknown" client = _get_client(config) dcontainer = None try: try: dcontainer = _get_container_infos(config, container)['Id'] except Exception: # print "Container not existing." return True else: if not dcontainer: return True if is_running(config, dcontainer): if not force: utils.error("Container running, won't remove it.") return False else: kill(config, dcontainer) client.remove_container(dcontainer, v=v) try: infos = _get_container_infos(config, dcontainer) if not infos: return True except Exception: # print "Container has been successfully removed." return True except Exception as e: err = e utils.error("Unable to remove container: %s"%err) return False
def get_images(config, name=None, quiet=False, all=True, *args, **kwargs): ''' List docker images :type name: string :param name: A repository name to filter on :type quiet: boolean :param quiet: Only show image ids :type all: boolean :param all: Show all images :rtype: dict :returns: the images ''' err = "Unknown" client = _get_client(config) try: infos = client.images(name=name, quiet=quiet, all=all) for i in range(len(infos)): inf = _set_id(infos[i]) try: inf['Human_Size'] = _sizeof_fmt(int(inf['Size'])) except ValueError: pass try: ts = int(inf['Created']) dts = datetime.datetime.fromtimestamp(ts) inf['Human_IsoCreated'] = dts.isoformat() inf['Human_Created'] = dts.strftime( '%Y-%m-%d %H:%M:%S') except Exception: pass try: inf['Human_VirtualSize'] = ( _sizeof_fmt(int(inf['VirtualSize']))) except ValueError: pass return infos except Exception as e: err = e utils.error("Unable to list Docker images: %s"%err) return None
def generate_hosts(config, app): ''' app: { "container id": continer details ... } ''' # hosts = {app[container]["NetworkSettings"]["IPAddress"]:app[container]["Name"].replace('/','') for container in app} hosts = {} for container in app: hosts[app[container]["NetworkSettings"]["IPAddress"]] = [app[container]["Name"].replace('/','')] for container in app: path = (app[container]["HostsPath"] if boot2docker.has() is not True else os.path.join(config["config_path"],"docker","containers",app[container]["Id"],"hosts")) try: with open(path, 'r+') as f: for host in hosts: f.write("%s\t%s\n"%(host," ".join(hosts[host]))) except Exception as e: utils.error(e)
def create_files(config, container, files=[]): failure = False for f in files: path = f.get("key") if not path: failure = True utils.error("Unable to read config file path.") continue dir_path = os.path.join(config["config_path"],"docker","files",container) if not os.path.exists(dir_path): os.makedirs(dir_path) host_path = os.path.join(dir_path,("%s"%path).replace('/','-')) content = f.get("value","") try: with open(host_path, 'w') as f: f.write(content) print "Configuration file %s created: %s."%(path,host_path) except Exception as e: failure = True utils.error("Unable to store configuration file %s: %s"%(host_path,e)) return None, failure
def preproc_deploy(config, appname, hostname, state, act): if "container" not in state: utils.error("Container name missing") return {} elif "image" not in state: utils.error("Image name missing") return {} print "--> Preparing to run container(s) %s from image %s ..."%(state["container"],state["image"]) actions = {} for action in _deploy.get('actions',{}).get(act,[]): params = {} for param in _deploy.get('attr',{}).get(action,{}): if not state.get(param): continue if hasattr(_deploy['attr'][action][param], '__call__'): params.update(_deploy['attr'][action][param](config,state,params)) elif type(state[param]) is list: params[_deploy['attr'][action][param]] = params.get(_deploy['attr'][action][param],[])+state[param] elif type(state[param]) is dict: params[_deploy['attr'][action][param]] = dict(params.get(_deploy['attr'][action][param],{}).items() +state[param].items()) else: params[_deploy['attr'][action][param]] = state[param] if hasattr(eval(action), '__call__'): if action in _deploy.get("convert",{}): actions[action] = _deploy["convert"][action](config, appname, hostname, params) else: actions[action] = params.copy() else: utils.error("Action not found: %s"%action) return actions
def start(config, container, binds=None, ports=None, port_bindings=None, lxc_conf=None, publish_all_ports=None, links=None, privileged=False, *args, **kwargs): ''' Start the specified container container Container id Returns boolean ''' if not binds: binds = {} if not ports: ports = {} err = "Unknown" client = _get_client(config) try: dcontainer = _get_container_infos(config, container)['Id'] if not is_running(config, container): bindings = None if port_bindings is not None: print "Binding container ports ..." bindings = {} for k, v in port_bindings.iteritems(): bindings[k] = (v.get('HostIp', ''), v['HostPort']) client.start(dcontainer, binds=binds, port_bindings=bindings, lxc_conf=lxc_conf, publish_all_ports=publish_all_ports, links=links, privileged=privileged) if is_running(config, dcontainer): print "Container has been started." return _get_container_infos(config, container) else: print "Container is already started." return _get_container_infos(config, container) except Exception as e: err = e utils.error("Unable to start your container: %s"%err) return None
def terminate_app(self, config, appname, app_dict): if boot2docker.has(): config["docker_sock"] = "tcp://%s:2375"%(boot2docker.ip(config,appname)) for hostname in app_dict.get("hosts",{}): for state in app_dict["hosts"][hostname]: if state == "linux.docker.deploy": for container in app_dict["hosts"][hostname][state]: container_name = "%s-%s-%s"%(appname,hostname,container) containers = ([container_name] if not app_dict["hosts"][hostname][state][container].get("count") else ["%s_%s"%(container_name,i) for i in range(1,int(app_dict["hosts"][hostname][state][container]["count"])+1)]) print containers for cname in containers: if dockervisops.remove_container(config, cname) is True: print "Container %s removed"%cname else: utils.error("Unable to remove container %s"%cname) if boot2docker.has(): boot2docker.delete(config, appname) print "App %s terminated."%appname
def _convert_running(config, appname, hostname, addin): addin["port_bindings"] = _replace_params(config, hostname, addin,"port_bindings") addin["volumes"] = _replace_params(config, hostname, addin,"volumes") addin["mem_limit"] = _replace_params(config, hostname, addin,"mem_limit") addin["cpu_shares"] = _replace_params(config, hostname, addin,"cpu_shares") addin["count"] = _replace_params(config, hostname, addin,"count") if addin.get("port_bindings"): ports = [] pb = {} for item in addin["port_bindings"]: key = item.get("key",None) value = item.get("value",None) if not key: continue # get user input ui = utils.user_param(config, "Update port binding for %s (host=container)"%addin["container"], ("%s=%s"%(key,value) if key not in config["port_bindings"][hostname].get(addin["container"],{}) else "%s=%s"%((key if key else ""),(value if value else "")))) # parse result if not ui: config["port_bindings"][hostname][addin["container"]][key] = value continue ui = ui.split("=") if len(ui) != 2: utils.error("Wrong port binding syntax") continue key, value = ui[1], ui[0] # persist config["port_bindings"][hostname][addin["container"]][key] = value if not key or not value: continue v = value.split(":") pb[key] = ({ "HostIp": v[0], "HostPort": v[1] } if len(v) == 2 else { "HostIp": "0.0.0.0", "HostPort": v[0] }) ports.append(key) addin.pop("port_bindings") if pb and ports: addin["port_bindings"] = pb addin["ports"] = ports if addin.get("volumes"): volumes = [] binds = {} vol = addin.get("volumes",{}) for item in vol: key = item.get("key") value = item.get("value") if not key: continue # get user input ui = utils.user_param(config, "Update mount point for %s"%addin["container"], ("%s=%s"%(key,value) if key not in config["volumes"][hostname].get(addin["container"],{}) else "%s=%s"%((key if key else ""),(value if value else "")))) # parse result if not ui: config["volumes"][hostname][addin["container"]][key] = value continue ui = ui.split("=") if len(ui) != 2: utils.error("Wrong volume syntax") continue key, value = ui[0], ui[1] if config.get("chroot"): key = os.path.join(config["chroot"],appname,hostname,addin["container"],key) # persist config["volumes"][hostname][addin["container"]][key] = value mp = value.split(":") ro = (True if (len(mp) == 2 and mp[1] == "ro") else False) value = mp[0] volumes.append(value) binds[key] = { 'bind': value, 'ro': ro } addin.pop("volumes") if volumes and binds: addin["volumes"] = volumes addin["binds"] = binds if addin.get("environment"): env = {} for item in addin["environment"]: key = item.get("key","") value = item.get("value","") if not key: continue env[key] = value addin.pop("environment") addin["environment"] = env if addin.get("links"): links = {} for item in addin["links"]: key = item.get("key","") value = item.get("value","") if not key or not value: continue links[key] = value addin.pop("links") addin["links"] = links if addin.get("cpu_shares"): # get user input ui = utils.user_param(config, "Update CPU shares for %s"%addin["container"], ("%s"%(addin.get("cpu_shares")) if addin["container"] not in config["cpu_shares"][hostname] else addin.get("cpu_shares"))) # parse result addin["cpu_shares"] = ui # persist config["cpu_shares"][hostname][addin["container"]] = ui if addin.get("mem_limit"): # get user input ui = utils.user_param(config, "Update memory limit for %s"%addin["container"], ("%s"%(addin.get("mem_limit")) if addin["container"] not in config["mem_limit"][hostname] else addin.get("mem_limit"))) # parse result mem = ui # persist config["cpu_shares"][hostname][addin["container"]] = ui mem_eq={ 'b': lambda x: x, 'k': lambda x: x << 10, 'm': lambda x: x << 20, 'g': lambda x: x << 30, 't': lambda x: x << 40, } addin["mem_limit"] = (mem_eq[mem[-1].lower()](int(mem[:-1])) if mem[-1].lower() in mem_eq else int(mem)) if not addin.get("count"): addin["containers"] = [addin["container"]] else: # get user input ui = utils.user_param(config, "Update number of containers for %s"%(addin["container"]), addin["count"]) # parse result addin["count"] = ui # persist config["count"][hostname][addin["container"]] = ui addin["containers"] = [] count = int(addin["count"]) i=0 while i < count: addin["containers"].append("%s_%s"%(addin["container"],i+1)) i += 1 addin.pop("container") return addin
def create_container(config, image, command=None, hostname=None, user=None, detach=True, entrypoint=None, stdin_open=False, tty=False, mem_limit=0, cpu_shares=None, ports=None, environment=None, dns=None, volumes=None, volumes_from=None, name=None, *args, **kwargs): ''' Create a new container image image to create the container from command command to execute while starting hostname hostname of the container user user to run docker as detach daemon mode entrypoint entrypoint to the container stdin_open let stdin open tty attach ttys mem_limit: memory size limit cpu_shares: cpu shares authorized ports ports redirections ({'222': {}}) environment environment variable mapping ({'foo':'BAR'}) dns list of DNS servers volumes list of volumes mapping:: (['/mountpoint/in/container:/guest/foo', '/same/path/mounted/point']) volumes_from container to get volumes definition from name name given to container Returns: created container / None ''' err = "Unknown" client = _get_client(config) try: img_infos = _get_image_infos(config, image) mountpoints = {} binds = {} # create empty mountpoints for them to be # editable # either we have a list of guest or host:guest if isinstance(volumes, list): for mountpoint in volumes: mounted = mountpoint if ':' in mountpoint: parts = mountpoint.split(':') mountpoint = parts[1] mounted = parts[0] mountpoints[mountpoint] = {} binds[mounted] = mountpoint info = _set_id(client.create_container( image=image, command=command, hostname=hostname, user=user, entrypoint=entrypoint, detach=detach, stdin_open=stdin_open, tty=tty, mem_limit=mem_limit, ports=ports, environment=environment, dns=dns, volumes=mountpoints, volumes_from=volumes_from, name=name, cpu_shares=cpu_shares )) print "Container '%s' created."%info['Id'] return info except Exception as e: err = e utils.error("Unable to create your container: %s"%err) return None
def action(*args, **kwargs): try: get_images(args[0]) except Exception: utils.error("Unable to find Docker client.\nPlease, ensure Docker is correcly setup.") return func(*args, **kwargs)
def running(config, containers, image, tag=None, entrypoint=None, command=None, environment=None, ports=None, volumes=None, mem_limit=0, cpu_shares=None, binds=None, publish_all_ports=False, links=None, port_bindings=None, force=True, hostname=None, *args, **kwargs): ''' Ensure that a container is running. (`docker inspect`) containers name of the containers to start image name of the image to start the container from entrypoint Entrypoint of the container command command to execute while starting environment environment variable mapping ({'foo':'BAR'}) ports List of ports definitions, either: - a port to map - a mapping of mapping portInHost : PortInContainer volumes List of volumes mem_limit: memory size limit cpu_shares: cpu shares authorized binds like -v of docker run command publish_all_ports links Link several container together port_bindings List of ports to expose on host system - a mapping port's guest, hostname's host and port's host. Returns Container Id ''' if not containers: utils.warning("No container specified") return [], True if ports and port_bindings: (ports,port_bindings) = _gen_ports(ports,port_bindings,len(containers)) if not ports or not port_bindings: utils.error("Unable to generate port bindings (is there enough space between each allocation required?)") return [], True containers_out = [] failure = False if tag: image = "%s:%s"%(image,tag) for container in containers: port = (ports.pop() if ports else None) port_binding = (port_bindings.pop() if port_bindings else None) ret = installed(config, container,image,entrypoint=entrypoint,command=command,environment=environment,ports=port, volumes=volumes,mem_limit=mem_limit,cpu_shares=cpu_shares,force=force,hostname=hostname) if ret: started = start(config, container, binds=binds, port_bindings=port_binding, publish_all_ports=publish_all_ports, links=links) if is_running(config, container) and started: print "Container started, id: %s"%started.get("Id") containers_out.append(started) else: failure = True utils.error("Unable to run container: %s - can't start"%container) else: failure = True utils.error("Unable to run container: %s - can't install"%container) return containers_out, failure
def installed(config, name, image, entrypoint=None, command=None, hostname=None, user=None, detach=True, stdin_open=False, tty=False, mem_limit=0, cpu_shares=None, ports=None, environment=None, dns=None, volumes=None, volumes_from=None, force=True, *args, **kwargs): ''' Ensure that a container with the given name exists; if not, build a new container from the specified image. (`docker run`) name Name for the container image Image from which to build this container entrypoint Entrypoint of the container command command to execute while starting hostname hostname of the container user user to run docker as detach daemon mode entrypoint entrypoint to the container stdin_open let stdin open tty attach ttys mem_limit: memory size limit cpu_shares: cpu shares authorized ports ports redirections ({'222': {}}) environment environment variable mapping ({'foo':'BAR'}) dns list of DNS servers ports List of ports definitions, either: - a port to map - a mapping of mapping portInHost : PortInContainer volumes List of volumes volumes_from Returns container .. note:: This command does not verify that the named container is running the specified image. ''' iinfos = _get_image_infos(config, image) if not iinfos: utils.error("Image not found.") return None cinfos = _get_container_infos(config, name) force = (config["force"] if config.get("force") != None else force) if cinfos and force: remove_container(config, container=name,force=True) print "Old container removed." elif cinfos and (not force): print "Container found: %s."%cinfos.get("Id") return cinfos dports, dvolumes, denvironment, de = {}, [], {}, {} if not ports: ports = [] if not volumes: volumes = [] if isinstance(environment, dict): print "Setting environment ..." for k in environment: denvironment[u'%s' % k] = u'%s' % environment[k] if isinstance(environment, list): print "Setting environment ..." for p in environment: if isinstance(p, dict): for k in p: denvironment[u'%s' % k] = u'%s' % p[k] if ports: print "Setting ports mapping ..." for p in ports: if not isinstance(p, dict): dports[str(p)] = {} else: for k in p: dports[str(p)] = {} if volumes: print "Setting volumes ..." for p in volumes: vals = [] if not isinstance(p, dict): vals.append('%s' % p) else: for k in p: vals.append('{0}:{1}'.format(k, p[k])) dvolumes.extend(vals) container = create_container( config, image=image, command=command, entrypoint=entrypoint, hostname=hostname, user=user, detach=detach, stdin_open=stdin_open, tty=tty, mem_limit=mem_limit, ports=dports, environment=denvironment, dns=dns, volumes=dvolumes, volumes_from=volumes_from, name=name) if container: print "Container created, id: %s"%(container.get("Id")) else: utils.error("Couldn't create container.") return container