def post(self, request, rid, command): with self._handle_exception(request): if (not docker_status()): e_msg = ('Docker service is not running. Start it and try ' 'again.') handle_exception(Exception(e_msg), request) try: rockon = RockOn.objects.get(id=rid) except: e_msg = ('Rock-on(%d) does not exist' % rid) handle_exception(Exception(e_msg), request) try: dname = 'ztask-daemon' e_msg = ('ztask daemon is not running and could not be started') o, e, rc = superctl(dname, 'status') if (rc == 1): superctl(dname, 'restart') time.sleep(5) except Exception, e: logger.exception(e) handle_exception(Exception(e_msg), request) finally:
def get_queryset(self, *args, **kwargs): if (docker_status()): pending_rids = {} failed_rids = {} for t in Task.objects.filter( function_name__regex='rockon_helpers'): rid = pickle.loads(t.args)[0] if (t.retry_count == 0 and t.failed is not None): failed_rids[rid] = t else: pending_rids[rid] = t #Remove old failed attempts #@todo: we should prune all failed tasks of the past, not here though. for rid in pending_rids.keys(): if (rid in failed_rids): pt = pending_rids[rid] ft = failed_rids[rid] if (failed_rids[rid].created > pending_rids[rid].created): #this should never be the case. pending tasks either #succeed and get deleted or they are marked failed. msg = ('Found a failed Task(%s) in the future of a ' 'pending Task(%s).' % (ft.uuid, pt.uuid)) handle_exception(Exception(msg), self.request) failed_rids[rid].delete() logger.debug('deleted failed task') del failed_rids[rid] for ro in RockOn.objects.all(): if (ro.state == 'installed'): # update current running status of installed rockons. if (ro.id not in pending_rids): ro.status = rockon_status(ro.name) elif (re.search('pending', ro.state) is not None): if (ro.id in failed_rids): #we update the status on behalf of the task runner func_name = t.function_name.split('.')[-1] ro.state = '%s_failed' % func_name elif (ro.id not in pending_rids): logger.error( 'Rockon(%s) is in pending state but there ' 'is no pending or failed task for it. ' % ro.name) ro.state = '%s_failed' % ro.state.split('_')[1] else: logger.debug('Rockon(%s) is in pending state' % ro.name) elif (ro.state == 'uninstall_failed'): ro.state = 'installed' ro.save() return RockOn.objects.filter().order_by('name')
def get_queryset(self, *args, **kwargs): if docker_status(): pending_rids = {} failed_rids = {} for t in Task.objects.filter( function_name__regex="rockon_helpers"): # noqa E501 rid = pickle.loads(t.args)[0] if t.retry_count == 0 and t.failed is not None: failed_rids[rid] = t else: pending_rids[rid] = t # Remove old failed attempts @todo: we should prune all failed # tasks of the past, not here though. for rid in pending_rids.keys(): if rid in failed_rids: pt = pending_rids[rid] ft = failed_rids[rid] if failed_rids[rid].created > pending_rids[rid].created: # this should never be the case. pending tasks either # succeed and get deleted or they are marked failed. msg = ("Found a failed Task ({}) in the future of a " "pending Task ({}).").format(ft.uuid, pt.uuid) handle_exception(Exception(msg), self.request) failed_rids[rid].delete() del failed_rids[rid] for ro in RockOn.objects.all(): if ro.state == "installed": # update current running status of installed rockons. if ro.id not in pending_rids: ro.status = rockon_status(ro.name) elif re.search("pending", ro.state) is not None: if ro.id in failed_rids: # we update the status on behalf of the task runner func_name = t.function_name.split(".")[-1] ro.state = "%s_failed" % func_name elif ro.id not in pending_rids: logger.error(("Rockon ({}) is in pending state but " "there is no pending or failed task " "for it.").format(ro.name)) ro.state = "%s_failed" % ro.state.split("_")[1] else: logger.debug( ("Rockon ({}) is in pending state.").format( ro.name)) elif ro.state == "uninstall_failed": ro.state = "installed" ro.save() return RockOn.objects.filter().order_by("name")
def get_queryset(self, *args, **kwargs): if (docker_status()): pending_rids = {} failed_rids = {} for t in Task.objects.filter(function_name__regex='rockon_helpers'): rid = pickle.loads(t.args)[0] if (t.retry_count == 0 and t.failed is not None): failed_rids[rid] = t else: pending_rids[rid] = t #Remove old failed attempts #@todo: we should prune all failed tasks of the past, not here though. for rid in pending_rids.keys(): if (rid in failed_rids): pt = pending_rids[rid] ft = failed_rids[rid] if (failed_rids[rid].created > pending_rids[rid].created): #this should never be the case. pending tasks either #succeed and get deleted or they are marked failed. msg = ('Found a failed Task(%s) in the future of a ' 'pending Task(%s).' % (ft.uuid, pt.uuid)) handle_exception(Exception(msg), self.request) failed_rids[rid].delete() logger.debug('deleted failed task') del failed_rids[rid] for ro in RockOn.objects.all(): if (ro.state == 'installed'): # update current running status of installed rockons. if (ro.id not in pending_rids): ro.status = rockon_status(ro.name) elif (re.search('pending', ro.state) is not None): if (ro.id in failed_rids): #we update the status on behalf of the task runner func_name = t.function_name.split('.')[-1] ro.state = '%s_failed' % func_name elif (ro.id not in pending_rids): logger.error('Rockon(%s) is in pending state but there ' 'is no pending or failed task for it. ' % ro.name) ro.state = '%s_failed' % ro.state.split('_')[1] else: logger.debug('Rockon(%s) is in pending state' % ro.name) elif (ro.state == 'uninstall_failed'): ro.state = 'installed' ro.save() return RockOn.objects.filter().order_by('name')
def get_queryset(self, *args, **kwargs): if docker_status(): pending_rids = {} failed_rids = {} for t in Task.objects.filter(function_name__regex="rockon_helpers"): rid = pickle.loads(t.args)[0] if t.retry_count == 0 and t.failed is not None: failed_rids[rid] = t else: pending_rids[rid] = t # Remove old failed attempts # @todo: we should prune all failed tasks of the past, not here though. for rid in pending_rids.keys(): if rid in failed_rids: pt = pending_rids[rid] ft = failed_rids[rid] if failed_rids[rid].created > pending_rids[rid].created: # this should never be the case. pending tasks either # succeed and get deleted or they are marked failed. msg = "Found a failed Task(%s) in the future of a " "pending Task(%s)." % (ft.uuid, pt.uuid) handle_exception(Exception(msg), self.request) failed_rids[rid].delete() logger.debug("deleted failed task") del failed_rids[rid] for ro in RockOn.objects.all(): if ro.state == "installed": # update current running status of installed rockons. if ro.id not in pending_rids: ro.status = rockon_status(ro.name) elif re.search("pending", ro.state) is not None: if ro.id in failed_rids: # we update the status on behalf of the task runner func_name = t.function_name.split(".")[-1] ro.state = "%s_failed" % func_name elif ro.id not in pending_rids: logger.error( "Rockon(%s) is in pending state but there " "is no pending or failed task for it. " % ro.name ) ro.state = "%s_failed" % ro.state.split("_")[1] else: logger.debug("Rockon(%s) is in pending state" % ro.name) elif ro.state == "uninstall_failed": ro.state = "installed" ro.save() return RockOn.objects.filter().order_by("name")
def get_queryset(self, *args, **kwargs): if (docker_status()): pending_rids = [] for t in Task.objects.all(): pending_rids.append(pickle.loads(t.args)[0]) for ro in RockOn.objects.all(): if (ro.state == 'installed'): # update current running status of installed rockons. ro.status = rockon_status(ro.name) elif (re.search('pending', ro.state) is not None and ro.id not in pending_rids): # reset rockons to their previosu state if they are stuck # in a pending transition. if (re.search('uninstall', ro.state) is not None): ro.state = 'installed' else: ro.state = 'available' ro.save() return RockOn.objects.filter().order_by('-id')
def post(self, request, rid, command): with self._handle_exception(request): if (not docker_status()): e_msg = ('Docker service is not running. Start it and try ' 'again.') handle_exception(Exception(e_msg), request) try: rockon = RockOn.objects.get(id=rid) except: e_msg = ('Rock-on(%d) does not exist' % rid) handle_exception(Exception(e_msg), request) try: dname = 'ztask-daemon' e_msg = ('ztask daemon is not running and could not be ' 'started') o, e, rc = superctl(dname, 'status') if (rc == 1): superctl(dname, 'restart') time.sleep(5) except Exception as e: logger.exception(e) handle_exception(Exception(e_msg), request) finally: if (rc == 1): o, e, rc = superctl(dname, 'status') if (rc == 1): handle_exception(Exception(e_msg), request) if (command == 'install'): self._pending_check(request) share_map = request.data.get('shares', {}) port_map = request.data.get('ports', {}) cc_map = request.data.get('cc', {}) env_map = request.data.get('environment', {}) containers = DContainer.objects.filter(rockon=rockon) for co in containers: for sname in share_map.keys(): dest_dir = share_map[sname] if (not Share.objects.filter(name=sname).exists()): e_msg = ('Invalid Share(%s).' % sname) handle_exception(Exception(e_msg), request) if (DVolume.objects.filter( container=co, dest_dir=dest_dir).exists()): so = Share.objects.get(name=sname) vo = DVolume.objects.get(container=co, dest_dir=dest_dir) vo.share = so vo.save() # {'host_port' : 'container_port', ... } for p in port_map.keys(): if (DPort.objects.filter(hostp=p).exists()): dup_po = DPort.objects.get(hostp=p) if (dup_po.container.rockon.id != rockon.id): if (dup_po.container.rockon.state in ('installed', 'pending_install')): # cannot claim from a rock-on that's # installed. conf_ro = dup_po.container.rockon.name e_msg = ( 'Port(%s) belongs to another ' 'Rock-n(%s). Choose a different ' 'port. If you must choose the same ' 'port, uninstall %s first and try ' 'again.' % (p, conf_ro, conf_ro)) handle_exception(Exception(e_msg), request) # change the host port to next available. dup_po.hostp = self._next_available_default_hostp( dup_po.hostp) # noqa E501 dup_po.save() for co2 in DContainer.objects.filter(rockon=rockon): if (DPort.objects.filter( container=co2, containerp=port_map[p]).exists()): # found the container that needs this port. po = DPort.objects.get(container=co2, containerp=port_map[p]) po.hostp = p po.save() break for c in cc_map.keys(): if (not DCustomConfig.objects.filter(rockon=rockon, key=c).exists()): e_msg = ('Invalid custom config key(%s)' % c) handle_exception(Exception(e_msg), request) cco = DCustomConfig.objects.get(rockon=rockon, key=c) cco.val = cc_map[c] cco.save() for e in env_map.keys(): if (not DContainerEnv.objects.filter(container=co, key=e).exists()): e_msg = ('Invalid environment variabled(%s)' % e) handle_exception(Exception(e_msg), request) ceo = DContainerEnv.objects.get(container=co, key=e) ceo.val = env_map[e] ceo.save() install. async (rockon.id) rockon.state = 'pending_install' rockon.save() elif (command == 'uninstall'): self._pending_check(request) if (rockon.state != 'installed'): e_msg = ('Rock-on(%s) is not currently installed. Cannot ' 'uninstall it' % rockon.name) handle_exception(Exception(e_msg), request) if (rockon.status == 'started' or rockon.status == 'pending_start'): e_msg = ('Rock-on(%s) must be stopped before it can ' 'be uninstalled. Stop it and try again' % rockon.name) handle_exception(Exception(e_msg), request) uninstall. async (rockon.id) rockon.state = 'pending_uninstall' rockon.save() for co in DContainer.objects.filter(rockon=rockon): DVolume.objects.filter(container=co, uservol=True).delete() elif (command == 'update'): self._pending_check(request) if (rockon.state != 'installed'): e_msg = ('Rock-on(%s) is not currently installed. Cannot ' 'update it' % rockon.name) handle_exception(Exception(e_msg), request) if (rockon.status == 'started' or rockon.status == 'pending_start'): e_msg = ('Rock-on(%s) must be stopped before it can ' 'be updated. Stop it and try again' % rockon.name) handle_exception(Exception(e_msg), request) share_map = request.data.get('shares') for co in DContainer.objects.filter(rockon=rockon): for s in share_map.keys(): sname = share_map[s] if (not Share.objects.filter(name=sname).exists()): e_msg = ('Invalid Share(%s).' % sname) handle_exception(Exception(e_msg), request) so = Share.objects.get(name=sname) if (DVolume.objects.filter(container=co, share=so).exists()): e_msg = ('Share(%s) is already assigned to ' 'this Rock-on' % sname) handle_exception(Exception(e_msg), request) if (DVolume.objects.filter(container=co, dest_dir=s).exists()): e_msg = ('Directory(%s) is already mapped for ' 'this Rock-on' % s) handle_exception(Exception(e_msg), request) if (not s.startswith('/')): e_msg = ('Invalid Directory(%s). Must provide an ' 'absolute path. Eg: /data/media' % s) handle_exception(Exception(e_msg), request) do = DVolume(container=co, share=so, uservol=True, dest_dir=s) do.save() rockon.state = 'pending_update' rockon.save() update. async (rockon.id) elif (command == 'stop'): stop. async (rockon.id) rockon.status = 'pending_stop' rockon.save() elif (command == 'start'): start. async (rockon.id) rockon.status = 'pending_start' rockon.save() elif (command == 'state_update'): state = request.data.get('new_state') rockon.state = state rockon.save() elif (command == 'status_update'): status = request.data.get('new_status') rockon.status = status rockon.save() return Response(RockOnSerializer(rockon).data)
def post(self, request, command=None): with self._handle_exception(request): if (not docker_status()): e_msg = ('Rock-on service is not running. Start it and try ' 'again') handle_exception(Exception(e_msg), request) if (command == 'update'): rockons = self._get_available(request) for r in rockons: name = r r_d = rockons[r] ro_defaults = {'description': r_d['description'], 'website': r_d['website'], 'version': '1.0', 'state': 'available', 'status': 'stopped'} ro, created = RockOn.objects.get_or_create(name=name, defaults=ro_defaults) if (not created): ro.description = ro_defaults['description'] ro.website = ro_defaults['website'] ro.version = ro_defaults['version'] if ('ui' in r_d): ui_d = r_d['ui'] ro.link = ui_d['slug'] if ('https' in ui_d): ro.https = ui_d['https'] if ('icon' in r_d): ro.icon = r_d['icon'] if ('volume_add_support' in r_d): ro.volume_add_support = r_d['volume_add_support'] if ('more_info' in r_d): ro.more_info = r_d['more_info'] ro.save() containers = r_d['containers'] for c in containers: c_d = containers[c] io, created = DImage.objects.get_or_create(name=c_d['image'], defaults={'tag': 'latest', 'repo': 'na'}) co_defaults = {'rockon': ro, 'dimage': io, 'launch_order': c_d['launch_order'],} co, created = DContainer.objects.get_or_create(name=c, defaults=co_defaults) if (co.rockon.name != ro.name): e_msg = ('Container(%s) belongs to another ' 'Rock-On(%s). Update rolled back.' % (c, co.rockon.name)) handle_exception(Exception(e_msg), request) if (not created): co.dimage = io co.launch_order = co_defaults['launch_order'] co.save() ports = {} if ('ports' in containers[c]): ports = containers[c]['ports'] for p in ports: p_d = ports[p] if ('protocol' not in p_d): p_d['protocol'] = None p = int(p) po = None if (DPort.objects.filter(containerp=p, container=co).exists()): po = DPort.objects.get(containerp=p, container=co) po.hostp_default = p_d['host_default'] po.description = p_d['description'] po.protocol = p_d['protocol'] po.label = p_d['label'] else: #let's find next available default if default is already taken def_hostp = p_d['host_default'] while (True): if (DPort.objects.filter(hostp=def_hostp).exists()): def_hostp += 1 else: break po = DPort(description=p_d['description'], hostp=def_hostp, containerp=p, hostp_default=def_hostp, container=co, protocol=p_d['protocol'], label=p_d['label']) if ('ui' in p_d): po.uiport = p_d['ui'] if (po.uiport): ro.ui = True ro.save() po.save() ports = [int(p) for p in ports] for po in DPort.objects.filter(container=co): if (po.containerp not in ports): po.delete() v_d = {} if ('volumes' in c_d): v_d = c_d['volumes'] for v in v_d: cv_d = v_d[v] vo_defaults = {'description': cv_d['description'], 'label': cv_d['label']} vo, created = DVolume.objects.get_or_create(dest_dir=v, container=co, defaults=vo_defaults) if (not created): vo.description = vo_defaults['description'] vo.label = vo_defaults['label'] if ('min_size' in cv_d): vo.min_size = cv_d['min_size'] vo.save() for vo in DVolume.objects.filter(container=co): if (vo.dest_dir not in v_d): vo.delete() if ('opts' in containers[c]): options = containers[c]['opts'] id_l = [] for o in options: #there are no unique constraints on this model, so we need this bandaid. if (ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).count() > 1): ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).delete() oo, created = ContainerOption.objects.get_or_create(container=co, name=o[0], val=o[1]) id_l.append(oo.id) for oo in ContainerOption.objects.filter(container=co): if (oo.id not in id_l): oo.delete() if ('container_links' in r_d): l_d = r_d['container_links'] for cname in l_d: ll = l_d[cname] lsources = [l['source_container'] for l in ll] co = DContainer.objects.get(rockon=ro, name=cname) for clo in co.destination_container.all(): if (clo.name not in lsources): clo.delete() for cl_d in ll: sco = DContainer.objects.get(rockon=ro, name=cl_d['source_container']) clo, created = DContainerLink.objects.get_or_create(source=sco, destination=co) clo.name = cl_d['name'] clo.save() cc_d = {} if ('custom_config' in r_d): cc_d = r_d['custom_config'] for k in cc_d: ccc_d = cc_d[k] cco, created = DCustomConfig.objects.get_or_create( rockon=ro, key=k, defaults={'description': ccc_d['description'], 'label': ccc_d['label']}) if (not created): cco.description = ccc_d['description'] cco.label = ccc_d['label'] cco.save() for cco in DCustomConfig.objects.filter(rockon=ro): if (cco.key not in cc_d): cco.delete() return Response()
def post(self, request, rid, command): with self._handle_exception(request): if not docker_status(): e_msg = "Docker service is not running. Start it and try again." handle_exception(Exception(e_msg), request) try: rockon = RockOn.objects.get(id=rid) except: e_msg = "Rock-on ({}) does not exist.".format(rid) handle_exception(Exception(e_msg), request) try: dname = "ztask-daemon" e_msg = "ztask daemon is not running and could not be started." o, e, rc = superctl(dname, "status") if rc == 1: superctl(dname, "restart") time.sleep(5) except Exception as e: logger.exception(e) handle_exception(Exception(e_msg), request) finally: if rc == 1: o, e, rc = superctl(dname, "status") if rc == 1: handle_exception(Exception(e_msg), request) if command == "install": self._pending_check(request) share_map = request.data.get("shares", {}) port_map = request.data.get("ports", {}) dev_map = request.data.get("devices", {}) cc_map = request.data.get("cc", {}) env_map = request.data.get("environment", {}) containers = DContainer.objects.filter(rockon=rockon) for co in containers: for sname in share_map.keys(): dest_dir = share_map[sname] if not Share.objects.filter(name=sname).exists(): e_msg = "Invalid share ({}).".format(sname) handle_exception(Exception(e_msg), request) if DVolume.objects.filter( container=co, dest_dir=dest_dir ).exists(): so = Share.objects.get(name=sname) vo = DVolume.objects.get(container=co, dest_dir=dest_dir) vo.share = so vo.save() # {'host_port' : 'container_port', ... } for p in port_map.keys(): if DPort.objects.filter(hostp=p).exists(): dup_po = DPort.objects.get(hostp=p) if dup_po.container.rockon.id != rockon.id: if dup_po.container.rockon.state in ( "installed", "pending_install", ): # cannot claim from a rock-on that's # installed. conf_ro = dup_po.container.rockon.name e_msg = ( "Port ({}) belongs to another " "rock-on ({}). Choose a different " "port. If you must choose the same " "port, uninstall ({}) first and try " "again." ).format(p, conf_ro, conf_ro) handle_exception(Exception(e_msg), request) # change the host port to next available. dup_po.hostp = self._next_available_default_hostp( dup_po.hostp ) # noqa E501 dup_po.save() for co2 in DContainer.objects.filter(rockon=rockon): if DPort.objects.filter( container=co2, containerp=port_map[p] ).exists(): # found the container that needs this port. po = DPort.objects.get( container=co2, containerp=port_map[p] ) po.hostp = p po.save() break for d in dev_map.keys(): if not DContainerDevice.objects.filter( container=co, dev=d ).exists(): e_msg = ("Invalid device variable ({}).").format(d) handle_exception(Exception(e_msg), request) cdo = DContainerDevice.objects.get(container=co, dev=d) cdo.val = dev_map[d] cdo.save() for c in cc_map.keys(): if not DCustomConfig.objects.filter( rockon=rockon, key=c ).exists(): e_msg = "Invalid custom config key ({}).".format(c) handle_exception(Exception(e_msg), request) cco = DCustomConfig.objects.get(rockon=rockon, key=c) cco.val = cc_map[c] cco.save() for e in env_map.keys(): if not DContainerEnv.objects.filter( container=co, key=e ).exists(): e_msg = ("Invalid environment variable ({}).").format(e) handle_exception(Exception(e_msg), request) ceo = DContainerEnv.objects.get(container=co, key=e) ceo.val = env_map[e] ceo.save() install.async(rockon.id) rockon.state = "pending_install" rockon.save() elif command == "uninstall": self._pending_check(request) if rockon.state != "installed": e_msg = ( "Rock-on ({}) is not currently installed. Cannot " "uninstall it." ).format(rockon.name) handle_exception(Exception(e_msg), request) if rockon.status == "started" or rockon.status == "pending_start": e_msg = ( "Rock-on ({}) must be stopped before it can " "be uninstalled. Stop it and " "try again." ).format(rockon.name) handle_exception(Exception(e_msg), request) uninstall.async(rockon.id) rockon.state = "pending_uninstall" rockon.save() for co in DContainer.objects.filter(rockon=rockon): DVolume.objects.filter(container=co, uservol=True).delete() DContainerLabel.objects.filter(container=co).delete() elif command == "update": self._pending_check(request) if rockon.state != "installed": e_msg = ( "Rock-on ({}) is not currently installed. Cannot update it." ).format(rockon.name) handle_exception(Exception(e_msg), request) if rockon.status == "started" or rockon.status == "pending_start": e_msg = ( "Rock-on ({}) must be stopped before it can " "be updated. Stop it and " "try again." ).format(rockon.name) handle_exception(Exception(e_msg), request) share_map = request.data.get("shares") label_map = request.data.get("labels") if bool(share_map): for co in DContainer.objects.filter(rockon=rockon): for s in share_map.keys(): sname = share_map[s] if not Share.objects.filter(name=sname).exists(): e_msg = "Invalid share ({}).".format(sname) handle_exception(Exception(e_msg), request) so = Share.objects.get(name=sname) if DVolume.objects.filter(container=co, share=so).exists(): e_msg = ( "Share ({}) is already assigned to this rock-on." ).format(sname) handle_exception(Exception(e_msg), request) if DVolume.objects.filter( container=co, dest_dir=s ).exists(): e_msg = ( "Directory ({}) is already mapped for " "this rock-on." ).format(s) handle_exception(Exception(e_msg), request) if not s.startswith("/"): e_msg = ( "Invalid directory ({}). Must provide an " "absolute path. Eg: " "(/data/media)." ).format(s) handle_exception(Exception(e_msg), request) do = DVolume( container=co, share=so, uservol=True, dest_dir=s ) do.save() if bool(label_map): for co in DContainer.objects.filter(rockon=rockon): for c in label_map.keys(): cname = label_map[c] coname = co.name if cname != coname: continue lo = DContainerLabel(container=co, key=cname, val=c) lo.save() rockon.state = "pending_update" rockon.save() update.async(rockon.id) elif command == "stop": stop.async(rockon.id) rockon.status = "pending_stop" rockon.save() elif command == "start": start.async(rockon.id) rockon.status = "pending_start" rockon.save() elif command == "state_update": state = request.data.get("new_state") rockon.state = state rockon.save() elif command == "status_update": status = request.data.get("new_status") rockon.status = status rockon.save() return Response(RockOnSerializer(rockon).data)
def post(self, request, command=None): with self._handle_exception(request): if (not docker_status()): e_msg = ('Rock-on service is not running. Start it and try ' 'again') handle_exception(Exception(e_msg), request) if (command == 'update'): rockons = self._get_available(request) for r in rockons.keys(): name = r ro = None if (RockOn.objects.filter(name=name).exists()): ro = RockOn.objects.get(name=name) if (ro.state != 'available'): #don't update metadata if it's installed or in some pending state. continue ro.description = rockons[r]['description'] else: ro = RockOn(name=name, description=rockons[r]['description'], version='1.0', state='available', status='stopped') ro.save() containers = rockons[r]['containers'] for c in containers.keys(): io = None iname = containers[c]['image'] if (DImage.objects.filter(name=iname).exists()): io = DImage.objects.get(name=iname) else: io = DImage(name=iname, tag='latest', repo='foo') io.save() co = None if (DContainer.objects.filter(name=c).exists()): co = DContainer.objects.get(name=c) co.dimage = io co.rockon = ro else: co = DContainer(rockon=ro, dimage=io, name=c) co.save() if ('ports' in containers[c]): ports = containers[c]['ports'] for p in ports.keys(): po = None if (DPort.objects.filter(hostp=p).exists()): po = DPort.objects.get(hostp=p) po.container = co elif (DPort.objects.filter(containerp=p, container=co).exists()): po = DPort.objects.get(containerp=p, container=co) po.hostp = p else: po = DPort(hostp=p, containerp=p, container=co) if (ports[p] == 'ui'): po.uiport = True else: po.protocol = ports[p] po.save() if ('volumes' in containers[c]): volumes = containers[c]['volumes'] for v in volumes: if (not DVolume.objects.filter( dest_dir=v, container=co).exists()): vo = DVolume(container=co, dest_dir=v) vo.save() for vo in DVolume.objects.filter(container=co): if (vo.dest_dir not in volumes): vo.delete() if ('opts' in containers[c]): options = containers[c]['opts'] for o in options.keys(): if (not ContainerOption.objects.filter( container=co, name=options[o]).exists()): oo = ContainerOption(container=co, name=o, val=options[o]) oo.save() if ('custom_config' in rockons[r]): cc_d = rockons[r]['custom_config'] for k in cc_d: cco, created = DCustomConfig.objects.get_or_create( rockon=ro, key=k, defaults={'description': cc_d[k]}) if (not created): cco.description = cc_d[k] if (not created and k == 'iprange' and ro.name == 'Plex'): from storageadmin.models import NetworkInterface try: ni = NetworkInterface.objects.filter(itype='management')[0] cco.val = ('%s/255.255.255.0' % ni.ipaddr) except: pass cco.save() if ('app_link' in rockons[r]): app_link = rockons[r]['app_link'] if (ro.state != 'installed'): ro.link = app_link if ('website' in rockons[r]): ro.website = rockons[r]['website'] ro.save() return Response()
def post(self, request, command=None): with self._handle_exception(request): if (not docker_status()): e_msg = ('Rock-on service is not running. Start it and try ' 'again') handle_exception(Exception(e_msg), request) if (command == 'update'): rockons = self._get_available(request) for r in rockons: name = r r_d = rockons[r] ro_defaults = { 'description': r_d['description'], 'website': r_d['website'], 'version': '1.0', 'state': 'available', 'status': 'stopped' } ro, created = RockOn.objects.get_or_create( name=name, defaults=ro_defaults) if (not created): ro.description = ro_defaults['description'] ro.website = ro_defaults['website'] ro.version = ro_defaults['version'] if ('ui' in r_d): ui_d = r_d['ui'] ro.link = ui_d['slug'] if ('https' in ui_d): ro.https = ui_d['https'] if ('icon' in r_d): ro.icon = r_d['icon'] if ('volume_add_support' in r_d): ro.volume_add_support = r_d['volume_add_support'] if ('more_info' in r_d): ro.more_info = r_d['more_info'] ro.save() containers = r_d['containers'] for c in containers: c_d = containers[c] io, created = DImage.objects.get_or_create( name=c_d['image'], defaults={ 'tag': 'latest', 'repo': 'na' }) co_defaults = { 'rockon': ro, 'dimage': io, 'launch_order': c_d['launch_order'], } co, created = DContainer.objects.get_or_create( name=c, defaults=co_defaults) if (co.rockon.name != ro.name): e_msg = ('Container(%s) belongs to another ' 'Rock-On(%s). Update rolled back.' % (c, co.rockon.name)) handle_exception(Exception(e_msg), request) if (not created): co.dimage = io co.launch_order = co_defaults['launch_order'] co.save() ports = {} if ('ports' in containers[c]): ports = containers[c]['ports'] for p in ports: p_d = ports[p] if ('protocol' not in p_d): p_d['protocol'] = None p = int(p) po = None if (DPort.objects.filter( containerp=p, container=co).exists()): po = DPort.objects.get(containerp=p, container=co) po.hostp_default = p_d['host_default'] po.description = p_d['description'] po.protocol = p_d['protocol'] po.label = p_d['label'] else: #let's find next available default if default is already taken def_hostp = p_d['host_default'] while (True): if (DPort.objects.filter( hostp=def_hostp).exists()): def_hostp += 1 else: break po = DPort(description=p_d['description'], hostp=def_hostp, containerp=p, hostp_default=def_hostp, container=co, protocol=p_d['protocol'], label=p_d['label']) if ('ui' in p_d): po.uiport = p_d['ui'] if (po.uiport): ro.ui = True ro.save() po.save() ports = [int(p) for p in ports] for po in DPort.objects.filter(container=co): if (po.containerp not in ports): po.delete() v_d = {} if ('volumes' in c_d): v_d = c_d['volumes'] for v in v_d: cv_d = v_d[v] vo_defaults = { 'description': cv_d['description'], 'label': cv_d['label'] } vo, created = DVolume.objects.get_or_create( dest_dir=v, container=co, defaults=vo_defaults) if (not created): vo.description = vo_defaults['description'] vo.label = vo_defaults['label'] if ('min_size' in cv_d): vo.min_size = cv_d['min_size'] vo.save() for vo in DVolume.objects.filter(container=co): if (vo.dest_dir not in v_d): vo.delete() if ('opts' in containers[c]): options = containers[c]['opts'] id_l = [] for o in options: #there are no unique constraints on this model, so we need this bandaid. if (ContainerOption.objects.filter( container=co, name=o[0], val=o[1]).count() > 1): ContainerOption.objects.filter( container=co, name=o[0], val=o[1]).delete() oo, created = ContainerOption.objects.get_or_create( container=co, name=o[0], val=o[1]) id_l.append(oo.id) for oo in ContainerOption.objects.filter( container=co): if (oo.id not in id_l): oo.delete() if ('container_links' in r_d): l_d = r_d['container_links'] for cname in l_d: ll = l_d[cname] lsources = [l['source_container'] for l in ll] co = DContainer.objects.get(rockon=ro, name=cname) for clo in co.destination_container.all(): if (clo.name not in lsources): clo.delete() for cl_d in ll: sco = DContainer.objects.get( rockon=ro, name=cl_d['source_container']) clo, created = DContainerLink.objects.get_or_create( source=sco, destination=co) clo.name = cl_d['name'] clo.save() cc_d = {} if ('custom_config' in r_d): cc_d = r_d['custom_config'] for k in cc_d: ccc_d = cc_d[k] cco, created = DCustomConfig.objects.get_or_create( rockon=ro, key=k, defaults={ 'description': ccc_d['description'], 'label': ccc_d['label'] }) if (not created): cco.description = ccc_d['description'] cco.label = ccc_d['label'] cco.save() for cco in DCustomConfig.objects.filter(rockon=ro): if (cco.key not in cc_d): cco.delete() return Response()
def post(self, request, rid, command): with self._handle_exception(request): if (not docker_status()): e_msg = ('Docker service is not running. Start it and try ' 'again.') handle_exception(Exception(e_msg), request) try: rockon = RockOn.objects.get(id=rid) except: e_msg = ('Rock-on(%d) does not exist' % rid) handle_exception(Exception(e_msg), request) try: dname = 'ztask-daemon' e_msg = ('ztask daemon is not running and could not be ' 'started') o, e, rc = superctl(dname, 'status') if (rc == 1): superctl(dname, 'restart') time.sleep(5) except Exception as e: logger.exception(e) handle_exception(Exception(e_msg), request) finally: if (rc == 1): o, e, rc = superctl(dname, 'status') if (rc == 1): handle_exception(Exception(e_msg), request) if (command == 'install'): self._pending_check(request) share_map = request.data.get('shares', {}) port_map = request.data.get('ports', {}) cc_map = request.data.get('cc', {}) env_map = request.data.get('environment', {}) containers = DContainer.objects.filter(rockon=rockon) for co in containers: for sname in share_map.keys(): dest_dir = share_map[sname] if (not Share.objects.filter(name=sname).exists()): e_msg = ('Invalid Share(%s).' % sname) handle_exception(Exception(e_msg), request) if (DVolume.objects.filter( container=co, dest_dir=dest_dir).exists()): so = Share.objects.get(name=sname) vo = DVolume.objects.get(container=co, dest_dir=dest_dir) vo.share = so vo.save() # {'host_port' : 'container_port', ... } for p in port_map.keys(): if (DPort.objects.filter(hostp=p).exists()): dup_po = DPort.objects.get(hostp=p) if (dup_po.container.rockon.id != rockon.id): if (dup_po.container.rockon.state in ('installed', 'pending_install')): # cannot claim from a rock-on that's # installed. conf_ro = dup_po.container.rockon.name e_msg = ( 'Port(%s) belongs to another ' 'Rock-n(%s). Choose a different ' 'port. If you must choose the same ' 'port, uninstall %s first and try ' 'again.' % (p, conf_ro, conf_ro)) handle_exception(Exception(e_msg), request) # change the host port to next available. dup_po.hostp = self._next_available_default_hostp(dup_po.hostp) # noqa E501 dup_po.save() for co2 in DContainer.objects.filter(rockon=rockon): if (DPort.objects.filter( container=co2, containerp=port_map[p]).exists()): # found the container that needs this port. po = DPort.objects.get(container=co2, containerp=port_map[p]) po.hostp = p po.save() break for c in cc_map.keys(): if (not DCustomConfig.objects.filter( rockon=rockon, key=c).exists()): e_msg = ('Invalid custom config key(%s)' % c) handle_exception(Exception(e_msg), request) cco = DCustomConfig.objects.get(rockon=rockon, key=c) cco.val = cc_map[c] cco.save() for e in env_map.keys(): if (not DContainerEnv.objects.filter( container=co, key=e).exists()): e_msg = ('Invalid environment variabled(%s)' % e) handle_exception(Exception(e_msg), request) ceo = DContainerEnv.objects.get(container=co, key=e) ceo.val = env_map[e] ceo.save() install.async(rockon.id) rockon.state = 'pending_install' rockon.save() elif (command == 'uninstall'): self._pending_check(request) if (rockon.state != 'installed'): e_msg = ('Rock-on(%s) is not currently installed. Cannot ' 'uninstall it' % rockon.name) handle_exception(Exception(e_msg), request) if (rockon.status == 'started' or rockon.status == 'pending_start'): e_msg = ('Rock-on(%s) must be stopped before it can ' 'be uninstalled. Stop it and try again' % rockon.name) handle_exception(Exception(e_msg), request) uninstall.async(rockon.id) rockon.state = 'pending_uninstall' rockon.save() for co in DContainer.objects.filter(rockon=rockon): DVolume.objects.filter(container=co, uservol=True).delete() elif (command == 'update'): self._pending_check(request) if (rockon.state != 'installed'): e_msg = ('Rock-on(%s) is not currently installed. Cannot ' 'update it' % rockon.name) handle_exception(Exception(e_msg), request) if (rockon.status == 'started' or rockon.status == 'pending_start'): e_msg = ('Rock-on(%s) must be stopped before it can ' 'be updated. Stop it and try again' % rockon.name) handle_exception(Exception(e_msg), request) share_map = request.data.get('shares') for co in DContainer.objects.filter(rockon=rockon): for s in share_map.keys(): sname = share_map[s] if (not Share.objects.filter(name=sname).exists()): e_msg = ('Invalid Share(%s).' % sname) handle_exception(Exception(e_msg), request) so = Share.objects.get(name=sname) if (DVolume.objects.filter( container=co, share=so).exists()): e_msg = ('Share(%s) is already assigned to ' 'this Rock-on' % sname) handle_exception(Exception(e_msg), request) if (DVolume.objects.filter( container=co, dest_dir=s).exists()): e_msg = ('Directory(%s) is already mapped for ' 'this Rock-on' % s) handle_exception(Exception(e_msg), request) if (not s.startswith('/')): e_msg = ('Invalid Directory(%s). Must provide an ' 'absolute path. Eg: /data/media' % s) handle_exception(Exception(e_msg), request) do = DVolume(container=co, share=so, uservol=True, dest_dir=s) do.save() rockon.state = 'pending_update' rockon.save() update.async(rockon.id) elif (command == 'stop'): stop.async(rockon.id) rockon.status = 'pending_stop' rockon.save() elif (command == 'start'): start.async(rockon.id) rockon.status = 'pending_start' rockon.save() elif (command == 'state_update'): state = request.data.get('new_state') rockon.state = state rockon.save() elif (command == 'status_update'): status = request.data.get('new_status') rockon.status = status rockon.save() return Response(RockOnSerializer(rockon).data)